Repository : http://git.fedorahosted.org/cgit/cura-tools.git
On branch : master
>---------------------------------------------------------------
commit 62011f550d197423715d91d9d0aa664fb5bc835c
Author: Peter Hatina <phatina(a)redhat.com>
Date: Wed Jul 17 09:54:04 2013 +0200
introduce constant values access
>---------------------------------------------------------------
cli-tools/lmi/lmi_client_shell.py | 175 +++++++++++++++++++++++++++++++++----
cli-tools/lmishell | 26 +++++-
2 files changed, 181 insertions(+), 20 deletions(-)
diff --git a/cli-tools/lmi/lmi_client_shell.py b/cli-tools/lmi/lmi_client_shell.py
index 8c25cec..87d0cb6 100644
--- a/cli-tools/lmi/lmi_client_shell.py
+++ b/cli-tools/lmi/lmi_client_shell.py
@@ -494,6 +494,92 @@ def lmi_class_fetch_lazy(fn):
return fn(self, *args, **kwargs)
return wrapped
+class _LmiConstantValues(BaseObject):
+ """
+ Abstract class for constant value objects.
+ """
+ __metaclass__ = abc.ABCMeta
+
+ def __init__(self, cim_property):
+ # Keys can contain various undesirable characters, such as python
+ # operators, etc. So we drop them.
+ keys = map(lambda v: "".join(c for c in v if c.isalnum()),
+ cim_property.qualifiers["Values"].value)
+ values = cim_property.qualifiers["ValueMap"].value
+ self._value_map = {}
+ for i in range(0, len(keys)):
+ try:
+ self._value_map[keys[i]] = cast_lmi_to_cim(self._cast_type, values[i])
+ except ValueError, e:
+ # Can not cast such value as interval. Can be found in
+ # DMTFReserved, VendorReserved values.
+ pass
+
+ def __repr__(self):
+ """
+ Returns a string of all constant names with corresponding value.
+ """
+ result = ""
+ for (k, v) in self._value_map.iteritems():
+ result += "%s = %s\n" % (k, v)
+ return result[:-1]
+
+ def __getattr__(self, name):
+ """
+ Returns either a member of the class, or a constant value.
+
+ Simplifies the code and constant value can be retreived by
+ object.constant_value.
+ """
+ if name in self.__dict__:
+ return self.__dict__[name]
+ if name in self._value_map:
+ return self._value_map[name]
+ raise AttributeError(name)
+
+ def print_values(self):
+ """
+ Prints all available constant names.
+ """
+ for k in self._value_map.keys():
+ sys.stdout.write("%s\n" % k)
+
+ def values_dict(self):
+ """
+ Returns a dictionary of constants' names and values.
+ """
+ return self._value_map
+
+ def values(self):
+ """
+ Returns a list of all available constant values.
+ """
+ return self._value_map.keys()
+
+ def value(self, value_name):
+ """
+ Returns a constant value.
+ Arguments:
+ value_name -- string containing a constant name
+ """
+ return getattr(self, value_name)
+
+class _LmiConstantValuesParamProp(_LmiConstantValues):
+ """
+ Derived class used for constant values of CIMProperty and CIMParameter.
+ """
+ def __init__(self, cim_property):
+ self._cast_type = cim_property.type
+ super(self.__class__, self).__init__(cim_property)
+
+class _LmiContantValuesMethodReturnType(_LmiConstantValues):
+ """
+ Derived class used for constant values of CIMMethod.
+ """
+ def __init__(self, cim_property):
+ self._cast_type = cim_property.return_type
+ super(self.__class__, self).__init__(cim_property)
+
class _LmiClass(BaseObject):
def __init__(self, client, namespace, classname):
super(self.__class__, self).__init__()
@@ -506,6 +592,21 @@ class _LmiClass(BaseObject):
return "%s(classname='%s', ...)" % (self.__class__.__name__, self.classname)
@lmi_class_fetch_lazy
+ def __getattr__(self, name):
+ """
+ Returns either a class member, or a constant value.
+
+ Simplifies the code and constant value can be retreived by
+ object.constant_value.
+ """
+ if name in self.__dict__:
+ return self.__dict__[name]
+ if name.endswith("Values"):
+ property_name = name[:-6]
+ return _LmiConstantValuesParamProp(self._cim_class.properties[property_name])
+ raise AttributeError(name)
+
+ @lmi_class_fetch_lazy
@lmi_return_val_if_fail("_namespace", None)
def create_instance(self, properties = {}, qualifiers = {}, property_list = None):
self_properties = self._cim_class.properties
@@ -537,6 +638,9 @@ class _LmiClass(BaseObject):
return
(self._cim_class, _, _) = self._client._get_class(self._cim_classname,
self._namespace.name, LocalOnly = False)
+ # Store the constant values as a list. This can consume some time, if computed on demand.
+ self._valuemap_properties_list = [ k for (k, v) in self._cim_class.properties.iteritems() \
+ if "ValueMap" in v.qualifiers ]
# NOTE: usage with Key=something, Value=something is deprecated
# NOTE: inst_filter is either None or dict
@@ -594,6 +698,14 @@ class _LmiClass(BaseObject):
@lmi_class_fetch_lazy
@lmi_return_val_if_fail("_namespace", [])
+ def valuemap_properties(self):
+ """
+ Returns a list of constant names.
+ """
+ return self._valuemap_properties_list
+
+ @lmi_class_fetch_lazy
+ @lmi_return_val_if_fail("_namespace", [])
def properties(self):
return self._cim_class.properties.keys()
@@ -687,26 +799,26 @@ def possibly_deleted(fn):
class _LmiInstanceMethod(BaseObject):
# 15 seconds sleep timeout for main waiting thread
- COND_WAIT_TIME = 15
+ _COND_WAIT_TIME = 15
# Wake count of main thread, when the GetInstance is performed to check,
# if the job object is present. Prevents infinite waiting for indication
# delivery. Maximum waiting time, before the GetInstance for job object
- # will be called is: COND_WAIT_TIME * COND_WAIT_WAKE_CNT
- COND_WAIT_WAKE_CNT = 8
+ # will be called is: _COND_WAIT_TIME * _COND_WAIT_WAKE_CNT
+ _COND_WAIT_WAKE_CNT = 8
# Default tcp port, where the indications will be delivered.
# TODO: create a configuration option for the port
- INDICATION_DESTINATION_PORT = 10240
+ _INDICATION_DESTINATION_PORT = 10240
# Job classes, which can be used for synchro method calls
# TODO: create a configuration option for the static filters' classnames
- INDICATION_FILTER_CLASSNAMES = (
+ _INDICATION_FILTER_CLASSNAMES = (
"LMI_StorageJob",
"LMI_SoftwareInstallationJob",
"LMI_NetworkJob"
)
# When performing a synchronous method call and using the polling method to
# get a job object status, the sleep time between 2 polls doubles if it is
- # less than POLLING_ADAPT_MAX_WAITING_TIME.
- POLLING_ADAPT_MAX_WAITING_TIME = 128
+ # less than _POLLING_ADAPT_MAX_WAITING_TIME.
+ _POLLING_ADAPT_MAX_WAITING_TIME = 128
def __init__(self, client, lmi_instance, method, sync_method):
super(self.__class__, self).__init__()
@@ -714,9 +826,15 @@ class _LmiInstanceMethod(BaseObject):
self._lmi_instance = lmi_instance
self._method = lmi_instance._lmi_class._cim_class.methods[method]
self._sync_method = sync_method
+ # Store the constant values as a list. This can consume some time, if computed on demand.
+ self._valuemap_parameters = [ k for (k, v) in self._method.parameters.iteritems() \
+ if "ValueMap" in v.qualifiers ]
+ # For simplicity, we add return value constans to the same list
+ if "ValueMap" in self._method.qualifiers:
+ self._valuemap_parameters.append(self._method.name)
@staticmethod
- def is_job_finished(job):
+ def _is_job_finished(job):
"""
Checks if a job object is in finished state. The range comes from the standard.
Arguments:
@@ -793,7 +911,7 @@ class _LmiInstanceMethod(BaseObject):
job_exception = PassByRef(None)
# There needs to be a pattern of at least 8 "X" in a row at the end of the indication_name
indication_name = "synchro-method-call-XXXXXXXX"
- listener = LmiIndicationListener("0.0.0.0", _LmiInstanceMethod.INDICATION_DESTINATION_PORT)
+ listener = LmiIndicationListener("0.0.0.0", _LmiInstanceMethod._INDICATION_DESTINATION_PORT)
indication_name = listener.add_handler(indication_name, handle_job, cond, job_finished,
job_out_params, job_exception)
if not listener.start():
@@ -820,7 +938,7 @@ class _LmiInstanceMethod(BaseObject):
# additional configuration to make this work. See LmiInstanceMethod() and PreferPolling.
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
- s.connect((netloc, _LmiInstanceMethod.INDICATION_DESTINATION_PORT))
+ s.connect((netloc, _LmiInstanceMethod._INDICATION_DESTINATION_PORT))
except socket.gaierror, e:
listener.stop()
errorstr = "Can not determine IP address of this machine"
@@ -832,7 +950,7 @@ class _LmiInstanceMethod(BaseObject):
cim_handler_props = {
"Name" : indication_name,
"Destination" : "http://%s:%d/%s" % (destination,
- _LmiInstanceMethod.INDICATION_DESTINATION_PORT, indication_name),
+ _LmiInstanceMethod._INDICATION_DESTINATION_PORT, indication_name),
}
(cim_handler, _, err) = self._client._create_instance("CIM_IndicationHandlerCIMXML",
"root/PG_InterOp", cim_handler_props)
@@ -857,7 +975,7 @@ class _LmiInstanceMethod(BaseObject):
# Check, if the job is not already in finished state,
# while we were subscribing for the indications
job_inst.refresh()
- job_finished.value = _LmiInstanceMethod.is_job_finished(job_inst)
+ job_finished.value = _LmiInstanceMethod._is_job_finished(job_inst)
if job_finished.value:
job_out_params.value = job_inst.JobOutParameters
@@ -869,19 +987,19 @@ class _LmiInstanceMethod(BaseObject):
while True:
if interrupt or job_finished.value:
break
- cond.wait(_LmiInstanceMethod.COND_WAIT_TIME)
+ cond.wait(_LmiInstanceMethod._COND_WAIT_TIME)
wake_cnt += 1
# XXX: threading.Condition.wait() does not inform about timeout or being awaken by
# notify call. There is a counting to 4 sleep cycles before we actually check for
# job status manually. This number can be increased, so we rely more on indications,
# rather then on manual polling.
- if not job_finished.value and wake_cnt >= _LmiInstanceMethod.COND_WAIT_WAKE_CNT:
+ if not job_finished.value and wake_cnt >= _LmiInstanceMethod._COND_WAIT_WAKE_CNT:
wake_cnt = 0
(refreshed, _, errorstr) = job_inst.refresh()
if not refreshed:
job_exception.value = errorstr
break
- if _LmiInstanceMethod.is_job_finished(job_inst):
+ if _LmiInstanceMethod._is_job_finished(job_inst):
job_out_params.value = job_inst.JobOutParameters
listener.stop()
break
@@ -905,10 +1023,10 @@ class _LmiInstanceMethod(BaseObject):
def __handle_synchro_method_call_polling(self, job_inst):
try:
sleep_time = 1
- while not _LmiInstanceMethod.is_job_finished(job_inst):
+ while not _LmiInstanceMethod._is_job_finished(job_inst):
# Sleep, a bit longer in every iteration
time.sleep(sleep_time)
- if sleep_time < _LmiInstanceMethod.POLLING_ADAPT_MAX_WAITING_TIME:
+ if sleep_time < _LmiInstanceMethod._POLLING_ADAPT_MAX_WAITING_TIME:
sleep_time *= 2
(refreshed, _, errorstr) = job_inst.refresh()
if not refreshed:
@@ -920,6 +1038,7 @@ class _LmiInstanceMethod(BaseObject):
rval = 0,
rparams = {"out" : job_inst.JobOutParameters}
)
+
def __call__(self, *args, **kwargs):
"""
Perform a method call.
@@ -965,7 +1084,7 @@ class _LmiInstanceMethod(BaseObject):
use_display_hook = True)
# Check if we can perform synchronous method call
job = call_rparams["job"] if "job" in call_rparams else None
- can_perform_sync_call = job.classname in _LmiInstanceMethod.INDICATION_FILTER_CLASSNAMES if job else False
+ can_perform_sync_call = job.classname in _LmiInstanceMethod._INDICATION_FILTER_CLASSNAMES if job else False
if self._sync_method and job and can_perform_sync_call:
# Synchronous method calls
job_inst = call_rparams['job'].to_instance()
@@ -1019,6 +1138,20 @@ class _LmiInstanceMethod(BaseObject):
rparams = call_rparams,
errorstr = call_errorstr)
+ def __getattr__(self, name):
+ """
+ Returns either a class member, or a constant value.
+ """
+ if name in self.__dict__:
+ return self.__dict__[name]
+ if name.endswith("Values"):
+ parameter_name = name[:-6]
+ if parameter_name in self._method.parameters:
+ return _LmiConstantValuesParamProp(self._method.parameters[parameter_name])
+ elif parameter_name == self._method.name:
+ return _LmiContantValuesMethodReturnType(self._method)
+ raise AttributeError(name)
+
@property
def return_type(self):
return self._method.return_type
@@ -1026,6 +1159,12 @@ class _LmiInstanceMethod(BaseObject):
def tomof(self):
_LmiMofFormatter(self._method.tomof()).fancy_format(self._client.interactive)
+ def valuemap_parameters(self):
+ """
+ Returns a list of constant names.
+ """
+ return self._valuemap_parameters
+
def parameters(self):
return self._method.parameters
diff --git a/cli-tools/lmishell b/cli-tools/lmishell
index bbbe0df..b9e16db 100755
--- a/cli-tools/lmishell
+++ b/cli-tools/lmishell
@@ -31,6 +31,8 @@ from lmi.lmi_client_shell import _LmiNamespaceRoot
from lmi.lmi_client_shell import _LmiClass
from lmi.lmi_client_shell import _LmiInstance
from lmi.lmi_client_shell import _LmiInstanceName
+from lmi.lmi_client_shell import _LmiInstanceMethod
+from lmi.lmi_client_shell import _LmiConstantValues
from lmi.lmi_client_shell import _lmi_start_indication_listener
from lmi.lmi_client_shell import _lmi_stop_indication_listener
from lmi.lmi_client_shell import _lmi_print_indication_listeners
@@ -116,6 +118,15 @@ class _LmiShellOptions(object):
sys.stdout.write(" -i, --interact inspect interactively after running a script\n")
class _LmiCompleter(rlcompleter.Completer):
+ LMI_CLASSES = (
+ _LmiNamespace,
+ _LmiClass,
+ _LmiInstance,
+ _LmiInstanceName,
+ _LmiConstantValues,
+ LmiReturnValue
+ )
+
def __init__(self, namespace = None):
rlcompleter.Completer.__init__(self, namespace)
self._last_complete = []
@@ -133,8 +144,7 @@ class _LmiCompleter(rlcompleter.Completer):
return result
def _callable_postfix(self, val, word):
- if hasattr(val, '__call__') \
- and not isinstance(val, (_LmiNamespace, _LmiClass, _LmiInstance, _LmiInstanceName, LmiReturnValue)):
+ if hasattr(val, '__call__') and not isinstance(val, _LmiCompleter.LMI_CLASSES):
word = word + "("
return word
@@ -160,6 +170,10 @@ class _LmiCompleter(rlcompleter.Completer):
for c in expr.classes():
if c.lower().startswith(to_complete.lower()):
self._last_complete.append(cmd + "." + c)
+ elif isinstance(expr, _LmiClass):
+ for v in expr.valuemap_properties():
+ if v.lower().startswith(to_complete.lower()):
+ self._last_complete.append(cmd + "." + v + "Values")
elif isinstance(expr, _LmiInstance):
expr_methods = expr.methods()
if expr_methods:
@@ -181,6 +195,14 @@ class _LmiCompleter(rlcompleter.Completer):
for p in expr.key_properties():
if p.lower().startswith(to_complete.lower()):
self._last_complete.append(cmd + "." + p)
+ elif isinstance(expr, _LmiInstanceMethod):
+ for p in expr.valuemap_parameters():
+ if p.lower().startswith(to_complete.lower()):
+ self._last_complete.append(cmd + "." + p + "Values")
+ elif isinstance(expr, _LmiConstantValues):
+ for v in expr.values():
+ if v.lower().startswith(to_complete.lower()):
+ self._last_complete.append(cmd + "." + v)
elif isinstance(expr, LmiReturnValue):
for p in expr.properties():
if p.lower().startswith(to_complete.lower()):