summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Minar <miminar@redhat.com>2013-08-22 09:37:03 +0200
committerMichal Minar <miminar@redhat.com>2013-08-23 06:47:40 +0200
commit00d048f15816a319044f192d8a12e09b96f8bf72 (patch)
tree3273f7cd1a19dcbb21ea8f2b63e55ebb808d15ff
parent1ad3a75d07f2b8d1d0518d76c83c3fb26540bdbe (diff)
downloadopenlmi-providers-00d048f15816a319044f192d8a12e09b96f8bf72.tar.gz
openlmi-providers-00d048f15816a319044f192d8a12e09b96f8bf72.tar.xz
openlmi-providers-00d048f15816a319044f192d8a12e09b96f8bf72.zip
software: added FindIdentity() function
Since disablement of SoftwareIdentity enumeration, there has been no way to search for particular package (using [WC]QL query for example). This serious limitation is now treated by this addition to LMI_SoftwareInstallationService.
-rw-r--r--mof/60_LMI_Software.mof33
-rw-r--r--src/software/lmi/software/LMI_SoftwareInstallationService.py93
-rw-r--r--src/software/lmi/software/core/InstallationService.py4
-rw-r--r--src/software/lmi/software/yumdb/__init__.py5
-rw-r--r--src/software/lmi/software/yumdb/jobs.py11
-rw-r--r--src/software/lmi/software/yumdb/process.py33
6 files changed, 166 insertions, 13 deletions
diff --git a/mof/60_LMI_Software.mof b/mof/60_LMI_Software.mof
index 49905c1..5c11ae2 100644
--- a/mof/60_LMI_Software.mof
+++ b/mof/60_LMI_Software.mof
@@ -636,6 +636,39 @@ class LMI_SoftwareInstallationService : CIM_SoftwareInstallationService {
" This is NULL in case that asynchronous job has been started.")]
LMI_SoftwareIdentityFileCheck REF Failed[]);
+ [Implemented(True), Description(
+ "Search for installed or available software identity matching"
+ " specified properties. In case \"Repository\" is given, only"
+ " available packages of this repository will be browsed."
+ " \"AllowDuplicates\" causes, that packages of the name <name>.<arch>"
+ " will be listed multiple times if more versions are available."
+ " Other input parameters with non-NULL values are compared to"
+ " corresponding properties of LMI_SoftwareIdentity instances."
+ " 0 is returned if any matching package is found, 1 otherwise.")]
+ uint32 FindIdentity(
+ [IN] string Name,
+ [IN] uint32 Epoch,
+ [IN] string Version,
+ [IN] string Release,
+ [IN] string Architecture,
+ [IN, Description(
+ "Allows to specify particular software repository, where the"
+ " search shall take place. If given, only available packages will"
+ " be browsed.")]
+ LMI_SoftwareIdentityResource REF Repository,
+ [IN, Description(
+ "Whether the different versions of the same package shall be"
+ " included in result. This defaults to \"False\".")]
+ boolean AllowDuplicates,
+ [IN, Description(
+ "Whether to compare \"Name\" for exact match. If \"False\", package"
+ " name and its summary string (\"Caption\") will be searched for"
+ " occurences of \"Name\" parameter's value. Defaults to \"True\".")]
+ boolean ExactMatch,
+ [IN(false), OUT, Description(
+ "All matching packages found shall be available in this parameter.")]
+ LMI_SoftwareIdentity REF Matches[]);
+
};
[Version("0.1.0")]
diff --git a/src/software/lmi/software/LMI_SoftwareInstallationService.py b/src/software/lmi/software/LMI_SoftwareInstallationService.py
index f4cb326..fa31df6 100644
--- a/src/software/lmi/software/LMI_SoftwareInstallationService.py
+++ b/src/software/lmi/software/LMI_SoftwareInstallationService.py
@@ -25,9 +25,12 @@ Instruments the CIM class LMI_SoftwareInstallationService
import pywbem
from pywbem.cim_provider2 import CIMProvider2
+from lmi.software.core import Identity
+from lmi.software.core import IdentityResource
from lmi.software.core import InstallationService
from lmi.software.core import Job
from lmi.software.util import cmpi_logging
+from lmi.software.yumdb import YumDB
LOG = cmpi_logging.get_logger(__name__)
@@ -859,3 +862,93 @@ class LMI_SoftwareInstallationService(CIMProvider2):
rval = exc.return_code
return (rval, out_params)
+ @cmpi_logging.trace_method
+ def cim_method_findidentity(self, env, object_name,
+ param_name=None,
+ param_epoch=None,
+ param_version=None,
+ param_release=None,
+ param_architecture=None,
+ param_allowduplicates=None,
+ param_exactmatch=None,
+ param_repository=None):
+ """Implements LMI_SoftwareInstallationService.FindIdentity()
+
+ Search for installed or available software identity matching
+ specified properties. In case "Repository" is given, only
+ available packages of this repository will be browsed.
+ "AllowDuplicates" causes, that packages of the name <name>.<arch>
+ will be listed multiple times if more versions are available.
+ Other input parameters with non-NULL values are compared to
+ corresponding properties of LMI_SoftwareIdentity instances. 0 is
+ returned if any matching package is found, 1 otherwise.
+
+ Keyword arguments:
+ env -- Provider Environment (pycimmb.ProviderEnvironment)
+ object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName
+ specifying the object on which the method FindIdentity()
+ should be invoked.
+ param_name -- The input parameter Name (type unicode)
+ param_repository -- The input parameter Repository (
+ type REF (pywbem.CIMInstanceName(
+ classname='LMI_SoftwareIdentityResource', ...))
+ Allows to specify particular software repository, where the
+ search shall take place. If given, only available packages
+ will be browsed.
+
+ param_epoch -- The input parameter Epoch (type pywbem.Uint32)
+ param_version -- The input parameter Version (type unicode)
+ param_architecture -- The input parameter Architecture (type unicode)
+ param_allowduplicates -- The input parameter AllowDuplicates (
+ type bool)
+ Whether the different versions of the same package shall be
+ included in result. This defaults to "False".
+ param_exactmatch -- The input parameter ExactMatch (type bool)
+ Whether to compare "Name" for exact match. If "False", package name
+ and its summary string ("Caption") will be searched for occurences
+ of "Name" parameter's value. Defaults to "True".
+ param_release -- The input parameter Release (type unicode)
+
+ Returns a two-tuple containing the return value (type pywbem.Uint32)
+ and a list of CIMParameter objects representing the output parameters
+
+ Output parameters:
+ Matches -- (type REF (pywbem.CIMInstanceName(
+ classname='LMI_SoftwareIdentity', ...))
+ All matching packages found shall be available in this
+ parameter.
+
+ 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)
+ """
+ InstallationService.check_path(env, object_name, "object_name")
+ out_params = [pywbem.CIMParameter(
+ 'Matches', type='reference', value=None, is_array=True)]
+ kwargs = {
+ 'name' : param_name,
+ 'epoch' : param_epoch,
+ 'version' : param_version,
+ 'release' : param_release,
+ 'arch' : param_architecture,
+ 'allow_duplicates' : param_allowduplicates,
+ 'exact_match' : param_exactmatch,
+ 'sort' : True,
+ }
+ if param_repository is not None:
+ repo = IdentityResource.object_path2repo(env, param_repository)
+ kwargs['repoid'] = repo.repoid
+ pkgs = YumDB.get_instance().filter_packages('all', **kwargs)
+ out_params[0].value = [Identity.pkg2model(p) for p in pkgs]
+ if len(pkgs) > 0:
+ rval = self.values.FindIdentity.Found
+ else:
+ rval = self.values.FindIdentity.NoMatch
+ return (rval, out_params)
+
diff --git a/src/software/lmi/software/core/InstallationService.py b/src/software/lmi/software/core/InstallationService.py
index 1df368f..70df285 100644
--- a/src/software/lmi/software/core/InstallationService.py
+++ b/src/software/lmi/software/core/InstallationService.py
@@ -560,6 +560,10 @@ class Values(object):
3: 'Error'
}
+ class FindIdentity(object):
+ Found = pywbem.Uint32(0)
+ NoMatch = pywbem.Uint32(1)
+
def get_path():
"""@return instance name with prefilled properties"""
systemop = ComputerSystem.get_path()
diff --git a/src/software/lmi/software/yumdb/__init__.py b/src/software/lmi/software/yumdb/__init__.py
index d9cd3bc..5ccdc1b 100644
--- a/src/software/lmi/software/yumdb/__init__.py
+++ b/src/software/lmi/software/yumdb/__init__.py
@@ -413,6 +413,7 @@ class YumDB(singletonmixin.Singleton):
@job_request()
def filter_packages(self, kind,
allow_duplicates=False,
+ exact_match=True,
sort=False,
include_repos=None,
exclude_repos=None,
@@ -422,8 +423,8 @@ class YumDB(singletonmixin.Singleton):
@see yumdb.jobs.YumFilterPackages job for supported filter keys
"""
return self._do_job(jobs.YumFilterPackages(
- kind, allow_duplicates=allow_duplicates, sort=sort,
- include_repos=include_repos, exclude_repos=exclude_repos,
+ kind, allow_duplicates=allow_duplicates, exact_match=exact_match,
+ sort=sort, include_repos=include_repos, exclude_repos=exclude_repos,
**filters))
@job_request()
diff --git a/src/software/lmi/software/yumdb/jobs.py b/src/software/lmi/software/yumdb/jobs.py
index dbd9d5e..7987382 100644
--- a/src/software/lmi/software/yumdb/jobs.py
+++ b/src/software/lmi/software/yumdb/jobs.py
@@ -412,7 +412,12 @@ class YumFilterPackages(YumGetPackageList): #pylint: disable=R0903
Job similar to YumGetPackageList, but allowing to specify
filter on packages.
Arguments (plus those in YumGetPackageList):
- name, epoch, version, release, arch, nevra, envra, evra
+ name, epoch, version, release, arch, nevra, envra, evra,
+ repoid, exact_match
+
+ Argument ``exact_match`` makes the name property being compared byte
+ by byte. If ``False``, all packages containing ``name``'s value either
+ in name of summary will match.
Some of those are redundant, but filtering is optimized for
speed, so supplying all of them won't affect performance.
@@ -421,9 +426,10 @@ class YumFilterPackages(YumGetPackageList): #pylint: disable=R0903
"""
__slots__ = (
'name', 'epoch', 'version', 'release', 'arch',
- 'nevra', 'envra', 'evra', 'repoid')
+ 'nevra', 'envra', 'evra', 'repoid', 'exact_match')
def __init__(self, kind, allow_duplicates,
+ exact_match=True,
sort=False, include_repos=None, exclude_repos=None,
name=None, epoch=None, version=None,
release=None, arch=None,
@@ -447,6 +453,7 @@ class YumFilterPackages(YumGetPackageList): #pylint: disable=R0903
self.evra = evra
self.envra = envra
self.repoid = repoid
+ self.exact_match = bool(exact_match)
class YumSpecificPackageJob(YumAsyncJob): #pylint: disable=R0903
"""
diff --git a/src/software/lmi/software/yumdb/process.py b/src/software/lmi/software/yumdb/process.py
index 07bca8f..1745e49 100644
--- a/src/software/lmi/software/yumdb/process.py
+++ b/src/software/lmi/software/yumdb/process.py
@@ -29,6 +29,7 @@ import logging
from multiprocessing import Process
import os
import Queue as TQueue # T as threaded
+import re
import sys
import time
import traceback
@@ -52,11 +53,14 @@ LOG = None
# *****************************************************************************
# Utilities
# ****************************************************************************
-def _get_package_filter_function(filters):
+def _get_package_filter_function(filters, exact_match=True):
"""
- @param filters is a dictionary, where keys are package property
- names and values are their desired values.
- @return a function used to filter list of packages
+ :param filters: (``dict``) Dictionary with keys of package property
+ names and values of their desired values.
+ :param exact_match: (``bool``) Whether the ``name`` should be checked
+ for exact match or for presence in package's name or summary
+ strings.
+ :rtype: (``function``) A function used to filter list of packages.
"""
if not isinstance(filters, dict):
raise TypeError("filters must be a dictionary")
@@ -78,6 +82,7 @@ def _get_package_filter_function(filters):
elif "evra" in filters:
for prop_name in ("epoch", "version", "release", "epoch"):
filters.pop(prop_name, None)
+
filter_list = []
# properties are sorted by their filtering ability
# (the most unprobable property, that can match, comes first)
@@ -85,10 +90,20 @@ def _get_package_filter_function(filters):
"release", "repoid", "arch"):
if not prop_name in filters:
continue
+ if not exact_match and 'name' in filters:
+ continue
filter_list.append((prop_name, filters.pop(prop_name)))
- def _cmp_props(pkg):
- """@return True if pkg matches properies filter"""
- return all(getattr(pkg, p) == v for p, v in filter_list)
+ if not exact_match and 'name' in filters:
+ re_name = re.compile(re.escape(filters['name']))
+ def _cmp_props(pkg):
+ """ :rtype: (``bool``) Does pkg matche properies filter? """
+ if re_name.search(pkg.name) or re_name.search(pkg.summary):
+ return all(getattr(pkg, p) == v for p, v in filter_list)
+ return False
+ else:
+ def _cmp_props(pkg):
+ """ :rtype: (``bool``) Does pkg matche properies filter? """
+ return all(getattr(pkg, p) == v for p, v in filter_list)
return _cmp_props
class RepoFilterSetter(object):
@@ -570,7 +585,7 @@ class YumWorker(Process):
@_needs_database
def _handle_filter_packages(self, kind, allow_duplicates, sort,
- include_repos=None, exclude_repos=None,
+ exact_match=True, include_repos=None, exclude_repos=None,
transform=True, **filters):
"""
Handler for filtering packages job.
@@ -588,7 +603,7 @@ class YumWorker(Process):
pkglist = self._handle_get_package_list(kind, allow_duplicates, False,
include_repos=include_repos, exclude_repos=exclude_repos,
transform=False)
- matches = _get_package_filter_function(filters)
+ matches = _get_package_filter_function(filters, exact_match)
result = [p for p in pkglist if matches(p)]
if sort is True:
result.sort()