From 148b5b7d18c449b87b1103c05612ff2a2fe83233 Mon Sep 17 00:00:00 2001 From: Michal Minar Date: Wed, 28 Nov 2012 10:24:59 +0100 Subject: added pylintlmi checker for python source checking pylintlmi uses pylint (python source code checking utility) - giving it custom configuration for openlmi project and plugins with additional checks for usage see src/software/README renamed directory "src/software/providers" to "src/software/openlmi/software" * allows installation to custom PYTHONPATH together with openlmi-python egg * that also allows running pylint on sources in devel directory without messages like: W0403: 28,0: Relative import 'openlmi.software.core', should be 'openlmi.software.openlmi.software.core' E0611: 28,0: No name 'software' in module 'openlmi' F0401: 28,0: Unable to import 'openlmi.software.core' --- src/software/openlmi/__init__.py | 21 + .../openlmi/software/LMI_SoftwareFileCheck.py | 413 +++++++++++ .../software/LMI_SoftwareInstalledPackage.py | 509 +++++++++++++ .../openlmi/software/LMI_SoftwarePackage.py | 522 +++++++++++++ .../openlmi/software/LMI_SoftwarePackageChecks.py | 311 ++++++++ src/software/openlmi/software/__init__.py | 20 + src/software/openlmi/software/util/__init__.py | 20 + src/software/openlmi/software/util/common.py | 809 +++++++++++++++++++++ .../openlmi/software/util/singletonmixin.py | 508 +++++++++++++ src/software/providers | 1 + src/software/providers/LMI_SoftwareFileCheck.py | 413 ----------- .../providers/LMI_SoftwareInstalledPackage.py | 509 ------------- src/software/providers/LMI_SoftwarePackage.py | 522 ------------- .../providers/LMI_SoftwarePackageChecks.py | 311 -------- src/software/providers/__init__.py | 20 - src/software/providers/util/__init__.py | 20 - src/software/providers/util/common.py | 809 --------------------- src/software/providers/util/singletonmixin.py | 508 ------------- src/software/setup.py | 4 +- tools/pylint/README | 36 + tools/pylint/logilab-modutils-0.57.1.patch | 22 + tools/pylint/plugins/__init__.py | 20 + tools/pylint/plugins/cim_provider_checker.py | 149 ++++ tools/pylint/plugins/unittest_checker.py | 82 +++ tools/pylint/pylintlmi | 8 + tools/pylint/pylintrc | 249 +++++++ 26 files changed, 3702 insertions(+), 3114 deletions(-) create mode 100644 src/software/openlmi/__init__.py create mode 100644 src/software/openlmi/software/LMI_SoftwareFileCheck.py create mode 100644 src/software/openlmi/software/LMI_SoftwareInstalledPackage.py create mode 100644 src/software/openlmi/software/LMI_SoftwarePackage.py create mode 100644 src/software/openlmi/software/LMI_SoftwarePackageChecks.py create mode 100644 src/software/openlmi/software/__init__.py create mode 100644 src/software/openlmi/software/util/__init__.py create mode 100644 src/software/openlmi/software/util/common.py create mode 100644 src/software/openlmi/software/util/singletonmixin.py create mode 120000 src/software/providers delete mode 100644 src/software/providers/LMI_SoftwareFileCheck.py delete mode 100644 src/software/providers/LMI_SoftwareInstalledPackage.py delete mode 100644 src/software/providers/LMI_SoftwarePackage.py delete mode 100644 src/software/providers/LMI_SoftwarePackageChecks.py delete mode 100644 src/software/providers/__init__.py delete mode 100644 src/software/providers/util/__init__.py delete mode 100644 src/software/providers/util/common.py delete mode 100644 src/software/providers/util/singletonmixin.py create mode 100644 tools/pylint/README create mode 100644 tools/pylint/logilab-modutils-0.57.1.patch create mode 100644 tools/pylint/plugins/__init__.py create mode 100644 tools/pylint/plugins/cim_provider_checker.py create mode 100644 tools/pylint/plugins/unittest_checker.py create mode 100755 tools/pylint/pylintlmi create mode 100644 tools/pylint/pylintrc diff --git a/src/software/openlmi/__init__.py b/src/software/openlmi/__init__.py new file mode 100644 index 0000000..085d611 --- /dev/null +++ b/src/software/openlmi/__init__.py @@ -0,0 +1,21 @@ +# 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 +# +__import__('pkg_resources').declare_namespace(__name__) diff --git a/src/software/openlmi/software/LMI_SoftwareFileCheck.py b/src/software/openlmi/software/LMI_SoftwareFileCheck.py new file mode 100644 index 0000000..c667352 --- /dev/null +++ b/src/software/openlmi/software/LMI_SoftwareFileCheck.py @@ -0,0 +1,413 @@ +# 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 +# + +"""Python Provider for LMI_SoftwareFileCheck + +Instruments the CIM class LMI_SoftwareFileCheck + +""" + +import pywbem +from pywbem.cim_provider2 import CIMProvider2 +from openlmi.software.util.common import * + +filecheck2model = SoftwareFileCheck.filecheck_wrapper( + 'root/cimv2', 'LMI_SoftwareFileCheck') + +class LMI_SoftwareFileCheck(CIMProvider2): + """Instrument the CIM class LMI_SoftwareFileCheck + + Identifies a file contained by RPM package. It's located in directory + identified in FileName. The Invoke methods check for file existence + and whether its attributes match those given by RPM package. + + """ + + 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__) + + with YumDB.getInstance(env) as yb: + vpkg = SoftwareFileCheck.object_path2yumcheck(env, model.path) + pkg = vpkg.po + fi = pkg.hdr.fiFromHeader() + return filecheck2model(vpkg, model['Name'], env, False) + + 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__) + + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement + + 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__) + # TODO create or modify the instance + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement + return 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__) + + # TODO delete the resource + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement + + def cim_method_invoke(self, env, object_name): + """Implements LMI_SoftwareFileCheck.Invoke() + + The Invoke method evaluates this Check. The details of the + evaluation are described by the specific subclasses of CIM_Check. + When the SoftwareElement being checked is already installed, the + CIM_InstalledSoftwareElement association identifies the + CIM_ComputerSystem in whose context the Invoke is executed. If + this association is not in place, then the InvokeOnSystem method + should be used - since it identifies the TargetSystem as an input + parameter of the method. \nThe results of the Invoke method are + based on the return value. A zero is returned if the condition is + satisfied. A one is returned if the method is not supported. Any + other value indicates the condition is not satisfied. + + Keyword arguments: + env -- Provider Environment (pycimmb.ProviderEnvironment) + object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName + specifying the object on which the method Invoke() + should be invoked. + + Returns a two-tuple containing the return value (type pywbem.Uint32) + and a list of CIMParameter objects representing the output parameters + + Output parameters: none + + 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_invoke()' \ + % self.__class__.__name__) + + with YumDB.getInstance(env) as yb: + vpkg = SoftwareFileCheck.object_path2yumcheck(env, object_name) + fc = SoftwareFileCheck.test_file(env, + SoftwareFileCheck.pkg_checksum_type(vpkg.po), + vpkg._files[object_name["Name"]]) + out_params = [] + ret = 0 if SoftwareFileCheck.filecheck_passed(fc) else 2 + return (pywbem.Uint32(ret), out_params) + + def cim_method_invokeonsystem(self, env, object_name, + param_targetsystem=None): + """Implements LMI_SoftwareFileCheck.InvokeOnSystem() + + The InvokeOnSystem method evaluates this Check. The details of the + evaluation are described by the specific subclasses of CIM_Check. + The method\'s TargetSystem input parameter specifies the + ComputerSystem in whose context the method is invoked. \nThe + results of the InvokeOnSystem method are based on the return + value. A zero is returned if the condition is satisfied. A one is + returned if the method is not supported. Any other value indicates + the condition is not satisfied. + + Keyword arguments: + env -- Provider Environment (pycimmb.ProviderEnvironment) + object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName + specifying the object on which the method InvokeOnSystem() + should be invoked. + param_targetsystem -- The input parameter TargetSystem ( + type REF (pywbem.CIMInstanceName( + classname='CIM_ComputerSystem', ...)) + Reference to ComputerSystem in whose context the method is to + be invoked. + + + Returns a two-tuple containing the return value (type pywbem.Uint32) + and a list of CIMParameter objects representing the output parameters + + Output parameters: none + + 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_invokeonsystem()' \ + % self.__class__.__name__) + + # TODO do something + raise pywbem.CIMError(pywbem.CIM_ERR_METHOD_NOT_AVAILABLE) # Remove to implemented + out_params = [] + #rval = # TODO (type pywbem.Uint32) + return (rval, out_params) + + class Values(object): + class TargetOperatingSystem(object): + Unknown = pywbem.Uint16(0) + Other = pywbem.Uint16(1) + MACOS = pywbem.Uint16(2) + ATTUNIX = pywbem.Uint16(3) + DGUX = pywbem.Uint16(4) + DECNT = pywbem.Uint16(5) + Tru64_UNIX = pywbem.Uint16(6) + OpenVMS = pywbem.Uint16(7) + HPUX = pywbem.Uint16(8) + AIX = pywbem.Uint16(9) + MVS = pywbem.Uint16(10) + OS400 = pywbem.Uint16(11) + OS_2 = pywbem.Uint16(12) + JavaVM = pywbem.Uint16(13) + MSDOS = pywbem.Uint16(14) + WIN3x = pywbem.Uint16(15) + WIN95 = pywbem.Uint16(16) + WIN98 = pywbem.Uint16(17) + WINNT = pywbem.Uint16(18) + WINCE = pywbem.Uint16(19) + NCR3000 = pywbem.Uint16(20) + NetWare = pywbem.Uint16(21) + OSF = pywbem.Uint16(22) + DC_OS = pywbem.Uint16(23) + Reliant_UNIX = pywbem.Uint16(24) + SCO_UnixWare = pywbem.Uint16(25) + SCO_OpenServer = pywbem.Uint16(26) + Sequent = pywbem.Uint16(27) + IRIX = pywbem.Uint16(28) + Solaris = pywbem.Uint16(29) + SunOS = pywbem.Uint16(30) + U6000 = pywbem.Uint16(31) + ASERIES = pywbem.Uint16(32) + HP_NonStop_OS = pywbem.Uint16(33) + HP_NonStop_OSS = pywbem.Uint16(34) + BS2000 = pywbem.Uint16(35) + LINUX = pywbem.Uint16(36) + Lynx = pywbem.Uint16(37) + XENIX = pywbem.Uint16(38) + VM = pywbem.Uint16(39) + Interactive_UNIX = pywbem.Uint16(40) + BSDUNIX = pywbem.Uint16(41) + FreeBSD = pywbem.Uint16(42) + NetBSD = pywbem.Uint16(43) + GNU_Hurd = pywbem.Uint16(44) + OS9 = pywbem.Uint16(45) + MACH_Kernel = pywbem.Uint16(46) + Inferno = pywbem.Uint16(47) + QNX = pywbem.Uint16(48) + EPOC = pywbem.Uint16(49) + IxWorks = pywbem.Uint16(50) + VxWorks = pywbem.Uint16(51) + MiNT = pywbem.Uint16(52) + BeOS = pywbem.Uint16(53) + HP_MPE = pywbem.Uint16(54) + NextStep = pywbem.Uint16(55) + PalmPilot = pywbem.Uint16(56) + Rhapsody = pywbem.Uint16(57) + Windows_2000 = pywbem.Uint16(58) + Dedicated = pywbem.Uint16(59) + OS_390 = pywbem.Uint16(60) + VSE = pywbem.Uint16(61) + TPF = pywbem.Uint16(62) + Windows__R__Me = pywbem.Uint16(63) + Caldera_Open_UNIX = pywbem.Uint16(64) + OpenBSD = pywbem.Uint16(65) + Not_Applicable = pywbem.Uint16(66) + Windows_XP = pywbem.Uint16(67) + z_OS = pywbem.Uint16(68) + Microsoft_Windows_Server_2003 = pywbem.Uint16(69) + Microsoft_Windows_Server_2003_64_Bit = pywbem.Uint16(70) + Windows_XP_64_Bit = pywbem.Uint16(71) + Windows_XP_Embedded = pywbem.Uint16(72) + Windows_Vista = pywbem.Uint16(73) + Windows_Vista_64_Bit = pywbem.Uint16(74) + Windows_Embedded_for_Point_of_Service = pywbem.Uint16(75) + Microsoft_Windows_Server_2008 = pywbem.Uint16(76) + Microsoft_Windows_Server_2008_64_Bit = pywbem.Uint16(77) + FreeBSD_64_Bit = pywbem.Uint16(78) + RedHat_Enterprise_Linux = pywbem.Uint16(79) + RedHat_Enterprise_Linux_64_Bit = pywbem.Uint16(80) + Solaris_64_Bit = pywbem.Uint16(81) + SUSE = pywbem.Uint16(82) + SUSE_64_Bit = pywbem.Uint16(83) + SLES = pywbem.Uint16(84) + SLES_64_Bit = pywbem.Uint16(85) + Novell_OES = pywbem.Uint16(86) + Novell_Linux_Desktop = pywbem.Uint16(87) + Sun_Java_Desktop_System = pywbem.Uint16(88) + Mandriva = pywbem.Uint16(89) + Mandriva_64_Bit = pywbem.Uint16(90) + TurboLinux = pywbem.Uint16(91) + TurboLinux_64_Bit = pywbem.Uint16(92) + Ubuntu = pywbem.Uint16(93) + Ubuntu_64_Bit = pywbem.Uint16(94) + Debian = pywbem.Uint16(95) + Debian_64_Bit = pywbem.Uint16(96) + Linux_2_4_x = pywbem.Uint16(97) + Linux_2_4_x_64_Bit = pywbem.Uint16(98) + Linux_2_6_x = pywbem.Uint16(99) + Linux_2_6_x_64_Bit = pywbem.Uint16(100) + Linux_64_Bit = pywbem.Uint16(101) + Other_64_Bit = pywbem.Uint16(102) + Microsoft_Windows_Server_2008_R2 = pywbem.Uint16(103) + VMware_ESXi = pywbem.Uint16(104) + Microsoft_Windows_7 = pywbem.Uint16(105) + CentOS_32_bit = pywbem.Uint16(106) + CentOS_64_bit = pywbem.Uint16(107) + Oracle_Enterprise_Linux_32_bit = pywbem.Uint16(108) + Oracle_Enterprise_Linux_64_bit = pywbem.Uint16(109) + eComStation_32_bitx = pywbem.Uint16(110) + + class SoftwareElementState(object): + Deployable = pywbem.Uint16(0) + Installable = pywbem.Uint16(1) + Executable = pywbem.Uint16(2) + Running = pywbem.Uint16(3) + + class FileType(object): + Unknown = pywbem.Uint16(0) + File = pywbem.Uint16(1) + Directory = pywbem.Uint16(2) + Symlink = pywbem.Uint16(3) + FIFO = pywbem.Uint16(4) + Character_Device = pywbem.Uint16(5) + Block_Device = pywbem.Uint16(6) + +## end of class LMI_SoftwareFileCheckProvider + +## get_providers() for associating CIM Class Name to python provider class name + +def get_providers(env): + lmi_softwarefilecheck_prov = LMI_SoftwareFileCheck(env) + return {'LMI_SoftwareFileCheck': lmi_softwarefilecheck_prov} 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 +# + +"""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} diff --git a/src/software/openlmi/software/LMI_SoftwarePackage.py b/src/software/openlmi/software/LMI_SoftwarePackage.py new file mode 100644 index 0000000..2395dca --- /dev/null +++ b/src/software/openlmi/software/LMI_SoftwarePackage.py @@ -0,0 +1,522 @@ +# -*- 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 +# + +"""Python Provider for LMI_SoftwarePackage + +Instruments the CIM class LMI_SoftwarePackage + +""" + +import itertools +import datetime +import pywbem +from pywbem.cim_provider2 import CIMProvider2 +from openlmi.software.util.common import * + +pkg2model = SoftwarePackage.pkg2model_wrapper('root/cimv2', "LMI_SoftwarePackage") + +class LMI_SoftwarePackage(CIMProvider2): + """Instrument the CIM class LMI_SoftwarePackage + + RPM package installed on particular computer system with YUM (The + Yellowdog Updated, Modified) package manager. + + """ + + 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__) + + with YumDB.getInstance(env): + pkg = SoftwarePackage.object_path2pkg(env, model.path, 'all') + return pkg2model(env, pkg, keys_only=False, model=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({'TargetOperatingSystem': None, 'Version': None, + 'SoftwareElementState': None, 'Name': None, + 'SoftwareElementID': None}) + + with YumDB.getInstance(env) as yb: + # get all packages + pl = yb.doPackageLists('all', showdups=True) + pl = itertools.chain(pl.installed, pl.available) + # NOTE: available ∩ installed = ∅ + for pkg in sorted(pl, key=lambda a:a.evra): + yield pkg2model(env, pkg, keys_only, model) + + 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__) + # TODO create or modify the instance + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement + return 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__) + + # TODO delete the resource + # Remove to implement + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) + + def cim_method_install(self, env, object_name): + """Implements LMI_SoftwarePackage.Install() + + Will install available package. + + 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. + + Returns a two-tuple containing the return value (type pywbem.Uint32 self.Values.Install) + 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. Null otherwise. + + 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_install()' \ + % self.__class__.__name__) + + with YumDB.getInstance(env) as yb: + # get available packages + pkg = SoftwarePackage.object_path2pkg_search(env, object_name) + out_params = [ pywbem.CIMParameter('Installed', type='reference') ] + if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): + out_params[0].value = pkg2model(env, pkg, True) + return (self.Values.Install.Already_installed, out_params) + + logger.log_info('installing package {}'.format(pkg.nevra)) + # install + yb.install(pkg) + yb.buildTransaction() + yb.processTransaction() + logger.log_info('package installed'.format(pkg.nevra)) + + out_params[0].value = pkg2model(env, pkg, True, object_name) + out_params[0].value['SoftwareElementState'] = \ + self.Values.SoftwareElementState.Executable + return (self.Values.Install.Successful_installation, out_params) + + def cim_method_remove(self, env, object_name): + """Implements LMI_SoftwarePackage.Remove() + + Will uninstall installed package. + + Keyword arguments: + env -- Provider Environment (pycimmb.ProviderEnvironment) + object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName + specifying the object on which the method Remove() + should be invoked. + + Returns a two-tuple containing the return value (type pywbem.Uint32 self.Values.Remove) + and a list of CIMParameter objects representing the output parameters + + Output parameters: none + + 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_remove()' \ + % self.__class__.__name__) + + with YumDB.getInstance(env) as yb: + pkg = SoftwarePackage.object_path2pkg(env, object_name, 'all') + if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): + logger.log_info('removing package "%s"' % pkg.nevra) + yb.remove(pkg) + yb.buildTransaction() + yb.processTransaction() + logger.log_info('package "%s" removed' % pkg.nevra) + rval = self.Values.Remove.Successful_removal + else: + rval = self.Values.Remove.Not_installed + #rval = # TODO (type pywbem.Uint32 self.Values.Remove) + return (rval, []) + + 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.. + + 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 + + class TargetOperatingSystem(object): + Unknown = pywbem.Uint16(0) + Other = pywbem.Uint16(1) + MACOS = pywbem.Uint16(2) + ATTUNIX = pywbem.Uint16(3) + DGUX = pywbem.Uint16(4) + DECNT = pywbem.Uint16(5) + Tru64_UNIX = pywbem.Uint16(6) + OpenVMS = pywbem.Uint16(7) + HPUX = pywbem.Uint16(8) + AIX = pywbem.Uint16(9) + MVS = pywbem.Uint16(10) + OS400 = pywbem.Uint16(11) + OS_2 = pywbem.Uint16(12) + JavaVM = pywbem.Uint16(13) + MSDOS = pywbem.Uint16(14) + WIN3x = pywbem.Uint16(15) + WIN95 = pywbem.Uint16(16) + WIN98 = pywbem.Uint16(17) + WINNT = pywbem.Uint16(18) + WINCE = pywbem.Uint16(19) + NCR3000 = pywbem.Uint16(20) + NetWare = pywbem.Uint16(21) + OSF = pywbem.Uint16(22) + DC_OS = pywbem.Uint16(23) + Reliant_UNIX = pywbem.Uint16(24) + SCO_UnixWare = pywbem.Uint16(25) + SCO_OpenServer = pywbem.Uint16(26) + Sequent = pywbem.Uint16(27) + IRIX = pywbem.Uint16(28) + Solaris = pywbem.Uint16(29) + SunOS = pywbem.Uint16(30) + U6000 = pywbem.Uint16(31) + ASERIES = pywbem.Uint16(32) + HP_NonStop_OS = pywbem.Uint16(33) + HP_NonStop_OSS = pywbem.Uint16(34) + BS2000 = pywbem.Uint16(35) + LINUX = pywbem.Uint16(36) + Lynx = pywbem.Uint16(37) + XENIX = pywbem.Uint16(38) + VM = pywbem.Uint16(39) + Interactive_UNIX = pywbem.Uint16(40) + BSDUNIX = pywbem.Uint16(41) + FreeBSD = pywbem.Uint16(42) + NetBSD = pywbem.Uint16(43) + GNU_Hurd = pywbem.Uint16(44) + OS9 = pywbem.Uint16(45) + MACH_Kernel = pywbem.Uint16(46) + Inferno = pywbem.Uint16(47) + QNX = pywbem.Uint16(48) + EPOC = pywbem.Uint16(49) + IxWorks = pywbem.Uint16(50) + VxWorks = pywbem.Uint16(51) + MiNT = pywbem.Uint16(52) + BeOS = pywbem.Uint16(53) + HP_MPE = pywbem.Uint16(54) + NextStep = pywbem.Uint16(55) + PalmPilot = pywbem.Uint16(56) + Rhapsody = pywbem.Uint16(57) + Windows_2000 = pywbem.Uint16(58) + Dedicated = pywbem.Uint16(59) + OS_390 = pywbem.Uint16(60) + VSE = pywbem.Uint16(61) + TPF = pywbem.Uint16(62) + Windows__R__Me = pywbem.Uint16(63) + Caldera_Open_UNIX = pywbem.Uint16(64) + OpenBSD = pywbem.Uint16(65) + Not_Applicable = pywbem.Uint16(66) + Windows_XP = pywbem.Uint16(67) + z_OS = pywbem.Uint16(68) + Microsoft_Windows_Server_2003 = pywbem.Uint16(69) + Microsoft_Windows_Server_2003_64_Bit = pywbem.Uint16(70) + Windows_XP_64_Bit = pywbem.Uint16(71) + Windows_XP_Embedded = pywbem.Uint16(72) + Windows_Vista = pywbem.Uint16(73) + Windows_Vista_64_Bit = pywbem.Uint16(74) + Windows_Embedded_for_Point_of_Service = pywbem.Uint16(75) + Microsoft_Windows_Server_2008 = pywbem.Uint16(76) + Microsoft_Windows_Server_2008_64_Bit = pywbem.Uint16(77) + FreeBSD_64_Bit = pywbem.Uint16(78) + RedHat_Enterprise_Linux = pywbem.Uint16(79) + RedHat_Enterprise_Linux_64_Bit = pywbem.Uint16(80) + Solaris_64_Bit = pywbem.Uint16(81) + SUSE = pywbem.Uint16(82) + SUSE_64_Bit = pywbem.Uint16(83) + SLES = pywbem.Uint16(84) + SLES_64_Bit = pywbem.Uint16(85) + Novell_OES = pywbem.Uint16(86) + Novell_Linux_Desktop = pywbem.Uint16(87) + Sun_Java_Desktop_System = pywbem.Uint16(88) + Mandriva = pywbem.Uint16(89) + Mandriva_64_Bit = pywbem.Uint16(90) + TurboLinux = pywbem.Uint16(91) + TurboLinux_64_Bit = pywbem.Uint16(92) + Ubuntu = pywbem.Uint16(93) + Ubuntu_64_Bit = pywbem.Uint16(94) + Debian = pywbem.Uint16(95) + Debian_64_Bit = pywbem.Uint16(96) + Linux_2_4_x = pywbem.Uint16(97) + Linux_2_4_x_64_Bit = pywbem.Uint16(98) + Linux_2_6_x = pywbem.Uint16(99) + Linux_2_6_x_64_Bit = pywbem.Uint16(100) + Linux_64_Bit = pywbem.Uint16(101) + Other_64_Bit = pywbem.Uint16(102) + Microsoft_Windows_Server_2008_R2 = pywbem.Uint16(103) + VMware_ESXi = pywbem.Uint16(104) + Microsoft_Windows_7 = pywbem.Uint16(105) + CentOS_32_bit = pywbem.Uint16(106) + CentOS_64_bit = pywbem.Uint16(107) + Oracle_Enterprise_Linux_32_bit = pywbem.Uint16(108) + Oracle_Enterprise_Linux_64_bit = pywbem.Uint16(109) + eComStation_32_bitx = pywbem.Uint16(110) + + class Remove(object): + Not_installed = pywbem.Uint32(0) + Successful_removal = pywbem.Uint32(1) + Failed = pywbem.Uint32(2) + + 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.. + + 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.. + + 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.. + + class SoftwareElementState(object): + Deployable = pywbem.Uint16(0) + Installable = pywbem.Uint16(1) + Executable = pywbem.Uint16(2) + Running = pywbem.Uint16(3) + + class PrimaryStatus(object): + Unknown = pywbem.Uint16(0) + OK = pywbem.Uint16(1) + Degraded = pywbem.Uint16(2) + Error = pywbem.Uint16(3) + # DMTF_Reserved = .. + # Vendor_Reserved = 0x8000.. + + class Install(object): + Already_installed = pywbem.Uint32(0) + Successful_installation = pywbem.Uint32(1) + Failed = pywbem.Uint32(2) + +## end of class LMI_SoftwarePackage + +## get_providers() for associating CIM Class Name to python provider class name + +def get_providers(env): + lmi_softwarepackage_prov = LMI_SoftwarePackage(env) + return {'LMI_SoftwarePackage': lmi_softwarepackage_prov} diff --git a/src/software/openlmi/software/LMI_SoftwarePackageChecks.py b/src/software/openlmi/software/LMI_SoftwarePackageChecks.py new file mode 100644 index 0000000..a2f798b --- /dev/null +++ b/src/software/openlmi/software/LMI_SoftwarePackageChecks.py @@ -0,0 +1,311 @@ +# 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 +# + +"""Python Provider for LMI_SoftwarePackageChecks + +Instruments the CIM class LMI_SoftwarePackageChecks + +""" + +import pywbem +from pywbem.cim_provider2 import CIMProvider2 +from openlmi.software.LMI_SoftwareFileCheck import filecheck2model +from openlmi.software.LMI_SoftwarePackage import pkg2model +from openlmi.software.util.common import * + +class LMI_SoftwarePackageChecks(CIMProvider2): + """Instrument the CIM class LMI_SoftwarePackageChecks + + This association ties a SoftwareElement to a specific Check to validate + its state or its movement to the next state. Note that + SoftwareElements in a running state cannot transition to another + state. Therefore, the value of the Phase property is restricted to 0 + ("In-State") for SoftwareElements in the running state. + + """ + + 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 "Check" in model: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Missing Check property.") + if not "Element" in model: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Missing Element property.") + vpkg = SoftwareFileCheck.object_path2yumcheck(env, model['Check']) + model['Check'] = filecheck2model(vpkg, model['Check']['Name'], + env, keys_only=True) + model['Element'] = pkg2model(env, vpkg.po, keys_only=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({'Check': None, 'Element': None}) + + while False: # TODO more instances? + # TODO fetch system resource + # Key properties + #model['Check'] = pywbem.CIMInstanceName(classname='LMI_SoftwareFileCheck', ...) # TODO (type = REF (pywbem.CIMInstanceName(classname='LMI_SoftwareFileCheck', ...)) + #model['Element'] = pywbem.CIMInstanceName(classname='LMI_SoftwarePackage', ...) # TODO (type = REF (pywbem.CIMInstanceName(classname='LMI_SoftwarePackage', ...)) + 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__) + # TODO create or modify the instance + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement + return 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__) + + # TODO delete the resource + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement + + 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() + + # 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({'Check': None, 'Element': None}) + + with YumDB.getInstance(env): + if ( (not role or role.lower() == 'element') + and ch.is_subclass(object_name.namespace, + sub=object_name.classname, + super='LMI_SoftwarePackage')): + filecheck_model = pywbem.CIMInstanceName( + classname='LMI_SoftwareFileCheck', + namespace="root/cimv2", + host=model.path.host) + model['Element'] = object_name + + pkg = SoftwarePackage.object_path2pkg(env, object_name) + vpkg = yum.packages._RPMVerifyPackage( + pkg, pkg.hdr.fiFromHeader(), + SoftwareFileCheck.pkg_checksum_type(pkg), [], True) + for fc in vpkg: + model['Check'] = filecheck2model( + vpkg, fc.filename, env, keys_only=True, + model=filecheck_model) + yield model + + if ( (not role or role.lower() == 'check') + and ch.is_subclass(object_name.namespace, + sub=object_name.classname, + super='LMI_SoftwareFileCheck')): + model['Check'] = object_name + + vpkg = SoftwareFileCheck.object_path2yumcheck(env, object_name) + model['Element'] = pkg2model( + env, vpkg.po, keys_only=True) + yield model + + class Values(object): + class Phase(object): + In_State = pywbem.Uint16(0) + Next_State = pywbem.Uint16(1) + +## end of class LMI_SoftwarePackageChecksProvider + +## get_providers() for associating CIM Class Name to python provider class name + +def get_providers(env): + lmi_softwarepackagechecks_prov = LMI_SoftwarePackageChecks(env) + return {'LMI_SoftwarePackageChecks': lmi_softwarepackagechecks_prov} diff --git a/src/software/openlmi/software/__init__.py b/src/software/openlmi/software/__init__.py new file mode 100644 index 0000000..2ebe827 --- /dev/null +++ b/src/software/openlmi/software/__init__.py @@ -0,0 +1,20 @@ +# 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 +# diff --git a/src/software/openlmi/software/util/__init__.py b/src/software/openlmi/software/util/__init__.py new file mode 100644 index 0000000..2ebe827 --- /dev/null +++ b/src/software/openlmi/software/util/__init__.py @@ -0,0 +1,20 @@ +# 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 +# diff --git a/src/software/openlmi/software/util/common.py b/src/software/openlmi/software/util/common.py new file mode 100644 index 0000000..7b54f1e --- /dev/null +++ b/src/software/openlmi/software/util/common.py @@ -0,0 +1,809 @@ +# -*- 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 +# + +"""Common utilities for LMI_Software* providers +""" + +import collections +from datetime import datetime +import grp +import hashlib +import itertools +import os +import platform +import pwd +import re +import rpm +import socket +import stat +import pywbem +import yum +import cmpi_pywbem_bindings as pycimmb +from openlmi.software.util import singletonmixin + +re_evra = re.compile(r'^(?P\d+):(?P[^-]+)' + r'-(?P.+)\.(?P[^.]+)$') +re_nevra = re.compile(r'^(?P.+)-(?P((?P\d+):)?(?P[^-]+)' + r'-(?P.+)\.(?P[^.]+))$') + +rpmdb_path = '/var/lib/rpm/Packages' + +class YumDB(singletonmixin.Singleton): + + ignoreSubsequent = True + + def __init__(self, env, *args, **kwargs): + if not isinstance(env, pycimmb.ProviderEnvironment): + raise TypeError("env must be instance of" + " pycimmb.ProviderEnvironment") + self._yum_args = (args, kwargs) + self._yum = None + self._db_mtime = 0 + self._lock_cnt = 0 + self.env = env + env.get_logger().log_info('init called') + + def is_dirty(self): + return self._db_mtime < os.stat(rpmdb_path).st_mtime + + def is_locked(self): + return self._yum._lockfile is not None + + def update_db(self): + self.env.get_logger().log_info('updating rpmdb') + self._db_mtime = os.stat(rpmdb_path).st_mtime + self._yum.doConfigSetup() + self._yum.doTsSetup() + self._yum.doRpmDBSetup() + + def __enter__(self): + self._lock_cnt += 1 + if self._lock_cnt < 2: + self._yum = yum.YumBase(*self._yum_args[0], **self._yum_args[1]) + if not self.is_locked() and self.is_dirty(): + self.update_db() + self._yum.doLock() + return self + + def __exit__(self, exc_type, exc_value, traceback): + if self._lock_cnt == 1: + del self._yum + self._lock_cnt -= 1 + + def __getattr__(self, name): + if not self.is_locked() and self.is_dirty(): + self.update_db() + return getattr(self._yum, name) + + +def _get_distname(): + if hasattr(platform, 'linux_distribution'): + return platform.linux_distribution( + full_distribution_name=False)[0].lower() + else: + return platform.dist()[0].lower() + + +def get_target_operating_system(): + """ + @return (val, text). + Where val is a number from ValueMap of TargetOperatingSystem property + of CIM_SoftwareElement class and text is its testual representation. + """ + + system = platform.system() + if system.lower() == 'linux': + try: + val, dist = \ + { 'redhat' : (79, 'RedHat Enterprise Linux') + , 'suse' : (81, 'SUSE') + , 'mandriva' : (88, 'Mandriva') + , 'ubuntu' : (93, 'Ubuntu') + , 'debian' : (95, 'Debian') + }[_get_distname()] + except KeyError: + linrel = platform.uname()[2] + if linrel.startswith('2.4'): + val, dist = (97, 'Linux 2.4.x') + elif linrel.startswith('2.6'): + val, dist = (99, 'Linux 2.6.x') + else: + return (36, 'LINUX') # no check for x86_64 + if platform.machine() == 'x86_64': + val += 1 + dist += ' 64-Bit' + return (val, dist) + elif system.lower() in ('macosx', 'darwin'): + return (2, 'MACOS') + # elif system.lower() == 'windows': # no general value + else: + return (0, 'Unknown') + +def get_computer_system_op(): + return pywbem.CIMInstanceName( + classname='CIM_ComputerSystem', + keybindings={ + "CreationClassName": "CIM_ComputerSystem" + , "Name" : socket.gethostname() }, + namespace="root/cimv2") + +def check_target_operating_system(system): + """ + @return if param system matches current target operating system + """ + if isinstance(system, basestring): + system = int(system) + if not isinstance(system, (int, long)): + raise TypeError("system must be either string or integer, not {}" + .format(system.__class__.__name__)) + tos = get_target_operating_system() + if system == tos: return True + if system == 36: # linux + if platform.system().lower() == "linux": return True + if ( system >= 97 and system <= 100 # linux 2.x.x + and platform.uname()[2].startswith('2.4' if system < 99 else '2.6') + # check machine + and ( bool(platform.machine().endswith('64')) + == bool(not (system % 2)))): + return True + return False + +def check_computer_system_op(env, system): + if not isinstance(system, pywbem.CIMInstanceName): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "\"System\" must be a CIMInstanceName") + our_system = get_computer_system_op() + ch = env.get_cimom_handle() + if not ch.is_subclass(system.namespace, + sub=system.classname, + super=our_system.classname): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Class of \"System\" must be a sublass of %s" % + our_system.classname) + if not 'CreationClassName' in system or not 'Name' in system: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "\"System\" is missing one of keys") + if not ch.is_subclass(system.namespace, + sub=system['CreationClassName'], + super=our_system.classname): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "CreationClassName of \"System\" must be a sublass of %s" % + our_system.classname) + if system['Name'] != our_system['Name']: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Name of \"System\" does not match \"%s\"" % + our_system['Name']) + return True + + +def match_pkg(pkg, **kwargs): + """ + all not Null and not empty arguments will be matched against pkg + attributes; if all of them match, return True + + possible arguments: + name, epoch, version, release, arch + evra, nevra + """ + for a in ('evra', 'nevra', 'name', 'epoch', 'version', 'release', 'arch'): + v = kwargs.get(a, None) + if v and getattr(pkg, a) != v: + return False + return True + +class SoftwarePackage: + """ + Just a namespace for common function related to SoftwarePackage provider. + """ + + @staticmethod + def parse_group(group, env): + try: + res = \ + { "amusements/games" : 3 + , "amusements/graphics" : 4 + , "applications/archiving" : 5 + , "applications/communications" : 6 + , "applications/databases" : 7 + , "applications/editors" : 8 + , "applications/emulators" : 9 + , "applications/engineering" : 10 + , "applications/file" : 11 + , "applications/internet" : 12 + , "applications/multimedia" : 13 + , "applications/productivity" : 14 + , "applications/publishing" : 15 + , "applications/system" : 16 + , "applications/text" : 17 + , "development/build tools" : 18 + , "development/debug" : 19 + , "development/debuggers" : 20 + , "development/documentation" : 21 + , "development/java" : 22 + , "development/languages" : 23 + , "development/libraries" : 24 + , "development/libraries/java" : 25 + , "development/system" : 26 + , "development/tools" : 27 + , "documentation" : 28 + , "internet/www/dynamic content" : 29 + , "system/libraries" : 30 + , "system environment/base" : 31 + , "system environment/daemons" : 32 + , "system environment/kernel" : 33 + , "system environment/libraries" : 34 + , "system environment/shells" : 35 + , "text processing/markup/xml" : 36 + , "user interface/desktops" : 37 + , "user interface/x" : 38 + , "user interface/x hardware support" : 39 + , "utilities" : 40 + }[group.lower()] + except KeyError: + logger = env.get_logger() + if not group or group.lower() == "unspecified": + logger.log_info("unspecified group '{}'".format(group)) + res = 2 + else: + logger.log_error("failed to parse group '{}'".format(group)) + res = 0 + return pywbem.Uint16(res) + + @staticmethod + def object_path2pkg(env, op, package_list='installed'): + """ + @param op must contain precise information of package, + otherwise a CIM_ERR_NOT_FOUND error is raised + @param package_list one of {'installed', 'all', 'available'} + says, where to look for given package + """ + if not isinstance(op, pywbem.CIMInstanceName): + raise TypeError("op must be an instance of CIMInstanceName") + if not isinstance(package_list, basestring): + raise TypeError("package_list must be a string") + if not package_list in ('installed', 'all', 'available'): + raise ValueError('unsupported package list "%s"'%package_list) + + tos = get_target_operating_system()[0] + if ( not op['Name'] or not op['SoftwareElementID'] + or not op['SoftwareElementID'].startswith(op['Name']) + or op['SoftwareElementID'].find(op['Version']) == -1): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "Wrong keys.") +# if op['SoftwareElementState'] not in ("2", 2): +# raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, +# "Only \"Executable\" software element state supported") + if not check_target_operating_system(op['TargetOperatingSystem']): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Wrong target operating system.") + if not op['Name'] or not op['Version']: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + 'Both "Name" and "Version" must be given') + m = re_nevra.match(op['SoftwareElementID']) + if not m: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Wrong SotwareElementID. Expected valid nevra" + " (name-[epoch:]version-release.arch).") + if op['Version'] != m.group('ver'): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Version does not match version part in SoftwareElementID.") + evra = "{}:{}-{}.{}".format(*( + (m.group(k) if k != "epoch" or m.group(k) else "0") + for k in ("epoch", 'ver', 'rel', 'arch'))) + with YumDB.getInstance(env) as yb: + pl = yb.doPackageLists(package_list, + showdups=package_list != 'installed') + if package_list != 'all': + pl = getattr(pl, package_list) + else: + # NOTE: available ∩ installed = ∅ + pl = itertools.chain(pl.available, pl.installed) + exact,_,_ = yum.packages.parsePackages(pl, [op['Name']]) + for pkg in yum.misc.unique(exact): + if pkg.evra == evra: break + else: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "No matching package found.") + return pkg + + @staticmethod + def object_path2pkg_search(env, op): + """ + similar to object_path2pkg, but tries to find best suitable + package matching keys + + If any matching package is already installed, it is returned. + Otherwise available package with highest version is returned. + + @param op may be object of CIMInstance or CIMInstanceName and + must contain at least \"Name\" or \"SoftwareElementID\" + @return instance of yum.rpmsack.RPMInstalledPackage in case of + installed package, otherwise yum.packages.YumAvailablePackage + """ + logger = env.get_logger() + if isinstance(op, pywbem.CIMInstance): + def _get_key(k): + v = op.properties.get(k, None) + if isinstance(v, pywbem.CIMProperty): return v.value + if v is not None: return v + logger.log_error('missing key "{}" in inst.props'.format(k)) + return op.path[k] if k in op.path else None + elif isinstance(op, pywbem.CIMInstanceName): + _get_key = lambda k: op[k] if k in op else None + else: + raise TypeError("op must be either CIMInstance or CIMInstanceName") + + # parse and check arguments + match_props = {} # args for match_pkg + if _get_key('SoftwareElementID'): + m = re_nevra.match(_get_key('SoftwareElementID')) + if not m: + raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, + "SoftwareElementID could not be parsed.") + for k in ('name', 'version', 'release', 'arch'): + mk = k if k not in ('version', 'release') else k[:3] + match_props[k] = m.group(mk) + if not m.group("epoch"): + match_props["epoch"] = "0" + else: + for k in ('name', 'epoch', 'version', 'release', 'arch'): + ik = k if k != 'arch' else "architecture" + if _get_key(ik): match_props[k] = _get_key(ik) + + if not match_props: + raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, + "Too few key values given (give at least a Name).") + if not 'name' in match_props: + raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, + "Missing either Name or SoftwareElementID property.") + + # get available packages + pl = YumDB.getInstance(env).doPackageLists('all', showdups=True) + # NOTE: available ∩ installed = ∅ + exact,_,_ = yum.packages.parsePackages( + itertools.chain(pl.available, pl.installed), + [match_props['name']]) + exact = yum.misc.unique(exact) + exact_orig = exact + exact = sorted( [ p for p in exact if match_pkg(p, **match_props) ] + , key=lambda a: a.evra) + if len(exact) == 0: + logger.log_error('could not find any package for query: {}' + ' in list: {}' + .format(match_props, [p.nevra for p in exact_orig])) + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "No matching package found.") + for pkg in exact: # check, whether package is already installed + if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): + return pkg + logger.log_info(('found multiple matching packages' + ' for query: {}' if len(exact) > 1 else + 'exact match found for query: {}') + .format(match_props)) + return exact[-1] # select highest version + + @staticmethod + def pkg2model_wrapper(namespace, classname): + """ + @return a function that transforms YumAvailablePackage object + to CIMInstanceName object + """ + + tos = pywbem.Uint16(get_target_operating_system()[0]) + + def pkg2model(env, pkg, keys_only=True, model=None): + """ + @param model if None, will be filled with data, otherwise + a new instance of CIMInstance or CIMObjectPath is created + """ + #if not isinstance(pkg, yum.rpmsack.RPMInstalledPackage): + #if not isinstance(pkg, yum.packages.YumHeaderPackage): + if not isinstance(pkg, yum.packages.YumAvailablePackage): + raise TypeError( + "pkg must be an instance of YumAvailablePackage") + if model is None: + model = pywbem.CIMInstanceName(classname, namespace=namespace) + if not keys_only: + model = pywbem.CIMInstance(classname, path=model) + if isinstance(model, pywbem.CIMInstance): + def _set_key(k, v): + model[k] = v + model.path[k] = v + else: + _set_key = model.__setitem__ + with YumDB.getInstance(env): + _set_key('Name', pkg.name) + _set_key('SoftwareElementID', pkg.nevra) + _set_key('SoftwareElementState', pywbem.Uint16(2 + if isinstance(pkg, yum.rpmsack.RPMInstalledPackage) + else 1)) + _set_key('TargetOperatingSystem', tos) + _set_key('Version', pkg.version) + if not keys_only: + model['Caption'] = pkg.summary + model['Description'] = pkg.description + if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): + model['InstallDate'] = pywbem.CIMDateTime( + datetime.fromtimestamp(pkg.installtime)) + if pkg.vendor: + model['Manufacturer'] = pkg.vendor + model['Release'] = pkg.release + model['Epoch'] = pywbem.Uint16(pkg.epoch) + model["Architecture"] = pkg.arch + model['License'] = pkg.license + model['Group'] = pkg.group + model['Size'] = pywbem.Uint64(pkg.size) + return model + + return pkg2model + +class SoftwareFileCheck: + """ + Just a namespace for functions related to FileCheck provider. + """ + + passed_flags_descriptions = ( + "Existence", + "File Type", + "File Size", + "File Mode", + "File Checksum", + "Device major/minor number", + "Symlink Target", + "User Ownership", "Group Ownership", + "Modify Time") + + checksumtype_str2num = dict((v, k) for (k, v) in + yum.constants.RPM_CHECKSUM_TYPES.items()) + + @staticmethod + def pkg_checksum_type(pkg): + """ + @return integer representation of checksum type + """ + if not isinstance(pkg, yum.packages.YumAvailablePackage): + raise TypeError("pkg must be an instance of YumAvailablePackage") + if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): + return pkg.hdr[rpm.RPMTAG_FILEDIGESTALGO] + with self: # ensure, that _yum is inited + return SoftwareFileCheck.checksumtype_str2pywbem( + pkg.yumdb_info.checksum_type) + + @staticmethod + def checksumtype_num2hash(csumt): + return getattr(hashlib, yum.constants.RPM_CHECKSUM_TYPES[csumt]) + + @staticmethod + def checksumtype_str2pywbem(alg): + try: + res = SoftwareFileCheck.checksumtype_str2num[alg.lower()] + except KeyError: res = 0 + return pywbem.Uint16(res) + + @staticmethod + def filetype_str2pywbem(ft): + try: + return pywbem.Uint16( + { 'file' : 1 + , 'directory' : 2 + , 'symlink' : 3 + , 'fifo' : 4 + , 'character device' : 5 + , 'block device' : 6 + }[ft]) + except KeyError: + return pywbem.Uint16(0) + + @staticmethod + def filetype_mode2pywbem(mode): + for i, name in enumerate( + ('REG', 'DIR', 'LNK', 'FIFO', 'CHR', 'BLK'), 1): + if getattr(stat, 'S_IS' + name)(mode): + return pywbem.Uint16(i) + return pywbem.Uint16(0) + + @staticmethod + def mode2pywbem_flags(mode): + """ + @param mode if None, file does not exist + """ + if mode is None: return None + flags = [] + for i, c in enumerate(( + stat.S_IXOTH, + stat.S_IWOTH, + stat.S_IROTH, + stat.S_IXGRP, + stat.S_IWGRP, + stat.S_IRGRP, + stat.S_IXUSR, + stat.S_IWUSR, + stat.S_IRUSR, + stat.S_ISVTX, + stat.S_ISGID, + stat.S_ISUID)): + if c & mode: + flags.append(pywbem.Uint8(i)) + return flags + + @staticmethod + def hashfile(afile, hashers, blocksize=65536): + """ + @param hashers is a list of hash objects + @return list of digest strings (in hex format) for each hash object + given in the same order + """ + if not isinstance(hashers, (tuple, list, set, frozenset)): + hashers = (hashers, ) + buf = afile.read(blocksize) + while len(buf) > 0: + for h in hashers: h.update(buf) + buf = afile.read(blocksize) + return [ h.hexdigest() for h in hashers ] + + @staticmethod + def compute_checksums(env, checksum_type, file_type, file_path): + """ + @param file_type is not a file, then zeroes are returned + @param checksum_type selected hash algorithm to compute second + checksum + @return (md5sum, checksum) + both checksums are computed from file_path's content + first one is always md5, the second one depends on checksum_type + if file does not exists, (None, None) is returned + """ + hashers = [hashlib.md5()] + if checksum_type != SoftwareFileCheck.checksumtype_str2num["md5"]: + hashers.append(SoftwareFileCheck.checksumtype_num2hash(checksum_type)()) + if file_type != SoftwareFileCheck.filetype_str2pywbem('file'): + rslts = ['0'*len(h.hexdigest()) for h in hashers] + else: + try: + with open(file_path, 'rb') as f: + rslts = SoftwareFileCheck.hashfile(f, hashers) + except (OSError, IOError) as e: + env.get_logger().log_error("could not open file \"%s\"" + " for reading: %s" % (file_path, e)) + return None, None + return (rslts[0], rslts[1] if len(rslts) > 1 else rslts[0]*2) + + @staticmethod + def object_path2yumcheck(env, op): + """ + @return instance of yum.packages._RPMVerifyPackage + this object holds RPMInstalledPackage under its po attribute + """ + if not isinstance(op, pywbem.CIMInstanceName): + raise TypeError("op must be instance of CIMInstanceName, " + "not \"%s\"" % op.__class__.__name__) + log = env.get_logger() + + tos = get_target_operating_system()[0] + if ( not op['Name'] or not op['SoftwareElementID'] + or not op['CheckID'] + or not op['CheckID'].endswith('#'+op['Name']) + or op['SoftwareElementID'].find(op['Version']) == -1): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "Wrong keys.") + if op['SoftwareElementState'] not in ("2", 2): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Only \"Executable\" software element state supported") + if not check_target_operating_system(op['TargetOperatingSystem']): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Wrong target operating system.") + if not op['Name'] or not op['Version']: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + 'Both "Name" and "Version" must be given') + m = re_nevra.match(op['SoftwareElementID']) + if not m: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Wrong SotwareElementID. Expected valid nevra" + " (name-epoch:version-release.arch).") + if op['Version'] != m.group('ver'): + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "Version does not match version part in SoftwareElementID.") + + evra = "{}:{}-{}.{}".format(*( + (m.group(k) if k != "epoch" or m.group(k) else "0") + for k in ("epoch", 'ver', 'rel', 'arch'))) + with YumDB.getInstance(env) as yb: + pl = yb.doPackageLists('installed') + exact, matched, unmatched = yum.packages.parsePackages( + pl.installed, [m.group('name')]) + exact = yum.misc.unique(exact) + for pkg in exact: + if pkg.evra == evra: break + else: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "No matching package installed.") + + fi = pkg.hdr.fiFromHeader() + vpkg = yum.packages._RPMVerifyPackage(pkg, fi, + SoftwareFileCheck.pkg_checksum_type(pkg), [], True) + if not op['Name'] in vpkg: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "File not found in RPM package.") + return vpkg + + """ + Named tuple to store results of rpm file check as pywbem values, + all results are in form: + (expected, reality) + where + expected is value from rpm package + reality is value obtained from installed file + None means, that value could not be obtained + except for "exists" and "md5_checksum" attributes, where "exists" + is boolean and md5_checksum is a string + for example: + file_check.file_type == (4, 3) + """ + FileCheck = collections.namedtuple('FileCheck', + 'exists, md5_checksum, file_type, file_size, file_mode, ' + 'file_checksum, device, link_target, user_id, group_id, ' + 'last_modification_time') + + @staticmethod + def test_file(env, checksum_type, vpf): + """ + @param checksum type is a pywbem value for ChecksumType property + @return instance of FileCheck + """ + if not isinstance(vpf, yum.packages._RPMVerifyPackageFile): + raise TypeError("vpf must be an instance of _RPMVerifyPackage," + " not \"%s\"" % vpf.__class__.__name__) + exists = os.path.lexists(vpf.filename) + md5_checksum = None + expected = { + "file_type" : SoftwareFileCheck.filetype_str2pywbem(vpf.ftype), + "user_id" : pywbem.Uint32(pwd.getpwnam(vpf.user).pw_uid), + "group_id" : pywbem.Uint32(grp.getgrnam(vpf.group).gr_gid), + "file_mode" : pywbem.Uint32(vpf.mode), + "file_size" : pywbem.Uint64(vpf.size), + "link_target" : vpf.readlink if vpf.readlink else None, + "file_checksum" : vpf.digest[1], + "device" : (pywbem.Uint64(vpf.dev) + if vpf.ftype.endswith('device') else None), + "last_modification_time" : pywbem.Uint64(vpf.mtime) + } + if not exists: + reality = collections.defaultdict(lambda: None) + else: + fstat = os.lstat(vpf.filename) + reality = { + "file_type" : SoftwareFileCheck.filetype_mode2pywbem(fstat.st_mode), + "user_id" : pywbem.Uint32(fstat.st_uid), + "group_id" : pywbem.Uint32(fstat.st_gid), + "file_mode" : pywbem.Uint32(fstat.st_mode), + "file_size" : pywbem.Uint64(fstat.st_size), + "last_modification_time" : pywbem.Uint64(fstat.st_mtime) + } + reality["device"] = (pywbem.Uint64(fstat.st_dev) + if reality['file_type'] == SoftwareFileCheck.filetype_str2pywbem( + "device") else None) + reality["link_target"] = (os.readlink(vpf.filename) + if os.path.islink(vpf.filename) else None) + md5_checksum, checksum = SoftwareFileCheck.compute_checksums( + env, checksum_type, reality["file_type"], vpf.filename) + reality["file_checksum"] = checksum + kwargs = dict(exists=exists, md5_checksum=md5_checksum, + **dict((k, (expected[k], reality[k])) for k in expected)) + return SoftwareFileCheck.FileCheck(**kwargs) + + @staticmethod + def filecheck_passed(fc): + if not isinstance(fc, SoftwareFileCheck.FileCheck): + raise TypeError("fc must be an instance of FileCheck") + return ( fc.exists + and all( v[0] == v[1] + for k, v in fc._asdict().items() if ( + isinstance(v, tuple) + and ( k != "last_modification_time" + or fc.file_type[0] == \ + SoftwareFileCheck.filetype_str2pywbem("file") + )))) + + @staticmethod + def filecheck_wrapper(namespace, classname): + + def _filecheck2model_flags(fc): + flags = [] + for k, v in fc._asdict().items(): + if isinstance(v, tuple): + if ( k != "last_modification_time" + or fc.file_type[0] == SoftwareFileCheck.filetype_str2pywbem( + 'file')): + # last_modification_time check is valid only for + # regular files + flag = fc.exists and v[0] == v[1] + else: + flag = True + flags.append(flag) + elif isinstance(v, bool): + flags.append(v) + return flags + + def filecheck2model(vpkg, fn, env, keys_only=True, + model=None, fc=None): + if not isinstance(vpkg, yum.packages._RPMVerifyPackage): + raise TypeError( + "vpkg must be an instance of _RPMVerifyPackage") + if not fn in vpkg: + raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, + "File \"%s\" not found among package files" % fn) + if model is None: + model = pywbem.CIMInstanceName(classname, namespace=namespace) + if not keys_only: + model = pywbem.CIMInstance(classname, path=model) + if fc is not None: + if not isinstance(fc, SoftwareFileCheck.FileCheck): + raise TypeError("fc must be an instance of FileCheck") + pkg = vpkg.po + vpf = vpkg._files[fn] + model['Name'] = vpf.filename + model['SoftwareElementID'] = pkg.nevra + model['SoftwareElementState'] = pywbem.Uint16(2) + model['TargetOperatingSystem'] = pywbem.Uint16( + get_target_operating_system()[0]) + model['Version'] = pkg.version + model['CheckID'] = '%s#%s' % (pkg.name, vpf.filename) + if not keys_only: + #model['Caption'] = '' # TODO + #model['CheckMode'] = bool() # TODO + #model['CRC1'] = pywbem.Uint32() # TODO + #model['CRC2'] = pywbem.Uint32() # TODO + #model['CreateTimeStamp'] = pywbem.CIMDateTime() # TODO + #model['Description'] = '' # TODO + #model['ElementName'] = '' # TODO + #model['InstanceID'] = '' # TODO + model['FileName'] = os.path.basename(vpf.filename) + model['FileChecksumType'] = csumt = \ + pywbem.Uint16(SoftwareFileCheck.pkg_checksum_type(pkg)) + if fc is None: + fc = SoftwareFileCheck.test_file(env, csumt, vpf) + for mattr, fattr in ( + ('FileType', 'file_type'), + ('FileUserID', 'user_id'), + ('FileGroupID', 'group_id'), + ('FileMode', 'file_mode'), + ('LastModificationTime', 'last_modification_time'), + ('FileSize', 'file_size'), + ('LinkTarget', 'link_target'), + ('FileChecksum', 'file_checksum')): + exp, rea = getattr(fc, fattr) + if exp is not None: + model['Expected' + mattr] = exp + if rea is not None: + model[mattr] = rea + model['ExpectedFileModeFlags'] = \ + SoftwareFileCheck.mode2pywbem_flags(fc.file_mode[0]) + if fc.exists: + model['FileModeFlags'] = SoftwareFileCheck.mode2pywbem_flags( + fc.file_mode[1]) + model['FileExists'] = fc.exists + if fc.md5_checksum is not None: + model['MD5Checksum'] = fc.md5_checksum + model['PassedFlags'] = _filecheck2model_flags(fc) + model['PassedFlagsDescriptions'] = list( + SoftwareFileCheck.passed_flags_descriptions) + return model + + return filecheck2model + diff --git a/src/software/openlmi/software/util/singletonmixin.py b/src/software/openlmi/software/util/singletonmixin.py new file mode 100644 index 0000000..8051695 --- /dev/null +++ b/src/software/openlmi/software/util/singletonmixin.py @@ -0,0 +1,508 @@ +""" +A Python Singleton mixin class that makes use of some of the ideas +found at http://c2.com/cgi/wiki?PythonSingleton. Just inherit +from it and you have a singleton. No code is required in +subclasses to create singleton behavior -- inheritance from +Singleton is all that is needed. + +Singleton creation is threadsafe. + +USAGE: + +Just inherit from Singleton. If you need a constructor, include +an __init__() method in your class as you usually would. However, +if your class is S, you instantiate the singleton using S.getInstance() +instead of S(). Repeated calls to S.getInstance() return the +originally-created instance. + +For example: + +class S(Singleton): + + def __init__(self, a, b=1): + pass + +S1 = S.getInstance(1, b=3) + + +Most of the time, that's all you need to know. However, there are some +other useful behaviors. Read on for a full description: + +1) Getting the singleton: + + S.getInstance() + +returns the instance of S. If none exists, it is created. + +2) The usual idiom to construct an instance by calling the class, i.e. + + S() + +is disabled for the sake of clarity. + +For one thing, the S() syntax means instantiation, but getInstance() +usually does not cause instantiation. So the S() syntax would +be misleading. + +Because of that, if S() were allowed, a programmer who didn't +happen to notice the inheritance from Singleton (or who +wasn't fully aware of what a Singleton pattern +does) might think he was creating a new instance, +which could lead to very unexpected behavior. + +So, overall, it is felt that it is better to make things clearer +by requiring the call of a class method that is defined in +Singleton. An attempt to instantiate via S() will result +in a SingletonException being raised. + +3) Use __S.__init__() for instantiation processing, +since S.getInstance() runs S.__init__(), passing it the args it has received. + +If no data needs to be passed in at instantiation time, you don't need S.__init__(). + +4) If S.__init__(.) requires parameters, include them ONLY in the +first call to S.getInstance(). If subsequent calls have arguments, +a SingletonException is raised by default. + +If you find it more convenient for subsequent calls to be allowed to +have arguments, but for those argumentsto be ignored, just include +'ignoreSubsequent = True' in your class definition, i.e.: + + class S(Singleton): + + ignoreSubsequent = True + + def __init__(self, a, b=1): + pass + +5) For testing, it is sometimes convenient for all existing singleton +instances to be forgotten, so that new instantiations can occur. For that +reason, a forgetAllSingletons() function is included. Just call + + forgetAllSingletons() + +and it is as if no earlier instantiations have occurred. + +6) As an implementation detail, classes that inherit +from Singleton may not have their own __new__ +methods. To make sure this requirement is followed, +an exception is raised if a Singleton subclass includ +es __new__. This happens at subclass instantiation +time (by means of the MetaSingleton metaclass. + + +By Gary Robinson, grobinson@flyfi.com. No rights reserved -- +placed in the public domain -- which is only reasonable considering +how much it owes to other people's code and ideas which are in the +public domain. The idea of using a metaclass came from +a comment on Gary's blog (see +http://www.garyrobinson.net/2004/03/python_singleto.html#comments). +Other improvements came from comments and email from other +people who saw it online. (See the blog post and comments +for further credits.) + +Not guaranteed to be fit for any particular purpose. Use at your +own risk. +""" + +import threading + +class SingletonException(Exception): + pass + +_stSingletons = set() +_lockForSingletons = threading.RLock() +_lockForSingletonCreation = threading.RLock() # Ensure only one instance of each Singleton + # class is created. This is not bound to the + # individual Singleton class since we need to + # ensure that there is only one mutex for each + # Singleton class, which would require having + # a lock when setting up the Singleton class, + # which is what this is anyway. So, when any + # Singleton is created, we lock this lock and + # then we don't need to lock it again for that + # class. + +def _createSingletonInstance(cls, lstArgs, dctKwArgs): + _lockForSingletonCreation.acquire() + try: + if cls._isInstantiated(): # some other thread got here first + return + + instance = cls.__new__(cls) + try: + instance.__init__(*lstArgs, **dctKwArgs) + except TypeError, e: + if e.message.find('__init__() takes') != -1: + raise SingletonException, 'If the singleton requires __init__ args, supply them on first call to getInstance().' + else: + raise + cls.cInstance = instance + _addSingleton(cls) + finally: + _lockForSingletonCreation.release() + +def _addSingleton(cls): + _lockForSingletons.acquire() + try: + assert cls not in _stSingletons + _stSingletons.add(cls) + finally: + _lockForSingletons.release() + +def _removeSingleton(cls): + _lockForSingletons.acquire() + try: + if cls in _stSingletons: + _stSingletons.remove(cls) + finally: + _lockForSingletons.release() + +def forgetAllSingletons(): + '''This is useful in tests, since it is hard to know which singletons need to be cleared to make a test work.''' + _lockForSingletons.acquire() + try: + for cls in _stSingletons.copy(): + cls._forgetClassInstanceReferenceForTesting() + + # Might have created some Singletons in the process of tearing down. + # Try one more time - there should be a limit to this. + iNumSingletons = len(_stSingletons) + if len(_stSingletons) > 0: + for cls in _stSingletons.copy(): + cls._forgetClassInstanceReferenceForTesting() + iNumSingletons -= 1 + assert iNumSingletons == len(_stSingletons), 'Added a singleton while destroying ' + str(cls) + assert len(_stSingletons) == 0, _stSingletons + finally: + _lockForSingletons.release() + +class MetaSingleton(type): + def __new__(metaclass, strName, tupBases, dct): + if dct.has_key('__new__'): + raise SingletonException, 'Can not override __new__ in a Singleton' + return super(MetaSingleton, metaclass).__new__(metaclass, strName, tupBases, dct) + + def __call__(cls, *lstArgs, **dictArgs): + raise SingletonException, 'Singletons may only be instantiated through getInstance()' + +class Singleton(object): + __metaclass__ = MetaSingleton + + def getInstance(cls, *lstArgs, **dctKwArgs): + """ + Call this to instantiate an instance or retrieve the existing instance. + If the singleton requires args to be instantiated, include them the first + time you call getInstance. + """ + if cls._isInstantiated(): + if (lstArgs or dctKwArgs) and not hasattr(cls, 'ignoreSubsequent'): + raise SingletonException, 'Singleton already instantiated, but getInstance() called with args.' + else: + _createSingletonInstance(cls, lstArgs, dctKwArgs) + + return cls.cInstance + getInstance = classmethod(getInstance) + + def _isInstantiated(cls): + # Don't use hasattr(cls, 'cInstance'), because that screws things up if there is a singleton that + # extends another singleton. hasattr looks in the base class if it doesn't find in subclass. + return 'cInstance' in cls.__dict__ + _isInstantiated = classmethod(_isInstantiated) + + # This can be handy for public use also + isInstantiated = _isInstantiated + + def _forgetClassInstanceReferenceForTesting(cls): + """ + This is designed for convenience in testing -- sometimes you + want to get rid of a singleton during test code to see what + happens when you call getInstance() under a new situation. + + To really delete the object, all external references to it + also need to be deleted. + """ + try: + if hasattr(cls.cInstance, '_prepareToForgetSingleton'): + # tell instance to release anything it might be holding onto. + cls.cInstance._prepareToForgetSingleton() + del cls.cInstance + _removeSingleton(cls) + except AttributeError: + # run up the chain of base classes until we find the one that has the instance + # and then delete it there + for baseClass in cls.__bases__: + if issubclass(baseClass, Singleton): + baseClass._forgetClassInstanceReferenceForTesting() + _forgetClassInstanceReferenceForTesting = classmethod(_forgetClassInstanceReferenceForTesting) + + +if __name__ == '__main__': + + import unittest + import time + + class singletonmixin_Public_TestCase(unittest.TestCase): + def testReturnsSameObject(self): + """ + Demonstrates normal use -- just call getInstance and it returns a singleton instance + """ + + class A(Singleton): + def __init__(self): + super(A, self).__init__() + + a1 = A.getInstance() + a2 = A.getInstance() + self.assertEquals(id(a1), id(a2)) + + def testInstantiateWithMultiArgConstructor(self): + """ + If the singleton needs args to construct, include them in the first + call to get instances. + """ + + class B(Singleton): + + def __init__(self, arg1, arg2): + super(B, self).__init__() + self.arg1 = arg1 + self.arg2 = arg2 + + b1 = B.getInstance('arg1 value', 'arg2 value') + b2 = B.getInstance() + self.assertEquals(b1.arg1, 'arg1 value') + self.assertEquals(b1.arg2, 'arg2 value') + self.assertEquals(id(b1), id(b2)) + + def testInstantiateWithKeywordArg(self): + + class B(Singleton): + + def __init__(self, arg1=5): + super(B, self).__init__() + self.arg1 = arg1 + + b1 = B.getInstance('arg1 value') + b2 = B.getInstance() + self.assertEquals(b1.arg1, 'arg1 value') + self.assertEquals(id(b1), id(b2)) + + def testTryToInstantiateWithoutNeededArgs(self): + + class B(Singleton): + + def __init__(self, arg1, arg2): + super(B, self).__init__() + self.arg1 = arg1 + self.arg2 = arg2 + + self.assertRaises(SingletonException, B.getInstance) + + def testPassTypeErrorIfAllArgsThere(self): + """ + Make sure the test for capturing missing args doesn't interfere with a normal TypeError. + """ + class B(Singleton): + + def __init__(self, arg1, arg2): + super(B, self).__init__() + self.arg1 = arg1 + self.arg2 = arg2 + raise TypeError, 'some type error' + + self.assertRaises(TypeError, B.getInstance, 1, 2) + + def testTryToInstantiateWithoutGetInstance(self): + """ + Demonstrates that singletons can ONLY be instantiated through + getInstance, as long as they call Singleton.__init__ during construction. + + If this check is not required, you don't need to call Singleton.__init__(). + """ + + class A(Singleton): + def __init__(self): + super(A, self).__init__() + + self.assertRaises(SingletonException, A) + + def testDontAllowNew(self): + + def instantiatedAnIllegalClass(): + class A(Singleton): + def __init__(self): + super(A, self).__init__() + + def __new__(metaclass, strName, tupBases, dct): + return super(MetaSingleton, metaclass).__new__(metaclass, strName, tupBases, dct) + + self.assertRaises(SingletonException, instantiatedAnIllegalClass) + + + def testDontAllowArgsAfterConstruction(self): + class B(Singleton): + + def __init__(self, arg1, arg2): + super(B, self).__init__() + self.arg1 = arg1 + self.arg2 = arg2 + + B.getInstance('arg1 value', 'arg2 value') + self.assertRaises(SingletonException, B, 'arg1 value', 'arg2 value') + + def test_forgetClassInstanceReferenceForTesting(self): + class A(Singleton): + def __init__(self): + super(A, self).__init__() + class B(A): + def __init__(self): + super(B, self).__init__() + + # check that changing the class after forgetting the instance produces + # an instance of the new class + a = A.getInstance() + assert a.__class__.__name__ == 'A' + A._forgetClassInstanceReferenceForTesting() + b = B.getInstance() + assert b.__class__.__name__ == 'B' + + # check that invoking the 'forget' on a subclass still deletes the instance + B._forgetClassInstanceReferenceForTesting() + a = A.getInstance() + B._forgetClassInstanceReferenceForTesting() + b = B.getInstance() + assert b.__class__.__name__ == 'B' + + def test_forgetAllSingletons(self): + # Should work if there are no singletons + forgetAllSingletons() + + class A(Singleton): + ciInitCount = 0 + def __init__(self): + super(A, self).__init__() + A.ciInitCount += 1 + + A.getInstance() + self.assertEqual(A.ciInitCount, 1) + + A.getInstance() + self.assertEqual(A.ciInitCount, 1) + + forgetAllSingletons() + A.getInstance() + self.assertEqual(A.ciInitCount, 2) + + def test_threadedCreation(self): + # Check that only one Singleton is created even if multiple + # threads try at the same time. If fails, would see assert in _addSingleton + class Test_Singleton(Singleton): + def __init__(self): + super(Test_Singleton, self).__init__() + + class Test_SingletonThread(threading.Thread): + def __init__(self, fTargetTime): + super(Test_SingletonThread, self).__init__() + self._fTargetTime = fTargetTime + self._eException = None + + def run(self): + try: + fSleepTime = self._fTargetTime - time.time() + if fSleepTime > 0: + time.sleep(fSleepTime) + Test_Singleton.getInstance() + except Exception, e: + self._eException = e + + fTargetTime = time.time() + 0.1 + lstThreads = [] + for _ in xrange(100): + t = Test_SingletonThread(fTargetTime) + t.start() + lstThreads.append(t) + eException = None + for t in lstThreads: + t.join() + if t._eException and not eException: + eException = t._eException + if eException: + raise eException + + def testNoInit(self): + """ + Demonstrates use with a class not defining __init__ + """ + + class A(Singleton): + pass + + #INTENTIONALLY UNDEFINED: + #def __init__(self): + # super(A, self).__init__() + + A.getInstance() #Make sure no exception is raised + + def testMultipleGetInstancesWithArgs(self): + + class A(Singleton): + + ignoreSubsequent = True + + def __init__(self, a, b=1): + pass + + a1 = A.getInstance(1) + a2 = A.getInstance(2) # ignores the second call because of ignoreSubsequent + + class B(Singleton): + + def __init__(self, a, b=1): + pass + + b1 = B.getInstance(1) + self.assertRaises(SingletonException, B.getInstance, 2) # No ignoreSubsequent included + + class C(Singleton): + + def __init__(self, a=1): + pass + + c1 = C.getInstance(a=1) + self.assertRaises(SingletonException, C.getInstance, a=2) # No ignoreSubsequent included + + def testInheritance(self): + """ + It's sometimes said that you can't subclass a singleton (see, for instance, + http://steve.yegge.googlepages.com/singleton-considered-stupid point e). This + test shows that at least rudimentary subclassing works fine for us. + """ + + class A(Singleton): + + def setX(self, x): + self.x = x + + def setZ(self, z): + raise NotImplementedError + + class B(A): + + def setX(self, x): + self.x = -x + + def setY(self, y): + self.y = y + + a = A.getInstance() + a.setX(5) + b = B.getInstance() + b.setX(5) + b.setY(50) + self.assertEqual((a.x, b.x, b.y), (5, -5, 50)) + self.assertRaises(AttributeError, eval, 'a.setY', {}, locals()) + self.assertRaises(NotImplementedError, b.setZ, 500) + + unittest.main() + diff --git a/src/software/providers b/src/software/providers new file mode 120000 index 0000000..6105f87 --- /dev/null +++ b/src/software/providers @@ -0,0 +1 @@ +openlmi/software \ No newline at end of file diff --git a/src/software/providers/LMI_SoftwareFileCheck.py b/src/software/providers/LMI_SoftwareFileCheck.py deleted file mode 100644 index c667352..0000000 --- a/src/software/providers/LMI_SoftwareFileCheck.py +++ /dev/null @@ -1,413 +0,0 @@ -# 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 -# - -"""Python Provider for LMI_SoftwareFileCheck - -Instruments the CIM class LMI_SoftwareFileCheck - -""" - -import pywbem -from pywbem.cim_provider2 import CIMProvider2 -from openlmi.software.util.common import * - -filecheck2model = SoftwareFileCheck.filecheck_wrapper( - 'root/cimv2', 'LMI_SoftwareFileCheck') - -class LMI_SoftwareFileCheck(CIMProvider2): - """Instrument the CIM class LMI_SoftwareFileCheck - - Identifies a file contained by RPM package. It's located in directory - identified in FileName. The Invoke methods check for file existence - and whether its attributes match those given by RPM package. - - """ - - 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__) - - with YumDB.getInstance(env) as yb: - vpkg = SoftwareFileCheck.object_path2yumcheck(env, model.path) - pkg = vpkg.po - fi = pkg.hdr.fiFromHeader() - return filecheck2model(vpkg, model['Name'], env, False) - - 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__) - - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement - - 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__) - # TODO create or modify the instance - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement - return 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__) - - # TODO delete the resource - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement - - def cim_method_invoke(self, env, object_name): - """Implements LMI_SoftwareFileCheck.Invoke() - - The Invoke method evaluates this Check. The details of the - evaluation are described by the specific subclasses of CIM_Check. - When the SoftwareElement being checked is already installed, the - CIM_InstalledSoftwareElement association identifies the - CIM_ComputerSystem in whose context the Invoke is executed. If - this association is not in place, then the InvokeOnSystem method - should be used - since it identifies the TargetSystem as an input - parameter of the method. \nThe results of the Invoke method are - based on the return value. A zero is returned if the condition is - satisfied. A one is returned if the method is not supported. Any - other value indicates the condition is not satisfied. - - Keyword arguments: - env -- Provider Environment (pycimmb.ProviderEnvironment) - object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName - specifying the object on which the method Invoke() - should be invoked. - - Returns a two-tuple containing the return value (type pywbem.Uint32) - and a list of CIMParameter objects representing the output parameters - - Output parameters: none - - 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_invoke()' \ - % self.__class__.__name__) - - with YumDB.getInstance(env) as yb: - vpkg = SoftwareFileCheck.object_path2yumcheck(env, object_name) - fc = SoftwareFileCheck.test_file(env, - SoftwareFileCheck.pkg_checksum_type(vpkg.po), - vpkg._files[object_name["Name"]]) - out_params = [] - ret = 0 if SoftwareFileCheck.filecheck_passed(fc) else 2 - return (pywbem.Uint32(ret), out_params) - - def cim_method_invokeonsystem(self, env, object_name, - param_targetsystem=None): - """Implements LMI_SoftwareFileCheck.InvokeOnSystem() - - The InvokeOnSystem method evaluates this Check. The details of the - evaluation are described by the specific subclasses of CIM_Check. - The method\'s TargetSystem input parameter specifies the - ComputerSystem in whose context the method is invoked. \nThe - results of the InvokeOnSystem method are based on the return - value. A zero is returned if the condition is satisfied. A one is - returned if the method is not supported. Any other value indicates - the condition is not satisfied. - - Keyword arguments: - env -- Provider Environment (pycimmb.ProviderEnvironment) - object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName - specifying the object on which the method InvokeOnSystem() - should be invoked. - param_targetsystem -- The input parameter TargetSystem ( - type REF (pywbem.CIMInstanceName( - classname='CIM_ComputerSystem', ...)) - Reference to ComputerSystem in whose context the method is to - be invoked. - - - Returns a two-tuple containing the return value (type pywbem.Uint32) - and a list of CIMParameter objects representing the output parameters - - Output parameters: none - - 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_invokeonsystem()' \ - % self.__class__.__name__) - - # TODO do something - raise pywbem.CIMError(pywbem.CIM_ERR_METHOD_NOT_AVAILABLE) # Remove to implemented - out_params = [] - #rval = # TODO (type pywbem.Uint32) - return (rval, out_params) - - class Values(object): - class TargetOperatingSystem(object): - Unknown = pywbem.Uint16(0) - Other = pywbem.Uint16(1) - MACOS = pywbem.Uint16(2) - ATTUNIX = pywbem.Uint16(3) - DGUX = pywbem.Uint16(4) - DECNT = pywbem.Uint16(5) - Tru64_UNIX = pywbem.Uint16(6) - OpenVMS = pywbem.Uint16(7) - HPUX = pywbem.Uint16(8) - AIX = pywbem.Uint16(9) - MVS = pywbem.Uint16(10) - OS400 = pywbem.Uint16(11) - OS_2 = pywbem.Uint16(12) - JavaVM = pywbem.Uint16(13) - MSDOS = pywbem.Uint16(14) - WIN3x = pywbem.Uint16(15) - WIN95 = pywbem.Uint16(16) - WIN98 = pywbem.Uint16(17) - WINNT = pywbem.Uint16(18) - WINCE = pywbem.Uint16(19) - NCR3000 = pywbem.Uint16(20) - NetWare = pywbem.Uint16(21) - OSF = pywbem.Uint16(22) - DC_OS = pywbem.Uint16(23) - Reliant_UNIX = pywbem.Uint16(24) - SCO_UnixWare = pywbem.Uint16(25) - SCO_OpenServer = pywbem.Uint16(26) - Sequent = pywbem.Uint16(27) - IRIX = pywbem.Uint16(28) - Solaris = pywbem.Uint16(29) - SunOS = pywbem.Uint16(30) - U6000 = pywbem.Uint16(31) - ASERIES = pywbem.Uint16(32) - HP_NonStop_OS = pywbem.Uint16(33) - HP_NonStop_OSS = pywbem.Uint16(34) - BS2000 = pywbem.Uint16(35) - LINUX = pywbem.Uint16(36) - Lynx = pywbem.Uint16(37) - XENIX = pywbem.Uint16(38) - VM = pywbem.Uint16(39) - Interactive_UNIX = pywbem.Uint16(40) - BSDUNIX = pywbem.Uint16(41) - FreeBSD = pywbem.Uint16(42) - NetBSD = pywbem.Uint16(43) - GNU_Hurd = pywbem.Uint16(44) - OS9 = pywbem.Uint16(45) - MACH_Kernel = pywbem.Uint16(46) - Inferno = pywbem.Uint16(47) - QNX = pywbem.Uint16(48) - EPOC = pywbem.Uint16(49) - IxWorks = pywbem.Uint16(50) - VxWorks = pywbem.Uint16(51) - MiNT = pywbem.Uint16(52) - BeOS = pywbem.Uint16(53) - HP_MPE = pywbem.Uint16(54) - NextStep = pywbem.Uint16(55) - PalmPilot = pywbem.Uint16(56) - Rhapsody = pywbem.Uint16(57) - Windows_2000 = pywbem.Uint16(58) - Dedicated = pywbem.Uint16(59) - OS_390 = pywbem.Uint16(60) - VSE = pywbem.Uint16(61) - TPF = pywbem.Uint16(62) - Windows__R__Me = pywbem.Uint16(63) - Caldera_Open_UNIX = pywbem.Uint16(64) - OpenBSD = pywbem.Uint16(65) - Not_Applicable = pywbem.Uint16(66) - Windows_XP = pywbem.Uint16(67) - z_OS = pywbem.Uint16(68) - Microsoft_Windows_Server_2003 = pywbem.Uint16(69) - Microsoft_Windows_Server_2003_64_Bit = pywbem.Uint16(70) - Windows_XP_64_Bit = pywbem.Uint16(71) - Windows_XP_Embedded = pywbem.Uint16(72) - Windows_Vista = pywbem.Uint16(73) - Windows_Vista_64_Bit = pywbem.Uint16(74) - Windows_Embedded_for_Point_of_Service = pywbem.Uint16(75) - Microsoft_Windows_Server_2008 = pywbem.Uint16(76) - Microsoft_Windows_Server_2008_64_Bit = pywbem.Uint16(77) - FreeBSD_64_Bit = pywbem.Uint16(78) - RedHat_Enterprise_Linux = pywbem.Uint16(79) - RedHat_Enterprise_Linux_64_Bit = pywbem.Uint16(80) - Solaris_64_Bit = pywbem.Uint16(81) - SUSE = pywbem.Uint16(82) - SUSE_64_Bit = pywbem.Uint16(83) - SLES = pywbem.Uint16(84) - SLES_64_Bit = pywbem.Uint16(85) - Novell_OES = pywbem.Uint16(86) - Novell_Linux_Desktop = pywbem.Uint16(87) - Sun_Java_Desktop_System = pywbem.Uint16(88) - Mandriva = pywbem.Uint16(89) - Mandriva_64_Bit = pywbem.Uint16(90) - TurboLinux = pywbem.Uint16(91) - TurboLinux_64_Bit = pywbem.Uint16(92) - Ubuntu = pywbem.Uint16(93) - Ubuntu_64_Bit = pywbem.Uint16(94) - Debian = pywbem.Uint16(95) - Debian_64_Bit = pywbem.Uint16(96) - Linux_2_4_x = pywbem.Uint16(97) - Linux_2_4_x_64_Bit = pywbem.Uint16(98) - Linux_2_6_x = pywbem.Uint16(99) - Linux_2_6_x_64_Bit = pywbem.Uint16(100) - Linux_64_Bit = pywbem.Uint16(101) - Other_64_Bit = pywbem.Uint16(102) - Microsoft_Windows_Server_2008_R2 = pywbem.Uint16(103) - VMware_ESXi = pywbem.Uint16(104) - Microsoft_Windows_7 = pywbem.Uint16(105) - CentOS_32_bit = pywbem.Uint16(106) - CentOS_64_bit = pywbem.Uint16(107) - Oracle_Enterprise_Linux_32_bit = pywbem.Uint16(108) - Oracle_Enterprise_Linux_64_bit = pywbem.Uint16(109) - eComStation_32_bitx = pywbem.Uint16(110) - - class SoftwareElementState(object): - Deployable = pywbem.Uint16(0) - Installable = pywbem.Uint16(1) - Executable = pywbem.Uint16(2) - Running = pywbem.Uint16(3) - - class FileType(object): - Unknown = pywbem.Uint16(0) - File = pywbem.Uint16(1) - Directory = pywbem.Uint16(2) - Symlink = pywbem.Uint16(3) - FIFO = pywbem.Uint16(4) - Character_Device = pywbem.Uint16(5) - Block_Device = pywbem.Uint16(6) - -## end of class LMI_SoftwareFileCheckProvider - -## get_providers() for associating CIM Class Name to python provider class name - -def get_providers(env): - lmi_softwarefilecheck_prov = LMI_SoftwareFileCheck(env) - return {'LMI_SoftwareFileCheck': lmi_softwarefilecheck_prov} diff --git a/src/software/providers/LMI_SoftwareInstalledPackage.py b/src/software/providers/LMI_SoftwareInstalledPackage.py deleted file mode 100644 index 51d15b6..0000000 --- a/src/software/providers/LMI_SoftwareInstalledPackage.py +++ /dev/null @@ -1,509 +0,0 @@ -# -*- 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 -# - -"""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} diff --git a/src/software/providers/LMI_SoftwarePackage.py b/src/software/providers/LMI_SoftwarePackage.py deleted file mode 100644 index 2395dca..0000000 --- a/src/software/providers/LMI_SoftwarePackage.py +++ /dev/null @@ -1,522 +0,0 @@ -# -*- 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 -# - -"""Python Provider for LMI_SoftwarePackage - -Instruments the CIM class LMI_SoftwarePackage - -""" - -import itertools -import datetime -import pywbem -from pywbem.cim_provider2 import CIMProvider2 -from openlmi.software.util.common import * - -pkg2model = SoftwarePackage.pkg2model_wrapper('root/cimv2', "LMI_SoftwarePackage") - -class LMI_SoftwarePackage(CIMProvider2): - """Instrument the CIM class LMI_SoftwarePackage - - RPM package installed on particular computer system with YUM (The - Yellowdog Updated, Modified) package manager. - - """ - - 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__) - - with YumDB.getInstance(env): - pkg = SoftwarePackage.object_path2pkg(env, model.path, 'all') - return pkg2model(env, pkg, keys_only=False, model=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({'TargetOperatingSystem': None, 'Version': None, - 'SoftwareElementState': None, 'Name': None, - 'SoftwareElementID': None}) - - with YumDB.getInstance(env) as yb: - # get all packages - pl = yb.doPackageLists('all', showdups=True) - pl = itertools.chain(pl.installed, pl.available) - # NOTE: available ∩ installed = ∅ - for pkg in sorted(pl, key=lambda a:a.evra): - yield pkg2model(env, pkg, keys_only, model) - - 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__) - # TODO create or modify the instance - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement - return 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__) - - # TODO delete the resource - # Remove to implement - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) - - def cim_method_install(self, env, object_name): - """Implements LMI_SoftwarePackage.Install() - - Will install available package. - - 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. - - Returns a two-tuple containing the return value (type pywbem.Uint32 self.Values.Install) - 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. Null otherwise. - - 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_install()' \ - % self.__class__.__name__) - - with YumDB.getInstance(env) as yb: - # get available packages - pkg = SoftwarePackage.object_path2pkg_search(env, object_name) - out_params = [ pywbem.CIMParameter('Installed', type='reference') ] - if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): - out_params[0].value = pkg2model(env, pkg, True) - return (self.Values.Install.Already_installed, out_params) - - logger.log_info('installing package {}'.format(pkg.nevra)) - # install - yb.install(pkg) - yb.buildTransaction() - yb.processTransaction() - logger.log_info('package installed'.format(pkg.nevra)) - - out_params[0].value = pkg2model(env, pkg, True, object_name) - out_params[0].value['SoftwareElementState'] = \ - self.Values.SoftwareElementState.Executable - return (self.Values.Install.Successful_installation, out_params) - - def cim_method_remove(self, env, object_name): - """Implements LMI_SoftwarePackage.Remove() - - Will uninstall installed package. - - Keyword arguments: - env -- Provider Environment (pycimmb.ProviderEnvironment) - object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName - specifying the object on which the method Remove() - should be invoked. - - Returns a two-tuple containing the return value (type pywbem.Uint32 self.Values.Remove) - and a list of CIMParameter objects representing the output parameters - - Output parameters: none - - 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_remove()' \ - % self.__class__.__name__) - - with YumDB.getInstance(env) as yb: - pkg = SoftwarePackage.object_path2pkg(env, object_name, 'all') - if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): - logger.log_info('removing package "%s"' % pkg.nevra) - yb.remove(pkg) - yb.buildTransaction() - yb.processTransaction() - logger.log_info('package "%s" removed' % pkg.nevra) - rval = self.Values.Remove.Successful_removal - else: - rval = self.Values.Remove.Not_installed - #rval = # TODO (type pywbem.Uint32 self.Values.Remove) - return (rval, []) - - 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.. - - 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 - - class TargetOperatingSystem(object): - Unknown = pywbem.Uint16(0) - Other = pywbem.Uint16(1) - MACOS = pywbem.Uint16(2) - ATTUNIX = pywbem.Uint16(3) - DGUX = pywbem.Uint16(4) - DECNT = pywbem.Uint16(5) - Tru64_UNIX = pywbem.Uint16(6) - OpenVMS = pywbem.Uint16(7) - HPUX = pywbem.Uint16(8) - AIX = pywbem.Uint16(9) - MVS = pywbem.Uint16(10) - OS400 = pywbem.Uint16(11) - OS_2 = pywbem.Uint16(12) - JavaVM = pywbem.Uint16(13) - MSDOS = pywbem.Uint16(14) - WIN3x = pywbem.Uint16(15) - WIN95 = pywbem.Uint16(16) - WIN98 = pywbem.Uint16(17) - WINNT = pywbem.Uint16(18) - WINCE = pywbem.Uint16(19) - NCR3000 = pywbem.Uint16(20) - NetWare = pywbem.Uint16(21) - OSF = pywbem.Uint16(22) - DC_OS = pywbem.Uint16(23) - Reliant_UNIX = pywbem.Uint16(24) - SCO_UnixWare = pywbem.Uint16(25) - SCO_OpenServer = pywbem.Uint16(26) - Sequent = pywbem.Uint16(27) - IRIX = pywbem.Uint16(28) - Solaris = pywbem.Uint16(29) - SunOS = pywbem.Uint16(30) - U6000 = pywbem.Uint16(31) - ASERIES = pywbem.Uint16(32) - HP_NonStop_OS = pywbem.Uint16(33) - HP_NonStop_OSS = pywbem.Uint16(34) - BS2000 = pywbem.Uint16(35) - LINUX = pywbem.Uint16(36) - Lynx = pywbem.Uint16(37) - XENIX = pywbem.Uint16(38) - VM = pywbem.Uint16(39) - Interactive_UNIX = pywbem.Uint16(40) - BSDUNIX = pywbem.Uint16(41) - FreeBSD = pywbem.Uint16(42) - NetBSD = pywbem.Uint16(43) - GNU_Hurd = pywbem.Uint16(44) - OS9 = pywbem.Uint16(45) - MACH_Kernel = pywbem.Uint16(46) - Inferno = pywbem.Uint16(47) - QNX = pywbem.Uint16(48) - EPOC = pywbem.Uint16(49) - IxWorks = pywbem.Uint16(50) - VxWorks = pywbem.Uint16(51) - MiNT = pywbem.Uint16(52) - BeOS = pywbem.Uint16(53) - HP_MPE = pywbem.Uint16(54) - NextStep = pywbem.Uint16(55) - PalmPilot = pywbem.Uint16(56) - Rhapsody = pywbem.Uint16(57) - Windows_2000 = pywbem.Uint16(58) - Dedicated = pywbem.Uint16(59) - OS_390 = pywbem.Uint16(60) - VSE = pywbem.Uint16(61) - TPF = pywbem.Uint16(62) - Windows__R__Me = pywbem.Uint16(63) - Caldera_Open_UNIX = pywbem.Uint16(64) - OpenBSD = pywbem.Uint16(65) - Not_Applicable = pywbem.Uint16(66) - Windows_XP = pywbem.Uint16(67) - z_OS = pywbem.Uint16(68) - Microsoft_Windows_Server_2003 = pywbem.Uint16(69) - Microsoft_Windows_Server_2003_64_Bit = pywbem.Uint16(70) - Windows_XP_64_Bit = pywbem.Uint16(71) - Windows_XP_Embedded = pywbem.Uint16(72) - Windows_Vista = pywbem.Uint16(73) - Windows_Vista_64_Bit = pywbem.Uint16(74) - Windows_Embedded_for_Point_of_Service = pywbem.Uint16(75) - Microsoft_Windows_Server_2008 = pywbem.Uint16(76) - Microsoft_Windows_Server_2008_64_Bit = pywbem.Uint16(77) - FreeBSD_64_Bit = pywbem.Uint16(78) - RedHat_Enterprise_Linux = pywbem.Uint16(79) - RedHat_Enterprise_Linux_64_Bit = pywbem.Uint16(80) - Solaris_64_Bit = pywbem.Uint16(81) - SUSE = pywbem.Uint16(82) - SUSE_64_Bit = pywbem.Uint16(83) - SLES = pywbem.Uint16(84) - SLES_64_Bit = pywbem.Uint16(85) - Novell_OES = pywbem.Uint16(86) - Novell_Linux_Desktop = pywbem.Uint16(87) - Sun_Java_Desktop_System = pywbem.Uint16(88) - Mandriva = pywbem.Uint16(89) - Mandriva_64_Bit = pywbem.Uint16(90) - TurboLinux = pywbem.Uint16(91) - TurboLinux_64_Bit = pywbem.Uint16(92) - Ubuntu = pywbem.Uint16(93) - Ubuntu_64_Bit = pywbem.Uint16(94) - Debian = pywbem.Uint16(95) - Debian_64_Bit = pywbem.Uint16(96) - Linux_2_4_x = pywbem.Uint16(97) - Linux_2_4_x_64_Bit = pywbem.Uint16(98) - Linux_2_6_x = pywbem.Uint16(99) - Linux_2_6_x_64_Bit = pywbem.Uint16(100) - Linux_64_Bit = pywbem.Uint16(101) - Other_64_Bit = pywbem.Uint16(102) - Microsoft_Windows_Server_2008_R2 = pywbem.Uint16(103) - VMware_ESXi = pywbem.Uint16(104) - Microsoft_Windows_7 = pywbem.Uint16(105) - CentOS_32_bit = pywbem.Uint16(106) - CentOS_64_bit = pywbem.Uint16(107) - Oracle_Enterprise_Linux_32_bit = pywbem.Uint16(108) - Oracle_Enterprise_Linux_64_bit = pywbem.Uint16(109) - eComStation_32_bitx = pywbem.Uint16(110) - - class Remove(object): - Not_installed = pywbem.Uint32(0) - Successful_removal = pywbem.Uint32(1) - Failed = pywbem.Uint32(2) - - 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.. - - 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.. - - 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.. - - class SoftwareElementState(object): - Deployable = pywbem.Uint16(0) - Installable = pywbem.Uint16(1) - Executable = pywbem.Uint16(2) - Running = pywbem.Uint16(3) - - class PrimaryStatus(object): - Unknown = pywbem.Uint16(0) - OK = pywbem.Uint16(1) - Degraded = pywbem.Uint16(2) - Error = pywbem.Uint16(3) - # DMTF_Reserved = .. - # Vendor_Reserved = 0x8000.. - - class Install(object): - Already_installed = pywbem.Uint32(0) - Successful_installation = pywbem.Uint32(1) - Failed = pywbem.Uint32(2) - -## end of class LMI_SoftwarePackage - -## get_providers() for associating CIM Class Name to python provider class name - -def get_providers(env): - lmi_softwarepackage_prov = LMI_SoftwarePackage(env) - return {'LMI_SoftwarePackage': lmi_softwarepackage_prov} diff --git a/src/software/providers/LMI_SoftwarePackageChecks.py b/src/software/providers/LMI_SoftwarePackageChecks.py deleted file mode 100644 index a2f798b..0000000 --- a/src/software/providers/LMI_SoftwarePackageChecks.py +++ /dev/null @@ -1,311 +0,0 @@ -# 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 -# - -"""Python Provider for LMI_SoftwarePackageChecks - -Instruments the CIM class LMI_SoftwarePackageChecks - -""" - -import pywbem -from pywbem.cim_provider2 import CIMProvider2 -from openlmi.software.LMI_SoftwareFileCheck import filecheck2model -from openlmi.software.LMI_SoftwarePackage import pkg2model -from openlmi.software.util.common import * - -class LMI_SoftwarePackageChecks(CIMProvider2): - """Instrument the CIM class LMI_SoftwarePackageChecks - - This association ties a SoftwareElement to a specific Check to validate - its state or its movement to the next state. Note that - SoftwareElements in a running state cannot transition to another - state. Therefore, the value of the Phase property is restricted to 0 - ("In-State") for SoftwareElements in the running state. - - """ - - 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 "Check" in model: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Missing Check property.") - if not "Element" in model: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Missing Element property.") - vpkg = SoftwareFileCheck.object_path2yumcheck(env, model['Check']) - model['Check'] = filecheck2model(vpkg, model['Check']['Name'], - env, keys_only=True) - model['Element'] = pkg2model(env, vpkg.po, keys_only=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({'Check': None, 'Element': None}) - - while False: # TODO more instances? - # TODO fetch system resource - # Key properties - #model['Check'] = pywbem.CIMInstanceName(classname='LMI_SoftwareFileCheck', ...) # TODO (type = REF (pywbem.CIMInstanceName(classname='LMI_SoftwareFileCheck', ...)) - #model['Element'] = pywbem.CIMInstanceName(classname='LMI_SoftwarePackage', ...) # TODO (type = REF (pywbem.CIMInstanceName(classname='LMI_SoftwarePackage', ...)) - 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__) - # TODO create or modify the instance - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement - return 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__) - - # TODO delete the resource - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED) # Remove to implement - - 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() - - # 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({'Check': None, 'Element': None}) - - with YumDB.getInstance(env): - if ( (not role or role.lower() == 'element') - and ch.is_subclass(object_name.namespace, - sub=object_name.classname, - super='LMI_SoftwarePackage')): - filecheck_model = pywbem.CIMInstanceName( - classname='LMI_SoftwareFileCheck', - namespace="root/cimv2", - host=model.path.host) - model['Element'] = object_name - - pkg = SoftwarePackage.object_path2pkg(env, object_name) - vpkg = yum.packages._RPMVerifyPackage( - pkg, pkg.hdr.fiFromHeader(), - SoftwareFileCheck.pkg_checksum_type(pkg), [], True) - for fc in vpkg: - model['Check'] = filecheck2model( - vpkg, fc.filename, env, keys_only=True, - model=filecheck_model) - yield model - - if ( (not role or role.lower() == 'check') - and ch.is_subclass(object_name.namespace, - sub=object_name.classname, - super='LMI_SoftwareFileCheck')): - model['Check'] = object_name - - vpkg = SoftwareFileCheck.object_path2yumcheck(env, object_name) - model['Element'] = pkg2model( - env, vpkg.po, keys_only=True) - yield model - - class Values(object): - class Phase(object): - In_State = pywbem.Uint16(0) - Next_State = pywbem.Uint16(1) - -## end of class LMI_SoftwarePackageChecksProvider - -## get_providers() for associating CIM Class Name to python provider class name - -def get_providers(env): - lmi_softwarepackagechecks_prov = LMI_SoftwarePackageChecks(env) - return {'LMI_SoftwarePackageChecks': lmi_softwarepackagechecks_prov} diff --git a/src/software/providers/__init__.py b/src/software/providers/__init__.py deleted file mode 100644 index 2ebe827..0000000 --- a/src/software/providers/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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 -# diff --git a/src/software/providers/util/__init__.py b/src/software/providers/util/__init__.py deleted file mode 100644 index 2ebe827..0000000 --- a/src/software/providers/util/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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 -# diff --git a/src/software/providers/util/common.py b/src/software/providers/util/common.py deleted file mode 100644 index 7b54f1e..0000000 --- a/src/software/providers/util/common.py +++ /dev/null @@ -1,809 +0,0 @@ -# -*- 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 -# - -"""Common utilities for LMI_Software* providers -""" - -import collections -from datetime import datetime -import grp -import hashlib -import itertools -import os -import platform -import pwd -import re -import rpm -import socket -import stat -import pywbem -import yum -import cmpi_pywbem_bindings as pycimmb -from openlmi.software.util import singletonmixin - -re_evra = re.compile(r'^(?P\d+):(?P[^-]+)' - r'-(?P.+)\.(?P[^.]+)$') -re_nevra = re.compile(r'^(?P.+)-(?P((?P\d+):)?(?P[^-]+)' - r'-(?P.+)\.(?P[^.]+))$') - -rpmdb_path = '/var/lib/rpm/Packages' - -class YumDB(singletonmixin.Singleton): - - ignoreSubsequent = True - - def __init__(self, env, *args, **kwargs): - if not isinstance(env, pycimmb.ProviderEnvironment): - raise TypeError("env must be instance of" - " pycimmb.ProviderEnvironment") - self._yum_args = (args, kwargs) - self._yum = None - self._db_mtime = 0 - self._lock_cnt = 0 - self.env = env - env.get_logger().log_info('init called') - - def is_dirty(self): - return self._db_mtime < os.stat(rpmdb_path).st_mtime - - def is_locked(self): - return self._yum._lockfile is not None - - def update_db(self): - self.env.get_logger().log_info('updating rpmdb') - self._db_mtime = os.stat(rpmdb_path).st_mtime - self._yum.doConfigSetup() - self._yum.doTsSetup() - self._yum.doRpmDBSetup() - - def __enter__(self): - self._lock_cnt += 1 - if self._lock_cnt < 2: - self._yum = yum.YumBase(*self._yum_args[0], **self._yum_args[1]) - if not self.is_locked() and self.is_dirty(): - self.update_db() - self._yum.doLock() - return self - - def __exit__(self, exc_type, exc_value, traceback): - if self._lock_cnt == 1: - del self._yum - self._lock_cnt -= 1 - - def __getattr__(self, name): - if not self.is_locked() and self.is_dirty(): - self.update_db() - return getattr(self._yum, name) - - -def _get_distname(): - if hasattr(platform, 'linux_distribution'): - return platform.linux_distribution( - full_distribution_name=False)[0].lower() - else: - return platform.dist()[0].lower() - - -def get_target_operating_system(): - """ - @return (val, text). - Where val is a number from ValueMap of TargetOperatingSystem property - of CIM_SoftwareElement class and text is its testual representation. - """ - - system = platform.system() - if system.lower() == 'linux': - try: - val, dist = \ - { 'redhat' : (79, 'RedHat Enterprise Linux') - , 'suse' : (81, 'SUSE') - , 'mandriva' : (88, 'Mandriva') - , 'ubuntu' : (93, 'Ubuntu') - , 'debian' : (95, 'Debian') - }[_get_distname()] - except KeyError: - linrel = platform.uname()[2] - if linrel.startswith('2.4'): - val, dist = (97, 'Linux 2.4.x') - elif linrel.startswith('2.6'): - val, dist = (99, 'Linux 2.6.x') - else: - return (36, 'LINUX') # no check for x86_64 - if platform.machine() == 'x86_64': - val += 1 - dist += ' 64-Bit' - return (val, dist) - elif system.lower() in ('macosx', 'darwin'): - return (2, 'MACOS') - # elif system.lower() == 'windows': # no general value - else: - return (0, 'Unknown') - -def get_computer_system_op(): - return pywbem.CIMInstanceName( - classname='CIM_ComputerSystem', - keybindings={ - "CreationClassName": "CIM_ComputerSystem" - , "Name" : socket.gethostname() }, - namespace="root/cimv2") - -def check_target_operating_system(system): - """ - @return if param system matches current target operating system - """ - if isinstance(system, basestring): - system = int(system) - if not isinstance(system, (int, long)): - raise TypeError("system must be either string or integer, not {}" - .format(system.__class__.__name__)) - tos = get_target_operating_system() - if system == tos: return True - if system == 36: # linux - if platform.system().lower() == "linux": return True - if ( system >= 97 and system <= 100 # linux 2.x.x - and platform.uname()[2].startswith('2.4' if system < 99 else '2.6') - # check machine - and ( bool(platform.machine().endswith('64')) - == bool(not (system % 2)))): - return True - return False - -def check_computer_system_op(env, system): - if not isinstance(system, pywbem.CIMInstanceName): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "\"System\" must be a CIMInstanceName") - our_system = get_computer_system_op() - ch = env.get_cimom_handle() - if not ch.is_subclass(system.namespace, - sub=system.classname, - super=our_system.classname): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Class of \"System\" must be a sublass of %s" % - our_system.classname) - if not 'CreationClassName' in system or not 'Name' in system: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "\"System\" is missing one of keys") - if not ch.is_subclass(system.namespace, - sub=system['CreationClassName'], - super=our_system.classname): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "CreationClassName of \"System\" must be a sublass of %s" % - our_system.classname) - if system['Name'] != our_system['Name']: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Name of \"System\" does not match \"%s\"" % - our_system['Name']) - return True - - -def match_pkg(pkg, **kwargs): - """ - all not Null and not empty arguments will be matched against pkg - attributes; if all of them match, return True - - possible arguments: - name, epoch, version, release, arch - evra, nevra - """ - for a in ('evra', 'nevra', 'name', 'epoch', 'version', 'release', 'arch'): - v = kwargs.get(a, None) - if v and getattr(pkg, a) != v: - return False - return True - -class SoftwarePackage: - """ - Just a namespace for common function related to SoftwarePackage provider. - """ - - @staticmethod - def parse_group(group, env): - try: - res = \ - { "amusements/games" : 3 - , "amusements/graphics" : 4 - , "applications/archiving" : 5 - , "applications/communications" : 6 - , "applications/databases" : 7 - , "applications/editors" : 8 - , "applications/emulators" : 9 - , "applications/engineering" : 10 - , "applications/file" : 11 - , "applications/internet" : 12 - , "applications/multimedia" : 13 - , "applications/productivity" : 14 - , "applications/publishing" : 15 - , "applications/system" : 16 - , "applications/text" : 17 - , "development/build tools" : 18 - , "development/debug" : 19 - , "development/debuggers" : 20 - , "development/documentation" : 21 - , "development/java" : 22 - , "development/languages" : 23 - , "development/libraries" : 24 - , "development/libraries/java" : 25 - , "development/system" : 26 - , "development/tools" : 27 - , "documentation" : 28 - , "internet/www/dynamic content" : 29 - , "system/libraries" : 30 - , "system environment/base" : 31 - , "system environment/daemons" : 32 - , "system environment/kernel" : 33 - , "system environment/libraries" : 34 - , "system environment/shells" : 35 - , "text processing/markup/xml" : 36 - , "user interface/desktops" : 37 - , "user interface/x" : 38 - , "user interface/x hardware support" : 39 - , "utilities" : 40 - }[group.lower()] - except KeyError: - logger = env.get_logger() - if not group or group.lower() == "unspecified": - logger.log_info("unspecified group '{}'".format(group)) - res = 2 - else: - logger.log_error("failed to parse group '{}'".format(group)) - res = 0 - return pywbem.Uint16(res) - - @staticmethod - def object_path2pkg(env, op, package_list='installed'): - """ - @param op must contain precise information of package, - otherwise a CIM_ERR_NOT_FOUND error is raised - @param package_list one of {'installed', 'all', 'available'} - says, where to look for given package - """ - if not isinstance(op, pywbem.CIMInstanceName): - raise TypeError("op must be an instance of CIMInstanceName") - if not isinstance(package_list, basestring): - raise TypeError("package_list must be a string") - if not package_list in ('installed', 'all', 'available'): - raise ValueError('unsupported package list "%s"'%package_list) - - tos = get_target_operating_system()[0] - if ( not op['Name'] or not op['SoftwareElementID'] - or not op['SoftwareElementID'].startswith(op['Name']) - or op['SoftwareElementID'].find(op['Version']) == -1): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "Wrong keys.") -# if op['SoftwareElementState'] not in ("2", 2): -# raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, -# "Only \"Executable\" software element state supported") - if not check_target_operating_system(op['TargetOperatingSystem']): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Wrong target operating system.") - if not op['Name'] or not op['Version']: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - 'Both "Name" and "Version" must be given') - m = re_nevra.match(op['SoftwareElementID']) - if not m: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Wrong SotwareElementID. Expected valid nevra" - " (name-[epoch:]version-release.arch).") - if op['Version'] != m.group('ver'): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Version does not match version part in SoftwareElementID.") - evra = "{}:{}-{}.{}".format(*( - (m.group(k) if k != "epoch" or m.group(k) else "0") - for k in ("epoch", 'ver', 'rel', 'arch'))) - with YumDB.getInstance(env) as yb: - pl = yb.doPackageLists(package_list, - showdups=package_list != 'installed') - if package_list != 'all': - pl = getattr(pl, package_list) - else: - # NOTE: available ∩ installed = ∅ - pl = itertools.chain(pl.available, pl.installed) - exact,_,_ = yum.packages.parsePackages(pl, [op['Name']]) - for pkg in yum.misc.unique(exact): - if pkg.evra == evra: break - else: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "No matching package found.") - return pkg - - @staticmethod - def object_path2pkg_search(env, op): - """ - similar to object_path2pkg, but tries to find best suitable - package matching keys - - If any matching package is already installed, it is returned. - Otherwise available package with highest version is returned. - - @param op may be object of CIMInstance or CIMInstanceName and - must contain at least \"Name\" or \"SoftwareElementID\" - @return instance of yum.rpmsack.RPMInstalledPackage in case of - installed package, otherwise yum.packages.YumAvailablePackage - """ - logger = env.get_logger() - if isinstance(op, pywbem.CIMInstance): - def _get_key(k): - v = op.properties.get(k, None) - if isinstance(v, pywbem.CIMProperty): return v.value - if v is not None: return v - logger.log_error('missing key "{}" in inst.props'.format(k)) - return op.path[k] if k in op.path else None - elif isinstance(op, pywbem.CIMInstanceName): - _get_key = lambda k: op[k] if k in op else None - else: - raise TypeError("op must be either CIMInstance or CIMInstanceName") - - # parse and check arguments - match_props = {} # args for match_pkg - if _get_key('SoftwareElementID'): - m = re_nevra.match(_get_key('SoftwareElementID')) - if not m: - raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, - "SoftwareElementID could not be parsed.") - for k in ('name', 'version', 'release', 'arch'): - mk = k if k not in ('version', 'release') else k[:3] - match_props[k] = m.group(mk) - if not m.group("epoch"): - match_props["epoch"] = "0" - else: - for k in ('name', 'epoch', 'version', 'release', 'arch'): - ik = k if k != 'arch' else "architecture" - if _get_key(ik): match_props[k] = _get_key(ik) - - if not match_props: - raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, - "Too few key values given (give at least a Name).") - if not 'name' in match_props: - raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, - "Missing either Name or SoftwareElementID property.") - - # get available packages - pl = YumDB.getInstance(env).doPackageLists('all', showdups=True) - # NOTE: available ∩ installed = ∅ - exact,_,_ = yum.packages.parsePackages( - itertools.chain(pl.available, pl.installed), - [match_props['name']]) - exact = yum.misc.unique(exact) - exact_orig = exact - exact = sorted( [ p for p in exact if match_pkg(p, **match_props) ] - , key=lambda a: a.evra) - if len(exact) == 0: - logger.log_error('could not find any package for query: {}' - ' in list: {}' - .format(match_props, [p.nevra for p in exact_orig])) - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "No matching package found.") - for pkg in exact: # check, whether package is already installed - if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): - return pkg - logger.log_info(('found multiple matching packages' - ' for query: {}' if len(exact) > 1 else - 'exact match found for query: {}') - .format(match_props)) - return exact[-1] # select highest version - - @staticmethod - def pkg2model_wrapper(namespace, classname): - """ - @return a function that transforms YumAvailablePackage object - to CIMInstanceName object - """ - - tos = pywbem.Uint16(get_target_operating_system()[0]) - - def pkg2model(env, pkg, keys_only=True, model=None): - """ - @param model if None, will be filled with data, otherwise - a new instance of CIMInstance or CIMObjectPath is created - """ - #if not isinstance(pkg, yum.rpmsack.RPMInstalledPackage): - #if not isinstance(pkg, yum.packages.YumHeaderPackage): - if not isinstance(pkg, yum.packages.YumAvailablePackage): - raise TypeError( - "pkg must be an instance of YumAvailablePackage") - if model is None: - model = pywbem.CIMInstanceName(classname, namespace=namespace) - if not keys_only: - model = pywbem.CIMInstance(classname, path=model) - if isinstance(model, pywbem.CIMInstance): - def _set_key(k, v): - model[k] = v - model.path[k] = v - else: - _set_key = model.__setitem__ - with YumDB.getInstance(env): - _set_key('Name', pkg.name) - _set_key('SoftwareElementID', pkg.nevra) - _set_key('SoftwareElementState', pywbem.Uint16(2 - if isinstance(pkg, yum.rpmsack.RPMInstalledPackage) - else 1)) - _set_key('TargetOperatingSystem', tos) - _set_key('Version', pkg.version) - if not keys_only: - model['Caption'] = pkg.summary - model['Description'] = pkg.description - if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): - model['InstallDate'] = pywbem.CIMDateTime( - datetime.fromtimestamp(pkg.installtime)) - if pkg.vendor: - model['Manufacturer'] = pkg.vendor - model['Release'] = pkg.release - model['Epoch'] = pywbem.Uint16(pkg.epoch) - model["Architecture"] = pkg.arch - model['License'] = pkg.license - model['Group'] = pkg.group - model['Size'] = pywbem.Uint64(pkg.size) - return model - - return pkg2model - -class SoftwareFileCheck: - """ - Just a namespace for functions related to FileCheck provider. - """ - - passed_flags_descriptions = ( - "Existence", - "File Type", - "File Size", - "File Mode", - "File Checksum", - "Device major/minor number", - "Symlink Target", - "User Ownership", "Group Ownership", - "Modify Time") - - checksumtype_str2num = dict((v, k) for (k, v) in - yum.constants.RPM_CHECKSUM_TYPES.items()) - - @staticmethod - def pkg_checksum_type(pkg): - """ - @return integer representation of checksum type - """ - if not isinstance(pkg, yum.packages.YumAvailablePackage): - raise TypeError("pkg must be an instance of YumAvailablePackage") - if isinstance(pkg, yum.rpmsack.RPMInstalledPackage): - return pkg.hdr[rpm.RPMTAG_FILEDIGESTALGO] - with self: # ensure, that _yum is inited - return SoftwareFileCheck.checksumtype_str2pywbem( - pkg.yumdb_info.checksum_type) - - @staticmethod - def checksumtype_num2hash(csumt): - return getattr(hashlib, yum.constants.RPM_CHECKSUM_TYPES[csumt]) - - @staticmethod - def checksumtype_str2pywbem(alg): - try: - res = SoftwareFileCheck.checksumtype_str2num[alg.lower()] - except KeyError: res = 0 - return pywbem.Uint16(res) - - @staticmethod - def filetype_str2pywbem(ft): - try: - return pywbem.Uint16( - { 'file' : 1 - , 'directory' : 2 - , 'symlink' : 3 - , 'fifo' : 4 - , 'character device' : 5 - , 'block device' : 6 - }[ft]) - except KeyError: - return pywbem.Uint16(0) - - @staticmethod - def filetype_mode2pywbem(mode): - for i, name in enumerate( - ('REG', 'DIR', 'LNK', 'FIFO', 'CHR', 'BLK'), 1): - if getattr(stat, 'S_IS' + name)(mode): - return pywbem.Uint16(i) - return pywbem.Uint16(0) - - @staticmethod - def mode2pywbem_flags(mode): - """ - @param mode if None, file does not exist - """ - if mode is None: return None - flags = [] - for i, c in enumerate(( - stat.S_IXOTH, - stat.S_IWOTH, - stat.S_IROTH, - stat.S_IXGRP, - stat.S_IWGRP, - stat.S_IRGRP, - stat.S_IXUSR, - stat.S_IWUSR, - stat.S_IRUSR, - stat.S_ISVTX, - stat.S_ISGID, - stat.S_ISUID)): - if c & mode: - flags.append(pywbem.Uint8(i)) - return flags - - @staticmethod - def hashfile(afile, hashers, blocksize=65536): - """ - @param hashers is a list of hash objects - @return list of digest strings (in hex format) for each hash object - given in the same order - """ - if not isinstance(hashers, (tuple, list, set, frozenset)): - hashers = (hashers, ) - buf = afile.read(blocksize) - while len(buf) > 0: - for h in hashers: h.update(buf) - buf = afile.read(blocksize) - return [ h.hexdigest() for h in hashers ] - - @staticmethod - def compute_checksums(env, checksum_type, file_type, file_path): - """ - @param file_type is not a file, then zeroes are returned - @param checksum_type selected hash algorithm to compute second - checksum - @return (md5sum, checksum) - both checksums are computed from file_path's content - first one is always md5, the second one depends on checksum_type - if file does not exists, (None, None) is returned - """ - hashers = [hashlib.md5()] - if checksum_type != SoftwareFileCheck.checksumtype_str2num["md5"]: - hashers.append(SoftwareFileCheck.checksumtype_num2hash(checksum_type)()) - if file_type != SoftwareFileCheck.filetype_str2pywbem('file'): - rslts = ['0'*len(h.hexdigest()) for h in hashers] - else: - try: - with open(file_path, 'rb') as f: - rslts = SoftwareFileCheck.hashfile(f, hashers) - except (OSError, IOError) as e: - env.get_logger().log_error("could not open file \"%s\"" - " for reading: %s" % (file_path, e)) - return None, None - return (rslts[0], rslts[1] if len(rslts) > 1 else rslts[0]*2) - - @staticmethod - def object_path2yumcheck(env, op): - """ - @return instance of yum.packages._RPMVerifyPackage - this object holds RPMInstalledPackage under its po attribute - """ - if not isinstance(op, pywbem.CIMInstanceName): - raise TypeError("op must be instance of CIMInstanceName, " - "not \"%s\"" % op.__class__.__name__) - log = env.get_logger() - - tos = get_target_operating_system()[0] - if ( not op['Name'] or not op['SoftwareElementID'] - or not op['CheckID'] - or not op['CheckID'].endswith('#'+op['Name']) - or op['SoftwareElementID'].find(op['Version']) == -1): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "Wrong keys.") - if op['SoftwareElementState'] not in ("2", 2): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Only \"Executable\" software element state supported") - if not check_target_operating_system(op['TargetOperatingSystem']): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Wrong target operating system.") - if not op['Name'] or not op['Version']: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - 'Both "Name" and "Version" must be given') - m = re_nevra.match(op['SoftwareElementID']) - if not m: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Wrong SotwareElementID. Expected valid nevra" - " (name-epoch:version-release.arch).") - if op['Version'] != m.group('ver'): - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "Version does not match version part in SoftwareElementID.") - - evra = "{}:{}-{}.{}".format(*( - (m.group(k) if k != "epoch" or m.group(k) else "0") - for k in ("epoch", 'ver', 'rel', 'arch'))) - with YumDB.getInstance(env) as yb: - pl = yb.doPackageLists('installed') - exact, matched, unmatched = yum.packages.parsePackages( - pl.installed, [m.group('name')]) - exact = yum.misc.unique(exact) - for pkg in exact: - if pkg.evra == evra: break - else: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "No matching package installed.") - - fi = pkg.hdr.fiFromHeader() - vpkg = yum.packages._RPMVerifyPackage(pkg, fi, - SoftwareFileCheck.pkg_checksum_type(pkg), [], True) - if not op['Name'] in vpkg: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "File not found in RPM package.") - return vpkg - - """ - Named tuple to store results of rpm file check as pywbem values, - all results are in form: - (expected, reality) - where - expected is value from rpm package - reality is value obtained from installed file - None means, that value could not be obtained - except for "exists" and "md5_checksum" attributes, where "exists" - is boolean and md5_checksum is a string - for example: - file_check.file_type == (4, 3) - """ - FileCheck = collections.namedtuple('FileCheck', - 'exists, md5_checksum, file_type, file_size, file_mode, ' - 'file_checksum, device, link_target, user_id, group_id, ' - 'last_modification_time') - - @staticmethod - def test_file(env, checksum_type, vpf): - """ - @param checksum type is a pywbem value for ChecksumType property - @return instance of FileCheck - """ - if not isinstance(vpf, yum.packages._RPMVerifyPackageFile): - raise TypeError("vpf must be an instance of _RPMVerifyPackage," - " not \"%s\"" % vpf.__class__.__name__) - exists = os.path.lexists(vpf.filename) - md5_checksum = None - expected = { - "file_type" : SoftwareFileCheck.filetype_str2pywbem(vpf.ftype), - "user_id" : pywbem.Uint32(pwd.getpwnam(vpf.user).pw_uid), - "group_id" : pywbem.Uint32(grp.getgrnam(vpf.group).gr_gid), - "file_mode" : pywbem.Uint32(vpf.mode), - "file_size" : pywbem.Uint64(vpf.size), - "link_target" : vpf.readlink if vpf.readlink else None, - "file_checksum" : vpf.digest[1], - "device" : (pywbem.Uint64(vpf.dev) - if vpf.ftype.endswith('device') else None), - "last_modification_time" : pywbem.Uint64(vpf.mtime) - } - if not exists: - reality = collections.defaultdict(lambda: None) - else: - fstat = os.lstat(vpf.filename) - reality = { - "file_type" : SoftwareFileCheck.filetype_mode2pywbem(fstat.st_mode), - "user_id" : pywbem.Uint32(fstat.st_uid), - "group_id" : pywbem.Uint32(fstat.st_gid), - "file_mode" : pywbem.Uint32(fstat.st_mode), - "file_size" : pywbem.Uint64(fstat.st_size), - "last_modification_time" : pywbem.Uint64(fstat.st_mtime) - } - reality["device"] = (pywbem.Uint64(fstat.st_dev) - if reality['file_type'] == SoftwareFileCheck.filetype_str2pywbem( - "device") else None) - reality["link_target"] = (os.readlink(vpf.filename) - if os.path.islink(vpf.filename) else None) - md5_checksum, checksum = SoftwareFileCheck.compute_checksums( - env, checksum_type, reality["file_type"], vpf.filename) - reality["file_checksum"] = checksum - kwargs = dict(exists=exists, md5_checksum=md5_checksum, - **dict((k, (expected[k], reality[k])) for k in expected)) - return SoftwareFileCheck.FileCheck(**kwargs) - - @staticmethod - def filecheck_passed(fc): - if not isinstance(fc, SoftwareFileCheck.FileCheck): - raise TypeError("fc must be an instance of FileCheck") - return ( fc.exists - and all( v[0] == v[1] - for k, v in fc._asdict().items() if ( - isinstance(v, tuple) - and ( k != "last_modification_time" - or fc.file_type[0] == \ - SoftwareFileCheck.filetype_str2pywbem("file") - )))) - - @staticmethod - def filecheck_wrapper(namespace, classname): - - def _filecheck2model_flags(fc): - flags = [] - for k, v in fc._asdict().items(): - if isinstance(v, tuple): - if ( k != "last_modification_time" - or fc.file_type[0] == SoftwareFileCheck.filetype_str2pywbem( - 'file')): - # last_modification_time check is valid only for - # regular files - flag = fc.exists and v[0] == v[1] - else: - flag = True - flags.append(flag) - elif isinstance(v, bool): - flags.append(v) - return flags - - def filecheck2model(vpkg, fn, env, keys_only=True, - model=None, fc=None): - if not isinstance(vpkg, yum.packages._RPMVerifyPackage): - raise TypeError( - "vpkg must be an instance of _RPMVerifyPackage") - if not fn in vpkg: - raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, - "File \"%s\" not found among package files" % fn) - if model is None: - model = pywbem.CIMInstanceName(classname, namespace=namespace) - if not keys_only: - model = pywbem.CIMInstance(classname, path=model) - if fc is not None: - if not isinstance(fc, SoftwareFileCheck.FileCheck): - raise TypeError("fc must be an instance of FileCheck") - pkg = vpkg.po - vpf = vpkg._files[fn] - model['Name'] = vpf.filename - model['SoftwareElementID'] = pkg.nevra - model['SoftwareElementState'] = pywbem.Uint16(2) - model['TargetOperatingSystem'] = pywbem.Uint16( - get_target_operating_system()[0]) - model['Version'] = pkg.version - model['CheckID'] = '%s#%s' % (pkg.name, vpf.filename) - if not keys_only: - #model['Caption'] = '' # TODO - #model['CheckMode'] = bool() # TODO - #model['CRC1'] = pywbem.Uint32() # TODO - #model['CRC2'] = pywbem.Uint32() # TODO - #model['CreateTimeStamp'] = pywbem.CIMDateTime() # TODO - #model['Description'] = '' # TODO - #model['ElementName'] = '' # TODO - #model['InstanceID'] = '' # TODO - model['FileName'] = os.path.basename(vpf.filename) - model['FileChecksumType'] = csumt = \ - pywbem.Uint16(SoftwareFileCheck.pkg_checksum_type(pkg)) - if fc is None: - fc = SoftwareFileCheck.test_file(env, csumt, vpf) - for mattr, fattr in ( - ('FileType', 'file_type'), - ('FileUserID', 'user_id'), - ('FileGroupID', 'group_id'), - ('FileMode', 'file_mode'), - ('LastModificationTime', 'last_modification_time'), - ('FileSize', 'file_size'), - ('LinkTarget', 'link_target'), - ('FileChecksum', 'file_checksum')): - exp, rea = getattr(fc, fattr) - if exp is not None: - model['Expected' + mattr] = exp - if rea is not None: - model[mattr] = rea - model['ExpectedFileModeFlags'] = \ - SoftwareFileCheck.mode2pywbem_flags(fc.file_mode[0]) - if fc.exists: - model['FileModeFlags'] = SoftwareFileCheck.mode2pywbem_flags( - fc.file_mode[1]) - model['FileExists'] = fc.exists - if fc.md5_checksum is not None: - model['MD5Checksum'] = fc.md5_checksum - model['PassedFlags'] = _filecheck2model_flags(fc) - model['PassedFlagsDescriptions'] = list( - SoftwareFileCheck.passed_flags_descriptions) - return model - - return filecheck2model - diff --git a/src/software/providers/util/singletonmixin.py b/src/software/providers/util/singletonmixin.py deleted file mode 100644 index 8051695..0000000 --- a/src/software/providers/util/singletonmixin.py +++ /dev/null @@ -1,508 +0,0 @@ -""" -A Python Singleton mixin class that makes use of some of the ideas -found at http://c2.com/cgi/wiki?PythonSingleton. Just inherit -from it and you have a singleton. No code is required in -subclasses to create singleton behavior -- inheritance from -Singleton is all that is needed. - -Singleton creation is threadsafe. - -USAGE: - -Just inherit from Singleton. If you need a constructor, include -an __init__() method in your class as you usually would. However, -if your class is S, you instantiate the singleton using S.getInstance() -instead of S(). Repeated calls to S.getInstance() return the -originally-created instance. - -For example: - -class S(Singleton): - - def __init__(self, a, b=1): - pass - -S1 = S.getInstance(1, b=3) - - -Most of the time, that's all you need to know. However, there are some -other useful behaviors. Read on for a full description: - -1) Getting the singleton: - - S.getInstance() - -returns the instance of S. If none exists, it is created. - -2) The usual idiom to construct an instance by calling the class, i.e. - - S() - -is disabled for the sake of clarity. - -For one thing, the S() syntax means instantiation, but getInstance() -usually does not cause instantiation. So the S() syntax would -be misleading. - -Because of that, if S() were allowed, a programmer who didn't -happen to notice the inheritance from Singleton (or who -wasn't fully aware of what a Singleton pattern -does) might think he was creating a new instance, -which could lead to very unexpected behavior. - -So, overall, it is felt that it is better to make things clearer -by requiring the call of a class method that is defined in -Singleton. An attempt to instantiate via S() will result -in a SingletonException being raised. - -3) Use __S.__init__() for instantiation processing, -since S.getInstance() runs S.__init__(), passing it the args it has received. - -If no data needs to be passed in at instantiation time, you don't need S.__init__(). - -4) If S.__init__(.) requires parameters, include them ONLY in the -first call to S.getInstance(). If subsequent calls have arguments, -a SingletonException is raised by default. - -If you find it more convenient for subsequent calls to be allowed to -have arguments, but for those argumentsto be ignored, just include -'ignoreSubsequent = True' in your class definition, i.e.: - - class S(Singleton): - - ignoreSubsequent = True - - def __init__(self, a, b=1): - pass - -5) For testing, it is sometimes convenient for all existing singleton -instances to be forgotten, so that new instantiations can occur. For that -reason, a forgetAllSingletons() function is included. Just call - - forgetAllSingletons() - -and it is as if no earlier instantiations have occurred. - -6) As an implementation detail, classes that inherit -from Singleton may not have their own __new__ -methods. To make sure this requirement is followed, -an exception is raised if a Singleton subclass includ -es __new__. This happens at subclass instantiation -time (by means of the MetaSingleton metaclass. - - -By Gary Robinson, grobinson@flyfi.com. No rights reserved -- -placed in the public domain -- which is only reasonable considering -how much it owes to other people's code and ideas which are in the -public domain. The idea of using a metaclass came from -a comment on Gary's blog (see -http://www.garyrobinson.net/2004/03/python_singleto.html#comments). -Other improvements came from comments and email from other -people who saw it online. (See the blog post and comments -for further credits.) - -Not guaranteed to be fit for any particular purpose. Use at your -own risk. -""" - -import threading - -class SingletonException(Exception): - pass - -_stSingletons = set() -_lockForSingletons = threading.RLock() -_lockForSingletonCreation = threading.RLock() # Ensure only one instance of each Singleton - # class is created. This is not bound to the - # individual Singleton class since we need to - # ensure that there is only one mutex for each - # Singleton class, which would require having - # a lock when setting up the Singleton class, - # which is what this is anyway. So, when any - # Singleton is created, we lock this lock and - # then we don't need to lock it again for that - # class. - -def _createSingletonInstance(cls, lstArgs, dctKwArgs): - _lockForSingletonCreation.acquire() - try: - if cls._isInstantiated(): # some other thread got here first - return - - instance = cls.__new__(cls) - try: - instance.__init__(*lstArgs, **dctKwArgs) - except TypeError, e: - if e.message.find('__init__() takes') != -1: - raise SingletonException, 'If the singleton requires __init__ args, supply them on first call to getInstance().' - else: - raise - cls.cInstance = instance - _addSingleton(cls) - finally: - _lockForSingletonCreation.release() - -def _addSingleton(cls): - _lockForSingletons.acquire() - try: - assert cls not in _stSingletons - _stSingletons.add(cls) - finally: - _lockForSingletons.release() - -def _removeSingleton(cls): - _lockForSingletons.acquire() - try: - if cls in _stSingletons: - _stSingletons.remove(cls) - finally: - _lockForSingletons.release() - -def forgetAllSingletons(): - '''This is useful in tests, since it is hard to know which singletons need to be cleared to make a test work.''' - _lockForSingletons.acquire() - try: - for cls in _stSingletons.copy(): - cls._forgetClassInstanceReferenceForTesting() - - # Might have created some Singletons in the process of tearing down. - # Try one more time - there should be a limit to this. - iNumSingletons = len(_stSingletons) - if len(_stSingletons) > 0: - for cls in _stSingletons.copy(): - cls._forgetClassInstanceReferenceForTesting() - iNumSingletons -= 1 - assert iNumSingletons == len(_stSingletons), 'Added a singleton while destroying ' + str(cls) - assert len(_stSingletons) == 0, _stSingletons - finally: - _lockForSingletons.release() - -class MetaSingleton(type): - def __new__(metaclass, strName, tupBases, dct): - if dct.has_key('__new__'): - raise SingletonException, 'Can not override __new__ in a Singleton' - return super(MetaSingleton, metaclass).__new__(metaclass, strName, tupBases, dct) - - def __call__(cls, *lstArgs, **dictArgs): - raise SingletonException, 'Singletons may only be instantiated through getInstance()' - -class Singleton(object): - __metaclass__ = MetaSingleton - - def getInstance(cls, *lstArgs, **dctKwArgs): - """ - Call this to instantiate an instance or retrieve the existing instance. - If the singleton requires args to be instantiated, include them the first - time you call getInstance. - """ - if cls._isInstantiated(): - if (lstArgs or dctKwArgs) and not hasattr(cls, 'ignoreSubsequent'): - raise SingletonException, 'Singleton already instantiated, but getInstance() called with args.' - else: - _createSingletonInstance(cls, lstArgs, dctKwArgs) - - return cls.cInstance - getInstance = classmethod(getInstance) - - def _isInstantiated(cls): - # Don't use hasattr(cls, 'cInstance'), because that screws things up if there is a singleton that - # extends another singleton. hasattr looks in the base class if it doesn't find in subclass. - return 'cInstance' in cls.__dict__ - _isInstantiated = classmethod(_isInstantiated) - - # This can be handy for public use also - isInstantiated = _isInstantiated - - def _forgetClassInstanceReferenceForTesting(cls): - """ - This is designed for convenience in testing -- sometimes you - want to get rid of a singleton during test code to see what - happens when you call getInstance() under a new situation. - - To really delete the object, all external references to it - also need to be deleted. - """ - try: - if hasattr(cls.cInstance, '_prepareToForgetSingleton'): - # tell instance to release anything it might be holding onto. - cls.cInstance._prepareToForgetSingleton() - del cls.cInstance - _removeSingleton(cls) - except AttributeError: - # run up the chain of base classes until we find the one that has the instance - # and then delete it there - for baseClass in cls.__bases__: - if issubclass(baseClass, Singleton): - baseClass._forgetClassInstanceReferenceForTesting() - _forgetClassInstanceReferenceForTesting = classmethod(_forgetClassInstanceReferenceForTesting) - - -if __name__ == '__main__': - - import unittest - import time - - class singletonmixin_Public_TestCase(unittest.TestCase): - def testReturnsSameObject(self): - """ - Demonstrates normal use -- just call getInstance and it returns a singleton instance - """ - - class A(Singleton): - def __init__(self): - super(A, self).__init__() - - a1 = A.getInstance() - a2 = A.getInstance() - self.assertEquals(id(a1), id(a2)) - - def testInstantiateWithMultiArgConstructor(self): - """ - If the singleton needs args to construct, include them in the first - call to get instances. - """ - - class B(Singleton): - - def __init__(self, arg1, arg2): - super(B, self).__init__() - self.arg1 = arg1 - self.arg2 = arg2 - - b1 = B.getInstance('arg1 value', 'arg2 value') - b2 = B.getInstance() - self.assertEquals(b1.arg1, 'arg1 value') - self.assertEquals(b1.arg2, 'arg2 value') - self.assertEquals(id(b1), id(b2)) - - def testInstantiateWithKeywordArg(self): - - class B(Singleton): - - def __init__(self, arg1=5): - super(B, self).__init__() - self.arg1 = arg1 - - b1 = B.getInstance('arg1 value') - b2 = B.getInstance() - self.assertEquals(b1.arg1, 'arg1 value') - self.assertEquals(id(b1), id(b2)) - - def testTryToInstantiateWithoutNeededArgs(self): - - class B(Singleton): - - def __init__(self, arg1, arg2): - super(B, self).__init__() - self.arg1 = arg1 - self.arg2 = arg2 - - self.assertRaises(SingletonException, B.getInstance) - - def testPassTypeErrorIfAllArgsThere(self): - """ - Make sure the test for capturing missing args doesn't interfere with a normal TypeError. - """ - class B(Singleton): - - def __init__(self, arg1, arg2): - super(B, self).__init__() - self.arg1 = arg1 - self.arg2 = arg2 - raise TypeError, 'some type error' - - self.assertRaises(TypeError, B.getInstance, 1, 2) - - def testTryToInstantiateWithoutGetInstance(self): - """ - Demonstrates that singletons can ONLY be instantiated through - getInstance, as long as they call Singleton.__init__ during construction. - - If this check is not required, you don't need to call Singleton.__init__(). - """ - - class A(Singleton): - def __init__(self): - super(A, self).__init__() - - self.assertRaises(SingletonException, A) - - def testDontAllowNew(self): - - def instantiatedAnIllegalClass(): - class A(Singleton): - def __init__(self): - super(A, self).__init__() - - def __new__(metaclass, strName, tupBases, dct): - return super(MetaSingleton, metaclass).__new__(metaclass, strName, tupBases, dct) - - self.assertRaises(SingletonException, instantiatedAnIllegalClass) - - - def testDontAllowArgsAfterConstruction(self): - class B(Singleton): - - def __init__(self, arg1, arg2): - super(B, self).__init__() - self.arg1 = arg1 - self.arg2 = arg2 - - B.getInstance('arg1 value', 'arg2 value') - self.assertRaises(SingletonException, B, 'arg1 value', 'arg2 value') - - def test_forgetClassInstanceReferenceForTesting(self): - class A(Singleton): - def __init__(self): - super(A, self).__init__() - class B(A): - def __init__(self): - super(B, self).__init__() - - # check that changing the class after forgetting the instance produces - # an instance of the new class - a = A.getInstance() - assert a.__class__.__name__ == 'A' - A._forgetClassInstanceReferenceForTesting() - b = B.getInstance() - assert b.__class__.__name__ == 'B' - - # check that invoking the 'forget' on a subclass still deletes the instance - B._forgetClassInstanceReferenceForTesting() - a = A.getInstance() - B._forgetClassInstanceReferenceForTesting() - b = B.getInstance() - assert b.__class__.__name__ == 'B' - - def test_forgetAllSingletons(self): - # Should work if there are no singletons - forgetAllSingletons() - - class A(Singleton): - ciInitCount = 0 - def __init__(self): - super(A, self).__init__() - A.ciInitCount += 1 - - A.getInstance() - self.assertEqual(A.ciInitCount, 1) - - A.getInstance() - self.assertEqual(A.ciInitCount, 1) - - forgetAllSingletons() - A.getInstance() - self.assertEqual(A.ciInitCount, 2) - - def test_threadedCreation(self): - # Check that only one Singleton is created even if multiple - # threads try at the same time. If fails, would see assert in _addSingleton - class Test_Singleton(Singleton): - def __init__(self): - super(Test_Singleton, self).__init__() - - class Test_SingletonThread(threading.Thread): - def __init__(self, fTargetTime): - super(Test_SingletonThread, self).__init__() - self._fTargetTime = fTargetTime - self._eException = None - - def run(self): - try: - fSleepTime = self._fTargetTime - time.time() - if fSleepTime > 0: - time.sleep(fSleepTime) - Test_Singleton.getInstance() - except Exception, e: - self._eException = e - - fTargetTime = time.time() + 0.1 - lstThreads = [] - for _ in xrange(100): - t = Test_SingletonThread(fTargetTime) - t.start() - lstThreads.append(t) - eException = None - for t in lstThreads: - t.join() - if t._eException and not eException: - eException = t._eException - if eException: - raise eException - - def testNoInit(self): - """ - Demonstrates use with a class not defining __init__ - """ - - class A(Singleton): - pass - - #INTENTIONALLY UNDEFINED: - #def __init__(self): - # super(A, self).__init__() - - A.getInstance() #Make sure no exception is raised - - def testMultipleGetInstancesWithArgs(self): - - class A(Singleton): - - ignoreSubsequent = True - - def __init__(self, a, b=1): - pass - - a1 = A.getInstance(1) - a2 = A.getInstance(2) # ignores the second call because of ignoreSubsequent - - class B(Singleton): - - def __init__(self, a, b=1): - pass - - b1 = B.getInstance(1) - self.assertRaises(SingletonException, B.getInstance, 2) # No ignoreSubsequent included - - class C(Singleton): - - def __init__(self, a=1): - pass - - c1 = C.getInstance(a=1) - self.assertRaises(SingletonException, C.getInstance, a=2) # No ignoreSubsequent included - - def testInheritance(self): - """ - It's sometimes said that you can't subclass a singleton (see, for instance, - http://steve.yegge.googlepages.com/singleton-considered-stupid point e). This - test shows that at least rudimentary subclassing works fine for us. - """ - - class A(Singleton): - - def setX(self, x): - self.x = x - - def setZ(self, z): - raise NotImplementedError - - class B(A): - - def setX(self, x): - self.x = -x - - def setY(self, y): - self.y = y - - a = A.getInstance() - a.setX(5) - b = B.getInstance() - b.setX(5) - b.setY(50) - self.assertEqual((a.x, b.x, b.y), (5, -5, 50)) - self.assertRaises(AttributeError, eval, 'a.setY', {}, locals()) - self.assertRaises(NotImplementedError, b.setZ, 500) - - unittest.main() - diff --git a/src/software/setup.py b/src/software/setup.py index 433be41..25eb001 100644 --- a/src/software/setup.py +++ b/src/software/setup.py @@ -6,10 +6,10 @@ setup( author_email='miminar@redhat.com', url='https://fedorahosted.org/openlmi/', version='0.5', - package=['openlmi'], - package_dir={'openlmi.software': 'providers'}, + namespace_packages=['openlmi'], packages=['openlmi.software', 'openlmi.software.util'], install_requires=['openlmi'], + license="LGPLv2+", classifiers=[ 'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)', 'Operating System :: POSIX :: Linux', diff --git a/tools/pylint/README b/tools/pylint/README new file mode 100644 index 0000000..0f30dc2 --- /dev/null +++ b/tools/pylint/README @@ -0,0 +1,36 @@ +This tool uses pylint to check for errors in python code. +Before using it, please ensure, that you have installed openlmi-python +and all of the other cim provider packages, that you want to chek, into +your PYTHONPATH. + +INSTALLATION TO PYTHON PATH + * If checking already installed providers under /usr/lib/pythonX.Y/* + you may skip this step. + 1. Choose some directory for your PYTHONPATH, if you don't have one yet. eg: + $ mkdir ~/.python_sandbox + $ export PYTHONPATH=~/.python_sandbox + note: you may put the export line into you .profile + 2. Go to the directory of python egg, you want to install and install it: + $ cd openlmi-providers/src/python + $ python setup.py develop --install-dir=$PYTHONPATH + 3. Repeat step 2 for providers you want to check. + 4. Check sources. + +FIX FOR PYLINT + * Due to a bug in pylint's module handling, it fails to work with namespace + packages. A bug is described here: http://www.logilab.org/ticket/8796 + * To fix this you may apply attached patch "logilab-modutils-0.57.1.patch" + to logilab module (this one is for version 0.57.1): + $ patch -d /usr/lib/python2.7/site-packages/logilab -p1 \ + 1: ++ module = sys.modules[modpath.pop(0)] ++ path = module.__path__ + try: + _, mp_filename, mp_desc = find_module(modpath[0], path) + except ImportError: diff --git a/tools/pylint/plugins/__init__.py b/tools/pylint/plugins/__init__.py new file mode 100644 index 0000000..2ebe827 --- /dev/null +++ b/tools/pylint/plugins/__init__.py @@ -0,0 +1,20 @@ +# 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 +# diff --git a/tools/pylint/plugins/cim_provider_checker.py b/tools/pylint/plugins/cim_provider_checker.py new file mode 100644 index 0000000..253cb9d --- /dev/null +++ b/tools/pylint/plugins/cim_provider_checker.py @@ -0,0 +1,149 @@ +# -*- 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 +""" +Pylint checker for CIM provider modules and classes. +""" + +import re +from logilab.astng import node_classes # pylint: disable=W0403 +from logilab.astng import scoped_nodes # pylint: disable=W0403 +from pylint.interfaces import IASTNGChecker +from pylint.checkers import BaseChecker + +_RE_PROVIDER_CLASS_NAME = re.compile( + r'^(?P[A-Z][a-zA-Z0-9]*)_(?P[A-Z][a-zA-Z]*)$') +_RE_PROVIDER_MODULE_NAME = re.compile( + r'^((?P.*)\.)?(?P(?P[A-Z][a-zA-Z0-9]*)' + r'_(?P[A-Z][a-zA-Z]*))$') +_RE_COMMON_MODULE_NAME = re.compile( + r'^([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)$') + +def supress_cim_provider_messages(linter, node): + """ + Supress some warnings for CIMProvider2 subclass. + @param node is a subclass of CIMProvider2 + """ + assert isinstance(node, scoped_nodes.Class) + if ( 'Values' in node + and isinstance(node['Values'], scoped_nodes.Class)): + linter.disable('R0903', scope='module', line=node['Values'].lineno) + linter.disable('C0111', scope='module', line=node['Values'].lineno) + for child in node['Values'].get_children(): + if not isinstance(child, scoped_nodes.Class): + continue + linter.disable('R0903', scope='module', line=child.lineno) + linter.disable('C0111', scope='module', line=child.lineno) + +class CIMProviderChecker(BaseChecker): + """ + Checks for compliance to naming conventions for python cim providers. + """ + + __implements__ = IASTNGChecker + + name = 'cim_provider' + msgs = { + 'C9904': ('Invalid provider class name %s', + "Class name representing cim provider should be in inform " + "_. Where and should be both " + "written in CamelCase."), + 'C9905': ('Invalid provider module name %s', + "Module containing cim provider(s) should be named as " + "_. Where both and are " + "CamelCased strings."), + 'C9906': ('Prefixes of module and class does not match: %s != %s', + "Module prefix has to match provider class prefix."), + 'E9907': ("Missing get_providers function in module %s", + "Provider module must contain get_providers function."), + 'W9908': ("get_providers in module %s is not a function", + "get_providers should be a callable function."), + 'W9909': ("Missing provider name \"%s\" in providers dictionary.", + "Function get_providers returns providers association" + " dictionary, that must include all module's provider" + " classes."), + 'C9910': ("Prefix different from LMI: %s", + "All OpenLMI CIM classes have LMI_ ORGID prefix."), + 'C9911': ("Invalid module name: %s", + "All modules, that does not declare cim provider class" + " should be named according to this regexp:" + " '^(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$'."), + } + + # this is important so that your checker is executed before others + priority = -2 + + def visit_class(self, node): + """ + Check every class, which inherits from + pywbem.cim_provider2.CIMProvider2. + """ + if "CIMProvider2" in [a.name for a in node.ancestors()]: + clsm = _RE_PROVIDER_CLASS_NAME.match(node.name) + if not clsm: + self.add_message('C9904', node=node, args=node.name) + parent = node.parent + while not isinstance(parent, scoped_nodes.Module): + parent = parent.parent + modm = _RE_PROVIDER_MODULE_NAME.match(parent.name) + if not modm: + self.add_message('C9905', node=node, args=parent.name) + if not clsm: + return + if clsm.group('prefix') != modm.group('prefix'): + self.add_message('C9906', node=node, + args=(modm.group('prefix'), clsm.group('prefix'))) + if clsm.group('prefix') != 'LMI': + self.add_message('C9910', node=node, args=clsm.group('prefix')) + if not 'get_providers' in parent.keys(): + self.add_message('E9907', node=parent, args=parent.name) + return + getprovs = parent['get_providers'] + if not isinstance(getprovs, scoped_nodes.Function): + self.add_message('W9908', node=getprovs, args=parent.name) + ret = getprovs.last_child() + if not isinstance(ret, node_classes.Return): + return + dictionary = ret.get_children().next() + if not isinstance(dictionary, node_classes.Dict): + return + if not node.name in [i[0].value for i in dictionary.items]: + self.add_message('W9909', node=getprovs, args=node.name) + supress_cim_provider_messages(self.linter, node) + + def visit_module(self, node): + """ + Check for invalid module name. + """ + modm = _RE_PROVIDER_MODULE_NAME.match(node.name) + if modm: + if not _RE_COMMON_MODULE_NAME.match(node.name): + for child in node.get_children(): + if ( isinstance(child, scoped_nodes.Class) + and 'CIMProvider2' in [ + a.name for a in child.ancestors()]): + break + else: + self.add_message('C9911', node=node, args=node.name) + +def register(linter): + """required method to auto register our checker""" + linter.register_checker(CIMProviderChecker(linter)) + diff --git a/tools/pylint/plugins/unittest_checker.py b/tools/pylint/plugins/unittest_checker.py new file mode 100644 index 0000000..da9e6e7 --- /dev/null +++ b/tools/pylint/plugins/unittest_checker.py @@ -0,0 +1,82 @@ +# -*- encoding: utf-8 -*- +# 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 +# +"""Pylint plugin to check OpenLMI unittest modules.""" + +from logilab.astng import scoped_nodes +from pylint.interfaces import IASTNGChecker +from pylint.checkers import BaseChecker +import unittest + +def is_test_case_method(node): + """ + Check, whether node method is defined by TestCase base class. + """ + if ( isinstance(node, scoped_nodes.Function) + and node.name in unittest.TestCase.__dict__): + return True + return False + +def is_test_case_subclass(node): + """ + Check, whether node is a subclass of TestCase base class. + """ + if not isinstance(node, scoped_nodes.Class): + return False + for ancestor in node.ancestors(): + if ( ancestor.name == 'TestCase' + and ancestor.getattr('__module__')[0].value.startswith('unittest')): + return True + return False + +class TestCaseChecker(BaseChecker): + """ + Checker for OpenLMI unittest modules. + Right now it just suppresses unwanted messages. + """ + + __implements__ = IASTNGChecker + + name = 'unittest_case' + # When we do have some real warning messages/reports, + # remote W9920. We need it just to get registered. + msgs = { 'W9920': ('Dummy', "This is a dummy message.")} + + priority = -1 + + def visit_class(self, node): + """ + Suppress Naming and 'Attribute creation out of __init__' + errors for every TestCase subclass. + """ + if not is_test_case_subclass(node): + return + if 'setUp' in node: + self.linter.disable('W0201', + scope='module', line=node['setUp'].lineno) + for child in node.get_children(): + if not is_test_case_method(child): + continue + self.linter.disable('C0103', + scope='module', line=child.lineno) + +def register(linter): + """required method to auto register our checker""" + linter.register_checker(TestCaseChecker(linter)) + diff --git a/tools/pylint/pylintlmi b/tools/pylint/pylintlmi new file mode 100755 index 0000000..4e39aeb --- /dev/null +++ b/tools/pylint/pylintlmi @@ -0,0 +1,8 @@ +#!/bin/sh + +dir=`dirname $0` +[[ -z "$dir" ]] && dir=. + +export PYLINTRC=$dir/pylintrc +export PYTHONPATH="$PYTHONPATH:$dir/plugins" +exec pylint $@ diff --git a/tools/pylint/pylintrc b/tools/pylint/pylintrc new file mode 100644 index 0000000..f065e65 --- /dev/null +++ b/tools/pylint/pylintrc @@ -0,0 +1,249 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +init-hook= + +# Profiled execution. +profile=no + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins=unittest_checker,cim_provider_checker + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). +disable=I0011 + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=text + +# Include message's id in output +include-ids=yes + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=yes + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (RP0004). +comment=no + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|([A-Z][a-zA-Z]*_[A-Z][a-zA-Z0-9]*))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=(([A-Z_][a-zA-Z0-9]+)|([A-Z][a-zA-Z]*_[A-Z][a-zA-Z0-9]*))$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__ + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=8 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception -- cgit