* Replaced Smis._wait_invoke() with SmisCommon.invoke_method_wait().
* Removed Smis._poll() and replace it with SmisCommon.invoke_method_wait().
* Replaced Smis._job_completed_ok with SmisCommon.cim_job_completed_ok() as
it used by Smis.job_status() and SmisCommon.invoke_method_wait().
* Tested on EMC VMAX for access group create/delete, volume mask/unmask,
volume create/delete.
Signed-off-by: Gris Ge <***@redhat.com>
---
plugin/smispy/smis.py | 241 +++++++++----------------------------------
plugin/smispy/smis_common.py | 113 ++++++++++++++++++++
2 files changed, 159 insertions(+), 195 deletions(-)
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index bdca963..1847e07 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -128,9 +128,6 @@ class Smis(IStorageAreaNetwork):
SMI-S plug-ing which exposes a small subset of the overall provided
functionality of SMI-S
"""
- _INVOKE_MAX_LOOP_COUNT = 60
- _INVOKE_CHECK_INTERVAL = 5
-
_JOB_ERROR_HANDLER = {
SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
smis_vol.volume_create_error_handler,
@@ -241,25 +238,6 @@ def capabilities(self, system, flags=0):
def plugin_info(self, flags=0):
return "Generic SMI-S support", VERSION
- @staticmethod
- def _job_completed_ok(status):
- """
- Given a concrete job instance, check the operational status. This
- is a little convoluted as different SMI-S proxies return the values in
- different positions in list :-)
- """
- rc = False
- op = status['OperationalStatus']
-
- if (len(op) > 1 and
- ((op[0] == dmtf.OP_STATUS_OK and
- op[1] == dmtf.OP_STATUS_COMPLETED) or
- (op[0] == dmtf.OP_STATUS_COMPLETED and
- op[1] == dmtf.OP_STATUS_OK))):
- rc = True
-
- return rc
-
@handle_cim_errors
def job_status(self, job_id, flags=0):
"""
@@ -298,7 +276,7 @@ def job_status(self, job_id, flags=0):
status = JobStatus.COMPLETE
percent_complete = 100
- if Smis._job_completed_ok(cim_job):
+ if SmisCommon.cim_job_completed_ok(cim_job):
if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
completed_item = self._new_vol_from_job(cim_job)
@@ -597,21 +575,6 @@ def volume_create(self, pool, volume_name, size_bytes, provisioning,
retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
method_data=volume_name)
- def _poll(self, msg, job):
- if job:
- while True:
- (s, percent, i) = self.job_status(job)
-
- if s == JobStatus.INPROGRESS:
- time.sleep(0.25)
- elif s == JobStatus.COMPLETE:
- self.job_free(job)
- return i
- else:
- raise LsmError(
- ErrorNumber.PLUGIN_BUG,
- msg + ", job error code= " + str(s))
-
def _detach_netapp_e(self, vol, sync):
#Get the Configuration service for the system we are interested in.
cim_scs = self._c.cim_scs_of_sys_id(vol.system_id)
@@ -619,10 +582,8 @@ def _detach_netapp_e(self, vol, sync):
in_params = {'Operation': pywbem.Uint16(2),
'Synchronization': sync.path}
- job_id = self._c.invoke_method(
- 'ModifySynchronization', cim_scs.path, in_params)[0]
-
- self._poll("ModifySynchronization, detach", job_id)
+ self._c.invoke_method_wait(
+ 'ModifySynchronization', cim_scs.path, in_params)
def _detach(self, vol, sync):
if self._c.is_netappe():
@@ -634,10 +595,8 @@ def _detach(self, vol, sync):
in_params = {'Operation': pywbem.Uint16(8),
'Synchronization': sync.path}
- job_id = self._c.invoke_method(
- 'ModifyReplicaSynchronization', cim_rs.path, in_params)[0]
-
- self._poll("ModifyReplicaSynchronization, detach", job_id)
+ self._c.invoke_method_wait(
+ 'ModifyReplicaSynchronization', cim_rs.path, in_params)
@staticmethod
def _cim_name_match(a, b):
@@ -917,18 +876,15 @@ def _cim_dev_mg_path_create(self, cim_gmms_path, name, cim_vol_path,
try:
(rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
**in_params)
- except CIMError as ce:
- if ce[0] == pywbem.CIM_ERR_FAILED:
- cim_dev_mg_path = self._check_exist_cim_dev_mg(
- name, cim_gmms_path, cim_vol_path, vol_id)
- if cim_dev_mg_path is None:
- raise
- else:
- raise
- if cim_dev_mg_path is None:
- cim_dev_mg_path = self._wait_invoke(
- rc, out, out_key='MaskingGroup',
+ cim_dev_mg_path = self._c.invoke_method_wait(
+ 'CreateGroup', cim_gmms_path, in_params,
+ out_key='MaskingGroup',
expect_class='CIM_TargetMaskingGroup')
+ except (LsmError, CIMError):
+ cim_dev_mg_path = self._check_exist_cim_dev_mg(
+ name, cim_gmms_path, cim_vol_path, vol_id)
+ if cim_dev_mg_path is None:
+ raise
return cim_dev_mg_path
@@ -963,21 +919,14 @@ def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmms_path, name,
cim_tgt_mg_path = None
try:
- (rc, out) = self._c.InvokeMethod('CreateGroup', cim_gmms_path,
- **in_params)
- except CIMError as ce:
- if ce[0] == pywbem.CIM_ERR_FAILED:
- cim_tgt_mg_path = self._check_exist_cim_tgt_mg(name)
- if cim_tgt_mg_path is None:
- raise
- else:
+ cim_tgt_mg_path = self._c.invoke_method_wait(
+ 'CreateGroup', cim_gmms_path, in_params,
+ out_key='MaskingGroup', expect_class='CIM_TargetMaskingGroup')
+ except (LsmError, CIMError):
+ cim_tgt_mg_path = self._check_exist_cim_tgt_mg(name)
+ if cim_tgt_mg_path is None:
raise
- if cim_tgt_mg_path is None:
- cim_tgt_mg_path = self._wait_invoke(
- rc, out, out_key='MaskingGroup',
- expect_class='CIM_TargetMaskingGroup')
-
return cim_tgt_mg_path
def _cim_spc_path_create(self, cim_gmms_path, cim_init_mg_path,
@@ -989,11 +938,9 @@ def _cim_spc_path_create(self, cim_gmms_path, cim_init_mg_path,
'DeviceMaskingGroup': cim_dev_mg_path,
}
- (rc, out) = self._c.InvokeMethod('CreateMaskingView', cim_gmms_path,
- **in_params)
-
- return self._wait_invoke(
- rc, out, out_key='ProtocolController',
+ return self._c.invoke_method_wait(
+ 'CreateMaskingView', cim_gmms_path, in_params,
+ out_key='ProtocolController',
expect_class='CIM_SCSIProtocolController')
def _volume_mask_group(self, access_group, volume, flags=0):
@@ -1075,10 +1022,8 @@ def _volume_mask_group(self, access_group, volume, flags=0):
'MaskingGroup': cim_dev_mg_path,
'Members': [cim_vol_path],
}
- (rc, out) = self._c.InvokeMethod(
- 'AddMembers',
- cim_gmms.path, **in_params)
- self._wait_invoke(rc, out)
+ self._c.invoke_method_wait(
+ 'AddMembers', cim_gmms.path, in_params)
return None
@handle_cim_errors
@@ -1116,10 +1061,7 @@ def _volume_mask_old(self, access_group, volume, flags):
'ProtocolControllers': [cim_spc_path],
'DeviceAccesses': [dmtf.CTRL_CONF_SRV_DA_RW]}
- (rc, out) = self._c.InvokeMethod(
- 'ExposePaths',
- cim_ccs.path, **in_params)
- self._wait_invoke(rc, out)
+ self._c.invoke_method_wait('ExposePaths', cim_ccs.path, in_params)
return None
def _volume_unmask_group(self, access_group, volume):
@@ -1202,19 +1144,15 @@ def _volume_unmask_group(self, access_group, volume):
in_params = {
'ProtocolController': cim_spc_path,
}
- (rc, out) = self._c.InvokeMethod(
- 'DeleteMaskingView',
- cim_gmms.path, **in_params)
- self._wait_invoke(rc, out)
+ self._c.invoke_method_wait(
+ 'DeleteMaskingView', cim_gmms.path, in_params)
in_params = {
'MaskingGroup': cim_dev_mg_path,
'Members': [cim_vol_path],
}
- (rc, out) = self._c.InvokeMethod(
- 'RemoveMembers',
- cim_gmms.path, **in_params)
- self._wait_invoke(rc, out)
+ self._c.invoke_method_wait(
+ 'RemoveMembers', cim_gmms.path, in_params)
return None
@@ -1242,10 +1180,7 @@ def _volume_unmask_old(self, access_group, volume):
hide_params = {'LUNames': [cim_vol['Name']],
'ProtocolControllers': [cim_spc_path]}
- (rc, out) = self._c.InvokeMethod('HidePaths', cim_ccs.path,
- **hide_params)
- self._wait_invoke(rc, out)
-
+ self._c.invoke_method_wait('HidePaths', cim_ccs.path, hide_params)
return None
def _is_access_group(self, cim_spc):
@@ -1484,12 +1419,10 @@ def _cim_init_path_create(self, system_id, init_id, dmtf_id_type):
in_params = {'StorageID': init_id,
'IDType': pywbem.Uint16(dmtf_id_type)}
- (rc, out) = self._c.InvokeMethod('CreateStorageHardwareID',
- cim_hwms.path, **in_params)
# CreateStorageHardwareID does not allow ASYNC
- return self._wait_invoke(
- rc, out, out_key='HardwareID',
- expect_class='CIM_StorageHardwareID')
+ return self._c.invoke_method_wait(
+ 'CreateStorageHardwareID', cim_hwms.path, in_params,
+ out_key='HardwareID', expect_class='CIM_StorageHardwareID')
def _ag_init_add_group(self, access_group, init_id, init_type):
cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
@@ -1520,12 +1453,10 @@ def _ag_init_add_group(self, access_group, init_id, init_type):
'MaskingGroup': cim_init_mg_path,
'Members': [cim_init_path],
}
- (rc, out) = self._c.InvokeMethod('AddMembers',
- cim_gmms.path, **in_params)
- new_cim_init_mg_path = self._wait_invoke(
- rc, out, out_key='MaskingGroup',
- expect_class='CIM_InitiatorMaskingGroup')
+ new_cim_init_mg_path = self._c.invoke_method_wait(
+ 'AddMembers', cim_gmms.path, in_params,
+ out_key='MaskingGroup', expect_class='CIM_InitiatorMaskingGroup')
cim_init_mg_pros = smis_ag.cim_init_mg_pros()
new_cim_init_mg = self._c.GetInstance(
new_cim_init_mg_path, PropertyList=cim_init_mg_pros,
@@ -1577,10 +1508,9 @@ def _ag_init_add_old(self, access_group, init_id, init_type):
in_params = {'InitiatorPortIDs': [init_id],
'ProtocolControllers': [cim_spc_path]}
- (rc, out) = self._c.InvokeMethod('ExposePaths',
- cim_ccs.path, **in_params)
- cim_spc_path = self._wait_invoke(
- rc, out, out_key='ProtocolControllers', flag_out_array=True,
+ cim_spc_path = self._c.invoke_method_wait(
+ 'ExposePaths', cim_ccs.path, in_params,
+ out_key='ProtocolControllers', flag_out_array=True,
expect_class='CIM_SCSIProtocolController')
cim_spc_pros = smis_ag.cim_spc_pros()
@@ -1623,10 +1553,7 @@ def _ag_init_del_group(self, access_group, init_id):
'Members': [cim_init.path],
}
- (rc, out) = self._c.InvokeMethod(
- 'RemoveMembers',
- cim_gmms.path, **in_params)
- self._wait_invoke(rc, out)
+ self._c.invoke_method_wait('RemoveMembers', cim_gmms.path, in_params)
cim_init_mg_pros = smis_ag.cim_init_mg_pros()
cim_init_mg = self._c.GetInstance(
@@ -1660,10 +1587,8 @@ def _ag_init_del_old(self, access_group, init_id):
hide_params = {'InitiatorPortIDs': [init_id],
'ProtocolControllers': [cim_spc_path]}
- (rc, out) = self._c.InvokeMethod(
- 'HidePaths', cim_ccs.path, **hide_params)
+ self._c.invoke_method_wait('HidePaths', cim_ccs.path, hide_params)
- self._wait_invoke(rc, out)
return None
@handle_cim_errors
@@ -2052,71 +1977,6 @@ def target_ports(self, search_key=None, search_value=None, flags=0):
return search_property(rc, search_key, search_value)
- def _wait_invoke(self, rc, out, out_key=None, expect_class=None,
- flag_out_array=False,):
- """
- Return out[out_key] if found rc == SmisCommon.SNIA_INVOKE_OK.
- For rc == SmisCommon.SNIA_INVOKE_ASYNC, we check every
- Smis._INVOKE_CHECK_INTERVAL
- seconds until done. Then return association via CIM_AffectedJobElement
- Return CIM_InstanceName
- Assuming only one CIM_InstanceName will get.
- """
- if rc == SmisCommon.SNIA_INVOKE_OK:
- if out_key is None:
- return None
- if out_key in out:
- if flag_out_array:
- if len(out[out_key]) != 1:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_wait_invoke(), %s is not length 1: %s"
- % (out_key, out.items()))
- return out[out_key][0]
- return out[out_key]
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_wait_invoke(), %s not exist in out %s" %
- (out_key, out.items()))
- elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
- cim_job_path = out['Job']
- loop_counter = 0
- job_pros = ['JobState', 'PercentComplete', 'ErrorDescription',
- 'OperationalStatus']
- cim_xxxs_path = []
- while(loop_counter <= Smis._INVOKE_MAX_LOOP_COUNT):
- cim_job = self._c.GetInstance(cim_job_path,
- PropertyList=job_pros,
- LocalOnly=False)
- job_state = cim_job['JobState']
- if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
- dmtf.JOB_STATE_RUNNING):
- loop_counter += 1
- time.sleep(Smis._INVOKE_CHECK_INTERVAL)
- continue
- elif job_state == dmtf.JOB_STATE_COMPLETED:
- if expect_class is None:
- return None
- cim_xxxs_path = self._c.AssociatorNames(
- cim_job.path,
- AssocClass='CIM_AffectedJobElement',
- ResultClass=expect_class)
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_wait_invoke(): Got unknown job state "
- "%d: %s" % (job_state, cim_job.items()))
- if len(cim_xxxs_path) != 1:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_wait_invoke(): got unexpected(not 1) "
- "return from CIM_AffectedJobElement: "
- "%s, out: %s, job: %s" %
- (cim_xxxs_path, out.items(),
- cim_job.items()))
- return cim_xxxs_path[0]
- else:
- raise LsmError(ErrorNumber.PLUGIN_BUG,
- "_wait_invoke(): Got unexpected rc code "
- "%d, out: %s" % (rc, out.items()))
-
def _cim_pep_path_of_fc_tgt(self, cim_fc_tgt_path):
"""
Return CIMInstanceName of CIM_SCSIProtocolEndpoint of CIM_FCPort
@@ -2178,10 +2038,7 @@ def _check_exist_cim_dev_mg(self, name, cim_gmms_path, cim_vol_path,
'MaskingGroup': cim_dev_mg.path,
'Members': [cim_vol_path],
}
- (rc, out) = self._c.InvokeMethod(
- 'AddMembers',
- cim_gmms_path, **in_params)
- self._wait_invoke(rc, out)
+ self._c.invoke_method_wait('AddMembers', cim_gmms_path, in_params)
return cim_dev_mg.path
return None
@@ -2248,13 +2105,10 @@ def access_group_create(self, name, init_id, init_type, system,
cim_init_mg_pros = smis_ag.cim_init_mg_pros()
try:
- (rc, out) = self._c.InvokeMethod(
- 'CreateGroup', cim_gmms.path, **in_params)
-
- cim_init_mg_path = self._wait_invoke(
- rc, out, out_key='MaskingGroup',
+ cim_init_mg_path = self._c.invoke_method_wait(
+ 'CreateGroup', cim_gmms.path, in_params,
+ out_key='MaskingGroup',
expect_class='CIM_InitiatorMaskingGroup')
-
except (LsmError, CIMError):
# Check possible failure
# 1. Initiator already exist in other group.
@@ -2327,8 +2181,5 @@ def access_group_delete(self, access_group, flags=0):
'Force': True,
}
- (rc, out) = self._c.InvokeMethod('DeleteGroup', cim_gmms.path,
- **in_params)
-
- self._wait_invoke(rc, out)
+ self._c.invoke_method_wait('DeleteGroup', cim_gmms.path, in_params)
return None
diff --git a/plugin/smispy/smis_common.py b/plugin/smispy/smis_common.py
index 456e6bc..5783a89 100644
--- a/plugin/smispy/smis_common.py
+++ b/plugin/smispy/smis_common.py
@@ -27,6 +27,7 @@
import traceback
import os
import datetime
+import time
import dmtf
from lsm import LsmError, ErrorNumber, md5
@@ -180,6 +181,9 @@ class SmisCommon(object):
IAAN_WBEM_HTTP_PORT = 5988
IAAN_WBEM_HTTPS_PORT = 5989
+ _INVOKE_MAX_LOOP_COUNT = 60
+ _INVOKE_CHECK_INTERVAL = 5
+
def __init__(self, url, username, password,
namespace=dmtf.DEFAULT_NAMESPACE,
no_ssl_verify=False, debug_path=None, system_list=None):
@@ -359,6 +363,25 @@ def _job_id_of_cim_job(cim_job, retrieve_data, method_data):
md5(cim_job['InstanceID']), int(retrieve_data), str(method_data))
@staticmethod
+ def cim_job_completed_ok(cim_job):
+ """
+ Given a CIM_ConcreteJob, check the operational status. This
+ is a little convoluted as different SMI-S proxies return the values in
+ different positions in list :-)
+ """
+ rc = False
+ op = cim_job['OperationalStatus']
+
+ if (len(op) > 1 and
+ ((op[0] == dmtf.OP_STATUS_OK and
+ op[1] == dmtf.OP_STATUS_COMPLETED) or
+ (op[0] == dmtf.OP_STATUS_COMPLETED and
+ op[1] == dmtf.OP_STATUS_OK))):
+ rc = True
+
+ return rc
+
+ @staticmethod
def parse_job_id(job_id):
"""
job_id is assembled by a md5 string, retrieve_data and method_data
@@ -457,6 +480,96 @@ def invoke_method(self, cmd, cim_path, in_params, out_handler=None,
else:
raise
+ def invoke_method_wait(self, cmd, cim_path, in_params,
+ out_key=None, expect_class=None,
+ flag_out_array=False):
+ """
+ InvokeMethod and wait it untile done.
+ Retrun a CIMInstanceName from out[out_key] or from cim_job:
+ CIM_ConcreteJob
+ |
+ | CIM_AffectedJobElement
+ v
+ CIMInstanceName # expect_class
+ If flag_out_array is True, return the first element of out[out_key].
+ """
+ (rc, out) = self.InvokeMethod(cmd, cim_path, **in_params)
+
+ if rc == SmisCommon.SNIA_INVOKE_OK:
+ if out_key is None:
+ return None
+ if out_key in out:
+ if flag_out_array:
+ if len(out[out_key]) == 1:
+ return out[out_key][0]
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "invoke_method_wait(), output contains %d " %
+ len(out[out_key]) +
+ "elements: %s" % out[out_key])
+ return out[out_key]
+ else:
+ raise LsmError(ErrorNumber.PLUGIN_BUG,
+ "invoke_method_wait(), %s not exist in out %s" %
+ (out_key, out.items()))
+
+ elif rc == SmisCommon.SNIA_INVOKE_ASYNC:
+ cim_job_path = out['Job']
+ loop_counter = 0
+ job_pros = ['JobState', 'ErrorDescription',
+ 'OperationalStatus']
+ cim_xxxs_path = []
+ while(loop_counter <= SmisCommon._INVOKE_MAX_LOOP_COUNT):
+ cim_job = self.GetInstance(cim_job_path,
+ PropertyList=job_pros)
+ job_state = cim_job['JobState']
+ if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
+ dmtf.JOB_STATE_RUNNING):
+ loop_counter += 1
+ time.sleep(SmisCommon._INVOKE_CHECK_INTERVAL)
+ continue
+ elif job_state == dmtf.JOB_STATE_COMPLETED:
+ if not SmisCommon.cim_job_completed_ok(cim_job):
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ str(cim_job['ErrorDescription']))
+ if expect_class is None:
+ return None
+ cim_xxxs_path = self.AssociatorNames(
+ cim_job.path,
+ AssocClass='CIM_AffectedJobElement',
+ ResultClass=expect_class)
+ break
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "invoke_method_wait(): Got unknown job state "
+ "%d: %s" % (job_state, cim_job.items()))
+
+ if loop_counter > SmisCommon._INVOKE_MAX_LOOP_COUNT:
+ raise LsmError(
+ ErrorNumber.TIMEOUT,
+ "The job generated by %s() failed to finish in %ds" %
+ (cmd,
+ SmisCommon._INVOKE_CHECK_INTERVAL *
+ SmisCommon._INVOKE_MAX_LOOP_COUNT))
+
+ if len(cim_xxxs_path) == 1:
+ return cim_xxxs_path[0]
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "invoke_method_wait(): got unexpected(not 1) "
+ "return from CIM_AffectedJobElement: "
+ "%s, out: %s, job: %s" %
+ (cim_xxxs_path, out.items(), cim_job.items()))
+ else:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "invoke_method_wait(): Got unexpected rc code "
+ "%d, out: %s" % (rc, out.items()))
+
def _cim_srv_of_sys_id(self, srv_name, sys_id, raise_error):
property_list = ['SystemName']
--
1.8.3.1
------------------------------------------------------------------------------