def create_ciminstance(self): """ Create a sample instance with multiple properties and property types. """ class TZ(tzinfo): """'Simplistic tsinfo subclass for this test""" def utcoffset(self, dt): # pylint: disable=unused-argument return timedelta(minutes=-399) dt = datetime(year=2016, month=3, day=31, hour=19, minute=30, second=40, microsecond=654321, tzinfo=MinutesFromUTC(120)) cim_dt = CIMDateTime(dt) props_input = { 'S1': b'Ham', 'Bool': True, 'UI8': Uint8(42), 'UI16': Uint16(4216), 'UI32': Uint32(4232), 'UI64': Uint64(4264), 'SI8': Sint8(-42), 'SI16': Sint16(-4216), 'SI32': Sint32(-4232), 'SI64': Sint64(-4264), 'R32': Real32(42.0), 'R64': Real64(42.64), 'DTI': CIMDateTime(timedelta(10, 49, 20)), 'DTF': cim_dt, 'DTP': CIMDateTime(datetime(2014, 9, 22, 10, 49, 20, 524789, tzinfo=TZ())), } # TODO python 2.7 will not write the following unicode character # For the moment, only add this property in python 3 test if six.PY3: props_input['S2'] = u'H\u00E4m' # U+00E4 = lower case a umlaut inst = CIMInstance('CIM_Foo', props_input) return inst
def uint16(num): """Convert number to uint16 WBEM client type if needed""" if getTesterCfg().isWMI: return num else: from pywbem import Uint16 return Uint16(num)
def test_single_valued(self): """Single-valued properties""" self._run_single(CIMProperty('Spotty', 'Foot')) self._run_single(CIMProperty('Age', Uint16(32))) self._run_single(CIMProperty('Foo', '', type='string')) self._run_single(CIMProperty('Foo', None, type='string')) self._run_single(CIMProperty('Age', None, type='uint16', qualifiers={'Key': CIMQualifier('Key', True)}))
def test_invoke_method(self): """ Emulates call to invokemethod to test parameter processing. Currently creates the pywbem_request component. Each test emulated a single cim operation with fixed data to create the input for the yaml, create the yaml, and test the result """ obj_name = self.create_ciminstancename() params = [ ('StringParam', 'Spotty'), ('Uint8', Uint8(1)), ('Sint8', Sint8(2)), ('Uint16', Uint16(3)), ('Sint16', Sint16(3)), ('Uint32', Uint32(4)), ('Sint32', Sint32(5)), ('Uint64', Uint64(6)), ('Sint64', Sint64(7)), ('Real32', Real32(8)), ('Real64', Real64(9)), ('Bool', True), ('DTN', CIMDateTime.now()), # ('DTI', timedelta(60)), ('Ref', obj_name) ] self.test_recorder.stage_pywbem_args(method='InvokeMethod', MethodName='Blah', ObjectName=obj_name, Params=params) method_result_tuple = None method_exception = None self.test_recorder.stage_pywbem_result(method_result_tuple, method_exception) self.test_recorder.record_staged() # reload the yaml to test created values test_yaml = self.loadYamlFile() test_yaml = test_yaml[0] pywbem_request = test_yaml['pywbem_request'] self.assertEqual(pywbem_request['url'], 'http://acme.com:80') operation = pywbem_request['operation'] self.assertEqual(operation['pywbem_method'], 'InvokeMethod') self.assertEqual(operation['MethodName'], 'Blah') param_dict = dict(params) self.assertEqual(len(param_dict), 14) self.assertEqual(param_dict['StringParam'], 'Spotty') self.assertEqual(param_dict['Uint8'], 1) self.assertEqual(param_dict['Bool'], True) # test other parameters ref = param_dict['Ref'] self.assertEqual(ref, obj_name)
def get_cim_rps(c): cim_rps = [] for n in INTEROP_NAMESPACES: try: cim_rps = c.EnumerateInstances('CIM_RegisteredProfile', namespace=n, localonly=False) except CIMError as e: if e[0] == pywbem.CIM_ERR_NOT_SUPPORTED or \ e[0] == pywbem.CIM_ERR_INVALID_NAMESPACE or \ e[0] == pywbem.CIM_ERR_INVALID_CLASS: pass else: raise if len(cim_rps): for cim_rp in cim_rps: if cim_rp['RegisteredOrganization'] == Uint16(11) and \ 'Array' == cim_rp['RegisteredName']: return cim_rp return None
def test_all(self): # Single-valued properties self._run_single(CIMProperty('Spotty', 'Foot')) self._run_single(CIMProperty('Age', Uint16(32))) self._run_single(CIMProperty('Foo', '', type='string')) self._run_single(CIMProperty('Foo', None, type='string')) self._run_single( CIMProperty('Age', None, type='uint16', qualifiers={'Key': CIMQualifier('Key', True)})) # Property arrays self._run_single(CIMProperty('Foo', ['a', 'b', 'c'])) self._run_single(CIMProperty('Foo', None, type='string', is_array=True)) self._run_single( CIMProperty('Foo', [Uint8(x) for x in [1, 2, 3]], qualifiers={'Key': CIMQualifier('Key', True)})) # Reference properties self._run_single(CIMProperty('Foo', None, type='reference')) self._run_single(CIMProperty('Foo', CIMInstanceName('CIM_Foo'))) self._run_single( CIMProperty('Foo', CIMInstanceName('CIM_Foo'), qualifiers={'Key': CIMQualifier('Key', True)})) # EmbeddedObject properties inst = CIMInstance('Foo_Class', {'one': Uint8(1), 'two': Uint8(2)}) self._run_single(CIMProperty('Foo', inst)) self._run_single(CIMProperty('Foo', [inst]))
obj=b"abc", exp_type_name=u'string', ), None, None, True), # Integer tests ("Object is an integer", dict( obj=42, exp_type_name=None, ), TypeError, None, True), ("Object is a Uint8 number", dict( obj=Uint8(42), exp_type_name=u'uint8', ), None, None, True), ("Object is a Uint16 number", dict( obj=Uint16(42), exp_type_name=u'uint16', ), None, None, True), ("Object is a Uint32 number", dict( obj=Uint32(42), exp_type_name=u'uint32', ), None, None, True), ("Object is a Uint64 number", dict( obj=Uint64(42), exp_type_name=u'uint64', ), None, None, True), ("Object is a Sint8 number", dict( obj=Sint8(42), exp_type_name=u'sint8',
def CreateInstance(self, namespace, new_instance): # pylint: disable=invalid-name """ Create an instance of the CIM_IndicationFilter class in an Interop namespace of the CIM repository, and if not yet existing create the new namespace in the CIM repository. See `~pywbem_mock.InstanceWriteProvider.CreateInstance` for documentation of validation and description of input parameters, noting extra conditions for this provider as described below: Parameters: namespace (:term:`string`): Must be a valid Interop namespace. new_instance (:class:`~pywbem.CIMInstance`): The following applies regarding its properties: * The 'Filter' and 'Handler' reference properties must exist. * If 'SubscriptionDuration' exists, 'SubscriptionTimeRemaining' will be set. * 'CreationClassName' property: This property is required and its value must match the class name of the new instance. Raises: :exc:`~pywbem.CIMError`: (CIM_ERR_INVALID_PARAMETER) if namespace is not the Interop namespace in the CIM repository or the Name property does not exist or the other properties cannot be added to the instance. """ self.parameter_is_interop(namespace, new_instance.classname) required_properties = ["Filter", "Handler"] self.validate_required_properties_exist(new_instance, namespace, required_properties) # Add missing properties that the might come from CIM_IndicationService new_instance['SubscriptionStartTime'] = CIMDateTime.now() new_instance['TimeOfLastStateChange'] = CIMDateTime.now() # Conditionally add the following properties set_property(new_instance, 'OnFatalErrorPolicy', Uint16(2)) set_property(new_instance, 'RepeatNotificationPolicy', Uint16(2)) set_property(new_instance, 'SubscriptionState', Uint16(2)) if 'SubscriptionDuration' in new_instance: new_instance['SubscriptionTimeRemaining'] = \ new_instance['SubscriptionDuration'] else: new_instance['SubscriptionDuration'] = CIMProperty( 'SubscriptionDuration', None, type='uint64') set_property(new_instance, 'SubscriptionInfo', CIMProperty('SubscriptionInfo', None, type='string')) set_property(new_instance, 'Description', "Pywbem mock CIMIndicationSubscriptionProvider instance") # Create the CIM instance for the new namespace in the CIM repository, # by delegating to the default provider method. return super(CIMIndicationSubscriptionProvider, self).CreateInstance(namespace, new_instance)
def CreateInstance(self, namespace, new_instance): # pylint: disable=invalid-name """ Create an instance of the CIM_ListenerDestinationCIMXML class in an Interop namespace of the CIM repository, and if not yet existing create the new namespace in the CIM repository. See `~pywbem_mock.InstanceWriteProvider.CreateInstance` for documentation of validation and description of input parameters, noting extra conditions for this provider as described below: Parameters: namespace (:term:`string`): Must be a valid Interop namespace. new_instance (:class:`~pywbem.CIMInstance`): The following applies regarding its properties: * 'Name' property: This property is required since it defines the name of the new namespace to be created. * 'CreationClassName' property: This property is required and its value must match the class name of the new instance. Raises: :exc:`~pywbem.CIMError`: (CIM_ERR_INVALID_PARAMETER) if namespace is not the Interop namespace in the CIM repository or the Name property does not exist or the other properties cannot be added to the instance. """ self.parameter_is_interop(namespace, new_instance.classname) ccn_pname = 'CreationClassName' name_pname = 'Name' sys_pname = 'SystemName' sccn_pname = 'SystemCreationClassName' required_properties = [name_pname] # Validate that required properties are specified in the new instance self.validate_required_properties_exist(new_instance, namespace, required_properties) # Validate or fix other key values in the new instance def _fix_key_prop(pname, new_prop_value, replacement=None): if pname not in new_instance or \ new_instance[pname].lower != new_prop_value.lower(): new_instance[pname] = replacement or new_prop_value # Set the keys to default if they don't exist or have invalid value _fix_key_prop(ccn_pname, new_instance.classname, new_instance.classname) _fix_key_prop(sys_pname, SYSTEMNAME) _fix_key_prop(sccn_pname, SYSTEMCREATIONCLASSNAME) # Add missing properties that the might come from CIM_IndicationService # if not already in instance set_property(new_instance, 'Protocol', Uint16(2)) set_property(new_instance, 'PersistenceType', Uint16(2)) set_property(new_instance, 'Description', "pywbem mock CIMListenerDestinationProvider instance") # Create the CIM instance for the new namespace in the CIM repository, # by delegating to the default provider method. return super(CIMListenerDestinationProvider, self).CreateInstance(namespace, new_instance)
def test_all(self): # Invoke on classname try: self.cimcall(self.conn.InvokeMethod, 'FooMethod', TEST_CLASS) except CIMError as ce: if ce.args[0] != CIM_ERR_METHOD_NOT_AVAILABLE: raise # Invoke on an InstanceName inst_names = self.cimcall(self.conn.EnumerateInstanceNames, TEST_CLASS) self.assertTrue(len(inst_names) >= 1) name = inst_names[0] # Pick the first returned instance try: self.cimcall(self.conn.InvokeMethod, 'FooMethod', name) except CIMError as ce: if ce.args[0] not in (CIM_ERR_METHOD_NOT_AVAILABLE, CIM_ERR_METHOD_NOT_FOUND): raise # Test remote instance name name2 = name.copy() name2.host = 'woot.com' name2.namespace = 'root/cimv2' try: self.cimcall(self.conn.InvokeMethod, 'FooMethod', name) except CIMError as ce: if ce.args[0] not in (CIM_ERR_METHOD_NOT_AVAILABLE, CIM_ERR_METHOD_NOT_FOUND): raise # Call with all possible parameter types try: self.cimcall(self.conn.InvokeMethod, 'FooMethod', TEST_CLASS, String='Spotty', Uint8=Uint8(1), Sint8=Sint8(2), Uint16=Uint16(3), Sint16=Sint16(3), Uint32=Uint32(4), Sint32=Sint32(5), Uint64=Uint64(6), Sint64=Sint64(7), Real32=Real32(8), Real64=Real64(9), Bool=True, Date1=CIMDateTime.now(), Date2=timedelta(60), Ref=name) except CIMError as ce: if ce.args[0] != CIM_ERR_METHOD_NOT_AVAILABLE: raise # Call with non-empty arrays try: self.cimcall(self.conn.InvokeMethod, 'FooMethod', TEST_CLASS, StringArray='Spotty', Uint8Array=[Uint8(1)], Sint8Array=[Sint8(2)], Uint16Array=[Uint16(3)], Sint16Array=[Sint16(3)], Uint32Array=[Uint32(4)], Sint32Array=[Sint32(5)], Uint64Array=[Uint64(6)], Sint64Array=[Sint64(7)], Real32Array=[Real32(8)], Real64Array=[Real64(9)], BoolArray=[False, True], Date1Array=[CIMDateTime.now(), CIMDateTime.now()], Date2Array=[timedelta(0), timedelta(60)], RefArray=[name, name]) except CIMError as ce: if ce.args[0] != CIM_ERR_METHOD_NOT_AVAILABLE: raise # Call with new Params arg try: self.cimcall( self.conn.InvokeMethod, 'FooMethod', TEST_CLASS, [('Spam', Uint16(1)), ('Ham', Uint16(2))], # Params Drink=Uint16(3), # begin of **params Beer=Uint16(4)) except CIMError as ce: if ce.args[0] != CIM_ERR_METHOD_NOT_AVAILABLE: raise
class SmisCommon(object): # Even many CIM_XXX_Service in DMTF shared the same return value # definition as SNIA do, but there is no DMTF standard motioned # InvokeMethod() should follow that list of return value. # We use SNIA definition here. # SNIA 1.6 rev4 Block book, BSP 5.5.3.12 Return Values section. SNIA_INVOKE_OK = 0 SNIA_INVOKE_NOT_SUPPORTED = 1 SNIA_INVOKE_FAILED = 4 SNIA_INVOKE_ASYNC = 4096 SNIA_BLK_ROOT_PROFILE = 'Array' SNIA_BLK_SRVS_PROFILE = 'Block Services' SNIA_DISK_LITE_PROFILE = 'Disk Drive Lite' SNIA_MULTI_SYS_PROFILE = 'Multiple Computer System' SNIA_MASK_PROFILE = 'Masking and Mapping' SNIA_GROUP_MASK_PROFILE = 'Group Masking and Mapping' SNIA_FC_TGT_PORT_PROFILE = 'FC Target Ports' SNIA_ISCSI_TGT_PORT_PROFILE = 'iSCSI Target Ports' SNIA_SPARE_DISK_PROFILE = 'Disk Sparing' SMIS_SPEC_VER_1_1 = '1.1' SMIS_SPEC_VER_1_4 = '1.4' SMIS_SPEC_VER_1_5 = '1.5' SMIS_SPEC_VER_1_6 = '1.6' SNIA_REG_ORG_CODE = Uint16(11) _MEGARAID_NAMESPACE = 'root/LsiMr13' _NETAPP_E_NAMESPACE = 'root/LsiArray13' _PRODUCT_MEGARAID = 'LSI MegaRAID' _PRODUCT_NETAPP_E = 'NetApp-E' JOB_RETRIEVE_NONE = 0 JOB_RETRIEVE_VOLUME = 1 JOB_RETRIEVE_VOLUME_CREATE = 2 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): self._wbem_conn = None self._profile_dict = {} self.root_blk_cim_rp = None # For root_cim_ self._vendor_product = None # For vendor workaround codes. self.system_list = system_list self._debug_path = debug_path if namespace is None: namespace = dmtf.DEFAULT_NAMESPACE self._wbem_conn = pywbem.WBEMConnection( url, (username, password), namespace) if no_ssl_verify: try: self._wbem_conn = pywbem.WBEMConnection( url, (username, password), namespace, no_verification=True) except TypeError: # pywbem is not holding fix from # https://bugzilla.redhat.com/show_bug.cgi?id=1039801 pass if debug_path is not None: self._wbem_conn.debug = True if namespace.lower() == SmisCommon._MEGARAID_NAMESPACE.lower(): # Skip profile register check on MegaRAID for better performance. # MegaRAID SMI-S profile support status will not change for a while. self._profile_dict = { # Provide a fake profile support status to pass the check. SmisCommon.SNIA_BLK_ROOT_PROFILE: SmisCommon.SMIS_SPEC_VER_1_4, SmisCommon.SNIA_BLK_SRVS_PROFILE: SmisCommon.SMIS_SPEC_VER_1_4, SmisCommon.SNIA_DISK_LITE_PROFILE: SmisCommon.SMIS_SPEC_VER_1_4, } self._vendor_product = SmisCommon._PRODUCT_MEGARAID else: (self._profile_dict, self.root_blk_cim_rp) = \ _profile_register_load(self._wbem_conn) if namespace.lower() == SmisCommon._NETAPP_E_NAMESPACE.lower(): self._vendor_product = SmisCommon._PRODUCT_NETAPP_E # NetApp-E indicates they support 1.0 version of FC/iSCSI target # But 1.0 does not define thoese profiles. Forcly change # support version to 1.4 self._profile_dict[SmisCommon.SNIA_FC_TGT_PORT_PROFILE] = \ SmisCommon.SMIS_SPEC_VER_1_4 self._profile_dict[SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE] = \ SmisCommon.SMIS_SPEC_VER_1_4 # NetApp-E indicates support of Mask and Mapping 1.2. But # SNIA website link for 1.2 broken. Change it to 1.4. self._profile_dict[SmisCommon.SNIA_MASK_PROFILE] = \ SmisCommon.SMIS_SPEC_VER_1_4 # Check 'Array' 1.4 support status. _profile_check( self._profile_dict, SmisCommon.SNIA_BLK_ROOT_PROFILE, SmisCommon.SMIS_SPEC_VER_1_4, raise_error=True) def profile_check(self, profile_name, spec_ver, raise_error=False): """ Usage: Check whether we support certain profile at certain SNIA specification version or later version. Will raise LsmError(ErrorNumber.NO_SUPPORT, 'xxx') if raise_error is True when nothing found. Parameter: profile_name # SmisCommon.SNIA_XXXX_PROFILE spec_ver # SmisCommon.SMIS_SPEC_VER_XXX raise_error # Raise LsmError if not found Returns: True or False """ return _profile_check( self._profile_dict, profile_name, spec_ver, raise_error) def _vendor_namespace(self): if self.root_blk_cim_rp: cim_syss_path = self._wbem_conn.AssociatorNames( self.root_blk_cim_rp.path, ResultClass='CIM_ComputerSystem', AssocClass='CIM_ElementConformsToProfile') if len(cim_syss_path) == 0: raise LsmError( ErrorNumber.NO_SUPPORT, "Target SMI-S provider does not support any " "CIM_ComputerSystem for SNIA SMI-S '%s' profile" % SmisCommon.SNIA_BLK_ROOT_PROFILE) return cim_syss_path[0].namespace else: raise LsmError( ErrorNumber.PLUGIN_BUG, "_vendor_namespace(): self.root_blk_cim_rp not set yet") def EnumerateInstances(self, ClassName, namespace=None, **params): if self._wbem_conn.default_namespace in dmtf.INTEROP_NAMESPACES: # We have to enumerate in vendor namespace self._wbem_conn.default_namespace = self._vendor_namespace() params['LocalOnly'] = False return self._wbem_conn.EnumerateInstances( ClassName, namespace, **params) def EnumerateInstanceNames(self, ClassName, namespace=None, **params): if self._wbem_conn.default_namespace in dmtf.INTEROP_NAMESPACES: # We have to enumerate in vendor namespace self._wbem_conn.default_namespace = self._vendor_namespace() params['LocalOnly'] = False return self._wbem_conn.EnumerateInstanceNames( ClassName, namespace, **params) def Associators(self, ObjectName, **params): return self._wbem_conn.Associators(ObjectName, **params) def AssociatorNames(self, ObjectName, **params): return self._wbem_conn.AssociatorNames(ObjectName, **params) def GetInstance(self, InstanceName, **params): params['LocalOnly'] = False return self._wbem_conn.GetInstance(InstanceName, **params) def DeleteInstance(self, InstanceName, **params): return self._wbem_conn.DeleteInstance(InstanceName, **params) def References(self, ObjectName, **params): return self._wbem_conn.References(ObjectName, **params) def is_megaraid(self): return self._vendor_product == SmisCommon._PRODUCT_MEGARAID def is_netappe(self): return self._vendor_product == SmisCommon._PRODUCT_NETAPP_E @staticmethod def cim_job_pros(): return ['InstanceID'] def cim_job_of_job_id(self, job_id, property_list=None): """ Return CIM_ConcreteJob for given job_id. """ if property_list is None: property_list = SmisCommon.cim_job_pros() else: property_list = merge_list( property_list, SmisCommon.cim_job_pros()) cim_jobs = self.EnumerateInstances( 'CIM_ConcreteJob', PropertyList=property_list) real_job_id = SmisCommon.parse_job_id(job_id)[0] for cim_job in cim_jobs: if md5(cim_job['InstanceID']) == real_job_id: return cim_job raise LsmError( ErrorNumber.NOT_FOUND_JOB, "Job %s not found" % job_id) @staticmethod def _job_id_of_cim_job(cim_job, retrieve_data, method_data): """ Return the MD5 has of CIM_ConcreteJob['InstanceID'] in conjunction with '@%s' % retrieve_data retrieve_data should be SmisCommon.JOB_RETRIEVE_NONE or SmisCommon.JOB_RETRIEVE_VOLUME or etc method_data is any string a method would like store for error handling by job_status(). """ return "%s@%d@%s" % ( md5(cim_job['InstanceID']), int(retrieve_data), str(method_data)) @staticmethod def parse_job_id(job_id): """ job_id is assembled by a md5 string, retrieve_data and method_data This method will split it and return (md5_str, retrieve_data, method_data) """ tmp_list = job_id.split('@', 3) md5_str = tmp_list[0] retrieve_data = SmisCommon.JOB_RETRIEVE_NONE method_data = None if len(tmp_list) == 3: retrieve_data = int(tmp_list[1]) method_data = tmp_list[2] return (md5_str, retrieve_data, method_data) def _dump_wbem_xml(self, file_prefix): """ When debugging issues with providers it's helpful to have the xml request/reply to give to provider developers. """ try: if self._debug_path is not None: if not os.path.exists(self._debug_path): os.makedirs(self._debug_path) if os.path.isdir(self._debug_path): debug_fn = "%s_%s" % ( file_prefix, datetime.datetime.now().isoformat()) debug_full = os.path.join( self._debug_path, debug_fn) # Dump the request & reply to a file with open(debug_full, 'w') as d: d.write("REQUEST:\n%s\n\nREPLY:\n%s\n" % (self._wbem_conn.last_request, self._wbem_conn.last_reply)) except Exception: # Lets not bother to try and report that we couldn't log the debug # data when we are most likely already in a bad spot pass def invoke_method(self, cmd, cim_path, in_params, out_handler=None, error_handler=None, retrieve_data=None, method_data=None): """ cmd A string of command, example: 'CreateOrModifyElementFromStoragePool' cim_path the CIMInstanceName, example: CIM_StorageConfigurationService.path in_params A dictionary of input parameter, example: {'ElementName': volume_name, 'ElementType': dmtf_element_type, 'InPool': cim_pool_path, 'Size': pywbem.Uint64(size_bytes)} out_handler A reference to a method to parse output, example: self._new_vol_from_name error_handler A reference to a method to handle all exceptions. retrieve_data SmisCommon.JOB_RETRIEVE_XXX, it will be used only when a ASYNC job has been created. method_data A string which will be stored in job_id, it could be used by job_status() to do error checking. """ if retrieve_data is None: retrieve_data = SmisCommon.JOB_RETRIEVE_NONE try: (rc, out) = self._wbem_conn.InvokeMethod( cmd, cim_path, **in_params) # Check to see if operation is done if rc == SmisCommon.SNIA_INVOKE_OK: if out_handler is None: return None, None else: return None, out_handler(out) elif rc == SmisCommon.SNIA_INVOKE_ASYNC: # We have an async operation job_id = SmisCommon._job_id_of_cim_job( out['Job'], retrieve_data, method_data) return job_id, None elif rc == SmisCommon.SNIA_INVOKE_NOT_SUPPORTED: raise LsmError( ErrorNumber.NO_SUPPORT, 'SMI-S error code indicates operation not supported') else: self._dump_wbem_xml(cmd) raise LsmError(ErrorNumber.PLUGIN_BUG, "Error: %s rc= %s" % (cmd, str(rc))) except Exception: exc_info = sys.exc_info() # Make sure to save off current exception as we could cause # another when trying to dump debug data. self._dump_wbem_xml(cmd) if error_handler is not None: error_handler(self, method_data, exc_info) 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 until done. Return 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._wbem_conn.InvokeMethod(cmd, cim_path, **in_params) try: 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: self._dump_wbem_xml(cmd) raise LsmError( ErrorNumber.PLUGIN_BUG, "invoke_method_wait(): Got unexpected rc code " "%d, out: %s" % (rc, out.items())) except Exception: exc_info = sys.exc_info() # Make sure to save off current exception as we could cause # another when trying to dump debug data. self._dump_wbem_xml(cmd) raise exc_info[0], exc_info[1], exc_info[2] def _cim_srv_of_sys_id(self, srv_name, sys_id, raise_error): property_list = ['SystemName'] try: cim_srvs = self.EnumerateInstances( srv_name, PropertyList=property_list) for cim_srv in cim_srvs: if cim_srv['SystemName'] == sys_id: return cim_srv except CIMError: if raise_error: raise else: return None if raise_error: raise LsmError( ErrorNumber.NO_SUPPORT, "Cannot find any '%s' for requested system ID" % srv_name) return None def cim_scs_of_sys_id(self, sys_id, raise_error=True): """ Return a CIMInstance of CIM_StorageConfigurationService for given system id. Using 'SystemName' property as system id of a service which is defined by DMTF CIM_Service. """ return self._cim_srv_of_sys_id( 'CIM_StorageConfigurationService', sys_id, raise_error) def cim_rs_of_sys_id(self, sys_id, raise_error=True): """ Return a CIMInstance of CIM_ReplicationService for given system id. Using 'SystemName' property as system id of a service which is defined by DMTF CIM_Service. """ return self._cim_srv_of_sys_id( 'CIM_ReplicationService', sys_id, raise_error) def cim_gmms_of_sys_id(self, sys_id, raise_error=True): """ Return a CIMInstance of CIM_GroupMaskingMappingService for given system id. Using 'SystemName' property as system id of a service which is defined by DMTF CIM_Service. """ return self._cim_srv_of_sys_id( 'CIM_GroupMaskingMappingService', sys_id, raise_error) def cim_ccs_of_sys_id(self, sys_id, raise_error=True): """ Return a CIMInstance of CIM_ControllerConfigurationService for given system id. Using 'SystemName' property as system id of a service which is defined by DMTF CIM_Service. """ return self._cim_srv_of_sys_id( 'CIM_ControllerConfigurationService', sys_id, raise_error) def cim_hwms_of_sys_id(self, sys_id, raise_error=True): """ Return a CIMInstance of CIM_StorageHardwareIDManagementService for given system id. Using 'SystemName' property as system id of a service which is defined by DMTF CIM_Service. """ return self._cim_srv_of_sys_id( 'CIM_StorageHardwareIDManagementService', sys_id, raise_error) @staticmethod def cim_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
# 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, see <http://www.gnu.org/licenses/>. # # Author: Gris Ge <*****@*****.**> # This class handle DMTF CIM constants and convert to LSM type. from pywbem import Uint16 # CIM_StorageHardwareID['IDType'] ID_TYPE_OTHER = Uint16(1) ID_TYPE_WWPN = Uint16(2) ID_TYPE_ISCSI = Uint16(5) TGT_PORT_USAGE_FRONTEND_ONLY = Uint16(2) TGT_PORT_USAGE_UNRESTRICTED = Uint16(4) # CIM_FCPort['PortDiscriminator'] FC_PORT_PORT_DISCRIMINATOR_FCOE = Uint16(10) # CIM_NetworkPort['LinkTechnology'] NET_PORT_LINK_TECH_ETHERNET = Uint16(2) # CIM_iSCSIProtocolEndpoint['Role'] ISCSI_TGT_ROLE_TARGET = Uint16(3) # CIM_SCSIProtocolController['NameFormat'] SPC_NAME_FORMAT_ISCSI = Uint16(3) # CIM_IPProtocolEndpoint['IPv6AddressType'] IPV6_ADDR_TYPE_GUA = Uint16(6)