00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 from string import split
00019 import time
00020 import copy
00021 import os
00022 import re
00023
00024 import pywbem
00025 from pywbem import CIMError
00026 import smis_cap
00027 import smis_sys
00028 import smis_pool
00029 import smis_disk
00030 from lsm.plugin.smispy import smis_vol
00031 from lsm.plugin.smispy import smis_ag
00032 import dmtf
00033
00034 from lsm import (IStorageAreaNetwork, uri_parse, LsmError, ErrorNumber,
00035 JobStatus, md5, Volume, AccessGroup, Pool,
00036 VERSION, TargetPort,
00037 search_property)
00038
00039 from utils import (merge_list, handle_cim_errors, hex_string_format)
00040
00041 from smis_common import SmisCommon
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 def _lsm_tgt_port_type_of_cim_fc_tgt(cim_fc_tgt):
00087 """
00088 We are assuming we got CIM_FCPort. Caller should make sure of that.
00089 Return TargetPool.PORT_TYPE_FC as fallback
00090 """
00091
00092
00093 if 'PortDiscriminator' in cim_fc_tgt and \
00094 cim_fc_tgt['PortDiscriminator'] and \
00095 dmtf.FC_PORT_PORT_DISCRIMINATOR_FCOE in cim_fc_tgt['PortDiscriminator']:
00096 return TargetPort.TYPE_FCOE
00097 if 'LinkTechnology' in cim_fc_tgt and \
00098 cim_fc_tgt['LinkTechnology'] == dmtf.NET_PORT_LINK_TECH_ETHERNET:
00099 return TargetPort.TYPE_FCOE
00100 return TargetPort.TYPE_FC
00101
00102
00103 class Smis(IStorageAreaNetwork):
00104 """
00105 SMI-S plug-ing which exposes a small subset of the overall provided
00106 functionality of SMI-S
00107 """
00108 _JOB_ERROR_HANDLER = {
00109 SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
00110 smis_vol.volume_create_error_handler,
00111 }
00112
00113 def __init__(self):
00114 self._c = None
00115 self.tmo = 0
00116
00117 @handle_cim_errors
00118 def plugin_register(self, uri, password, timeout, flags=0):
00119 """
00120 Called when the plug-in runner gets the start request from the client.
00121 Checkout interop support status via:
00122 1. Enumerate CIM_RegisteredProfile in 'interop' namespace.
00123 2. if nothing found, then
00124 Enumerate CIM_RegisteredProfile in 'root/interop' namespace.
00125 3. if nothing found, then
00126 Enumerate CIM_RegisteredProfile in user defined namespace.
00127 """
00128 protocol = 'http'
00129 port = SmisCommon.IAAN_WBEM_HTTP_PORT
00130 u = uri_parse(uri, ['scheme', 'netloc', 'host'], None)
00131
00132 if u['scheme'].lower() == 'smispy+ssl':
00133 protocol = 'https'
00134 port = SmisCommon.IAAN_WBEM_HTTPS_PORT
00135
00136 if 'port' in u:
00137 port = u['port']
00138
00139 url = "%s://%s:%s" % (protocol, u['host'], port)
00140
00141
00142 system_list = None
00143
00144 if 'systems' in u['parameters']:
00145 system_list = split(u['parameters']["systems"], ":")
00146
00147 namespace = None
00148 if 'namespace' in u['parameters']:
00149 namespace = u['parameters']['namespace']
00150
00151 no_ssl_verify = False
00152 if "no_ssl_verify" in u["parameters"] \
00153 and u["parameters"]["no_ssl_verify"] == 'yes':
00154 no_ssl_verify = True
00155
00156 debug_path = None
00157 if 'debug_path' in u['parameters']:
00158 debug_path = u['parameters']['debug_path']
00159
00160 self._c = SmisCommon(
00161 url, u['username'], password, namespace, no_ssl_verify,
00162 debug_path, system_list)
00163
00164 self.tmo = timeout
00165
00166 @handle_cim_errors
00167 def time_out_set(self, ms, flags=0):
00168 self.tmo = ms
00169
00170 @handle_cim_errors
00171 def time_out_get(self, flags=0):
00172 return self.tmo
00173
00174 @handle_cim_errors
00175 def plugin_unregister(self, flags=0):
00176 self._c = None
00177
00178 @handle_cim_errors
00179 def capabilities(self, system, flags=0):
00180 cim_sys = smis_sys.cim_sys_of_sys_id(self._c, system.id)
00181 return smis_cap.get(self._c, cim_sys, system)
00182
00183 @handle_cim_errors
00184 def plugin_info(self, flags=0):
00185 return "Generic SMI-S support", VERSION
00186
00187 @handle_cim_errors
00188 def job_status(self, job_id, flags=0):
00189 """
00190 Given a job id returns the current status as a tuple
00191 (status (enum), percent_complete(integer), volume (None or Volume))
00192 """
00193 completed_item = None
00194
00195 error_handler = None
00196
00197 (ignore, retrieve_data, method_data) = SmisCommon.parse_job_id(job_id)
00198
00199 if retrieve_data in Smis._JOB_ERROR_HANDLER.keys():
00200 error_handler = Smis._JOB_ERROR_HANDLER[retrieve_data]
00201
00202 cim_job_pros = SmisCommon.cim_job_pros()
00203 cim_job_pros.extend(
00204 ['JobState', 'PercentComplete', 'ErrorDescription',
00205 'OperationalStatus'])
00206 cim_job = self._c.cim_job_of_job_id(job_id, cim_job_pros)
00207
00208 job_state = cim_job['JobState']
00209
00210 try:
00211 if job_state in (dmtf.JOB_STATE_NEW, dmtf.JOB_STATE_STARTING,
00212 dmtf.JOB_STATE_RUNNING):
00213 status = JobStatus.INPROGRESS
00214
00215 pc = cim_job['PercentComplete']
00216 if pc > 100:
00217 percent_complete = 100
00218 else:
00219 percent_complete = pc
00220
00221 elif job_state == dmtf.JOB_STATE_COMPLETED:
00222 status = JobStatus.COMPLETE
00223 percent_complete = 100
00224
00225 if SmisCommon.cim_job_completed_ok(cim_job):
00226 if retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME or \
00227 retrieve_data == SmisCommon.JOB_RETRIEVE_VOLUME_CREATE:
00228 completed_item = self._new_vol_from_job(cim_job)
00229 else:
00230 raise LsmError(
00231 ErrorNumber.PLUGIN_BUG,
00232 str(cim_job['ErrorDescription']))
00233 else:
00234 raise LsmError(
00235 ErrorNumber.PLUGIN_BUG, str(cim_job['ErrorDescription']))
00236
00237 except Exception:
00238 if error_handler is not None:
00239 error_handler(self._c, method_data)
00240 else:
00241 raise
00242 return status, percent_complete, completed_item
00243
00244 def _new_vol_from_name(self, out):
00245 """
00246 Given a volume by CIMInstanceName, return a lsm Volume object
00247 """
00248 cim_vol = None
00249 cim_vol_pros = smis_vol.cim_vol_pros()
00250
00251 if 'TheElement' in out:
00252 cim_vol = self._c.GetInstance(
00253 out['TheElement'],
00254 PropertyList=cim_vol_pros)
00255 elif 'TargetElement' in out:
00256 cim_vol = self._c.GetInstance(
00257 out['TargetElement'],
00258 PropertyList=cim_vol_pros)
00259
00260 pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
00261 sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
00262
00263 return smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id)
00264
00265 def _new_vol_from_job(self, job):
00266 """
00267 Given a concrete job instance, return referenced volume as lsm volume
00268 """
00269 cim_vol_pros = smis_vol.cim_vol_pros()
00270 cim_vols = []
00271
00272
00273
00274
00275 if job.path.classname == 'TPD_ConcreteJob':
00276 cim_vols = self._c.Associators(
00277 job.path,
00278 AssocClass='CIM_AffectedJobElement',
00279 ResultClass='CIM_StorageVolume')
00280 else:
00281 cim_vols = self._c.Associators(
00282 job.path,
00283 AssocClass='CIM_AffectedJobElement',
00284 ResultClass='CIM_StorageVolume',
00285 PropertyList=cim_vol_pros)
00286 for cim_vol in cim_vols:
00287 pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
00288 sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
00289 return smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id)
00290 return None
00291
00292 @handle_cim_errors
00293 def volumes(self, search_key=None, search_value=None, flags=0):
00294 """
00295 Return all volumes.
00296 We are basing on "Block Services Package" profile version 1.4 or
00297 later:
00298 CIM_ComputerSystem
00299 |
00300 | (CIM_HostedStoragePool)
00301 |
00302 v
00303 CIM_StoragePool
00304 |
00305 | (CIM_AllocatedFromStoragePool)
00306 |
00307 v
00308 CIM_StorageVolume
00309 As 'Block Services Package' is mandatory for 'Array' profile, we
00310 don't check support status here as startup() already checked 'Array'
00311 profile.
00312 """
00313 rc = []
00314 cim_sys_pros = smis_sys.cim_sys_id_pros()
00315 cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
00316 cim_vol_pros = smis_vol.cim_vol_pros()
00317 for cim_sys in cim_syss:
00318 sys_id = smis_sys.sys_id_of_cim_sys(cim_sys)
00319 pool_pros = smis_pool.cim_pool_id_pros()
00320 cim_pools = smis_pool.cim_pools_of_cim_sys_path(
00321 self._c, cim_sys.path, pool_pros)
00322 for cim_pool in cim_pools:
00323 pool_id = smis_pool.pool_id_of_cim_pool(cim_pool)
00324 cim_vols = smis_vol.cim_vol_of_cim_pool_path(
00325 self._c, cim_pool.path, cim_vol_pros)
00326 for cim_vol in cim_vols:
00327 rc.append(
00328 smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id))
00329 return search_property(rc, search_key, search_value)
00330
00331 @handle_cim_errors
00332 def pools(self, search_key=None, search_value=None, flags=0):
00333 """
00334 Convert CIM_StoragePool to lsm.Pool.
00335 To list all CIM_StoragePool:
00336 1. List all root CIM_ComputerSystem.
00337 2. List all CIM_StoragePool associated to CIM_ComputerSystem.
00338 """
00339 rc = []
00340 cim_pool_pros = smis_pool.cim_pool_pros()
00341
00342 cim_sys_pros = smis_sys.cim_sys_id_pros()
00343 cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
00344
00345 for cim_sys in cim_syss:
00346 system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
00347 cim_pools = smis_pool.cim_pools_of_cim_sys_path(
00348 self._c, cim_sys.path, cim_pool_pros)
00349 for cim_pool in cim_pools:
00350 rc.append(
00351 smis_pool.cim_pool_to_lsm_pool(
00352 self._c, cim_pool, system_id))
00353
00354 return search_property(rc, search_key, search_value)
00355
00356 @handle_cim_errors
00357 def systems(self, flags=0):
00358 """
00359 Return the storage arrays accessible from this plug-in at this time
00360
00361 As 'Block Services Package' is mandatory for 'Array' profile, we
00362 don't check support status here as startup() already checked 'Array'
00363 profile.
00364 """
00365 cim_sys_pros = smis_sys.cim_sys_pros()
00366 cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
00367
00368 return [smis_sys.cim_sys_to_lsm_sys(s) for s in cim_syss]
00369
00370 @handle_cim_errors
00371 def volume_create(self, pool, volume_name, size_bytes, provisioning,
00372 flags=0):
00373 """
00374 Create a volume.
00375 """
00376
00377 if not Pool.ELEMENT_TYPE_VOLUME & pool.element_type:
00378 raise LsmError(
00379 ErrorNumber.NO_SUPPORT,
00380 "Pool not suitable for creating volumes")
00381
00382
00383 dmtf_element_type = dmtf.ELEMENT_THICK_VOLUME
00384
00385 if provisioning == Volume.PROVISION_DEFAULT:
00386
00387
00388 if not Pool.ELEMENT_TYPE_VOLUME_FULL & pool.element_type and \
00389 Pool.ELEMENT_TYPE_VOLUME_THIN & pool.element_type:
00390 dmtf_element_type = dmtf.ELEMENT_THIN_VOLUME
00391 else:
00392
00393 if provisioning == Volume.PROVISION_FULL and \
00394 Pool.ELEMENT_TYPE_VOLUME_FULL & pool.element_type:
00395 dmtf_element_type = dmtf.ELEMENT_THICK_VOLUME
00396 elif (provisioning == Volume.PROVISION_THIN and
00397 Pool.ELEMENT_TYPE_VOLUME_THIN & pool.element_type):
00398 dmtf_element_type = dmtf.ELEMENT_THIN_VOLUME
00399 else:
00400 raise LsmError(
00401 ErrorNumber.NO_SUPPORT,
00402 "Pool not suitable for creating volume with "
00403 "requested provisioning type")
00404
00405
00406 cim_scs = self._c.cim_scs_of_sys_id(pool.system_id)
00407
00408 cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(
00409 self._c, pool)
00410
00411 in_params = {'ElementName': volume_name,
00412 'ElementType': dmtf_element_type,
00413 'InPool': cim_pool_path,
00414 'Size': pywbem.Uint64(size_bytes)}
00415
00416 error_handler = Smis._JOB_ERROR_HANDLER[
00417 SmisCommon.JOB_RETRIEVE_VOLUME_CREATE]
00418
00419 return self._c.invoke_method(
00420 'CreateOrModifyElementFromStoragePool', cim_scs.path,
00421 in_params,
00422 out_handler=self._new_vol_from_name,
00423 error_handler=error_handler,
00424 retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME_CREATE,
00425 method_data=volume_name)
00426
00427 def _detach_netapp_e(self, vol, sync):
00428
00429 cim_scs = self._c.cim_scs_of_sys_id(vol.system_id)
00430
00431 in_params = {'Operation': pywbem.Uint16(2),
00432 'Synchronization': sync.path}
00433
00434 self._c.invoke_method_wait(
00435 'ModifySynchronization', cim_scs.path, in_params)
00436
00437 def _detach(self, vol, sync):
00438 if self._c.is_netappe():
00439 return self._detach_netapp_e(vol, sync)
00440
00441 cim_rs = self._c.cim_rs_of_sys_id(vol.system_id, raise_error=False)
00442
00443 if cim_rs:
00444 in_params = {'Operation': pywbem.Uint16(8),
00445 'Synchronization': sync.path}
00446
00447 self._c.invoke_method_wait(
00448 'ModifyReplicaSynchronization', cim_rs.path, in_params)
00449
00450 @staticmethod
00451 def _cim_name_match(a, b):
00452 if a['DeviceID'] == b['DeviceID'] \
00453 and a['SystemName'] == b['SystemName'] \
00454 and a['SystemCreationClassName'] == \
00455 b['SystemCreationClassName']:
00456 return True
00457 else:
00458 return False
00459
00460 def _deal_volume_associations_netappe(self, vol, cim_vol_path):
00461 """
00462 Check a volume to see if it has any associations with other
00463 volumes.
00464 """
00465 rc = False
00466
00467 ss = self._c.References(cim_vol_path,
00468 ResultClass='CIM_StorageSynchronized')
00469
00470 if len(ss):
00471 for s in ss:
00472 if 'SyncedElement' in s:
00473 item = s['SyncedElement']
00474
00475 if Smis._cim_name_match(item, cim_vol_path):
00476 self._detach(vol, s)
00477 rc = True
00478
00479 if 'SystemElement' in s:
00480 item = s['SystemElement']
00481
00482 if Smis._cim_name_match(item, cim_vol_path):
00483 self._detach(vol, s)
00484 rc = True
00485
00486 return rc
00487
00488 def _deal_volume_associations(self, vol, cim_vol_path):
00489 """
00490 Check a volume to see if it has any associations with other
00491 volumes and deal with them.
00492 """
00493 if self._c.is_netappe():
00494 return self._deal_volume_associations_netappe(vol, cim_vol_path)
00495
00496 try:
00497 ss = self._c.References(cim_vol_path,
00498 ResultClass='CIM_StorageSynchronized')
00499 except pywbem.CIMError as e:
00500 if e[0] == pywbem.CIM_ERR_INVALID_CLASS:
00501 return
00502 else:
00503 raise
00504
00505 if len(ss):
00506 for s in ss:
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 if 'SyncState' in s and 'CopyType' in s:
00522 if s['SyncState'] == dmtf.ST_SYNC_STATE_SYNCHRONIZED and \
00523 s['CopyType'] != \
00524 dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_ASSOC:
00525 if 'SyncedElement' in s:
00526 item = s['SyncedElement']
00527
00528 if Smis._cim_name_match(item, cim_vol_path):
00529 self._detach(vol, s)
00530
00531 if 'SystemElement' in s:
00532 item = s['SystemElement']
00533
00534 if Smis._cim_name_match(item, cim_vol_path):
00535 self._detach(vol, s)
00536
00537 def _volume_delete_netapp_e(self, volume, flags=0):
00538 cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
00539 cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
00540
00541
00542
00543 if not self._deal_volume_associations(volume, cim_vol_path):
00544 in_params = {'TheElement': cim_vol_path}
00545
00546
00547 return self._c.invoke_method(
00548 'ReturnToStoragePool', cim_scs.path, in_params)[0]
00549
00550
00551 try:
00552 cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=[])
00553 while cim_vol is not None:
00554 cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=[])
00555 time.sleep(0.125)
00556 except (LsmError, CIMError) as e:
00557 pass
00558
00559 @handle_cim_errors
00560 def volume_delete(self, volume, flags=0):
00561 """
00562 Delete a volume
00563 """
00564 cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
00565
00566 cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
00567
00568 self._deal_volume_associations(volume, cim_vol_path)
00569
00570 in_params = {'TheElement': cim_vol_path}
00571
00572
00573 return self._c.invoke_method(
00574 'ReturnToStoragePool', cim_scs.path, in_params)[0]
00575
00576 @handle_cim_errors
00577 def volume_resize(self, volume, new_size_bytes, flags=0):
00578 """
00579 Re-size a volume
00580 """
00581 cim_scs = self._c.cim_scs_of_sys_id(volume.system_id)
00582
00583 cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
00584
00585 in_params = {'ElementType': pywbem.Uint16(2),
00586 'TheElement': cim_vol_path,
00587 'Size': pywbem.Uint64(new_size_bytes)}
00588
00589 return self._c.invoke_method(
00590 'CreateOrModifyElementFromStoragePool', cim_scs.path, in_params,
00591 out_handler=self._new_vol_from_name,
00592 retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)
00593
00594 def _get_supported_sync_and_mode(self, system_id, rep_type):
00595 """
00596 Converts from a library capability to a suitable array capability
00597
00598 returns a tuple (sync, mode)
00599 """
00600 rc = [None, None]
00601
00602 cim_rs = self._c.cim_rs_of_sys_id(system_id, raise_error=False)
00603
00604 if cim_rs:
00605 rs_cap = self._c.Associators(
00606 cim_rs.path,
00607 AssocClass='CIM_ElementCapabilities',
00608 ResultClass='CIM_ReplicationServiceCapabilities')[0]
00609
00610 s_rt = rs_cap['SupportedReplicationTypes']
00611
00612 if rep_type == Volume.REPLICATE_COPY:
00613 if dmtf.REPLICA_CAP_TYPE_SYNC_CLONE_LOCAL in s_rt:
00614 rc[0] = dmtf.SYNC_TYPE_CLONE
00615 rc[1] = dmtf.REPLICA_MODE_SYNC
00616 elif dmtf.REPLICA_CAP_TYPE_ASYNC_CLONE_LOCAL in s_rt:
00617 rc[0] = dmtf.SYNC_TYPE_CLONE
00618 rc[1] = dmtf.REPLICA_MODE_ASYNC
00619
00620 elif rep_type == Volume.REPLICATE_MIRROR_ASYNC:
00621 if dmtf.REPLICA_CAP_TYPE_ASYNC_MIRROR_LOCAL in s_rt:
00622 rc[0] = dmtf.SYNC_TYPE_MIRROR
00623 rc[1] = dmtf.REPLICA_MODE_ASYNC
00624
00625 elif rep_type == Volume.REPLICATE_MIRROR_SYNC:
00626 if dmtf.REPLICA_CAP_TYPE_SYNC_MIRROR_LOCAL in s_rt:
00627 rc[0] = dmtf.SYNC_TYPE_MIRROR
00628 rc[1] = dmtf.REPLICA_MODE_SYNC
00629
00630 elif rep_type == Volume.REPLICATE_CLONE:
00631 if dmtf.REPLICA_CAP_TYPE_SYNC_CLONE_LOCAL in s_rt:
00632 rc[0] = dmtf.SYNC_TYPE_SNAPSHOT
00633 rc[1] = dmtf.REPLICA_MODE_SYNC
00634 elif dmtf.REPLICA_CAP_TYPE_ASYNC_CLONE_LOCAL in s_rt:
00635 rc[0] = dmtf.SYNC_TYPE_SNAPSHOT
00636 rc[1] = dmtf.REPLICA_MODE_ASYNC
00637
00638 if rc[0] is None:
00639 raise LsmError(ErrorNumber.NO_SUPPORT,
00640 "Replication type not supported")
00641
00642 return tuple(rc)
00643
00644 @handle_cim_errors
00645 def volume_replicate(self, pool, rep_type, volume_src, name, flags=0):
00646 """
00647 Replicate a volume
00648 """
00649 if rep_type == Volume.REPLICATE_MIRROR_ASYNC \
00650 or rep_type == Volume.REPLICATE_MIRROR_SYNC:
00651 raise LsmError(ErrorNumber.NO_SUPPORT, "Mirroring not supported")
00652
00653 cim_rs = self._c.cim_rs_of_sys_id(
00654 volume_src.system_id, raise_error=False)
00655
00656
00657
00658 if smis_vol.volume_name_exists(self._c, name):
00659 raise LsmError(ErrorNumber.NAME_CONFLICT,
00660 "Volume with name '%s' already exists!" % name)
00661
00662 cim_pool_path = None
00663 if pool is not None:
00664 cim_pool_path = smis_pool.lsm_pool_to_cim_pool_path(self._c, pool)
00665
00666 src_cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(
00667 self._c, volume_src)
00668
00669 if cim_rs:
00670 method = 'CreateElementReplica'
00671
00672 sync, mode = self._get_supported_sync_and_mode(
00673 volume_src.system_id, rep_type)
00674
00675 in_params = {'ElementName': name,
00676 'SyncType': sync,
00677
00678 'SourceElement': src_cim_vol_path,
00679 'WaitForCopyState': dmtf.COPY_STATE_SYNC}
00680
00681 else:
00682
00683
00684 method = 'CreateReplica'
00685
00686
00687 cim_rs = self._c.cim_scs_of_sys_id(
00688 volume_src.system_id, raise_error=False)
00689
00690 ct = Volume.REPLICATE_CLONE
00691 if rep_type == Volume.REPLICATE_CLONE:
00692 ct = dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_ASSOC
00693 elif rep_type == Volume.REPLICATE_COPY:
00694 ct = dmtf.ST_CONF_CAP_COPY_TYPE_UNSYNC_UNASSOC
00695 elif rep_type == Volume.REPLICATE_MIRROR_ASYNC:
00696 ct = dmtf.ST_CONF_CAP_COPY_TYPE_ASYNC
00697 elif rep_type == Volume.REPLICATE_MIRROR_SYNC:
00698 ct = dmtf.ST_CONF_CAP_COPY_TYPE_SYNC
00699
00700 in_params = {'ElementName': name,
00701 'CopyType': ct,
00702 'SourceElement': src_cim_vol_path}
00703 if cim_rs:
00704
00705 if cim_pool_path is not None:
00706 in_params['TargetPool'] = cim_pool_path
00707
00708 return self._c.invoke_method(
00709 method, cim_rs.path, in_params,
00710 out_handler=self._new_vol_from_name,
00711 retrieve_data=SmisCommon.JOB_RETRIEVE_VOLUME)
00712
00713 raise LsmError(ErrorNumber.NO_SUPPORT,
00714 "volume-replicate not supported")
00715
00716 def _cim_dev_mg_path_create(self, cim_gmms_path, name, cim_vol_path,
00717 vol_id):
00718 rc = SmisCommon.SNIA_INVOKE_FAILED
00719 out = None
00720
00721 in_params = {
00722 'GroupName': name,
00723 'Members': [cim_vol_path],
00724 'Type': dmtf.MASK_GROUP_TYPE_DEV}
00725
00726 cim_dev_mg_path = None
00727 try:
00728 cim_dev_mg_path = self._c.invoke_method_wait(
00729 'CreateGroup', cim_gmms_path, in_params,
00730 out_key='MaskingGroup',
00731 expect_class='CIM_TargetMaskingGroup')
00732 except (LsmError, CIMError):
00733 cim_dev_mg_path = self._check_exist_cim_dev_mg(
00734 name, cim_gmms_path, cim_vol_path, vol_id)
00735 if cim_dev_mg_path is None:
00736 raise
00737
00738 return cim_dev_mg_path
00739
00740 def _cim_tgt_mg_path_create(self, cim_sys_path, cim_gmms_path, name,
00741 init_type):
00742 """
00743 Create CIM_TargetMaskingGroup
00744 Currently, LSM does not support target ports masking
00745 we will mask to all target ports.
00746 Return CIMInstanceName of CIM_TargetMaskingGroup
00747 """
00748 rc = SmisCommon.SNIA_INVOKE_FAILED
00749 out = None
00750
00751 in_params = {
00752 'GroupName': name,
00753 'Type': dmtf.MASK_GROUP_TYPE_TGT}
00754
00755 if init_type == AccessGroup.INIT_TYPE_WWPN:
00756 cim_fc_tgts = self._cim_fc_tgt_of(cim_sys_path)
00757 all_cim_fc_peps_path = []
00758 all_cim_fc_peps_path.extend(
00759 [self._cim_pep_path_of_fc_tgt(x.path) for x in cim_fc_tgts])
00760 in_params['Members'] = all_cim_fc_peps_path
00761
00762 elif init_type == AccessGroup.INIT_TYPE_ISCSI_IQN:
00763 cim_iscsi_pgs = self._cim_iscsi_pg_of(cim_sys_path)
00764 in_params['Members'] = [x.path for x in cim_iscsi_pgs]
00765 else:
00766
00767 pass
00768
00769 cim_tgt_mg_path = None
00770 try:
00771 cim_tgt_mg_path = self._c.invoke_method_wait(
00772 'CreateGroup', cim_gmms_path, in_params,
00773 out_key='MaskingGroup', expect_class='CIM_TargetMaskingGroup')
00774 except (LsmError, CIMError):
00775 cim_tgt_mg_path = self._check_exist_cim_tgt_mg(name)
00776 if cim_tgt_mg_path is None:
00777 raise
00778
00779 return cim_tgt_mg_path
00780
00781 def _cim_spc_path_create(self, cim_gmms_path, cim_init_mg_path,
00782 cim_tgt_mg_path, cim_dev_mg_path, name):
00783 in_params = {
00784 'ElementName': name,
00785 'InitiatorMaskingGroup': cim_init_mg_path,
00786 'TargetMaskingGroup': cim_tgt_mg_path,
00787 'DeviceMaskingGroup': cim_dev_mg_path,
00788 }
00789
00790 return self._c.invoke_method_wait(
00791 'CreateMaskingView', cim_gmms_path, in_params,
00792 out_key='ProtocolController',
00793 expect_class='CIM_SCSIProtocolController')
00794
00795 def _volume_mask_group(self, access_group, volume, flags=0):
00796 """
00797 Grant access to a volume to an group
00798 Use GroupMaskingMappingService.AddMembers() for Group Masking
00799 Use ControllerConfigurationService.ExposePaths() for Masking.
00800 Currently, LSM does not have a way to control which target port to
00801 mask.
00802 If CIM_TargetMaskingGroup already defined for current
00803 CIM_InitiatorMaskingGroup, we use that.
00804 If No CIM_TargetMaskingGroup exist, we create one with all possible
00805 target ports(all FC and FCoE port for access_group.init_type == WWPN,
00806 and the same to iSCSI)
00807 """
00808 cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
00809 self._c, access_group)
00810
00811 cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
00812 self._c, cim_init_mg_path)
00813 if len(cim_inits) == 0:
00814 raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
00815 "Access group %s is empty(no member), " %
00816 access_group.id +
00817 "will not do volume_mask()")
00818
00819 if access_group.init_type != AccessGroup.INIT_TYPE_WWPN and \
00820 access_group.init_type != AccessGroup.INIT_TYPE_ISCSI_IQN:
00821 raise LsmError(ErrorNumber.NO_SUPPORT,
00822 "SMI-S plugin only support iSCSI and FC/FCoE "
00823 "access group volume masking, but got "
00824 "access group init_type: %d" %
00825 access_group.init_type)
00826
00827 cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
00828
00829 cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
00830
00831 cim_spcs_path = self._c.AssociatorNames(
00832 cim_init_mg_path,
00833 AssocClass='CIM_AssociatedInitiatorMaskingGroup',
00834 ResultClass='CIM_SCSIProtocolController')
00835
00836 if len(cim_spcs_path) == 0:
00837
00838 cim_sys = smis_sys.cim_sys_of_sys_id(
00839 self._c, access_group.system_id)
00840
00841 cim_tgt_mg_path = self._cim_tgt_mg_path_create(
00842 cim_sys.path, cim_gmms.path, access_group.name,
00843 access_group.init_type)
00844 cim_dev_mg_path = self._cim_dev_mg_path_create(
00845 cim_gmms.path, access_group.name, cim_vol_path, volume.id)
00846
00847 self._cim_spc_path_create(
00848 cim_gmms.path, cim_init_mg_path, cim_tgt_mg_path,
00849 cim_dev_mg_path, access_group.name)
00850 else:
00851
00852
00853 for cim_spc_path in cim_spcs_path:
00854
00855 cim_vols = smis_ag.cim_vols_masked_to_cim_spc_path(
00856 self._c, cim_spc_path, smis_vol.cim_vol_id_pros())
00857 for cur_cim_vol in cim_vols:
00858 if smis_vol.vol_id_of_cim_vol(cur_cim_vol) == volume.id:
00859 raise LsmError(
00860 ErrorNumber.NO_STATE_CHANGE,
00861 "Volume already masked to requested access group")
00862
00863
00864
00865 cim_dev_mg_path = self._c.AssociatorNames(
00866 cim_spc_path,
00867 AssocClass='CIM_AssociatedDeviceMaskingGroup',
00868 ResultClass='CIM_DeviceMaskingGroup')[0]
00869 in_params = {
00870 'MaskingGroup': cim_dev_mg_path,
00871 'Members': [cim_vol_path],
00872 }
00873 self._c.invoke_method_wait(
00874 'AddMembers', cim_gmms.path, in_params)
00875 return None
00876
00877 @handle_cim_errors
00878 def volume_mask(self, access_group, volume, flags=0):
00879 """
00880 Grant access to a volume to an group
00881 """
00882 mask_type = smis_cap.mask_type(self._c, raise_error=True)
00883
00884 if mask_type == smis_cap.MASK_TYPE_GROUP:
00885 cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
00886 if cim_sys.path.classname == 'Clar_StorageSystem':
00887 mask_type = smis_cap.MASK_TYPE_MASK
00888
00889 if mask_type == smis_cap.MASK_TYPE_GROUP:
00890 return self._volume_mask_group(access_group, volume, flags)
00891 return self._volume_mask_old(access_group, volume, flags)
00892
00893 def _cim_vol_masked_to_spc(self, cim_spc_path, vol_id, property_list=None):
00894 """
00895 Check whether provided volume id is masked to cim_spc_path.
00896 If so, return cim_vol, or return None
00897 """
00898 if property_list is None:
00899 property_list = smis_vol.cim_vol_id_pros()
00900 else:
00901 property_list = merge_list(
00902 property_list, smis_vol.cim_vol_id_pros())
00903
00904 masked_cim_vols = smis_ag.cim_vols_masked_to_cim_spc_path(
00905 self._c, cim_spc_path, property_list)
00906 for masked_cim_vol in masked_cim_vols:
00907 if smis_vol.vol_id_of_cim_vol(masked_cim_vol) == vol_id:
00908 return masked_cim_vol
00909
00910 return None
00911
00912 def _volume_mask_old(self, access_group, volume, flags):
00913 cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)
00914
00915 cim_inits = smis_ag.cim_init_of_cim_spc_path(self._c, cim_spc_path)
00916 if len(cim_inits) == 0:
00917 raise LsmError(ErrorNumber.EMPTY_ACCESS_GROUP,
00918 "Access group %s is empty(no member), " %
00919 access_group.id +
00920 "will not do volume_mask()")
00921
00922
00923 if self._cim_vol_masked_to_spc(cim_spc_path, volume.id):
00924 raise LsmError(
00925 ErrorNumber.NO_STATE_CHANGE,
00926 "Volume already masked to requested access group")
00927
00928 cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)
00929
00930 cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
00931 cim_vol = self._c.GetInstance(cim_vol_path, PropertyList=['Name'])
00932
00933 in_params = {'LUNames': [cim_vol['Name']],
00934 'ProtocolControllers': [cim_spc_path],
00935 'DeviceAccesses': [dmtf.CTRL_CONF_SRV_DA_RW]}
00936
00937 self._c.invoke_method_wait('ExposePaths', cim_ccs.path, in_params)
00938 return None
00939
00940 def _volume_unmask_group(self, access_group, volume):
00941 """
00942 Use CIM_GroupMaskingMappingService.RemoveMembers() against
00943 CIM_DeviceMaskingGroup
00944 If SupportedDeviceGroupFeatures does not allow empty
00945 DeviceMaskingGroup in SPC, we remove SPC and DeviceMaskingGroup.
00946 """
00947 cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
00948
00949 cim_gmms_cap = self._c.Associators(
00950 cim_sys.path,
00951 AssocClass='CIM_ElementCapabilities',
00952 ResultClass='CIM_GroupMaskingMappingCapabilities',
00953 PropertyList=['SupportedDeviceGroupFeatures',
00954 'SupportedSynchronousActions',
00955 'SupportedAsynchronousActions'])[0]
00956
00957 flag_empty_dev_in_spc = False
00958
00959 if dmtf.GMM_CAP_DEV_MG_ALLOW_EMPTY_W_SPC in \
00960 cim_gmms_cap['SupportedDeviceGroupFeatures']:
00961 flag_empty_dev_in_spc = True
00962
00963 if flag_empty_dev_in_spc is False:
00964 if ((dmtf.GMM_CAP_DELETE_SPC not in
00965 cim_gmms_cap['SupportedSynchronousActions']) and
00966 (dmtf.GMM_CAP_DELETE_SPC not in
00967 cim_gmms_cap['SupportedAsynchronousActions'])):
00968 raise LsmError(
00969 ErrorNumber.NO_SUPPORT,
00970 "volume_unmask() not supported. It requires one of these "
00971 "1. support of DeleteMaskingView(). 2. allowing empty "
00972 "DeviceMaskingGroup in SPC. But target SMI-S provider "
00973 "does not support any of these")
00974
00975 cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
00976 vol_cim_spcs_path = self._c.AssociatorNames(
00977 cim_vol_path,
00978 AssocClass='CIM_ProtocolControllerForUnit',
00979 ResultClass='CIM_SCSIProtocolController')
00980
00981 if len(vol_cim_spcs_path) == 0:
00982
00983 raise LsmError(
00984 ErrorNumber.NO_STATE_CHANGE,
00985 "Volume is not masked to requested access group")
00986
00987 cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
00988 self._c, access_group)
00989 ag_cim_spcs_path = self._c.AssociatorNames(
00990 cim_init_mg_path,
00991 AssocClass='CIM_AssociatedInitiatorMaskingGroup',
00992 ResultClass='CIM_SCSIProtocolController')
00993
00994 found_cim_spc_path = None
00995 for ag_cim_spc_path in ag_cim_spcs_path:
00996 for vol_cim_spc_path in vol_cim_spcs_path:
00997 if vol_cim_spc_path == ag_cim_spc_path:
00998 found_cim_spc_path = vol_cim_spc_path
00999 break
01000
01001 if found_cim_spc_path is None:
01002
01003 raise LsmError(
01004 ErrorNumber.NO_STATE_CHANGE,
01005 "Volume is not masked to requested access group")
01006
01007
01008 cim_dev_mg_path = self._c.AssociatorNames(
01009 found_cim_spc_path,
01010 AssocClass='CIM_AssociatedDeviceMaskingGroup',
01011 ResultClass='CIM_DeviceMaskingGroup')[0]
01012
01013 cim_gmms = self._c.cim_gmms_of_sys_id(volume.system_id)
01014
01015 if flag_empty_dev_in_spc is False:
01016
01017
01018
01019 cur_cim_vols_path = self._c.AssociatorNames(
01020 cim_dev_mg_path,
01021 AssocClass='CIM_OrderedMemberOfCollection',
01022 ResultClass='CIM_StorageVolume')
01023 if len(cur_cim_vols_path) == 1:
01024
01025 in_params = {
01026 'ProtocolController': found_cim_spc_path,
01027 }
01028 self._c.invoke_method_wait(
01029 'DeleteMaskingView', cim_gmms.path, in_params)
01030
01031 in_params = {
01032 'MaskingGroup': cim_dev_mg_path,
01033 'Members': [cim_vol_path],
01034 }
01035 self._c.invoke_method_wait(
01036 'RemoveMembers', cim_gmms.path, in_params)
01037
01038 return None
01039
01040 @handle_cim_errors
01041 def volume_unmask(self, access_group, volume, flags=0):
01042 mask_type = smis_cap.mask_type(self._c, raise_error=True)
01043
01044 if mask_type == smis_cap.MASK_TYPE_GROUP:
01045 cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
01046 if cim_sys.path.classname == 'Clar_StorageSystem':
01047 mask_type = smis_cap.MASK_TYPE_MASK
01048
01049 if mask_type == smis_cap.MASK_TYPE_GROUP:
01050 return self._volume_unmask_group(access_group, volume)
01051 return self._volume_unmask_old(access_group, volume)
01052
01053 def _volume_unmask_old(self, access_group, volume):
01054 cim_ccs = self._c.cim_ccs_of_sys_id(volume.system_id)
01055 cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)
01056
01057
01058 cim_vol = self._cim_vol_masked_to_spc(
01059 cim_spc_path, volume.id, ['Name'])
01060
01061 if cim_vol is None:
01062 raise LsmError(
01063 ErrorNumber.NO_STATE_CHANGE,
01064 "Volume is not masked to requested access group")
01065
01066 hide_params = {'LUNames': [cim_vol['Name']],
01067 'ProtocolControllers': [cim_spc_path]}
01068
01069 self._c.invoke_method_wait('HidePaths', cim_ccs.path, hide_params)
01070 return None
01071
01072 def _is_access_group(self, cim_spc):
01073 if self._c.is_netappe():
01074 return True
01075
01076 rc = True
01077 _SMIS_EMC_ADAPTER_ROLE_MASKING = 'MASK_VIEW'
01078
01079 if 'EMCAdapterRole' in cim_spc:
01080
01081
01082
01083
01084 emc_adp_roles = cim_spc['EMCAdapterRole'].split(' ')
01085 if _SMIS_EMC_ADAPTER_ROLE_MASKING not in emc_adp_roles:
01086 rc = False
01087 return rc
01088
01089 def _cim_spc_of(self, system_id, property_list=None):
01090 """
01091 Return a list of CIM_SCSIProtocolController.
01092 Following SNIA SMIS 'Masking and Mapping Profile':
01093 CIM_ControllerConfigurationService
01094 |
01095 | CIM_ConcreteDependency
01096 v
01097 CIM_SCSIProtocolController
01098 """
01099 cim_ccs = None
01100 rc_cim_spcs = []
01101
01102 if property_list is None:
01103 property_list = []
01104
01105 try:
01106 cim_ccs = self._c.cim_ccs_of_sys_id(system_id, raise_error=False)
01107 except CIMError as ce:
01108 error_code = tuple(ce)[0]
01109 if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
01110 error_code == pywbem.CIM_ERR_INVALID_PARAMETER:
01111 raise LsmError(ErrorNumber.NO_SUPPORT,
01112 'AccessGroup is not supported ' +
01113 'by this array')
01114 if cim_ccs is None:
01115 raise LsmError(ErrorNumber.NO_SUPPORT,
01116 'AccessGroup is not supported by this array')
01117
01118 cim_spcs = self._c.Associators(
01119 cim_ccs.path,
01120 AssocClass='CIM_ConcreteDependency',
01121 ResultClass='CIM_SCSIProtocolController',
01122 PropertyList=property_list)
01123 for cim_spc in cim_spcs:
01124 if self._is_access_group(cim_spc):
01125 rc_cim_spcs.append(cim_spc)
01126 return rc_cim_spcs
01127
01128 @handle_cim_errors
01129 def volumes_accessible_by_access_group(self, access_group, flags=0):
01130 mask_type = smis_cap.mask_type(self._c, raise_error=True)
01131 cim_vols = []
01132 cim_vol_pros = smis_vol.cim_vol_pros()
01133
01134
01135 if mask_type == smis_cap.MASK_TYPE_GROUP:
01136 cim_sys = smis_sys.cim_sys_of_sys_id(
01137 self._c, access_group.system_id)
01138 if cim_sys.path.classname == 'Clar_StorageSystem':
01139 mask_type = smis_cap.MASK_TYPE_MASK
01140
01141 if mask_type == smis_cap.MASK_TYPE_GROUP:
01142 cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
01143 self._c, access_group)
01144
01145 cim_spcs_path = self._c.AssociatorNames(
01146 cim_init_mg_path,
01147 AssocClass='CIM_AssociatedInitiatorMaskingGroup',
01148 ResultClass='CIM_SCSIProtocolController')
01149
01150 for cim_spc_path in cim_spcs_path:
01151 cim_vols.extend(
01152 smis_ag.cim_vols_masked_to_cim_spc_path(
01153 self._c, cim_spc_path, cim_vol_pros))
01154 else:
01155 cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
01156 self._c, access_group)
01157 cim_vols = smis_ag.cim_vols_masked_to_cim_spc_path(
01158 self._c, cim_spc_path, cim_vol_pros)
01159 rc = []
01160 for cim_vol in cim_vols:
01161 pool_id = smis_pool.pool_id_of_cim_vol(self._c, cim_vol.path)
01162 sys_id = smis_sys.sys_id_of_cim_vol(cim_vol)
01163 rc.append(
01164 smis_vol.cim_vol_to_lsm_vol(cim_vol, pool_id, sys_id))
01165 return rc
01166
01167 @handle_cim_errors
01168 def access_groups_granted_to_volume(self, volume, flags=0):
01169 rc = []
01170 mask_type = smis_cap.mask_type(self._c, raise_error=True)
01171 cim_vol_path = smis_vol.lsm_vol_to_cim_vol_path(self._c, volume)
01172
01173
01174 if mask_type == smis_cap.MASK_TYPE_GROUP:
01175 cim_sys = smis_sys.cim_sys_of_sys_id(self._c, volume.system_id)
01176 if cim_sys.path.classname == 'Clar_StorageSystem':
01177 mask_type = smis_cap.MASK_TYPE_MASK
01178
01179 cim_spc_pros = None
01180 if mask_type == smis_cap.MASK_TYPE_GROUP:
01181 cim_spc_pros = []
01182 else:
01183 cim_spc_pros = smis_ag.cim_spc_pros()
01184
01185 cim_spcs = self._c.Associators(
01186 cim_vol_path,
01187 AssocClass='CIM_ProtocolControllerForUnit',
01188 ResultClass='CIM_SCSIProtocolController',
01189 PropertyList=cim_spc_pros)
01190
01191 if mask_type == smis_cap.MASK_TYPE_GROUP:
01192 cim_init_mg_pros = smis_ag.cim_init_mg_pros()
01193 for cim_spc in cim_spcs:
01194 cim_init_mgs = self._c.Associators(
01195 cim_spc.path,
01196 AssocClass='CIM_AssociatedInitiatorMaskingGroup',
01197 ResultClass='CIM_InitiatorMaskingGroup',
01198 PropertyList=cim_init_mg_pros)
01199 rc.extend(
01200 list(
01201 smis_ag.cim_init_mg_to_lsm_ag(
01202 self._c, x, volume.system_id)
01203 for x in cim_init_mgs))
01204 else:
01205 for cim_spc in cim_spcs:
01206 if self._is_access_group(cim_spc):
01207 rc.append(
01208 smis_ag.cim_spc_to_lsm_ag(
01209 self._c, cim_spc, volume.system_id))
01210
01211 return rc
01212
01213 def _cim_init_mg_of(self, system_id, property_list=None):
01214 """
01215 We use this association to get all CIM_InitiatorMaskingGroup:
01216 CIM_GroupMaskingMappingService
01217 |
01218 | CIM_ServiceAffectsElement
01219 v
01220 CIM_InitiatorMaskingGroup
01221 """
01222 if property_list is None:
01223 property_list = []
01224
01225 cim_gmms = self._c.cim_gmms_of_sys_id(system_id)
01226
01227 return self._c.Associators(
01228 cim_gmms.path,
01229 AssocClass='CIM_ServiceAffectsElement',
01230 ResultClass='CIM_InitiatorMaskingGroup',
01231 PropertyList=property_list)
01232
01233 @handle_cim_errors
01234 def access_groups(self, search_key=None, search_value=None, flags=0):
01235 rc = []
01236 mask_type = smis_cap.mask_type(self._c, raise_error=True)
01237
01238 cim_sys_pros = smis_sys.cim_sys_id_pros()
01239 cim_syss = smis_sys.root_cim_sys(self._c, cim_sys_pros)
01240
01241 cim_spc_pros = smis_ag.cim_spc_pros()
01242 for cim_sys in cim_syss:
01243 if cim_sys.path.classname == 'Clar_StorageSystem':
01244
01245
01246
01247 mask_type = smis_cap.MASK_TYPE_MASK
01248
01249 system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
01250 if mask_type == smis_cap.MASK_TYPE_GROUP:
01251 cim_init_mg_pros = smis_ag.cim_init_mg_pros()
01252 cim_init_mgs = self._cim_init_mg_of(
01253 system_id, cim_init_mg_pros)
01254 rc.extend(
01255 list(
01256 smis_ag.cim_init_mg_to_lsm_ag(self._c, x, system_id)
01257 for x in cim_init_mgs))
01258 elif mask_type == smis_cap.MASK_TYPE_MASK:
01259 cim_spcs = self._cim_spc_of(system_id, cim_spc_pros)
01260 rc.extend(
01261 list(
01262 smis_ag.cim_spc_to_lsm_ag(self._c, cim_spc, system_id)
01263 for cim_spc in cim_spcs))
01264 else:
01265 raise LsmError(ErrorNumber.PLUGIN_BUG,
01266 "_get_cim_spc_by_id(): Got invalid mask_type: "
01267 "%s" % mask_type)
01268
01269 return search_property(rc, search_key, search_value)
01270
01271 def _ag_init_add_group(self, access_group, init_id, init_type):
01272 cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
01273
01274 if cim_sys.path.classname == 'Clar_StorageSystem':
01275 raise LsmError(ErrorNumber.NO_SUPPORT,
01276 "EMC VNX/CX require WWNN defined when adding a "
01277 "new initiator which is not supported by LSM yet. "
01278 "Please do it via EMC vendor specific tools.")
01279
01280 cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
01281 self._c, access_group)
01282
01283 exist_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
01284 self._c, cim_init_mg_path)
01285
01286
01287 for exist_cim_init in exist_cim_inits:
01288 if smis_ag.init_id_of_cim_init(exist_cim_init) == init_id:
01289 return copy.deepcopy(access_group)
01290
01291 cim_init_path = smis_ag.cim_init_path_check_or_create(
01292 self._c, access_group.system_id, init_id, init_type)
01293
01294 cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
01295
01296 in_params = {
01297 'MaskingGroup': cim_init_mg_path,
01298 'Members': [cim_init_path],
01299 }
01300
01301 new_cim_init_mg_path = self._c.invoke_method_wait(
01302 'AddMembers', cim_gmms.path, in_params,
01303 out_key='MaskingGroup', expect_class='CIM_InitiatorMaskingGroup')
01304 cim_init_mg_pros = smis_ag.cim_init_mg_pros()
01305 new_cim_init_mg = self._c.GetInstance(
01306 new_cim_init_mg_path, PropertyList=cim_init_mg_pros,
01307 LocalOnly=False)
01308 return smis_ag.cim_init_mg_to_lsm_ag(
01309 self._c, new_cim_init_mg, access_group.system_id)
01310
01311 @handle_cim_errors
01312 def access_group_initiator_add(self, access_group, init_id, init_type,
01313 flags=0):
01314 init_id = smis_ag.lsm_init_id_to_snia(init_id)
01315 mask_type = smis_cap.mask_type(self._c, raise_error=True)
01316
01317 if mask_type == smis_cap.MASK_TYPE_GROUP:
01318 return self._ag_init_add_group(access_group, init_id, init_type)
01319 else:
01320 return self._ag_init_add_old(access_group, init_id, init_type)
01321
01322 def _ag_init_add_old(self, access_group, init_id, init_type):
01323
01324
01325 cim_sys = smis_sys.cim_sys_of_sys_id(self._c, access_group.system_id)
01326
01327 if cim_sys.path.classname == 'Clar_StorageSystem':
01328 raise LsmError(ErrorNumber.NO_SUPPORT,
01329 "EMC VNX/CX require WWNN defined when adding "
01330 "new initiator which is not supported by LSM yet. "
01331 "Please do it via EMC vendor specific tools. "
01332 "EMC VNX does not support adding iSCSI IQN neither")
01333
01334 cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(
01335 self._c, access_group)
01336
01337 exist_cim_inits = smis_ag.cim_init_of_cim_spc_path(
01338 self._c, cim_spc_path)
01339
01340 for exist_cim_init in exist_cim_inits:
01341 if smis_ag.init_id_of_cim_init(exist_cim_init) == init_id:
01342 return copy.deepcopy(access_group)
01343
01344
01345
01346
01347 smis_ag.cim_init_path_check_or_create(
01348 self._c, access_group.system_id, init_id, init_type)
01349
01350 cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)
01351
01352 in_params = {'InitiatorPortIDs': [init_id],
01353 'ProtocolControllers': [cim_spc_path]}
01354
01355 cim_spc_path = self._c.invoke_method_wait(
01356 'ExposePaths', cim_ccs.path, in_params,
01357 out_key='ProtocolControllers', flag_out_array=True,
01358 expect_class='CIM_SCSIProtocolController')
01359
01360 cim_spc_pros = smis_ag.cim_spc_pros()
01361 cim_spc = self._c.GetInstance(
01362 cim_spc_path, PropertyList=cim_spc_pros, LocalOnly=False)
01363 return smis_ag.cim_spc_to_lsm_ag(
01364 self._c, cim_spc, access_group.system_id)
01365
01366 def _ag_init_del_group(self, access_group, init_id):
01367 """
01368 Call CIM_GroupMaskingMappingService.RemoveMembers() against
01369 CIM_InitiatorMaskingGroup.
01370 """
01371 cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
01372 self._c, access_group)
01373 cur_cim_inits = smis_ag.cim_init_of_cim_init_mg_path(
01374 self._c, cim_init_mg_path)
01375
01376 cim_init = None
01377 for cur_cim_init in cur_cim_inits:
01378 if smis_ag.init_id_of_cim_init(cur_cim_init) == init_id:
01379 cim_init = cur_cim_init
01380 break
01381
01382 if cim_init is None:
01383 raise LsmError(ErrorNumber.NO_STATE_CHANGE,
01384 "Initiator %s does not exist in defined "
01385 "access group %s" %
01386 (init_id, access_group.id))
01387
01388 if len(cur_cim_inits) == 1:
01389 raise LsmError(ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
01390 "Refuse to remove last initiator from access group")
01391
01392 cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
01393
01394
01395 in_params = {
01396 'MaskingGroup': cim_init_mg_path,
01397 'Members': [cim_init.path],
01398 }
01399
01400 self._c.invoke_method_wait('RemoveMembers', cim_gmms.path, in_params)
01401
01402 cim_init_mg_pros = smis_ag.cim_init_mg_pros()
01403 cim_init_mg = self._c.GetInstance(
01404 cim_init_mg_path, PropertyList=cim_init_mg_pros)
01405
01406 return smis_ag.cim_init_mg_to_lsm_ag(
01407 self._c, cim_init_mg, access_group.system_id)
01408
01409 @handle_cim_errors
01410 def access_group_initiator_delete(self, access_group, init_id, init_type,
01411 flags=0):
01412 if self._c.is_netappe():
01413
01414
01415
01416 raise LsmError(ErrorNumber.NO_SUPPORT,
01417 "SMI-S plugin does not support "
01418 "access_group_initiator_delete() against NetApp-E")
01419 init_id = smis_ag.lsm_init_id_to_snia(init_id)
01420 mask_type = smis_cap.mask_type(self._c, raise_error=True)
01421
01422 if mask_type == smis_cap.MASK_TYPE_GROUP:
01423 return self._ag_init_del_group(access_group, init_id)
01424 else:
01425 return self._ag_init_del_old(access_group, init_id)
01426
01427 def _ag_init_del_old(self, access_group, init_id):
01428 cim_spc_path = smis_ag.lsm_ag_to_cim_spc_path(self._c, access_group)
01429
01430 cim_ccs = self._c.cim_ccs_of_sys_id(access_group.system_id)
01431
01432 hide_params = {'InitiatorPortIDs': [init_id],
01433 'ProtocolControllers': [cim_spc_path]}
01434 self._c.invoke_method_wait('HidePaths', cim_ccs.path, hide_params)
01435
01436 return None
01437
01438 @handle_cim_errors
01439 def job_free(self, job_id, flags=0):
01440 """
01441 Frees the resources given a job number.
01442 """
01443 cim_job = self._c.cim_job_of_job_id(job_id, ['DeleteOnCompletion'])
01444
01445
01446 if not cim_job['DeleteOnCompletion']:
01447 try:
01448 self._c.DeleteInstance(cim_job.path)
01449 except CIMError:
01450 pass
01451
01452 @handle_cim_errors
01453 def disks(self, search_key=None, search_value=None, flags=0):
01454 """
01455 return all object of data.Disk.
01456 We are using "Disk Drive Lite Subprofile" v1.4 of SNIA SMI-S for these
01457 classes to create LSM Disk:
01458 CIM_DiskDrive
01459 CIM_StorageExtent (Primordial)
01460 Due to 'Multiple Computer System' profile, disks might associated to
01461 sub ComputerSystem. To improve performance of listing disks, we will
01462 use EnumerateInstances(). Which means we have to filter the results
01463 by ourselves in case URI contain 'system=xxx'.
01464 """
01465 rc = []
01466 self._c.profile_check(SmisCommon.SNIA_DISK_LITE_PROFILE,
01467 SmisCommon.SMIS_SPEC_VER_1_4,
01468 raise_error=True)
01469 cim_disk_pros = smis_disk.cim_disk_pros()
01470 cim_disks = self._c.EnumerateInstances(
01471 'CIM_DiskDrive', PropertyList=cim_disk_pros)
01472 for cim_disk in cim_disks:
01473 if self._c.system_list and \
01474 smis_disk.sys_id_of_cim_disk(cim_disk) not in \
01475 self._c.system_list:
01476 continue
01477
01478 rc.extend([smis_disk.cim_disk_to_lsm_disk(self._c, cim_disk)])
01479 return search_property(rc, search_key, search_value)
01480
01481 @staticmethod
01482 def _is_frontend_fc_tgt(cim_fc_tgt):
01483 """
01484 Check CIM_FCPort['UsageRestriction'] for frontend port.
01485 """
01486 dmtf_usage = cim_fc_tgt['UsageRestriction']
01487 if dmtf_usage == dmtf.TGT_PORT_USAGE_FRONTEND_ONLY or \
01488 dmtf_usage == dmtf.TGT_PORT_USAGE_UNRESTRICTED:
01489 return True
01490 return False
01491
01492 def _cim_fc_tgt_of(self, cim_sys_path, property_list=None):
01493 """
01494 Get all CIM_FCPort (frontend only) from CIM_ComputerSystem and its
01495 leaf CIM_ComputerSystem
01496 """
01497 rc = []
01498 if property_list is None:
01499 property_list = ['UsageRestriction']
01500 else:
01501 property_list = merge_list(property_list, ['UsageRestriction'])
01502 all_cim_syss_path = [cim_sys_path]
01503 if smis_cap.multi_sys_is_supported(self._c):
01504 all_cim_syss_path.extend(
01505 self._leaf_cim_syss_path_of(cim_sys_path))
01506 for cur_cim_sys_path in all_cim_syss_path:
01507 cur_cim_fc_tgts = self._c.Associators(
01508 cur_cim_sys_path,
01509 AssocClass='CIM_SystemDevice',
01510 ResultClass='CIM_FCPort',
01511 PropertyList=property_list)
01512 for cim_fc_tgt in cur_cim_fc_tgts:
01513 if Smis._is_frontend_fc_tgt(cim_fc_tgt):
01514 rc.extend([cim_fc_tgt])
01515 return rc
01516
01517 @staticmethod
01518 def _cim_fc_tgt_to_lsm(cim_fc_tgt, system_id):
01519 """
01520 Convert CIM_FCPort to Lsm.TargetPort
01521 """
01522 port_id = md5(cim_fc_tgt['DeviceID'])
01523 port_type = _lsm_tgt_port_type_of_cim_fc_tgt(cim_fc_tgt)
01524
01525
01526 wwpn = hex_string_format(cim_fc_tgt['PermanentAddress'], 16, 2)
01527 port_name = cim_fc_tgt['ElementName']
01528 plugin_data = None
01529 return TargetPort(port_id, port_type, wwpn, wwpn, wwpn, port_name,
01530 system_id, plugin_data)
01531
01532 def _iscsi_node_names_of(self, cim_iscsi_pg_path):
01533 """
01534 CIM_iSCSIProtocolEndpoint
01535 |
01536 |
01537 v
01538 CIM_SAPAvailableForElement
01539 |
01540 |
01541 v
01542 CIM_SCSIProtocolController # iSCSI Node
01543 """
01544 cim_spcs = self._c.Associators(
01545 cim_iscsi_pg_path,
01546 ResultClass='CIM_SCSIProtocolController',
01547 AssocClass='CIM_SAPAvailableForElement',
01548 PropertyList=['Name', 'NameFormat'])
01549 cim_iscsi_nodes = []
01550 for cim_spc in cim_spcs:
01551 if cim_spc.classname == 'Clar_MappingSCSIProtocolController':
01552
01553
01554 continue
01555 if cim_spc['NameFormat'] == dmtf.SPC_NAME_FORMAT_ISCSI:
01556 cim_iscsi_nodes.extend([cim_spc])
01557
01558 if len(cim_iscsi_nodes) == 0:
01559 return []
01560 return [n['Name'] for n in cim_iscsi_nodes]
01561
01562 def _cim_iscsi_pg_of(self, cim_sys_path, property_list=None):
01563 """
01564 Get all CIM_iSCSIProtocolEndpoint(Target only) from CIM_ComputerSystem
01565 and its leaf CIM_ComputerSystem
01566 """
01567 rc = []
01568 if property_list is None:
01569 property_list = ['Role']
01570 else:
01571 property_list = merge_list(property_list, ['Role'])
01572 all_cim_syss_path = [cim_sys_path]
01573 if smis_cap.multi_sys_is_supported(self._c):
01574 all_cim_syss_path.extend(
01575 self._leaf_cim_syss_path_of(cim_sys_path))
01576 for cur_cim_sys_path in all_cim_syss_path:
01577 cur_cim_iscsi_pgs = self._c.Associators(
01578 cur_cim_sys_path,
01579 AssocClass='CIM_HostedAccessPoint',
01580 ResultClass='CIM_iSCSIProtocolEndpoint',
01581 PropertyList=property_list)
01582 for cim_iscsi_pg in cur_cim_iscsi_pgs:
01583 if cim_iscsi_pg['Role'] == dmtf.ISCSI_TGT_ROLE_TARGET:
01584 rc.extend([cim_iscsi_pg])
01585 return rc
01586
01587 def _cim_iscsi_pg_to_lsm(self, cim_iscsi_pg, system_id):
01588 """
01589 Return a list of TargetPort CIM_iSCSIProtocolEndpoint
01590 Associations:
01591 CIM_SCSIProtocolController # iSCSI Node
01592 ^
01593 | CIM_SAPAvailableForElement
01594 |
01595 CIM_iSCSIProtocolEndpoint # iSCSI Portal Group
01596 |
01597 | CIM_BindsTo
01598 v
01599 CIM_TCPProtocolEndpoint # Need TCP port, default is 3260
01600 |
01601 | CIM_BindsTo
01602 v
01603 CIM_IPProtocolEndpoint # Need IPv4 and IPv6 address
01604 |
01605 | CIM_DeviceSAPImplementation
01606 v
01607 CIM_EthernetPort # Need MAC address (Optional)
01608 Assuming there is storage array support iSER
01609 (iSCSI over RDMA of Infinity Band),
01610 this method is only for iSCSI over TCP.
01611 """
01612 rc = []
01613 port_type = TargetPort.TYPE_ISCSI
01614 plugin_data = None
01615 cim_tcps = self._c.Associators(
01616 cim_iscsi_pg.path,
01617 ResultClass='CIM_TCPProtocolEndpoint',
01618 AssocClass='CIM_BindsTo',
01619 PropertyList=['PortNumber'])
01620 if len(cim_tcps) == 0:
01621 raise LsmError(ErrorNumber.PLUGIN_BUG,
01622 "_cim_iscsi_pg_to_lsm(): "
01623 "No CIM_TCPProtocolEndpoint associated to %s"
01624 % cim_iscsi_pg.path)
01625 iscsi_node_names = self._iscsi_node_names_of(cim_iscsi_pg.path)
01626
01627 if len(iscsi_node_names) == 0:
01628 return []
01629
01630 for cim_tcp in cim_tcps:
01631 tcp_port = cim_tcp['PortNumber']
01632 cim_ips = self._c.Associators(
01633 cim_tcp.path,
01634 ResultClass='CIM_IPProtocolEndpoint',
01635 AssocClass='CIM_BindsTo',
01636 PropertyList=['IPv4Address', 'IPv6Address', 'SystemName',
01637 'EMCPortNumber', 'IPv6AddressType'])
01638 for cim_ip in cim_ips:
01639 ipv4_addr = ''
01640 ipv6_addr = ''
01641
01642 if 'IPv4Address' in cim_ip and cim_ip['IPv4Address']:
01643 ipv4_addr = cim_ip['IPv4Address']
01644 if 'IPv6Address' in cim_ip and cim_ip['IPv6Address']:
01645 ipv6_addr = cim_ip['IPv6Address']
01646
01647
01648
01649
01650 if 'IPv6AddressType' in cim_ip and cim_ip['IPv6AddressType']:
01651 ipv6_addr_type = cim_ip['IPv6AddressType']
01652 if ipv6_addr_type != dmtf.IPV6_ADDR_TYPE_GUA and \
01653 ipv6_addr_type != dmtf.IPV6_ADDR_TYPE_6TO4 and \
01654 ipv6_addr_type != dmtf.IPV6_ADDR_TYPE_ULA:
01655 ipv6_addr = ''
01656
01657
01658
01659
01660
01661
01662 if ipv6_addr[0:29] == '0000:0000:0000:0000:0000:0000':
01663 ipv6_addr = ''
01664
01665 if ipv4_addr is None and ipv6_addr is None:
01666 continue
01667 cim_eths = self._c.Associators(
01668 cim_ip.path,
01669 ResultClass='CIM_EthernetPort',
01670 AssocClass='CIM_DeviceSAPImplementation',
01671 PropertyList=['PermanentAddress', 'ElementName'])
01672 nics = []
01673
01674
01675
01676
01677 if len(cim_eths) == 0:
01678 nics = [('', '')]
01679 else:
01680 for cim_eth in cim_eths:
01681 mac_addr = ''
01682 port_name = ''
01683 if 'PermanentAddress' in cim_eth and \
01684 cim_eth["PermanentAddress"]:
01685 mac_addr = cim_eth["PermanentAddress"]
01686
01687 if 'ElementName' in cim_eth and cim_eth["ElementName"]:
01688 port_name = cim_eth['ElementName']
01689 nics.extend([(mac_addr, port_name)])
01690 for nic in nics:
01691 mac_address = nic[0]
01692 port_name = nic[1]
01693 if mac_address:
01694
01695 mac_address = hex_string_format(mac_address, 12, 2)
01696
01697 if ipv4_addr:
01698 network_address = "%s:%s" % (ipv4_addr, tcp_port)
01699
01700 rc.extend(
01701 [TargetPort(
01702 md5(
01703 "%s:%s:%s" % (
01704 mac_address, network_address,
01705 iscsi_node_name)),
01706 port_type, iscsi_node_name,
01707 network_address, mac_address, port_name,
01708 system_id, plugin_data)
01709 for iscsi_node_name in iscsi_node_names])
01710 if ipv6_addr:
01711
01712
01713 if len(ipv6_addr) == 39:
01714 ipv6_addr = ipv6_addr.replace(':', '')
01715 if len(ipv6_addr) == 32:
01716 ipv6_addr = hex_string_format(
01717 ipv6_addr, 32, 4)
01718
01719 network_address = "[%s]:%s" % (ipv6_addr, tcp_port)
01720 rc.extend([
01721 TargetPort(
01722 md5(
01723 "%s:%s:%s" % (
01724 mac_address, network_address,
01725 iscsi_node_name)),
01726 port_type, iscsi_node_name,
01727 network_address, mac_address, port_name,
01728 system_id, plugin_data)
01729 for iscsi_node_name in iscsi_node_names])
01730 return rc
01731
01732 def _leaf_cim_syss_path_of(self, cim_sys_path):
01733 """
01734 Return a list of CIMInstanceName of leaf CIM_ComputerSystem
01735 """
01736 max_loop_count = 10
01737
01738 loop_counter = max_loop_count
01739 rc = []
01740 leaf_cim_syss_path = []
01741 try:
01742 leaf_cim_syss_path = self._c.AssociatorNames(
01743 cim_sys_path,
01744 ResultClass='CIM_ComputerSystem',
01745 AssocClass='CIM_ComponentCS',
01746 Role='GroupComponent',
01747 ResultRole='PartComponent')
01748 except CIMError as ce:
01749 error_code = tuple(ce)[0]
01750 if error_code == pywbem.CIM_ERR_INVALID_CLASS or \
01751 error_code == pywbem.CIM_ERR_NOT_SUPPORTED:
01752 return []
01753
01754 if len(leaf_cim_syss_path) > 0:
01755 rc = leaf_cim_syss_path
01756 for cim_sys_path in leaf_cim_syss_path:
01757 rc.extend(self._leaf_cim_syss_path_of(cim_sys_path))
01758
01759 return rc
01760
01761 @handle_cim_errors
01762 def target_ports(self, search_key=None, search_value=None, flags=0):
01763 rc = []
01764
01765 cim_fc_tgt_pros = ['UsageRestriction', 'ElementName', 'SystemName',
01766 'PermanentAddress', 'PortDiscriminator',
01767 'LinkTechnology', 'DeviceID']
01768
01769 cim_syss = smis_sys.root_cim_sys(
01770 self._c, property_list=smis_sys.cim_sys_id_pros())
01771 for cim_sys in cim_syss:
01772 system_id = smis_sys.sys_id_of_cim_sys(cim_sys)
01773 flag_fc_support = smis_cap.fc_tgt_is_supported(self._c)
01774 flag_iscsi_support = smis_cap.iscsi_tgt_is_supported(self._c)
01775
01776
01777
01778
01779 if flag_fc_support is False and flag_iscsi_support is False:
01780 raise LsmError(ErrorNumber.NO_SUPPORT,
01781 "Target SMI-S provider does not support any of"
01782 "these profiles: '%s %s', '%s %s'"
01783 % (SmisCommon.SMIS_SPEC_VER_1_4,
01784 SmisCommon.SNIA_FC_TGT_PORT_PROFILE,
01785 SmisCommon.SMIS_SPEC_VER_1_1,
01786 SmisCommon.SNIA_ISCSI_TGT_PORT_PROFILE))
01787
01788 if flag_fc_support:
01789
01790
01791
01792 cim_fc_tgt_pros = ['UsageRestriction', 'ElementName',
01793 'SystemName', 'PermanentAddress',
01794 'PortDiscriminator', 'LinkTechnology',
01795 'DeviceID']
01796 cim_fc_tgts = self._cim_fc_tgt_of(cim_sys.path,
01797 cim_fc_tgt_pros)
01798 rc.extend(
01799 list(
01800 Smis._cim_fc_tgt_to_lsm(x, system_id)
01801 for x in cim_fc_tgts))
01802
01803 if flag_iscsi_support:
01804 cim_iscsi_pgs = self._cim_iscsi_pg_of(cim_sys.path)
01805 for cim_iscsi_pg in cim_iscsi_pgs:
01806 rc.extend(
01807 self._cim_iscsi_pg_to_lsm(cim_iscsi_pg, system_id))
01808
01809
01810
01811
01812 if len(cim_syss) >= 1 and \
01813 cim_syss[0].classname == 'ONTAP_StorageSystem':
01814 id_list = []
01815 new_rc = []
01816
01817 for lsm_tp in rc:
01818 if lsm_tp.id not in id_list:
01819 id_list.extend([lsm_tp.id])
01820 new_rc.extend([lsm_tp])
01821 rc = new_rc
01822
01823 return search_property(rc, search_key, search_value)
01824
01825 def _cim_pep_path_of_fc_tgt(self, cim_fc_tgt_path):
01826 """
01827 Return CIMInstanceName of CIM_SCSIProtocolEndpoint of CIM_FCPort
01828 In 1.4r6, it's one-to-one map.
01829 """
01830 return self._c.AssociatorNames(
01831 cim_fc_tgt_path,
01832 AssocClass='CIM_DeviceSAPImplementation',
01833 ResultClass='CIM_SCSIProtocolEndpoint')[0]
01834
01835 def _check_exist_cim_tgt_mg(self, name):
01836 """
01837 We should do more checks[1] in stead of use it directly.
01838 But considering EMC VMAX is the only support vendor, make it quick
01839 and works could be priority 1.
01840 We can improve this for any bug report.
01841
01842 [1] At least check whether CIM_TargetMaskingGroup is already used
01843 by other SPC.
01844 """
01845 cim_tgt_mgs = self._c.EnumerateInstances(
01846 'CIM_TargetMaskingGroup',
01847 PropertyList=['ElementName'])
01848 for cim_tgt_mg in cim_tgt_mgs:
01849 if cim_tgt_mg['ElementName'] == name:
01850 return cim_tgt_mg.path
01851
01852 return None
01853
01854 def _check_exist_cim_dev_mg(self, name, cim_gmms_path, cim_vol_path,
01855 vol_id):
01856 """
01857 This is buggy check, but it works on EMC VMAX which is only supported
01858 platform of Group Masking and Mapping.
01859 When found CIM_DeviceMaskingGroup, make sure cim_vol is included.
01860 """
01861 cim_dev_mgs = self._c.EnumerateInstances(
01862 'CIM_DeviceMaskingGroup',
01863 PropertyList=['ElementName'])
01864 cim_dev_mg = None
01865 for tmp_cim_dev_mg in cim_dev_mgs:
01866 if tmp_cim_dev_mg['ElementName'] == name:
01867 cim_dev_mg = tmp_cim_dev_mg
01868 break
01869 if cim_dev_mg:
01870
01871 cim_vol_pros = smis_vol.cim_vol_id_pros()
01872 cim_vols = self._c.Associators(
01873 cim_dev_mg.path,
01874 AssocClass='CIM_OrderedMemberOfCollection',
01875 ResultClass='CIM_StorageVolume',
01876 PropertyList=cim_vol_pros)
01877 for cim_vol in cim_vols:
01878 if smis_vol.vol_id_of_cim_vol(cim_vol) == vol_id:
01879 return cim_dev_mg.path
01880
01881
01882 in_params = {
01883 'MaskingGroup': cim_dev_mg.path,
01884 'Members': [cim_vol_path],
01885 }
01886 self._c.invoke_method_wait('AddMembers', cim_gmms_path, in_params)
01887 return cim_dev_mg.path
01888
01889 return None
01890
01891 @handle_cim_errors
01892 def access_group_create(self, name, init_id, init_type, system,
01893 flags=0):
01894 """
01895 Using 1.5.0 'Group Masking and Mapping' profile.
01896 Actually, only EMC VMAX/DMX support this now(July 2014).
01897 Steps:
01898 0. Check exist SPC of init_id for duplication call and
01899 conflict.
01900 1. Create CIM_InitiatorMaskingGroup
01901 """
01902 org_init_id = init_id
01903 init_id = smis_ag.lsm_init_id_to_snia(init_id)
01904
01905 self._c.profile_check(SmisCommon.SNIA_GROUP_MASK_PROFILE,
01906 SmisCommon.SMIS_SPEC_VER_1_5,
01907 raise_error=True)
01908
01909 if init_type != AccessGroup.INIT_TYPE_WWPN and \
01910 init_type != AccessGroup.INIT_TYPE_ISCSI_IQN:
01911 raise LsmError(ErrorNumber.NO_SUPPORT,
01912 "SMI-S plugin only support creating FC/FCoE WWPN "
01913 "and iSCSI AccessGroup")
01914
01915 cim_sys = smis_sys.cim_sys_of_sys_id(self._c, system.id)
01916 if cim_sys.path.classname == 'Clar_StorageSystem':
01917
01918
01919 raise LsmError(ErrorNumber.NO_SUPPORT,
01920 "access_group_create() is not supported by "
01921 "EMC VNX/CX which lacks the support of SNIA 1.5+ "
01922 "Group Masking and Mapping profile")
01923
01924 flag_fc_support = smis_cap.fc_tgt_is_supported(self._c)
01925 flag_iscsi_support = smis_cap.iscsi_tgt_is_supported(self._c)
01926
01927 if init_type == AccessGroup.INIT_TYPE_WWPN and not flag_fc_support:
01928 raise LsmError(ErrorNumber.NO_SUPPORT,
01929 "Target SMI-S provider does not support "
01930 "FC target port, which not allow creating "
01931 "WWPN access group")
01932
01933 if init_type == AccessGroup.INIT_TYPE_ISCSI_IQN and \
01934 not flag_iscsi_support:
01935 raise LsmError(ErrorNumber.NO_SUPPORT,
01936 "Target SMI-S provider does not support "
01937 "iSCSI target port, which not allow creating "
01938 "iSCSI IQN access group")
01939
01940 cim_init_path = smis_ag.cim_init_path_check_or_create(
01941 self._c, system.id, init_id, init_type)
01942
01943
01944 cim_gmms = self._c.cim_gmms_of_sys_id(system.id)
01945
01946 in_params = {'GroupName': name,
01947 'Members': [cim_init_path],
01948 'Type': dmtf.MASK_GROUP_TYPE_INIT}
01949
01950 cim_init_mg_pros = smis_ag.cim_init_mg_pros()
01951
01952 try:
01953 cim_init_mg_path = self._c.invoke_method_wait(
01954 'CreateGroup', cim_gmms.path, in_params,
01955 out_key='MaskingGroup',
01956 expect_class='CIM_InitiatorMaskingGroup')
01957 except (LsmError, CIMError):
01958
01959
01960 exist_cim_init_mg_paths = self._c.AssociatorNames(
01961 cim_init_path,
01962 AssocClass='CIM_MemberOfCollection',
01963 ResultClass='CIM_InitiatorMaskingGroup')
01964
01965 if len(exist_cim_init_mg_paths) != 0:
01966 raise LsmError(ErrorNumber.EXISTS_INITIATOR,
01967 "Initiator %s " % org_init_id +
01968 "already exist in other access group")
01969
01970
01971 exist_cim_init_mgs = self._cim_init_mg_of(
01972 system.id, property_list=['ElementName'])
01973 for exist_cim_init_mg in exist_cim_init_mgs:
01974 if exist_cim_init_mg['ElementName'] == name:
01975 raise LsmError(ErrorNumber.NAME_CONFLICT,
01976 "Requested name %s is used by " % name +
01977 "another access group")
01978 raise
01979
01980 cim_init_mg = self._c.GetInstance(
01981 cim_init_mg_path, PropertyList=cim_init_mg_pros)
01982 return smis_ag.cim_init_mg_to_lsm_ag(self._c, cim_init_mg, system.id)
01983
01984 @handle_cim_errors
01985 def access_group_delete(self, access_group, flags=0):
01986 self._c.profile_check(
01987 SmisCommon.SNIA_GROUP_MASK_PROFILE, SmisCommon.SMIS_SPEC_VER_1_5,
01988 raise_error=True)
01989
01990 cim_init_mg_path = smis_ag.lsm_ag_to_cim_init_mg_path(
01991 self._c, access_group)
01992
01993
01994 cim_spcs_path = self._c.AssociatorNames(
01995 cim_init_mg_path,
01996 AssocClass='CIM_AssociatedInitiatorMaskingGroup',
01997 ResultClass='CIM_SCSIProtocolController')
01998
01999 for cim_spc_path in cim_spcs_path:
02000 if len(self._c.AssociatorNames(
02001 cim_spc_path,
02002 AssocClass='CIM_ProtocolControllerForUnit',
02003 ResultClass='CIM_StorageVolume')) >= 1:
02004 raise LsmError(ErrorNumber.IS_MASKED,
02005 "Access Group %s has volume masked" %
02006 access_group.id)
02007
02008 cim_gmms = self._c.cim_gmms_of_sys_id(access_group.system_id)
02009
02010 in_params = {
02011 'MaskingGroup': cim_init_mg_path,
02012 'Force': True,
02013 }
02014
02015 self._c.invoke_method_wait('DeleteGroup', cim_gmms.path, in_params)
02016 return None