1# Copyright (c) 2015 FUJITSU LIMITED 2# Copyright (c) 2012 EMC Corporation, Inc. 3# All Rights Reserved. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may 6# not use this file except in compliance with the License. You may obtain 7# a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations 15# under the License. 16 17import mock 18import six 19import tempfile 20 21from oslo_utils import units 22 23from cinder import exception 24from cinder import test 25from cinder.volume import configuration as conf 26 27with mock.patch.dict('sys.modules', pywbem=mock.Mock()): 28 from cinder.volume.drivers.fujitsu import eternus_dx_common as dx_common 29 from cinder.volume.drivers.fujitsu import eternus_dx_fc as dx_fc 30 from cinder.volume.drivers.fujitsu import eternus_dx_iscsi as dx_iscsi 31 32CONFIG_FILE_NAME = 'cinder_fujitsu_eternus_dx.xml' 33STORAGE_SYSTEM = '172.16.0.2' 34 35CONF = """<?xml version='1.0' encoding='UTF-8'?> 36<FUJITSU> 37<EternusIP>172.16.0.2</EternusIP> 38<EternusPort>5988</EternusPort> 39<EternusUser>testuser</EternusUser> 40<EternusPassword>testpass</EternusPassword> 41<EternusISCSIIP>10.0.0.3</EternusISCSIIP> 42<EternusPool>abcd1234_TPP</EternusPool> 43<EternusSnapPool>abcd1234_OSVD</EternusSnapPool> 44</FUJITSU>""" 45 46TEST_VOLUME = { 47 'id': '3d6eeb5d-109b-4435-b891-d01415178490', 48 'name': 'volume1', 49 'display_name': 'volume1', 50 'provider_location': None, 51 'volume_metadata': [], 52 'size': 1, 53} 54 55TEST_SNAP = { 56 'id': 'f47a8da3-d9e2-46aa-831f-0ef04158d5a1', 57 'volume_name': 'volume-3d6eeb5d-109b-4435-b891-d01415178490', 58 'name': 'snap1', 59 'display_name': 'test_snapshot', 60 'volume': TEST_VOLUME, 61 'volume_id': '3d6eeb5d-109b-4435-b891-d01415178490', 62} 63 64TEST_CLONE = { 65 'name': 'clone1', 66 'size': 1, 67 'volume_name': 'vol1', 68 'id': '391fb914-8a55-4384-a747-588641db3b15', 69 'project_id': 'project', 70 'display_name': 'clone1', 71 'display_description': 'volume created from snapshot', 72 'volume_metadata': [], 73} 74 75ISCSI_INITIATOR = 'iqn.1993-08.org.debian:01:8261afe17e4c' 76ISCSI_TARGET_IP = '10.0.0.3' 77ISCSI_TARGET_IQN = 'iqn.2000-09.com.fujitsu:storage-system.eternus-dxl:0' 78FC_TARGET_WWN = ['500000E0DA000001', '500000E0DA000002'] 79TEST_WWPN = ['0123456789111111', '0123456789222222'] 80TEST_CONNECTOR = {'initiator': ISCSI_INITIATOR, 'wwpns': TEST_WWPN} 81 82 83STOR_CONF_SVC = 'FUJITSU_StorageConfigurationService' 84CTRL_CONF_SVC = 'FUJITSU_ControllerConfigurationService' 85REPL_SVC = 'FUJITSU_ReplicationService' 86STOR_VOL = 'FUJITSU_StorageVolume' 87SCSI_PROT_CTR = 'FUJITSU_AffinityGroupController' 88STOR_HWID = 'FUJITSU_StorageHardwareID' 89STOR_HWID_MNG_SVC = 'FUJITSU_StorageHardwareIDManagementService' 90STOR_POOL = 'FUJITSU_RAIDStoragePool' 91STOR_POOLS = ['FUJITSU_ThinProvisioningPool', 'FUJITSU_RAIDStoragePool'] 92AUTH_PRIV = 'FUJITSU_AuthorizedPrivilege' 93STOR_SYNC = 'FUJITSU_StorageSynchronized' 94PROT_CTRL_UNIT = 'CIM_ProtocolControllerForUnit' 95STORAGE_TYPE = 'abcd1234_TPP' 96LUNMASKCTRL_IDS = ['AFG0010_CM00CA00P00', 'AFG0011_CM01CA00P00'] 97 98MAP_STAT = '0' 99VOL_STAT = '0' 100 101FAKE_CAPACITY = 1170368102400 102FAKE_LUN_ID1 = '600000E00D2A0000002A011500140000' 103FAKE_LUN_NO1 = '0x0014' 104FAKE_LUN_ID2 = '600000E00D2A0000002A0115001E0000' 105FAKE_LUN_NO2 = '0x001E' 106FAKE_SYSTEM_NAME = 'ET603SA4621302115' 107 108FAKE_STATS = { 109 'vendor_name': 'FUJITSU', 110 'total_capacity_gb': FAKE_CAPACITY / units.Gi, 111 'free_capacity_gb': FAKE_CAPACITY / units.Gi, 112} 113 114FAKE_KEYBIND1 = { 115 'CreationClassName': 'FUJITSU_StorageVolume', 116 'SystemName': STORAGE_SYSTEM, 117 'DeviceID': FAKE_LUN_ID1, 118 'SystemCreationClassName': 'FUJITSU_StorageComputerSystem', 119} 120 121FAKE_LOCATION1 = { 122 'classname': 'FUJITSU_StorageVolume', 123 'keybindings': FAKE_KEYBIND1, 124} 125 126FAKE_LUN_META1 = { 127 'FJ_Pool_Type': 'Thinporvisioning_POOL', 128 'FJ_Volume_No': FAKE_LUN_NO1, 129 'FJ_Volume_Name': u'FJosv_0qJ4rpOHgFE8ipcJOMfBmg==', 130 'FJ_Pool_Name': STORAGE_TYPE, 131 'FJ_Backend': FAKE_SYSTEM_NAME, 132} 133 134FAKE_MODEL_INFO1 = { 135 'provider_location': six.text_type(FAKE_LOCATION1), 136 'metadata': FAKE_LUN_META1, 137} 138 139FAKE_KEYBIND2 = { 140 'CreationClassName': 'FUJITSU_StorageVolume', 141 'SystemName': STORAGE_SYSTEM, 142 'DeviceID': FAKE_LUN_ID2, 143 'SystemCreationClassName': 'FUJITSU_StorageComputerSystem', 144} 145 146FAKE_LOCATION2 = { 147 'classname': 'FUJITSU_StorageVolume', 148 'keybindings': FAKE_KEYBIND2, 149} 150 151FAKE_SNAP_INFO = {'provider_location': six.text_type(FAKE_LOCATION2)} 152 153FAKE_LUN_META2 = { 154 'FJ_Pool_Type': 'Thinporvisioning_POOL', 155 'FJ_Volume_No': FAKE_LUN_NO1, 156 'FJ_Volume_Name': u'FJosv_UkCZqMFZW3SU_JzxjHiKfg==', 157 'FJ_Pool_Name': STORAGE_TYPE, 158 'FJ_Backend': FAKE_SYSTEM_NAME, 159} 160 161FAKE_MODEL_INFO2 = { 162 'provider_location': six.text_type(FAKE_LOCATION1), 163 'metadata': FAKE_LUN_META2, 164} 165 166 167class FJ_StorageVolume(dict): 168 pass 169 170 171class FJ_StoragePool(dict): 172 pass 173 174 175class FJ_AffinityGroupController(dict): 176 pass 177 178 179class FakeCIMInstanceName(dict): 180 181 def fake_create_eternus_instance_name(self, classname, bindings): 182 instancename = FakeCIMInstanceName() 183 for key in bindings: 184 instancename[key] = bindings[key] 185 instancename.classname = classname 186 instancename.namespace = 'root/eternus' 187 return instancename 188 189 190class FakeEternusConnection(object): 191 def InvokeMethod(self, MethodName, Service, ElementName=None, InPool=None, 192 ElementType=None, TheElement=None, LUNames=None, 193 Size=None, Type=None, Mode=None, Locality=None, 194 InitiatorPortIDs=None, TargetPortIDs=None, 195 DeviceAccesses=None, SyncType=None, 196 SourceElement=None, TargetElement=None, 197 Operation=None, CopyType=None, 198 Synchronization=None, ProtocolControllers=None, 199 TargetPool=None): 200 global MAP_STAT, VOL_STAT 201 if MethodName == 'CreateOrModifyElementFromStoragePool': 202 VOL_STAT = '1' 203 rc = 0 204 vol = self._enum_volumes() 205 job = {'TheElement': vol[0].path} 206 elif MethodName == 'ReturnToStoragePool': 207 VOL_STAT = '0' 208 rc = 0 209 job = {} 210 elif MethodName == 'GetReplicationRelationships': 211 rc = 0 212 job = {'Synchronizations': []} 213 elif MethodName == 'ExposePaths': 214 MAP_STAT = '1' 215 rc = 0 216 job = {} 217 elif MethodName == 'HidePaths': 218 MAP_STAT = '0' 219 rc = 0 220 job = {} 221 elif MethodName == 'CreateElementReplica': 222 rc = 0 223 snap = self._enum_snapshots() 224 job = {'TargetElement': snap[0].path} 225 elif MethodName == 'CreateReplica': 226 rc = 0 227 snap = self._enum_snapshots() 228 job = {'TargetElement': snap[0].path} 229 elif MethodName == 'ModifyReplicaSynchronization': 230 rc = 0 231 job = {} 232 else: 233 raise exception.VolumeBackendAPIException(data="invoke method") 234 235 return (rc, job) 236 237 def EnumerateInstanceNames(self, name): 238 result = [] 239 if name == 'FUJITSU_StorageVolume': 240 result = self._enum_volumes() 241 elif name == 'FUJITSU_StorageConfigurationService': 242 result = self._enum_confservice() 243 elif name == 'FUJITSU_ReplicationService': 244 result = self._enum_repservice() 245 elif name == 'FUJITSU_ControllerConfigurationService': 246 result = self._enum_ctrlservice() 247 elif name == 'FUJITSU_AffinityGroupController': 248 result = self._enum_afntyservice() 249 elif name == 'FUJITSU_StorageHardwareIDManagementService': 250 result = self._enum_sthwidmngsvc() 251 elif name == 'CIM_ProtocolControllerForUnit': 252 result = self._ref_unitnames() 253 elif name == 'CIM_StoragePool': 254 result = self._enum_pools() 255 elif name == 'FUJITSU_SCSIProtocolEndpoint': 256 result = self._enum_scsiport_endpoint() 257 elif name == 'FUJITSU_IPProtocolEndpoint': 258 result = self._enum_ipproto_endpoint() 259 260 return result 261 262 def EnumerateInstances(self, name): 263 result = None 264 if name == 'FUJITSU_StorageProduct': 265 result = self._enum_sysnames() 266 elif name == 'FUJITSU_RAIDStoragePool': 267 result = self._enum_pool_details('RAID') 268 elif name == 'FUJITSU_ThinProvisioningPool': 269 result = self._enum_pool_details('TPP') 270 elif name == 'FUJITSU_SCSIProtocolEndpoint': 271 result = self._enum_scsiport_endpoint() 272 elif name == 'FUJITSU_iSCSIProtocolEndpoint': 273 result = self._enum_iscsiprot_endpoint() 274 elif name == 'FUJITSU_StorageHardwareID': 275 result = self._enum_sthwid() 276 elif name == 'CIM_SCSIProtocolEndpoint': 277 result = self._enum_scsiport_endpoint() 278 elif name == 'FUJITSU_StorageHardwareID': 279 result = None 280 else: 281 result = None 282 283 return result 284 285 def GetInstance(self, objectpath, LocalOnly=False): 286 try: 287 name = objectpath['CreationClassName'] 288 except KeyError: 289 name = objectpath.classname 290 291 result = None 292 293 if name == 'FUJITSU_StorageVolume': 294 result = self._getinstance_storagevolume(objectpath) 295 elif name == 'FUJITSU_IPProtocolEndpoint': 296 result = self._getinstance_ipprotocolendpoint(objectpath) 297 elif name == 'CIM_ProtocolControllerForUnit': 298 result = self._getinstance_unit(objectpath) 299 elif name == 'FUJITSU_AffinityGroupController': 300 result = self._getinstance_unit(objectpath) 301 302 return result 303 304 def Associators(self, objectpath, AssocClass=None, 305 ResultClass='FUJITSU_StorageHardwareID'): 306 result = None 307 if ResultClass == 'FUJITSU_StorageHardwareID': 308 result = self._assoc_hdwid() 309 elif ResultClass == 'FUJITSU_iSCSIProtocolEndpoint': 310 result = self._assoc_endpoint(objectpath) 311 elif ResultClass == 'FUJITSU_StorageVolume': 312 result = self._assoc_storagevolume(objectpath) 313 elif ResultClass == 'FUJITSU_AuthorizedPrivilege': 314 result = self._assoc_authpriv() 315 else: 316 result = self._default_assoc(objectpath) 317 318 return result 319 320 def AssociatorNames(self, objectpath, AssocClass=None, 321 ResultClass=SCSI_PROT_CTR): 322 result = None 323 if ResultClass == SCSI_PROT_CTR: 324 result = self._assocnames_lunmaskctrl() 325 elif ResultClass == 'FUJITSU_TCPProtocolEndpoint': 326 result = self._assocnames_tcp_endpoint() 327 elif ResultClass == 'FUJITSU_AffinityGroupController': 328 result = self._assocnames_afngroup() 329 else: 330 result = self._default_assocnames(objectpath) 331 332 return result 333 334 def ReferenceNames(self, objectpath, 335 ResultClass='CIM_ProtocolControllerForUnit'): 336 result = [] 337 if ResultClass == 'CIM_ProtocolControllerForUnit': 338 if MAP_STAT == '1': 339 result = self._ref_unitnames() 340 else: 341 result = [] 342 elif ResultClass == 'FUJITSU_StorageSynchronized': 343 result = self._ref_storage_sync() 344 else: 345 result = self._default_ref(objectpath) 346 347 return result 348 349 def _ref_unitnames(self): 350 unitnames = [] 351 352 unitname = FJ_AffinityGroupController() 353 dependent = {} 354 dependent['CreationClassName'] = STOR_VOL 355 dependent['DeviceID'] = FAKE_LUN_ID1 356 dependent['SystemName'] = STORAGE_SYSTEM 357 358 antecedent = {} 359 antecedent['CreationClassName'] = SCSI_PROT_CTR 360 antecedent['DeviceID'] = LUNMASKCTRL_IDS[0] 361 antecedent['SystemName'] = STORAGE_SYSTEM 362 363 unitname['Dependent'] = dependent 364 unitname['Antecedent'] = antecedent 365 unitname['CreationClassName'] = PROT_CTRL_UNIT 366 unitname.path = unitname 367 unitnames.append(unitname) 368 369 unitname2 = FJ_AffinityGroupController() 370 dependent2 = {} 371 dependent2['CreationClassName'] = STOR_VOL 372 dependent2['DeviceID'] = FAKE_LUN_ID1 373 dependent2['SystemName'] = STORAGE_SYSTEM 374 375 antecedent2 = {} 376 antecedent2['CreationClassName'] = SCSI_PROT_CTR 377 antecedent2['DeviceID'] = LUNMASKCTRL_IDS[1] 378 antecedent2['SystemName'] = STORAGE_SYSTEM 379 380 unitname2['Dependent'] = dependent2 381 unitname2['Antecedent'] = antecedent2 382 unitname2['CreationClassName'] = PROT_CTRL_UNIT 383 unitname2.path = unitname2 384 unitnames.append(unitname2) 385 386 return unitnames 387 388 def _ref_storage_sync(self): 389 syncnames = [] 390 return syncnames 391 392 def _default_ref(self, objectpath): 393 return objectpath 394 395 def _default_assoc(self, objectpath): 396 return objectpath 397 398 def _assocnames_lunmaskctrl(self): 399 return self._enum_lunmaskctrls() 400 401 def _assocnames_tcp_endpoint(self): 402 return self._enum_tcp_endpoint() 403 404 def _assocnames_afngroup(self): 405 return self._enum_afntyservice() 406 407 def _default_assocnames(self, objectpath): 408 return objectpath 409 410 def _assoc_authpriv(self): 411 authprivs = [] 412 iscsi = {} 413 iscsi['InstanceID'] = ISCSI_INITIATOR 414 authprivs.append(iscsi) 415 416 fc = {} 417 fc['InstanceID'] = TEST_WWPN[0] 418 authprivs.append(fc) 419 420 fc1 = {} 421 fc1['InstanceID'] = TEST_WWPN[1] 422 authprivs.append(fc1) 423 424 return authprivs 425 426 def _assoc_endpoint(self, objectpath): 427 targetlist = [] 428 tgtport1 = {} 429 tgtport1['CreationClassName'] = 'FUJITSU_IPProtocolEndpoint' 430 tgtport1['Name'] = ('iqn.2000-09.com.fujitsu:storage-system.' 431 'eternus-dxl:0123456789,t,0x0009') 432 targetlist.append(tgtport1) 433 434 return targetlist 435 436 def _getinstance_unit(self, objectpath): 437 unit = FJ_AffinityGroupController() 438 unit.path = None 439 440 if MAP_STAT == '0': 441 return unit 442 dependent = {} 443 dependent['CreationClassName'] = STOR_VOL 444 dependent['DeviceID'] = FAKE_LUN_ID1 445 dependent['ElementName'] = TEST_VOLUME['name'] 446 dependent['SystemName'] = STORAGE_SYSTEM 447 448 antecedent = {} 449 antecedent['CreationClassName'] = SCSI_PROT_CTR 450 antecedent['DeviceID'] = LUNMASKCTRL_IDS[0] 451 antecedent['SystemName'] = STORAGE_SYSTEM 452 453 unit['Dependent'] = dependent 454 unit['Antecedent'] = antecedent 455 unit['CreationClassName'] = PROT_CTRL_UNIT 456 unit['DeviceNumber'] = '0' 457 unit.path = unit 458 459 return unit 460 461 def _enum_sysnames(self): 462 sysnamelist = [] 463 sysname = {} 464 sysname['IdentifyingNumber'] = FAKE_SYSTEM_NAME 465 sysnamelist.append(sysname) 466 return sysnamelist 467 468 def _enum_confservice(self): 469 services = [] 470 service = {} 471 service['Name'] = 'FUJITSU:ETERNUS SMI-S Agent' 472 service['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem' 473 service['SystemName'] = STORAGE_SYSTEM 474 service['CreationClassName'] = 'FUJITSU_StorageConfigurationService' 475 services.append(service) 476 return services 477 478 def _enum_ctrlservice(self): 479 services = [] 480 service = {} 481 service['SystemName'] = STORAGE_SYSTEM 482 service['CreationClassName'] = 'FUJITSU_ControllerConfigurationService' 483 services.append(service) 484 return services 485 486 def _enum_afntyservice(self): 487 services = [] 488 service = {} 489 service['SystemName'] = STORAGE_SYSTEM 490 service['CreationClassName'] = 'FUJITSU_AffinityGroupController' 491 services.append(service) 492 return services 493 494 def _enum_repservice(self): 495 services = [] 496 service = {} 497 service['Name'] = 'FUJITSU:ETERNUS SMI-S Agent' 498 service['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem' 499 service['SystemName'] = STORAGE_SYSTEM 500 service['CreationClassName'] = 'FUJITSU_ReplicationService' 501 services.append(service) 502 return services 503 504 def _enum_pools(self): 505 pools = [] 506 pool = {} 507 pool['InstanceID'] = 'FUJITSU:RSP0004' 508 pool['CreationClassName'] = 'FUJITSU_RAIDStoragePool' 509 pools.append(pool) 510 511 pool2 = {} 512 pool2['InstanceID'] = 'FUJITSU:TPP0004' 513 pool2['CreationClassName'] = 'FUJITSU_ThinProvisioningPool' 514 pools.append(pool2) 515 return pools 516 517 def _enum_pool_details(self, pooltype): 518 pools = [] 519 pool = FJ_StoragePool() 520 521 if pooltype == 'RAID': 522 pool['InstanceID'] = 'FUJITSU:RSP0004' 523 pool['CreationClassName'] = 'FUJITSU_RAIDStoragePool' 524 pool['ElementName'] = 'abcd1234_OSVD' 525 pool['TotalManagedSpace'] = 1170368102400 526 pool['RemainingManagedSpace'] = 1170368102400 527 pool.path = pool 528 pool.path.classname = 'FUJITSU_RAIDStoragePool' 529 else: 530 pool = FJ_StoragePool() 531 pool['InstanceID'] = 'FUJITSU:TPP0004' 532 pool['CreationClassName'] = 'FUJITSU_ThinProvisioningPool' 533 pool['ElementName'] = 'abcd1234_TPP' 534 pool['TotalManagedSpace'] = 1170368102400 535 pool['RemainingManagedSpace'] = 1170368102400 536 pool.path = pool 537 pool.path.classname = 'FUJITSU_ThinProvisioningPool' 538 539 pools.append(pool) 540 return pools 541 542 def _enum_volumes(self): 543 volumes = [] 544 if VOL_STAT == '0': 545 return volumes 546 volume = FJ_StorageVolume() 547 volume['name'] = TEST_VOLUME['name'] 548 volume['CreationClassName'] = 'FUJITSU_StorageVolume' 549 volume['Name'] = FAKE_LUN_ID1 550 volume['DeviceID'] = FAKE_LUN_ID1 551 volume['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem' 552 volume['SystemName'] = STORAGE_SYSTEM 553 volume['ElementName'] = 'FJosv_0qJ4rpOHgFE8ipcJOMfBmg==' 554 volume['volume_type_id'] = None 555 volume.path = volume 556 volume.path.classname = volume['CreationClassName'] 557 558 name = {} 559 name['classname'] = 'FUJITSU_StorageVolume' 560 keys = {} 561 keys['CreationClassName'] = 'FUJITSU_StorageVolume' 562 keys['SystemName'] = STORAGE_SYSTEM 563 keys['DeviceID'] = volume['DeviceID'] 564 keys['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem' 565 name['keybindings'] = keys 566 volume['provider_location'] = str(name) 567 568 volumes.append(volume) 569 570 snap_vol = FJ_StorageVolume() 571 snap_vol['name'] = TEST_SNAP['name'] 572 snap_vol['CreationClassName'] = 'FUJITSU_StorageVolume' 573 snap_vol['Name'] = FAKE_LUN_ID2 574 snap_vol['DeviceID'] = FAKE_LUN_ID2 575 snap_vol['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem' 576 snap_vol['SystemName'] = STORAGE_SYSTEM 577 snap_vol['ElementName'] = 'FJosv_OgEZj1mSvKRvIKOExKktlg==' 578 snap_vol.path = snap_vol 579 snap_vol.path.classname = snap_vol['CreationClassName'] 580 581 name2 = {} 582 name2['classname'] = 'FUJITSU_StorageVolume' 583 keys2 = {} 584 keys2['CreationClassName'] = 'FUJITSU_StorageVolume' 585 keys2['SystemName'] = STORAGE_SYSTEM 586 keys2['DeviceID'] = snap_vol['DeviceID'] 587 keys2['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem' 588 name2['keybindings'] = keys2 589 snap_vol['provider_location'] = str(name2) 590 591 volumes.append(snap_vol) 592 593 clone_vol = FJ_StorageVolume() 594 clone_vol['name'] = TEST_CLONE['name'] 595 clone_vol['CreationClassName'] = 'FUJITSU_StorageVolume' 596 clone_vol['ElementName'] = TEST_CLONE['name'] 597 clone_vol['DeviceID'] = FAKE_LUN_ID2 598 clone_vol['SystemName'] = STORAGE_SYSTEM 599 clone_vol['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem' 600 clone_vol.path = clone_vol 601 clone_vol.path.classname = clone_vol['CreationClassName'] 602 volumes.append(clone_vol) 603 604 return volumes 605 606 def _enum_snapshots(self): 607 snapshots = [] 608 snap = FJ_StorageVolume() 609 snap['CreationClassName'] = 'FUJITSU_StorageVolume' 610 snap['SystemName'] = STORAGE_SYSTEM 611 snap['DeviceID'] = FAKE_LUN_ID2 612 snap['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem' 613 snap.path = snap 614 snap.path.classname = snap['CreationClassName'] 615 616 snapshots.append(snap) 617 618 return snapshots 619 620 def _enum_lunmaskctrls(self): 621 ctrls = [] 622 ctrl = {} 623 ctrl2 = {} 624 if MAP_STAT == '1': 625 ctrl['CreationClassName'] = SCSI_PROT_CTR 626 ctrl['SystemName'] = STORAGE_SYSTEM 627 ctrl['DeviceID'] = LUNMASKCTRL_IDS[0] 628 ctrls.append(ctrl) 629 630 ctrl2['CreationClassName'] = SCSI_PROT_CTR 631 ctrl2['SystemName'] = STORAGE_SYSTEM 632 ctrl2['DeviceID'] = LUNMASKCTRL_IDS[1] 633 ctrls.append(ctrl2) 634 635 return ctrls 636 637 def _enum_scsiport_endpoint(self): 638 targetlist = [] 639 tgtport1 = {} 640 tgtport1['Name'] = '1234567890000021' 641 tgtport1['CreationClassName'] = 'FUJITSU_SCSIProtocolEndpoint' 642 tgtport1['ConnectionType'] = 2 643 tgtport1['RAMode'] = 0 644 targetlist.append(tgtport1) 645 646 return targetlist 647 648 def _enum_ipproto_endpoint(self): 649 targetlist = [] 650 tgtport1 = {} 651 tgtport1['CreationClassName'] = 'FUJITSU_IPProtocolEndpoint' 652 tgtport1['NAME'] = 'IP_CM01CA00P00_00' 653 targetlist.append(tgtport1) 654 655 return targetlist 656 657 def _enum_tcp_endpoint(self): 658 targetlist = [] 659 tgtport1 = {} 660 tgtport1['CreationClassName'] = 'FUJITSU_TCPProtocolEndpoint' 661 tgtport1['NAME'] = 'TCP_CM01CA00P00_00' 662 targetlist.append(tgtport1) 663 664 return targetlist 665 666 def _enum_iscsiprot_endpoint(self): 667 targetlist = [] 668 tgtport1 = {} 669 tgtport1['Name'] = ('iqn.2000-09.com.fujitsu:storage-system.' 670 'eternus-dxl:0123456789,t,0x0009') 671 tgtport1['ConnectionType'] = 7 672 tgtport1['RAMode'] = 0 673 targetlist.append(tgtport1) 674 675 return targetlist 676 677 def _getinstance_storagevolume(self, objpath): 678 foundinstance = None 679 instance = FJ_StorageVolume() 680 volumes = self._enum_volumes() 681 for volume in volumes: 682 if volume['DeviceID'] == objpath['DeviceID']: 683 instance = volume 684 break 685 if not instance: 686 foundinstance = None 687 else: 688 foundinstance = instance 689 return foundinstance 690 691 def _getinstance_ipprotocolendpoint(self, objpath): 692 instance = {} 693 instance['IPv4Address'] = '10.0.0.3' 694 return instance 695 696 697class FJFCDriverTestCase(test.TestCase): 698 def __init__(self, *args, **kwargs): 699 super(FJFCDriverTestCase, self).__init__(*args, **kwargs) 700 701 def setUp(self): 702 super(FJFCDriverTestCase, self).setUp() 703 704 # Make fake xml-configuration file. 705 self.config_file = tempfile.NamedTemporaryFile("w+", suffix='.xml') 706 self.addCleanup(self.config_file.close) 707 self.config_file.write(CONF) 708 self.config_file.flush() 709 710 # Make fake Object by using mock as configuration object. 711 self.configuration = mock.Mock(spec=conf.Configuration) 712 self.configuration.cinder_eternus_config_file = self.config_file.name 713 714 self.mock_object(dx_common.FJDXCommon, '_get_eternus_connection', 715 self.fake_eternus_connection) 716 717 instancename = FakeCIMInstanceName() 718 self.mock_object(dx_common.FJDXCommon, '_create_eternus_instance_name', 719 instancename.fake_create_eternus_instance_name) 720 721 # Set iscsi driver to self.driver. 722 driver = dx_fc.FJDXFCDriver(configuration=self.configuration) 723 self.driver = driver 724 725 def fake_eternus_connection(self): 726 conn = FakeEternusConnection() 727 return conn 728 729 def test_get_volume_stats(self): 730 ret = self.driver.get_volume_stats(True) 731 stats = {'vendor_name': ret['vendor_name'], 732 'total_capacity_gb': ret['total_capacity_gb'], 733 'free_capacity_gb': ret['free_capacity_gb']} 734 self.assertEqual(FAKE_STATS, stats) 735 736 def test_create_and_delete_volume(self): 737 model_info = self.driver.create_volume(TEST_VOLUME) 738 self.assertEqual(FAKE_MODEL_INFO1, model_info) 739 740 self.driver.delete_volume(TEST_VOLUME) 741 742 @mock.patch.object(dx_common.FJDXCommon, '_get_mapdata') 743 def test_map_unmap(self, mock_mapdata): 744 fake_data = {'target_wwn': FC_TARGET_WWN, 745 'target_lun': 0} 746 747 mock_mapdata.return_value = fake_data 748 fake_mapdata = dict(fake_data) 749 fake_mapdata['initiator_target_map'] = { 750 initiator: FC_TARGET_WWN for initiator in TEST_WWPN 751 } 752 753 fake_mapdata['volume_id'] = TEST_VOLUME['id'] 754 fake_mapdata['target_discovered'] = True 755 fake_info = {'driver_volume_type': 'fibre_channel', 756 'data': fake_mapdata} 757 758 model_info = self.driver.create_volume(TEST_VOLUME) 759 self.assertEqual(FAKE_MODEL_INFO1, model_info) 760 761 info = self.driver.initialize_connection(TEST_VOLUME, 762 TEST_CONNECTOR) 763 self.assertEqual(fake_info, info) 764 # Call terminate_connection with connector. 765 self.driver.terminate_connection(TEST_VOLUME, 766 TEST_CONNECTOR) 767 768 info = self.driver.initialize_connection(TEST_VOLUME, 769 TEST_CONNECTOR) 770 self.assertEqual(fake_info, info) 771 # Call terminate_connection without connector. 772 self.driver.terminate_connection(TEST_VOLUME, 773 None) 774 775 self.driver.delete_volume(TEST_VOLUME) 776 777 def test_create_and_delete_snapshot(self): 778 model_info = self.driver.create_volume(TEST_VOLUME) 779 self.assertEqual(FAKE_MODEL_INFO1, model_info) 780 781 snap_info = self.driver.create_snapshot(TEST_SNAP) 782 self.assertEqual(FAKE_SNAP_INFO, snap_info) 783 784 self.driver.delete_snapshot(TEST_SNAP) 785 self.driver.delete_volume(TEST_VOLUME) 786 787 def test_create_volume_from_snapshot(self): 788 model_info = self.driver.create_volume(TEST_VOLUME) 789 self.assertEqual(FAKE_MODEL_INFO1, model_info) 790 791 snap_info = self.driver.create_snapshot(TEST_SNAP) 792 self.assertEqual(FAKE_SNAP_INFO, snap_info) 793 794 model_info = self.driver.create_volume_from_snapshot(TEST_CLONE, 795 TEST_SNAP) 796 self.assertEqual(FAKE_MODEL_INFO2, model_info) 797 798 self.driver.delete_snapshot(TEST_SNAP) 799 self.driver.delete_volume(TEST_CLONE) 800 self.driver.delete_volume(TEST_VOLUME) 801 802 def test_create_cloned_volume(self): 803 model_info = self.driver.create_volume(TEST_VOLUME) 804 self.assertEqual(FAKE_MODEL_INFO1, model_info) 805 806 model_info = self.driver.create_cloned_volume(TEST_CLONE, TEST_VOLUME) 807 self.assertEqual(FAKE_MODEL_INFO2, model_info) 808 809 self.driver.delete_volume(TEST_CLONE) 810 self.driver.delete_volume(TEST_VOLUME) 811 812 def test_extend_volume(self): 813 model_info = self.driver.create_volume(TEST_VOLUME) 814 self.assertEqual(FAKE_MODEL_INFO1, model_info) 815 816 self.driver.extend_volume(TEST_VOLUME, 10) 817 818 819class FJISCSIDriverTestCase(test.TestCase): 820 def __init__(self, *args, **kwargs): 821 super(FJISCSIDriverTestCase, self).__init__(*args, **kwargs) 822 823 def setUp(self): 824 super(FJISCSIDriverTestCase, self).setUp() 825 826 # Make fake xml-configuration file. 827 self.config_file = tempfile.NamedTemporaryFile("w+", suffix='.xml') 828 self.addCleanup(self.config_file.close) 829 self.config_file.write(CONF) 830 self.config_file.flush() 831 832 # Make fake Object by using mock as configuration object. 833 self.configuration = mock.Mock(spec=conf.Configuration) 834 self.configuration.cinder_eternus_config_file = self.config_file.name 835 836 self.mock_object(dx_common.FJDXCommon, '_get_eternus_connection', 837 self.fake_eternus_connection) 838 839 instancename = FakeCIMInstanceName() 840 self.mock_object(dx_common.FJDXCommon, '_create_eternus_instance_name', 841 instancename.fake_create_eternus_instance_name) 842 843 self.mock_object(dx_common.FJDXCommon, '_get_mapdata_iscsi', 844 self.fake_get_mapdata) 845 846 # Set iscsi driver to self.driver. 847 driver = dx_iscsi.FJDXISCSIDriver(configuration=self.configuration) 848 self.driver = driver 849 850 def fake_eternus_connection(self): 851 conn = FakeEternusConnection() 852 return conn 853 854 def fake_get_mapdata(self, vol_instance, connector, target_portlist): 855 multipath = connector.get('multipath', False) 856 if multipath: 857 return {'target_portals': [ISCSI_TARGET_IP], 858 'target_iqns': [ISCSI_TARGET_IQN], 859 'target_luns': [0]} 860 else: 861 return {'target_portal': ISCSI_TARGET_IP, 862 'target_iqns': ISCSI_TARGET_IQN, 863 'target_lun': 0} 864 865 def test_get_volume_stats(self): 866 ret = self.driver.get_volume_stats(True) 867 stats = {'vendor_name': ret['vendor_name'], 868 'total_capacity_gb': ret['total_capacity_gb'], 869 'free_capacity_gb': ret['free_capacity_gb']} 870 self.assertEqual(FAKE_STATS, stats) 871 872 def test_create_and_delete_volume(self): 873 model_info = self.driver.create_volume(TEST_VOLUME) 874 self.assertEqual(FAKE_MODEL_INFO1, model_info) 875 876 self.driver.delete_volume(TEST_VOLUME) 877 878 def test_map_unmap(self): 879 fake_mapdata = self.fake_get_mapdata(None, {}, None) 880 fake_mapdata['volume_id'] = TEST_VOLUME['id'] 881 fake_mapdata['target_discovered'] = True 882 fake_info = {'driver_volume_type': 'iscsi', 883 'data': fake_mapdata} 884 885 model_info = self.driver.create_volume(TEST_VOLUME) 886 self.assertEqual(FAKE_MODEL_INFO1, model_info) 887 888 info = self.driver.initialize_connection(TEST_VOLUME, 889 TEST_CONNECTOR) 890 self.assertEqual(fake_info, info) 891 # Call terminate_connection with connector. 892 self.driver.terminate_connection(TEST_VOLUME, 893 TEST_CONNECTOR) 894 895 info = self.driver.initialize_connection(TEST_VOLUME, 896 TEST_CONNECTOR) 897 self.assertEqual(fake_info, info) 898 # Call terminate_connection without connector. 899 self.driver.terminate_connection(TEST_VOLUME, 900 None) 901 self.driver.delete_volume(TEST_VOLUME) 902 903 def test_create_and_delete_snapshot(self): 904 model_info = self.driver.create_volume(TEST_VOLUME) 905 self.assertEqual(FAKE_MODEL_INFO1, model_info) 906 907 snap_info = self.driver.create_snapshot(TEST_SNAP) 908 self.assertEqual(FAKE_SNAP_INFO, snap_info) 909 910 self.driver.delete_snapshot(TEST_SNAP) 911 self.driver.delete_volume(TEST_VOLUME) 912 913 def test_create_volume_from_snapshot(self): 914 model_info = self.driver.create_volume(TEST_VOLUME) 915 self.assertEqual(FAKE_MODEL_INFO1, model_info) 916 917 snap_info = self.driver.create_snapshot(TEST_SNAP) 918 self.assertEqual(FAKE_SNAP_INFO, snap_info) 919 920 model_info = self.driver.create_volume_from_snapshot(TEST_CLONE, 921 TEST_SNAP) 922 self.assertEqual(FAKE_MODEL_INFO2, model_info) 923 924 self.driver.delete_snapshot(TEST_SNAP) 925 self.driver.delete_volume(TEST_CLONE) 926 self.driver.delete_volume(TEST_VOLUME) 927 928 def test_create_cloned_volume(self): 929 model_info = self.driver.create_volume(TEST_VOLUME) 930 self.assertEqual(FAKE_MODEL_INFO1, model_info) 931 932 model_info = self.driver.create_cloned_volume(TEST_CLONE, TEST_VOLUME) 933 self.assertEqual(FAKE_MODEL_INFO2, model_info) 934 935 self.driver.delete_volume(TEST_CLONE) 936 self.driver.delete_volume(TEST_VOLUME) 937 938 def test_extend_volume(self): 939 model_info = self.driver.create_volume(TEST_VOLUME) 940 self.assertEqual(FAKE_MODEL_INFO1, model_info) 941 942 self.driver.extend_volume(TEST_VOLUME, 10) 943