Coverage for manila/tests/share/drivers/dell_emc/plugins/powerscale/test_powerscale.py: 100%
809 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright (c) 2015 EMC Corporation.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
16from unittest import mock
18import ddt
19from oslo_log import log
20from oslo_utils import units
22from manila.common import constants as const
23from manila import exception
24from manila.i18n import _
25from manila.share.drivers.dell_emc.plugins.powerscale import powerscale
26from manila import test
28LOG = log.getLogger(__name__)
31@ddt.ddt
32class PowerScaleTest(test.TestCase):
33 """Integration test for the PowerScale Manila driver."""
35 POWERSCALE_ADDR = '10.0.0.1'
36 API_URL = 'https://%s:8080' % POWERSCALE_ADDR
37 AUTH = ('admin', 'admin')
39 ROOT_DIR = '/ifs/manila-test'
40 SHARE_NAME = 'share-foo'
41 SHARE_DIR = ROOT_DIR + '/' + SHARE_NAME
42 ADMIN_HOME_DIR = '/ifs/home/admin'
43 CLONE_DIR = ROOT_DIR + '/clone-dir'
45 class MockConfig(object):
47 def safe_get(self, value):
48 if value == 'emc_nas_server':
49 return '10.0.0.1'
50 elif value == 'emc_nas_server_port':
51 return '8080'
52 elif value == 'emc_nas_login':
53 return 'admin'
54 elif value == 'emc_nas_password':
55 return 'a'
56 elif value == 'emc_nas_root_dir':
57 return '/ifs/manila-test'
58 elif value == 'powerscale_dir_permission':
59 return '0777'
60 else:
61 return None
63 class MockInvalidConfig(object):
65 def safe_get(self, value):
66 if value == 'emc_nas_server':
67 return '10.0.0.1'
68 elif value == 'emc_nas_server_port':
69 return '8080'
70 elif value == 'emc_nas_login':
71 return 'admin'
72 elif value == 'emc_nas_root_dir':
73 return '/ifs/manila-test'
74 else:
75 return None
77 @mock.patch(
78 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.'
79 'powerscale_api.PowerScaleApi', autospec=True)
80 def setUp(self, mock_isi_api):
81 super(PowerScaleTest, self).setUp()
83 self._mock_powerscale_api = mock_isi_api.return_value
84 self.storage_connection = powerscale.PowerScaleStorageConnection(LOG)
86 self.mock_context = mock.Mock('Context')
87 self.mock_emc_driver = mock.Mock('EmcDriver')
89 self.mock_emc_driver.attach_mock(self.MockConfig(), 'configuration')
90 self.storage_connection.connect(
91 self.mock_emc_driver, self.mock_context)
93 def test_allow_access(self):
94 self.assertRaises(
95 NotImplementedError,
96 self.storage_connection.allow_access,
97 self.mock_context,
98 share=None,
99 access=None,
100 share_server=None,
101 )
103 def test_deny_access(self):
104 self.assertRaises(
105 NotImplementedError,
106 self.storage_connection.deny_access,
107 self.mock_context,
108 share=None,
109 access=None,
110 share_server=None,
111 )
113 def test_create_share_nfs(self):
114 share_path = self.SHARE_DIR
115 self.assertFalse(self._mock_powerscale_api.create_directory.called)
116 self.assertFalse(self._mock_powerscale_api.create_nfs_export.called)
118 # create the share
119 share = {"name": self.SHARE_NAME, "share_proto": 'NFS', "size": 8}
120 location = self.storage_connection.create_share(self.mock_context,
121 share, None)
123 # verify location and API call made
124 path = '%s:%s' % (self.POWERSCALE_ADDR, self.SHARE_DIR)
125 expected_location = [{'is_admin_only': False,
126 'metadata': {"preferred": True},
127 'path': path}]
129 self.assertEqual(expected_location, location)
130 self._mock_powerscale_api.create_directory.assert_called_with(
131 share_path, False)
132 self._mock_powerscale_api.create_nfs_export.assert_called_with(
133 share_path)
135 # verify directory quota call made
136 self._mock_powerscale_api.quota_create.assert_called_with(
137 share_path, 'directory', 8 * units.Gi)
139 def test_create_share_cifs(self):
140 self.assertFalse(self._mock_powerscale_api.create_directory.called)
141 self.assertFalse(self._mock_powerscale_api.create_smb_share.called)
143 # create the share
144 share = {"name": self.SHARE_NAME, "share_proto": 'CIFS', "size": 8}
145 location = self.storage_connection.create_share(self.mock_context,
146 share, None)
147 path = '\\\\{0}\\{1}'.format(self.POWERSCALE_ADDR, self.SHARE_NAME)
148 expected_location = [{'is_admin_only': False,
149 'metadata': {"preferred": True},
150 'path': path}]
152 self.assertEqual(expected_location, location)
153 self._mock_powerscale_api.create_directory.assert_called_once_with(
154 self.SHARE_DIR, False)
155 self._mock_powerscale_api.create_smb_share.assert_called_once_with(
156 self.SHARE_NAME, self.SHARE_DIR)
158 # verify directory quota call made
159 self._mock_powerscale_api.quota_create.assert_called_with(
160 self.SHARE_DIR, 'directory', 8 * units.Gi)
162 def test_create_share_invalid_share_protocol(self):
163 share = {"name": self.SHARE_NAME, "share_proto": 'FOO_PROTOCOL'}
165 self.assertRaises(
166 exception.InvalidShare, self.storage_connection.create_share,
167 self.mock_context, share, share_server=None)
169 def test_create_share_nfs_backend_failure(self):
170 share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
171 self._mock_powerscale_api.create_nfs_export.return_value = False
173 self.assertRaises(
174 exception.ShareBackendException,
175 self.storage_connection.create_share,
176 self.mock_context, share, share_server=None)
178 def test_create_share_cifs_backend_failure(self):
179 share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'}
180 self._mock_powerscale_api.create_smb_share.return_value = False
182 self.assertRaises(
183 exception.ShareBackendException,
184 self.storage_connection.create_share,
185 self.mock_context, share, share_server=None)
187 def test_create_directory_backend_failure(self):
188 share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
189 self._mock_powerscale_api.create_directory.return_value = False
191 self.assertRaises(
192 exception.ShareBackendException,
193 self.storage_connection.create_share,
194 self.mock_context, share, share_server=None)
196 def test_create_snapshot(self):
198 # create snapshot
199 snapshot_name = "snapshot01"
200 snapshot_path = '/ifs/home/admin'
201 share = {"name": self.SHARE_NAME, "share_proto": 'NFS',
202 "mount_snapshot_support": False}
203 snapshot = {'name': snapshot_name, 'share_name': snapshot_path,
204 'share': share}
205 self.storage_connection.create_snapshot(self.mock_context, snapshot,
206 None)
208 # verify the create snapshot API call is executed
209 self._mock_powerscale_api.create_snapshot.assert_called_with(
210 snapshot_name, snapshot_path)
212 def test_create_snapshot_backend_failure(self):
213 snapshot_name = "snapshot01"
214 snapshot_path = '/ifs/home/admin'
215 share = {"name": self.SHARE_NAME, "share_proto": 'NFS',
216 "mount_snapshot_support": False}
217 snapshot = {'name': snapshot_name, 'share_name': snapshot_path,
218 'share': share}
219 self._mock_powerscale_api.create_snapshot.return_value = None
221 self._mock_powerscale_api.create_snapshot.return_value = None
222 self.assertRaises(
223 exception.ShareBackendException,
224 self.storage_connection.create_snapshot,
225 self.mock_context, snapshot, None)
227 def test_create_share_from_snapshot_nfs(self):
228 # assertions
229 self.assertFalse(self._mock_powerscale_api.create_nfs_export.called)
230 self.assertFalse(self._mock_powerscale_api.clone_snapshot.called)
232 snapshot_name = "snapshot01"
233 snapshot_path = '/ifs/home/admin'
235 # execute method under test
236 snapshot = {'name': snapshot_name, 'share_name': snapshot_path,
237 'provider_location': None, }
238 share = {"name": self.SHARE_NAME, "share_proto": 'NFS', 'size': 5,
239 'share_type_id': 'fake_id', }
240 location = self.storage_connection.create_share_from_snapshot(
241 self.mock_context, share, snapshot, None)
243 # verify NFS export created at expected location
244 self._mock_powerscale_api.create_nfs_export.assert_called_with(
245 self.SHARE_DIR)
247 # verify clone_directory(container_path) method called
248 self._mock_powerscale_api.clone_snapshot.assert_called_once_with(
249 snapshot_name, self.SHARE_DIR, None)
250 path = '{0}:{1}'.format(
251 self.POWERSCALE_ADDR, self.SHARE_DIR)
252 expected_location = {'is_admin_only': False,
253 'metadata': {"preferred": True},
254 'path': path}
256 self.assertEqual(expected_location, location[0])
258 # verify directory quota call made
259 self._mock_powerscale_api.quota_create.assert_called_with(
260 self.SHARE_DIR, 'directory', 5 * units.Gi)
262 def test_create_share_from_snapshot_cifs(self):
263 # assertions
264 self.assertFalse(self._mock_powerscale_api.create_smb_share.called)
265 self.assertFalse(self._mock_powerscale_api.clone_snapshot.called)
266 # setup
267 snapshot_name = "snapshot01"
268 snapshot_path = '/ifs/home/admin'
269 new_share_name = 'clone-dir'
271 # execute method under test
272 snapshot = {'name': snapshot_name, 'share_name': snapshot_path,
273 'provider_location': None, }
274 share = {"name": new_share_name, "share_proto": 'CIFS', "size": 2,
275 'share_type_id': 'fake_id', }
276 location = self.storage_connection.create_share_from_snapshot(
277 self.mock_context, share, snapshot, None)
279 # verify call made to create new CIFS share
280 self._mock_powerscale_api.create_smb_share.assert_called_once_with(
281 new_share_name, self.CLONE_DIR)
282 self._mock_powerscale_api.clone_snapshot.assert_called_once_with(
283 snapshot_name, self.CLONE_DIR, None)
284 path = '\\\\{0}\\{1}'.format(self.POWERSCALE_ADDR, new_share_name)
285 expected_location = {'is_admin_only': False,
286 'metadata': {"preferred": True},
287 'path': path}
288 self.assertEqual(expected_location, location[0])
290 # verify directory quota call made
291 expected_share_path = '{0}/{1}'.format(self.ROOT_DIR, new_share_name)
292 self._mock_powerscale_api.quota_create.assert_called_with(
293 expected_share_path, 'directory', 2 * units.Gi)
295 def test_delete_share_nfs(self):
296 share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
297 fake_share_num = 42
298 self._mock_powerscale_api.lookup_nfs_export.return_value = (
299 fake_share_num)
300 self.assertFalse(self._mock_powerscale_api.delete_nfs_share.called)
302 # delete the share
303 self.storage_connection.delete_share(self.mock_context, share, None)
305 # verify share delete
306 self._mock_powerscale_api.delete_nfs_share.assert_called_with(
307 fake_share_num)
309 def test_delete_share_cifs(self):
310 self.assertFalse(self._mock_powerscale_api.delete_smb_share.called)
312 # delete the share
313 share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'}
314 self._mock_powerscale_api.lookup_smb_share.return_value = {
315 'id': self.SHARE_NAME,
316 'path': '/ifs/manila-test/share-foo',
317 }
318 container_path = '/ifs/manila-test/share-foo'
319 self.storage_connection._get_container_path = mock.MagicMock(
320 return_value=container_path)
321 self.storage_connection.delete_share(self.mock_context, share, None)
323 # verify share deleted
324 self._mock_powerscale_api.delete_smb_share.assert_called_with(
325 self.SHARE_NAME)
327 @mock.patch(
328 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG')
329 def test_delete_share_invalid_share_proto(self, mock_log):
330 share = {"name": self.SHARE_NAME, "share_proto": 'FOO_PROTOCOL'}
332 self.storage_connection.delete_share(self.mock_context, share, None)
333 mock_log.warning.assert_called_once_with(
334 'Unsupported share type: FOO_PROTOCOL.')
336 def test_delete_nfs_share_backend_failure(self):
337 share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
339 self._mock_powerscale_api.delete_nfs_share.return_value = False
340 self.assertRaises(
341 exception.ShareBackendException,
342 self.storage_connection.delete_share,
343 self.mock_context, share, None
344 )
346 def test_delete_nfs_share_share_does_not_exist(self):
347 self._mock_powerscale_api.lookup_nfs_export.return_value = None
348 share = {"name": self.SHARE_NAME, "share_proto": 'NFS'}
350 # verify the calling delete on a non-existent share returns and does
351 # not throw exception
352 self.storage_connection.delete_share(self.mock_context, share, None)
354 def test_delete_cifs_share_backend_failure(self):
355 share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'}
356 self._mock_powerscale_api.lookup_smb_share.return_value = {
357 'id': self.SHARE_NAME,
358 'path': '/ifs/manila-test/share-foo',
359 }
360 container_path = '/ifs/manila-test/share-foo'
361 self.storage_connection._get_container_path = mock.MagicMock(
362 return_value=container_path)
363 self._mock_powerscale_api.delete_smb_share.return_value = False
364 self.assertRaises(
365 exception.ShareBackendException,
366 self.storage_connection.delete_share,
367 self.mock_context, share, None
368 )
370 def test_delete_cifs_share_share_does_not_exist(self):
371 share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'}
372 self._mock_powerscale_api.lookup_smb_share.return_value = None
374 # verify the calling delete on a non-existent share returns and does
375 # not throw exception
376 self.storage_connection.delete_share(self.mock_context, share, None)
378 @mock.patch(
379 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
380 )
381 def test_delete_quota_success(self, mock_log):
382 path = '/path/to/quota'
383 quota_id = '123'
384 quota_data = {'id': quota_id}
385 self._mock_powerscale_api.quota_get.return_value = quota_data
386 self._mock_powerscale_api.delete_quota.return_value = True
387 self.storage_connection._delete_quota(path)
388 self._mock_powerscale_api.quota_get.assert_called_once_with(
389 path, 'directory')
390 self._mock_powerscale_api.delete_quota.assert_called_once_with(
391 quota_id)
392 mock_log.debug.assert_called_once_with(f'Removing quota {quota_id}')
393 mock_log.warning.assert_not_called()
395 @mock.patch(
396 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
397 )
398 def test_delete_quota_failure(self, mock_log):
399 path = '/path/to/quota'
400 quota_id = '123'
401 quota_data = {'id': quota_id}
402 self._mock_powerscale_api.quota_get.return_value = quota_data
403 self._mock_powerscale_api.delete_quota.return_value = False
404 self.storage_connection._delete_quota(path)
405 self._mock_powerscale_api.quota_get.assert_called_once_with(
406 path, 'directory')
407 self._mock_powerscale_api.delete_quota.assert_called_once_with(
408 quota_id)
409 mock_log.debug.assert_called_once_with(f'Removing quota {quota_id}')
410 mock_log.error.assert_called_once_with(
411 _('Failed to delete quota "%(quota_id)s" for '
412 'directory "%(dir)s".') %
413 {'quota_id': quota_id, 'dir': path})
414 mock_log.warning.assert_not_called()
416 @mock.patch(
417 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
418 )
419 def test_delete_quota_not_found(self, mock_log):
420 path = '/path/to/quota'
421 self._mock_powerscale_api.quota_get.return_value = None
422 self.storage_connection._delete_quota(path)
423 self._mock_powerscale_api.quota_get.assert_called_once_with(
424 path, 'directory')
425 self._mock_powerscale_api.delete_quota.assert_not_called()
426 mock_log.debug.assert_not_called()
427 mock_log.warning.assert_called_once_with(f'Quota not found for {path}')
429 @mock.patch(
430 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
431 )
432 def test_delete_directory_success(self, mock_log):
433 path = '/path/to/directory'
434 self._mock_powerscale_api.is_path_existent.return_value = True
435 self._mock_powerscale_api.delete_path.return_value = True
436 self.storage_connection._delete_directory(path)
437 self._mock_powerscale_api.delete_path.assert_called_once_with(
438 path, recursive=True)
439 mock_log.debug.assert_called_once_with(f'Removing directory {path}')
440 mock_log.warning.assert_not_called()
442 @mock.patch(
443 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
444 )
445 def test_delete_directory_failure(self, mock_log):
446 path = '/path/to/directory'
447 self._mock_powerscale_api.is_path_existent.return_value = True
448 self._mock_powerscale_api.delete_path.return_value = False
449 self.storage_connection._delete_directory(path)
450 self._mock_powerscale_api.delete_path.assert_called_once_with(
451 path, recursive=True)
452 mock_log.debug.assert_called_once_with(f'Removing directory {path}')
453 mock_log.error.assert_called_once_with(
454 _('Failed to delete directory "%(dir)s".') %
455 {'dir': path})
456 mock_log.warning.assert_not_called()
458 @mock.patch(
459 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.LOG'
460 )
461 def test_delete_directory_not_found(self, mock_log):
462 path = '/path/to/directory'
463 self._mock_powerscale_api.is_path_existent.return_value = False
464 self.storage_connection._delete_directory(path)
465 self._mock_powerscale_api.delete_path.assert_not_called()
466 mock_log.warning.assert_called_once_with(
467 _('Directory not found for %s') % path)
469 def test_delete_snapshot(self):
470 # create a snapshot
471 snapshot_name = "snapshot01"
472 snapshot_path = '/ifs/home/admin'
473 share = {"name": self.SHARE_NAME, "share_proto": 'NFS',
474 "mount_snapshot_support": False}
475 snapshot = {'name': snapshot_name, 'share_name': snapshot_path,
476 'share': share}
477 self.assertFalse(self._mock_powerscale_api.delete_snapshot.called)
479 # delete the created snapshot
480 self.storage_connection.delete_snapshot(self.mock_context, snapshot,
481 None)
483 # verify the API call was made to delete the snapshot
484 self._mock_powerscale_api.delete_snapshot.assert_called_once_with(
485 snapshot_name)
487 def test_delete_snapshot_failure(self):
488 share = {"name": self.SHARE_NAME, "share_proto": 'NFS',
489 "mount_snapshot_support": False}
490 snapshot = {'name': 'test_snapshot', 'share': share}
491 self._mock_powerscale_api.delete_snapshot.return_value = False
492 self.assertRaises(
493 exception.ShareBackendException,
494 self.storage_connection.delete_snapshot,
495 self.mock_context, snapshot, None)
496 self._mock_powerscale_api.delete_snapshot.assert_called_once_with(
497 snapshot['name'])
499 def test_ensure_share(self):
500 share = {"name": self.SHARE_NAME, "share_proto": 'CIFS'}
501 self.assertRaises(NotImplementedError,
502 self.storage_connection.ensure_share,
503 self.mock_context, share, None)
505 @mock.patch(
506 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.'
507 'powerscale_api.PowerScaleApi', autospec=True)
508 def test_connect(self, mock_isi_api):
509 storage_connection = powerscale.PowerScaleStorageConnection(LOG)
511 # execute method under test
512 storage_connection.connect(
513 self.mock_emc_driver, self.mock_context)
515 # verify connect sets driver params appropriately
516 mock_config = self.MockConfig()
517 server_addr = mock_config.safe_get('emc_nas_server')
518 self.assertEqual(server_addr, storage_connection._server)
519 expected_port = mock_config.safe_get('emc_nas_server_port')
520 self.assertEqual(expected_port, storage_connection._port)
521 self.assertEqual('https://{0}:{1}'.format(server_addr, expected_port),
522 storage_connection._server_url)
523 expected_username = mock_config.safe_get('emc_nas_login')
524 self.assertEqual(expected_username, storage_connection._username)
525 expected_password = mock_config.safe_get('emc_nas_password')
526 self.assertEqual(expected_password, storage_connection._password)
527 self.assertFalse(storage_connection._verify_ssl_cert)
528 expected_dir_permission = mock_config.safe_get(
529 'powerscale_dir_permission')
530 self.assertEqual(expected_dir_permission,
531 storage_connection._dir_permission)
533 @mock.patch(
534 'manila.share.drivers.dell_emc.plugins.powerscale.powerscale.'
535 'powerscale_api.PowerScaleApi', autospec=True)
536 def test_connect_root_dir_does_not_exist(self, mock_isi_api):
537 mock_powerscale_api = mock_isi_api.return_value
538 mock_powerscale_api.is_path_existent.return_value = False
539 storage_connection = powerscale.PowerScaleStorageConnection(LOG)
541 # call method under test
542 storage_connection.connect(self.mock_emc_driver, self.mock_context)
544 mock_powerscale_api.create_directory.assert_called_once_with(
545 self.ROOT_DIR, recursive=True)
547 def test_connect_invalid_config(self):
548 mock_emc_driver = mock.Mock('EmcDriver')
549 mock_emc_driver.attach_mock(self.MockInvalidConfig(), 'configuration')
551 self.assertRaises(exception.BadConfigurationException,
552 self.storage_connection.connect,
553 mock_emc_driver,
554 self.mock_context
555 )
557 def test_update_share_stats(self):
558 self._mock_powerscale_api.get_space_stats.return_value = {
559 'total': 1000 * units.Gi,
560 'free': 100 * units.Gi,
561 }
562 self._mock_powerscale_api.get_allocated_space.return_value = 2110.0
563 stats_dict = {'share_backend_name': 'PowerScale_backend'}
564 self.storage_connection.update_share_stats(stats_dict)
566 expected_pool_stats = {
567 'pool_name': 'PowerScale_backend',
568 'reserved_percentage': 0,
569 'reserved_snapshot_percentage': 0,
570 'reserved_share_extend_percentage': 0,
571 'max_over_subscription_ratio': None,
572 'thin_provisioning': True,
573 'total_capacity_gb': 1000,
574 'free_capacity_gb': 100,
575 'allocated_capacity_gb': 2110.0,
576 'qos': False,
577 'mount_snapshot_support': True,
578 'mount_point_name_support': True,
579 }
580 expected_stats = {
581 'share_backend_name': 'PowerScale_backend',
582 'driver_version': powerscale.VERSION,
583 'storage_protocol': 'NFS_CIFS',
584 'pools': [expected_pool_stats]
585 }
586 self.assertEqual(expected_stats, stats_dict)
588 def test_get_network_allocations_number(self):
589 # call method under test
590 num = self.storage_connection.get_network_allocations_number()
592 self.assertEqual(0, num)
594 def test_extend_share(self):
595 quota_id = 'abcdef'
596 new_share_size = 8
597 share = {
598 "name": self.SHARE_NAME,
599 "share_proto": 'NFS',
600 "size": new_share_size
601 }
602 self._mock_powerscale_api.quota_get.return_value = {'id': quota_id}
603 self.assertFalse(self._mock_powerscale_api.quota_set.called)
605 self.storage_connection.extend_share(share, new_share_size)
607 share_path = '{0}/{1}'.format(self.ROOT_DIR, self.SHARE_NAME)
608 expected_quota_size = new_share_size * units.Gi
609 self._mock_powerscale_api.quota_set.assert_called_once_with(
610 share_path, 'directory', expected_quota_size)
612 def test_update_access_add_nfs(self):
613 share = {
614 "name": self.SHARE_NAME,
615 "share_proto": 'NFS',
616 }
617 fake_export_id = 4
618 self._mock_powerscale_api.lookup_nfs_export.return_value = (
619 fake_export_id)
620 self._mock_powerscale_api.get_nfs_export.return_value = {
621 'clients': [],
622 'read_only_clients': []
623 }
624 nfs_access = {
625 'access_type': 'ip',
626 'access_to': '10.1.1.10',
627 'access_level': const.ACCESS_LEVEL_RW,
628 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
629 }
630 access_rules = [nfs_access]
631 self._mock_powerscale_api.modify_nfs_export_access.return_value = True
632 rule_map = self.storage_connection.update_access(
633 self.mock_context, share, access_rules, [],
634 [], share_server=None)
635 expected_rule_map = {
636 '09960614-8574-4e03-89cf-7cf267b0bd08': {
637 'state': 'active'
638 }
639 }
640 self._mock_powerscale_api.modify_nfs_export_access. \
641 assert_called_once_with(fake_export_id, [], ['10.1.1.10'])
642 self.assertEqual(expected_rule_map, rule_map)
644 def test_update_access_add_cifs(self):
645 share = {
646 "name": self.SHARE_NAME,
647 "share_proto": 'CIFS',
648 }
649 access = {
650 'access_type': 'user',
651 'access_to': 'foo',
652 'access_level': const.ACCESS_LEVEL_RW,
653 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
654 }
655 access_rules = [access]
657 self._mock_powerscale_api.get_user_sid.return_value = {
658 'id': 'SID:S-1-5-22',
659 'name': 'foo',
660 'type': 'user',
661 }
662 rule_map = self.storage_connection.update_access(
663 self.mock_context, share, access_rules, [], [])
665 expected_permissions = [
666 {
667 "permission": "change",
668 "permission_type": "allow",
669 "trustee": {
670 "id": "SID:S-1-5-22",
671 "name": "foo",
672 "type": "user"
673 }
674 }
675 ]
676 self._mock_powerscale_api.modify_smb_share_access.\
677 assert_called_once_with(
678 self.SHARE_NAME, host_acl=[], permissions=expected_permissions)
679 expected_rule_map = {
680 '09960614-8574-4e03-89cf-7cf267b0bd08': {
681 'state': 'active'
682 }
683 }
684 self.assertEqual(expected_rule_map, rule_map)
686 def test_update_access_delete_nfs(self):
687 share = {
688 "name": self.SHARE_NAME,
689 "share_proto": 'NFS',
690 }
691 fake_export_id = 4
692 self._mock_powerscale_api.lookup_nfs_export.return_value = (
693 fake_export_id)
694 # simulate an IP added to the whitelist
695 ip_addr = '10.0.0.4'
696 ip_addr_ro = '10.0.0.50'
697 self._mock_powerscale_api.get_nfs_export.return_value = {
698 'clients': [ip_addr], 'read_only_clients': [ip_addr_ro]}
699 access_rules = []
700 self._mock_powerscale_api.modify_nfs_export_access.return_value = True
702 rule_map = self.storage_connection.update_access(
703 self.mock_context, share, access_rules, [], [])
705 self._mock_powerscale_api.modify_nfs_export_access. \
706 assert_called_once_with(fake_export_id, [], [])
707 self.assertEqual({}, rule_map)
709 def test_update_access_delete_cifs(self):
710 share = {
711 "name": self.SHARE_NAME,
712 "share_proto": 'CIFS',
713 }
714 access_rules = []
715 self._mock_powerscale_api.lookup_smb_share.return_value = {
716 'permissions': [
717 {
718 'permission': 'change',
719 'permission_type': 'allow',
720 'trustee': {
721 'id': 'SID:S-1-5-21',
722 'name': 'newuser',
723 'type': 'user',
724 }
726 }
727 ]
728 }
730 self._mock_powerscale_api.modify_smb_share_access.return_value = None
731 rule_map = self.storage_connection.update_access(
732 self.mock_context, share, access_rules, [], [])
734 self._mock_powerscale_api.modify_smb_share_access.\
735 assert_called_once_with(
736 self.SHARE_NAME, host_acl=[], permissions=[])
737 self.assertEqual({}, rule_map)
739 def test_update_access_nfs_share_not_found(self):
740 share = {
741 "name": self.SHARE_NAME,
742 "share_proto": 'NFS',
743 }
744 access = {
745 'access_type': 'user',
746 'access_to': 'foouser',
747 'access_level': const.ACCESS_LEVEL_RW,
748 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
749 }
750 access_rules = [access]
751 self._mock_powerscale_api.lookup_nfs_export.return_value = None
753 rule_map = self.storage_connection.update_access(
754 self.mock_context, share, access_rules, [], [])
756 expected_rule_map = {
757 '09960614-8574-4e03-89cf-7cf267b0bd08': {
758 'state': 'error'
759 }
760 }
761 self.assertEqual(expected_rule_map, rule_map)
763 def test_update_access_nfs_http_error_on_clear_rules(self):
764 share = {
765 "name": self.SHARE_NAME,
766 "share_proto": 'NFS',
767 }
768 access = {
769 'access_type': 'user',
770 'access_to': 'foouser',
771 'access_level': const.ACCESS_LEVEL_RW,
772 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
773 }
774 access_rules = [access]
775 self._mock_powerscale_api.modify_nfs_export_access.return_value = False
777 rule_map = self.storage_connection.update_access(
778 self.mock_context, share, access_rules, [], [])
780 expected_rule_map = {
781 '09960614-8574-4e03-89cf-7cf267b0bd08': {
782 'state': 'error'
783 }
784 }
785 self.assertEqual(expected_rule_map, rule_map)
787 def test_update_access_cifs_http_error_on_clear_rules(self):
788 share = {
789 "name": self.SHARE_NAME,
790 "share_proto": 'CIFS',
791 }
792 access = {
793 'access_type': 'user',
794 'access_to': 'foo',
795 'access_level': const.ACCESS_LEVEL_RW,
796 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
797 }
798 access_rules = [access]
799 self._mock_powerscale_api.modify_smb_share_access.return_value = False
801 rule_map = self.storage_connection.update_access(
802 self.mock_context, share, access_rules, None, None)
804 expected_rule_map = {
805 '09960614-8574-4e03-89cf-7cf267b0bd08': {
806 'state': 'error'
807 }
808 }
809 self.assertEqual(expected_rule_map, rule_map)
811 def test_update_access_cifs_invalid_user_access_level(self):
812 share = {
813 "name": self.SHARE_NAME,
814 "share_proto": 'CIFS',
815 }
816 access = {
817 'access_type': 'user',
818 'access_to': 'foo',
819 'access_level': 'fake',
820 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
821 }
822 access_rules = [access]
823 self._mock_powerscale_api.modify_smb_share_access.return_value = False
825 rule_map = self.storage_connection.update_access(
826 self.mock_context, share, access_rules, [], [])
828 expected_rule_map = {
829 '09960614-8574-4e03-89cf-7cf267b0bd08': {
830 'state': 'error'
831 }
832 }
833 self.assertEqual(expected_rule_map, rule_map)
835 def test_update_access_cifs_user_not_found(self):
836 share = {
837 "name": self.SHARE_NAME,
838 "share_proto": 'CIFS',
839 }
840 access = {
841 'access_type': 'user',
842 'access_to': 'foo',
843 'access_level': const.ACCESS_LEVEL_RW,
844 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
845 }
846 access_rules = [access]
847 self._mock_powerscale_api.get_user_sid.return_value = None
848 self._mock_powerscale_api.modify_smb_share_access.return_value = True
850 rule_map = self.storage_connection.update_access(
851 self.mock_context, share, access_rules, [], [])
853 expected_rule_map = {
854 '09960614-8574-4e03-89cf-7cf267b0bd08': {
855 'state': 'error'
856 }
857 }
858 self.assertEqual(expected_rule_map, rule_map)
860 def test_update_access_cifs_invalid_access_type(self):
861 share = {
862 "name": self.SHARE_NAME,
863 "share_proto": 'CIFS',
864 }
865 access = {
866 'access_type': 'foo',
867 'access_to': 'foo',
868 'access_level': const.ACCESS_LEVEL_RW,
869 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
870 }
871 access_rules = [access]
873 rule_map = self.storage_connection.update_access(
874 self.mock_context, share, access_rules, [], [])
876 expected_rule_map = {
877 '09960614-8574-4e03-89cf-7cf267b0bd08': {
878 'state': 'error'
879 }
880 }
881 self.assertEqual(expected_rule_map, rule_map)
883 def test_update_access_recover_nfs(self):
884 # verify that new ips are added and ips not in rules are removed
885 share = {
886 "name": self.SHARE_NAME,
887 "share_proto": 'NFS',
888 }
889 fake_export_id = 4
890 self._mock_powerscale_api.lookup_nfs_export.return_value = (
891 fake_export_id)
892 self._mock_powerscale_api.get_nfs_export.return_value = {
893 'clients': ['10.1.1.8'],
894 'read_only_clients': ['10.2.0.2']
895 }
896 nfs_access_1 = {
897 'access_type': 'ip',
898 'access_to': '10.1.1.10',
899 'access_level': const.ACCESS_LEVEL_RW,
900 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
901 }
902 nfs_access_2 = {
903 'access_type': 'ip',
904 'access_to': '10.1.1.2',
905 'access_level': const.ACCESS_LEVEL_RO,
906 'access_id': '19960614-8574-4e03-89cf-7cf267b0bd08'
907 }
908 access_rules = [nfs_access_1, nfs_access_2]
910 self._mock_powerscale_api.modify_nfs_export_access.return_value = True
912 rule_map = self.storage_connection.update_access(
913 self.mock_context, share, access_rules, [], [])
915 expected_rule_map = {
916 '09960614-8574-4e03-89cf-7cf267b0bd08': {
917 'state': 'active'
918 },
919 '19960614-8574-4e03-89cf-7cf267b0bd08': {
920 'state': 'active'
921 }
922 }
923 self._mock_powerscale_api.modify_nfs_export_access. \
924 assert_called_once_with(fake_export_id,
925 ['10.1.1.2'],
926 ['10.1.1.10'])
927 self.assertEqual(expected_rule_map, rule_map)
929 def test_update_access_recover_cifs(self):
930 share = {
931 "name": self.SHARE_NAME,
932 "share_proto": 'CIFS',
933 }
934 self._mock_powerscale_api.get_user_sid.return_value = {
935 'id': 'SID:S-1-5-22',
936 'name': 'testuser',
937 'type': 'user',
938 }
939 self._mock_powerscale_api.modify_smb_share_access.return_value = True
940 access_1 = {
941 'access_type': 'ip',
942 'access_to': '10.1.1.10',
943 'access_level': const.ACCESS_LEVEL_RW,
944 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
945 }
946 access_2 = {
947 'access_type': 'user',
948 'access_to': 'testuser',
949 'access_level': const.ACCESS_LEVEL_RO,
950 'access_id': '19960614-8574-4e03-89cf-7cf267b0bd08'
951 }
952 access_rules = [access_1, access_2]
954 rule_map = self.storage_connection.update_access(
955 self.mock_context, share, access_rules, [], [])
957 expected_data = {
958 'host_acl': ['allow:10.1.1.10', 'deny:ALL'],
959 'permissions': [
960 {
961 'permission': 'read',
962 'permission_type': 'allow',
963 'trustee': {
964 'id': 'SID:S-1-5-22',
965 'name': 'testuser',
966 'type': 'user',
967 }
968 }
969 ]
970 }
971 expected_rule_map = {
972 '09960614-8574-4e03-89cf-7cf267b0bd08': {
973 'state': 'active'
974 },
975 '19960614-8574-4e03-89cf-7cf267b0bd08': {
976 'state': 'active'
977 }
978 }
979 self._mock_powerscale_api.lookup_smb_share.assert_not_called()
980 self._mock_powerscale_api.get_user_sid.assert_called_once_with(
981 'testuser')
982 self._mock_powerscale_api.modify_smb_share_access.\
983 assert_called_once_with(
984 self.SHARE_NAME,
985 host_acl=expected_data['host_acl'],
986 permissions=expected_data['permissions']
987 )
988 self.assertEqual(expected_rule_map, rule_map)
990 def test_update_access_with_cifs_ip_readonly(self):
991 # Note: Driver does not currently support readonly access for "ip" type
992 share = {'name': self.SHARE_NAME, 'share_proto': 'CIFS'}
993 access = {'access_type': 'ip', 'access_to': '10.1.1.10',
994 'access_level': const.ACCESS_LEVEL_RO,
995 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'}
997 rule_map = self.storage_connection.update_access(
998 self.mock_context, share, [access], None, None)
999 expected_rule_map = {
1000 '09960614-8574-4e03-89cf-7cf267b0bd08': {'state': 'error'}}
1001 self.assertEqual(expected_rule_map, rule_map)
1003 def test_delete_quota_when_quota_exists(self):
1004 path = '/path/to/quota'
1005 quota_id = '123'
1006 quota_data = {'id': quota_id}
1007 self._mock_powerscale_api.quota_get.return_value = quota_data
1008 self._mock_powerscale_api.delete_quota.return_value = True
1010 self.storage_connection._delete_quota(path)
1012 self._mock_powerscale_api.quota_get.assert_called_once_with(
1013 path, 'directory')
1014 self._mock_powerscale_api.delete_quota.assert_called_once_with(
1015 quota_id)
1017 def test_delete_quota_when_quota_does_not_exist(self):
1018 path = '/path/to/quota'
1019 self._mock_powerscale_api.quota_get.return_value = None
1021 self.storage_connection._delete_quota(path)
1023 self._mock_powerscale_api.quota_get.assert_called_once_with(
1024 path, 'directory')
1025 self._mock_powerscale_api.delete_quota.assert_not_called()
1027 def test_delete_directory_when_path_exists(self):
1028 path = '/path/to/directory'
1029 self.storage_connection._delete_directory(path)
1030 self._mock_powerscale_api.is_path_existent.assert_called_with(path)
1031 self._mock_powerscale_api.delete_path.assert_called_with(
1032 path, recursive=True)
1034 def test_delete_directory_when_path_does_not_exist(self):
1035 path = '/path/to/directory'
1036 self._mock_powerscale_api.is_path_existent.return_value = False
1037 self.storage_connection._delete_directory(path)
1038 self._mock_powerscale_api.is_path_existent.assert_called_with(path)
1039 self._mock_powerscale_api.delete_path.assert_not_called()
1041 def test_get_backend_info(self):
1042 self._mock_powerscale_api.get_cluster_version.return_value = '1.0'
1043 result = self.storage_connection.get_backend_info(None)
1044 expected_info = {
1045 'driver_version': powerscale.VERSION,
1046 'cluster_version': '1.0',
1047 'rest_server': self.POWERSCALE_ADDR,
1048 'rest_port': '8080',
1049 }
1050 self.assertEqual(expected_info, result)
1052 def test_ensure_shares_nfs_share_exists(self):
1053 share = {
1054 'id': '123',
1055 'share_proto': 'NFS',
1056 'name': 'my_share',
1057 }
1058 container_path = '/ifs/my_share'
1059 location = '10.0.0.1:/ifs/my_share'
1060 self.storage_connection._get_container_path = mock.MagicMock(
1061 return_value=container_path)
1062 self._mock_powerscale_api.lookup_nfs_export.return_value = '123'
1064 result = self.storage_connection.ensure_shares(None, [share])
1065 expected_result = {
1066 '123': {
1067 'export_locations': [location],
1068 'status': 'available',
1069 'reapply_access_rules': True,
1070 }
1071 }
1072 self.assertEqual(result, expected_result)
1074 def test_ensure_shares_cifs_share_exists(self):
1075 share = {
1076 'id': '123',
1077 'share_proto': 'CIFS',
1078 'name': 'my_share',
1079 }
1080 location = '\\\\10.0.0.1\\my_share'
1081 self._mock_powerscale_api.lookup_smb_share.return_value = share
1083 result = self.storage_connection.ensure_shares(None, [share])
1084 expected_result = {
1085 '123': {
1086 'export_locations': [location],
1087 'status': 'available',
1088 'reapply_access_rules': True,
1089 }
1090 }
1091 self.assertEqual(result, expected_result)
1093 def test_ensure_shares_nfs_share_does_not_exist(self):
1094 share = {
1095 'id': '123',
1096 'share_proto': 'NFS',
1097 'name': 'my_share',
1098 }
1099 self._mock_powerscale_api.lookup_nfs_export.return_value = None
1100 result = self.storage_connection.ensure_shares(None, [share])
1101 expected_result = {
1102 '123': {
1103 'export_locations': [],
1104 'status': 'error',
1105 'reapply_access_rules': False,
1106 }
1107 }
1108 self.assertEqual(result, expected_result)
1110 def test_ensure_shares_cifs_share_does_not_exist(self):
1111 share = {
1112 'id': '123',
1113 'share_proto': 'CIFS',
1114 'name': 'my_share',
1115 }
1116 self._mock_powerscale_api.lookup_smb_share.return_value = None
1117 result = self.storage_connection.ensure_shares(None, [share])
1118 expected_result = {
1119 '123': {
1120 'export_locations': [],
1121 'status': 'error',
1122 'reapply_access_rules': False,
1123 }
1124 }
1125 self.assertEqual(result, expected_result)
1127 def test_shrink_share_success(self):
1128 share = {"name": self.SHARE_NAME, "share_proto": "CIFS", "size": 8}
1129 path = f"{self.ROOT_DIR}/{self.SHARE_NAME}"
1130 self._mock_powerscale_api.quota_get.return_value = {
1131 'usage': {'logical': 5 * units.Gi}
1132 }
1133 self.storage_connection.shrink_share(share, new_size=6)
1134 self._mock_powerscale_api.quota_get.assert_called_once_with(
1135 path, 'directory'
1136 )
1137 self._mock_powerscale_api.quota_set.assert_called_once_with(
1138 path, 'directory', 6 * units.Gi
1139 )
1141 def test_shrink_share_raises_when_new_quota_less_than_used(self):
1142 share = {"name": self.SHARE_NAME, "share_proto": "NFS", "size": 8}
1143 path = f"{self.ROOT_DIR}/{self.SHARE_NAME}"
1144 self._mock_powerscale_api.quota_get.return_value = {
1145 'usage': {'logical': 7 * units.Gi}
1146 }
1147 self.assertRaises(
1148 exception.ShareShrinkingPossibleDataLoss,
1149 self.storage_connection.shrink_share,
1150 share, 6
1151 )
1152 self._mock_powerscale_api.quota_get.assert_called_once_with(
1153 path, 'directory'
1154 )
1155 self._mock_powerscale_api.quota_set.assert_not_called()
1157 def _get_base_snapshot(self):
1158 return {
1159 'id': 'snapshot-id-123',
1160 'provider_location': '123',
1161 'name': 'test-ss',
1162 'share': {
1163 'id': 'share-id-123',
1164 'name': self.SHARE_NAME,
1165 'mount_snapshot_support': False,
1166 'size': 8,
1167 "share_proto": "NFS",
1168 'export_locations': [{
1169 # NFS-style export: <ip>:/ifs/manila-test/share-foo
1170 'path': '%s:%s' % (self.POWERSCALE_ADDR, self.SHARE_DIR),
1171 }],
1172 },
1173 }
1175 def test_manage_existing_snapshot_not_found_in_backend(self):
1176 snapshot = self._get_base_snapshot()
1177 driver_options = {}
1179 # Backend returns no snapshot
1180 self._mock_powerscale_api.get_snapshot_id.return_value = None
1182 self.assertRaises(
1183 exception.ManageInvalidShareSnapshot,
1184 self.storage_connection.manage_existing_snapshot,
1185 snapshot,
1186 driver_options,
1187 )
1188 self._mock_powerscale_api.get_snapshot_id.assert_called_once_with(
1189 snapshot['provider_location'])
1191 def test_manage_existing_snapshot_share_path_mismatch(self):
1192 snapshot = self._get_base_snapshot()
1193 driver_options = {}
1195 # Snapshot exists but path does not match share export path
1196 self._mock_powerscale_api.get_snapshot_id.return_value = {
1197 'id': 'backend-snap-id',
1198 'path': '/ifs/some/other/path',
1199 }
1201 self.assertRaises(
1202 exception.ManageInvalidShareSnapshot,
1203 self.storage_connection.manage_existing_snapshot,
1204 snapshot,
1205 driver_options,
1206 )
1207 self._mock_powerscale_api.get_snapshot_id.assert_called_once_with(
1208 snapshot['provider_location'])
1210 def test_manage_existing_snapshot_invalid_size_value(self):
1211 snapshot = self._get_base_snapshot()
1212 driver_options = {
1213 # This will cause int("invalid") to raise ValueError
1214 'size': 'invalid',
1215 }
1217 self._mock_powerscale_api.get_snapshot_id.return_value = {
1218 'id': 'backend-snap-id',
1219 'path': self.SHARE_DIR,
1220 }
1222 self.assertRaises(
1223 exception.ManageInvalidShareSnapshot,
1224 self.storage_connection.manage_existing_snapshot,
1225 snapshot,
1226 driver_options,
1227 )
1229 def test_manage_existing_snapshot_invalid_size_type(self):
1230 snapshot = self._get_base_snapshot()
1231 driver_options = {
1232 # This will cause int(None) to raise TypeError
1233 'size': None,
1234 }
1236 self._mock_powerscale_api.get_snapshot_id.return_value = {
1237 'id': 'backend-snap-id',
1238 'path': self.SHARE_DIR,
1239 }
1241 self.assertRaises(
1242 exception.ManageInvalidShareSnapshot,
1243 self.storage_connection.manage_existing_snapshot,
1244 snapshot,
1245 driver_options,
1246 )
1248 def test_manage_existing_snapshot_no_size_uses_share_size(self):
1249 snapshot = self._get_base_snapshot()
1250 driver_options = {} # size not provided
1252 self._mock_powerscale_api.get_snapshot_id.return_value = {
1253 'id': 'backend-snap-id',
1254 'path': self.SHARE_DIR,
1255 }
1257 result = self.storage_connection.manage_existing_snapshot(
1258 snapshot, driver_options)
1260 self._mock_powerscale_api.get_snapshot_id.assert_called_once_with(
1261 snapshot['provider_location'])
1262 # Should fall back to share['size']
1263 self.assertEqual(
1264 {'size': snapshot['share']['size'],
1265 'provider_location': snapshot['provider_location']},
1266 result)
1268 def test_manage_existing_snapshot_explicit_size_used(self):
1269 snapshot = self._get_base_snapshot()
1270 driver_options = {
1271 'size': '3', # valid integer string
1272 }
1274 self._mock_powerscale_api.get_snapshot_id.return_value = {
1275 'id': 'backend-snap-id',
1276 'path': self.SHARE_DIR,
1277 }
1279 result = self.storage_connection.manage_existing_snapshot(
1280 snapshot, driver_options)
1282 self._mock_powerscale_api.get_snapshot_id.assert_called_once_with(
1283 snapshot['provider_location'])
1284 self.assertEqual(
1285 {'size': 3, 'provider_location': snapshot['provider_location']},
1286 result)
1288 def test_manage_existing_snapshot_with_mount_support(self):
1289 snapshot = self._get_base_snapshot()
1290 snapshot['share']['mount_snapshot_support'] = True
1291 driver_options = {
1292 'size': '3', # valid integer string
1293 }
1295 self._mock_powerscale_api.get_snapshot_id.return_value = {
1296 'id': 'backend-snap-id',
1297 'path': self.SHARE_DIR,
1298 'name': 'fake-snap-name',
1299 }
1301 result = self.storage_connection.manage_existing_snapshot(
1302 snapshot, driver_options)
1304 self._mock_powerscale_api.get_snapshot_id.assert_called_once_with(
1305 snapshot['provider_location'])
1306 self.assertEqual(
1307 {'size': 3, 'provider_location': snapshot['provider_location'],
1308 'export_locations': [{'is_admin_only': False,
1309 'metadata': {'preferred': True},
1310 'path': '10.0.0.1:/ifs/'
1311 '.snapshot/fake-snap-name'}]},
1312 result)
1314 def test_delete_snapshot_with_provider_location_success(self):
1315 share = {"name": self.SHARE_NAME, "share_proto": 'NFS',
1316 "mount_snapshot_support": False}
1317 snapshot = {
1318 'name': 'snap-001',
1319 'provider_location': 'backend-snap-loc-001',
1320 'share': share
1321 }
1323 # Backend delete succeeds
1324 (self._mock_powerscale_api.
1325 delete_snapshot_by_id).return_value = True
1327 # Should not raise
1328 self.storage_connection.delete_snapshot(
1329 self.mock_context, snapshot, share_server=None)
1331 # Must be called with provider_location, not name
1332 (self._mock_powerscale_api.delete_snapshot_by_id.
1333 assert_called_once_with(snapshot['provider_location']))
1335 def test_delete_snapshot_with_provider_location_failure(self):
1336 share = {"name": self.SHARE_NAME, "share_proto": 'NFS',
1337 "mount_snapshot_support": False}
1338 snapshot = {
1339 'name': 'snap-001',
1340 'provider_location': 'backend-snap-loc-001',
1341 'share': share
1342 }
1344 # Backend delete fails
1345 (self._mock_powerscale_api.
1346 delete_snapshot_by_id).return_value = False
1348 # Expect backend exception
1349 self.assertRaises(
1350 exception.ShareBackendException,
1351 self.storage_connection.delete_snapshot,
1352 self.mock_context,
1353 snapshot,
1354 None,
1355 )
1357 # Must be called with provider_location
1358 (self._mock_powerscale_api.delete_snapshot_by_id.
1359 assert_called_once_with(snapshot['provider_location']))
1361 def test_manage_existing_nfs_success(self):
1362 share = {
1363 'share_proto': 'NFS',
1364 'export_location': '10.0.0.1:/ifs/manila-test/share-foo',
1365 }
1366 self._mock_powerscale_api.lookup_nfs_export.return_value = 42
1367 self._mock_powerscale_api.quota_get.return_value = {
1368 'thresholds': {'hard': 10 * units.Gi},
1369 }
1370 result = self.storage_connection.manage_existing(
1371 share, driver_options={}
1372 )
1373 self.assertEqual(
1374 ['10.0.0.1:/ifs/manila-test/share-foo'],
1375 result['export_locations'],
1376 )
1377 self.assertEqual(10, result['size'])
1378 self._mock_powerscale_api.lookup_nfs_export.assert_called_once_with(
1379 '/ifs/manila-test/share-foo'
1380 )
1381 self._mock_powerscale_api.quota_get.assert_called_once_with(
1382 '/ifs/manila-test/share-foo', 'directory'
1383 )
1385 def test_manage_existing_nfs_not_found(self):
1386 share = {
1387 'share_proto': 'NFS',
1388 'export_location': '10.0.0.1:/ifs/missing',
1389 }
1390 self._mock_powerscale_api.lookup_nfs_export.return_value = None
1391 self.assertRaises(
1392 exception.ShareBackendException,
1393 self.storage_connection.manage_existing,
1394 share,
1395 driver_options={},
1396 )
1398 def test_manage_existing_cifs_success(self):
1399 share = {
1400 'share_proto': 'CIFS',
1401 'export_location': '\\\\10.0.0.1\\share-foo',
1402 }
1403 self._mock_powerscale_api.lookup_smb_share.return_value = {
1404 'name': 'share-foo',
1405 'path': '/ifs/manila-test/share-foo',
1406 }
1407 self._mock_powerscale_api.quota_get.return_value = {
1408 'thresholds': {'hard': 5 * units.Gi},
1409 }
1410 result = self.storage_connection.manage_existing(
1411 share, driver_options={}
1412 )
1413 self.assertEqual(
1414 ['\\\\10.0.0.1\\share-foo'], result['export_locations'],
1415 )
1416 self.assertEqual(5, result['size'])
1417 self._mock_powerscale_api.lookup_smb_share.assert_called_once_with(
1418 'share-foo'
1419 )
1420 self._mock_powerscale_api.quota_get.assert_called_once_with(
1421 '/ifs/manila-test/share-foo', 'directory'
1422 )
1424 def test_manage_existing_cifs_share_not_found(self):
1425 share = {
1426 'share_proto': 'CIFS',
1427 'export_location': '\\\\10.0.0.1\\missing',
1428 }
1429 self._mock_powerscale_api.lookup_smb_share.return_value = None
1430 self.assertRaises(
1431 exception.ShareBackendException,
1432 self.storage_connection.manage_existing,
1433 share,
1434 driver_options={},
1435 )
1437 def test_manage_existing_cifs_path_not_resolved(self):
1438 share = {
1439 'share_proto': 'CIFS',
1440 'export_location': '\\\\10.0.0.1\\share-foo',
1441 }
1442 self._mock_powerscale_api.lookup_smb_share.return_value = {
1443 'name': 'share-foo'
1444 }
1445 self.assertRaises(
1446 exception.ShareBackendException,
1447 self.storage_connection.manage_existing,
1448 share,
1449 driver_options={},
1450 )
1452 def test_manage_existing_nfs_export_locations_fallback(self):
1453 """Fallback for export_location using export_locations list."""
1454 share = {
1455 'share_proto': 'NFS',
1456 'export_locations': ['10.0.0.2:/ifs/projects/teamX'],
1457 }
1458 self._mock_powerscale_api.lookup_nfs_export.return_value = 77
1459 self._mock_powerscale_api.quota_get.return_value = {
1460 'thresholds': {'hard': 9 * units.Gi},
1461 }
1462 result = self.storage_connection.manage_existing(
1463 share, driver_options={}
1464 )
1465 self.assertEqual(
1466 ['10.0.0.2:/ifs/projects/teamX'], result['export_locations'],
1467 )
1468 self.assertEqual(9, result['size'])
1469 self._mock_powerscale_api.lookup_nfs_export.assert_called_once_with(
1470 '/ifs/projects/teamX'
1471 )
1472 self._mock_powerscale_api.quota_get.assert_called_once_with(
1473 '/ifs/projects/teamX', 'directory'
1474 )
1476 def test_manage_existing_cifs_export_locations_fallback(self):
1477 share = {
1478 'share_proto': 'CIFS',
1479 'export_locations': ['\\\\10.0.0.1\\share-foo'],
1480 }
1481 self._mock_powerscale_api.lookup_smb_share.return_value = {
1482 'name': 'share-foo',
1483 'path': f'{self.ROOT_DIR}/{self.SHARE_NAME}',
1484 }
1485 self._mock_powerscale_api.quota_get.return_value = {
1486 'thresholds': {'hard': 12 * units.Gi},
1487 }
1488 result = self.storage_connection.manage_existing(
1489 share, driver_options={}
1490 )
1491 self.assertEqual(
1492 ['\\\\10.0.0.1\\share-foo'],
1493 result['export_locations'],
1494 )
1495 self.assertEqual(12, result['size'])
1496 self._mock_powerscale_api.lookup_smb_share.assert_called_once_with(
1497 'share-foo'
1498 )
1499 self._mock_powerscale_api.quota_get.assert_called_once_with(
1500 f'{self.ROOT_DIR}/{self.SHARE_NAME}', 'directory'
1501 )
1503 def test_manage_existing_cifs_raises_when_quota_absent(self):
1504 share = {
1505 'share_proto': 'CIFS',
1506 'export_location': '\\\\10.0.0.1\\share-foo',
1507 }
1508 self._mock_powerscale_api.lookup_smb_share.return_value = {
1509 'name': 'share-foo',
1510 'path': f'{self.ROOT_DIR}/{self.SHARE_NAME}',
1511 }
1512 self._mock_powerscale_api.quota_get.return_value = None
1514 self.assertRaises(
1515 exception.ManageInvalidShare,
1516 self.storage_connection.manage_existing,
1517 share,
1518 driver_options={},
1519 )
1521 def test_manage_existing_nfs_raises_when_quota_absent(self):
1522 share = {
1523 'share_proto': 'NFS',
1524 'export_location': '10.0.0.1:/ifs/projects/teamX',
1525 }
1526 self._mock_powerscale_api.lookup_nfs_export.return_value = 42
1527 self._mock_powerscale_api.quota_get.return_value = None
1529 self.assertRaises(
1530 exception.ManageInvalidShare,
1531 self.storage_connection.manage_existing,
1532 share,
1533 driver_options={},
1534 )
1536 def test_manage_existing_raises_when_hard_limit_missing_usage_only(self):
1537 share = {
1538 'share_proto': 'CIFS',
1539 'export_location': '\\\\10.0.0.1\\share-foo',
1540 }
1541 self._mock_powerscale_api.lookup_smb_share.return_value = {
1542 'name': 'share-foo',
1543 'path': f'{self.ROOT_DIR}/{self.SHARE_NAME}',
1544 }
1545 self._mock_powerscale_api.quota_get.return_value = {
1546 'usage': {'logical': 7 * units.Gi},
1547 }
1548 self.assertRaises(
1549 exception.ManageInvalidShare,
1550 self.storage_connection.manage_existing,
1551 share,
1552 driver_options={},
1553 )
1555 def _make_snapshot(self, proto="NFS"):
1556 return {
1557 "name": "snap-001",
1558 "share": {
1559 "share_proto": proto,
1560 }
1561 }
1563 def test_create_snap_export_path_nfs(self):
1564 snapshot = self._make_snapshot(proto="NFS")
1566 snap_path = "/ifs/manila-test/.snapshots/snap-001"
1567 export_path = "%s:%s" % (self.POWERSCALE_ADDR, snap_path)
1568 expected_location = [{"path": export_path,
1569 "is_admin_only": False,
1570 "metadata": {"preferred": True}}]
1571 self.storage_connection._format_nfs_path = mock.Mock(
1572 return_value=export_path)
1573 self.storage_connection._get_location = mock.Mock(
1574 return_value=expected_location)
1575 self.storage_connection._get_snapshot_path = mock.Mock(
1576 return_value=snap_path)
1577 (self._mock_powerscale_api.
1578 lookup_nfs_export).return_value = None
1579 (self.
1580 _mock_powerscale_api.
1581 create_snapshot_nfs_export).return_value = True
1582 result = self.storage_connection._create_snap_export_path(snapshot)
1583 self.storage_connection._get_snapshot_path.assert_called_once_with(
1584 snapshot)
1585 (self.
1586 _mock_powerscale_api.
1587 create_snapshot_nfs_export.assert_called_once_with(snap_path))
1588 self.storage_connection._format_nfs_path.assert_called_once_with(
1589 snap_path)
1590 self.storage_connection._get_location.assert_called_once_with(
1591 {export_path: True})
1592 self.assertEqual({"export_locations": expected_location}, result)
1594 def test_create_snap_export_path_cifs(self):
1595 snap_path = "/ifs/manila-test/.snapshots/snap-001"
1596 snapshot = self._make_snapshot(proto="CIFS")
1597 smb_export_path = "\\\\%s\\snap-001" % self.POWERSCALE_ADDR
1598 expected_location = [{"path": smb_export_path,
1599 "is_admin_only": False,
1600 "metadata": {"preferred": True}}]
1601 self.storage_connection._format_smb_path = mock.Mock(
1602 return_value=smb_export_path)
1603 self.storage_connection._get_location = mock.Mock(
1604 return_value=expected_location)
1605 self.storage_connection._get_snapshot_path = mock.Mock(
1606 return_value=snap_path)
1607 (self.
1608 _mock_powerscale_api.
1609 create_snapshot_smb_export).return_value = True
1610 (self._mock_powerscale_api.
1611 lookup_smb_share).return_value = None
1612 result = self.storage_connection._create_snap_export_path(snapshot)
1613 self.storage_connection._get_snapshot_path.assert_called_once_with(
1614 snapshot)
1615 (self.
1616 _mock_powerscale_api.
1617 create_snapshot_smb_export.assert_called_once_with("snap-001",
1618 snap_path))
1619 self.storage_connection._format_smb_path.assert_called_once_with(
1620 "snap-001")
1621 self.storage_connection._get_location.assert_called_once_with(
1622 {smb_export_path: True})
1624 self.assertEqual({"export_locations": expected_location}, result)
1626 def test_create_snap_export_path_failure_raises(self):
1627 snapshot = self._make_snapshot(proto="NFS")
1628 snap_path = "/ifs/manila-test/.snapshots/snap-001"
1629 self.storage_connection._get_snapshot_path = mock.Mock(
1630 return_value=snap_path)
1631 (self._mock_powerscale_api.
1632 lookup_nfs_export).return_value = None
1633 (self.
1634 _mock_powerscale_api.
1635 create_snapshot_nfs_export).return_value = False
1636 self.assertRaises(
1637 exception.ShareBackendException,
1638 self.storage_connection._create_snap_export_path,
1639 snapshot)
1641 def test_snapshot_update_access_nfs(self):
1642 snapshot = self._make_snapshot(proto="NFS")
1643 access_rules = [{"access_to": "10.10.10.10"}]
1644 snap_path = "/ifs/manila-test/.snapshots/snap-001"
1645 expected_state = {"10.10.10.10": "active"}
1646 self.storage_connection._get_snapshot_path = mock.Mock(
1647 return_value=snap_path)
1648 self.storage_connection._update_access_nfs = mock.Mock(
1649 return_value=expected_state)
1650 result = self.storage_connection.snapshot_update_access(
1651 self.mock_context,
1652 snapshot,
1653 access_rules,
1654 add_rules=None,
1655 delete_rules=None,
1656 share_server=None)
1657 self.storage_connection._get_snapshot_path.assert_called_once_with(
1658 snapshot)
1659 self.storage_connection._update_access_nfs.assert_called_once_with(
1660 "snap-001", snap_path, access_rules)
1661 self.assertEqual(expected_state, result)
1663 def test_snapshot_update_access_cifs(self):
1664 snapshot = self._make_snapshot(proto="CIFS")
1665 access_rules = [{"access_to": "user1"}]
1666 expected_state = {"user1": "active"}
1667 self.storage_connection._update_access_cifs = mock.Mock(
1668 return_value=expected_state)
1669 result = self.storage_connection.snapshot_update_access(
1670 self.mock_context,
1671 snapshot,
1672 access_rules,
1673 add_rules=None,
1674 delete_rules=None,
1675 share_server=None)
1676 self.storage_connection._update_access_cifs.assert_called_once_with(
1677 "snap-001", access_rules, read_only=True)
1678 self.assertEqual(expected_state, result)
1680 def test_update_snapshot_ip_access_rule(self):
1681 snapshot = self._make_snapshot(proto="CIFS")
1682 access = {
1683 'access_type': 'ip',
1684 'access_to': '1.1.1.1',
1685 'access_level': const.ACCESS_LEVEL_RO,
1686 'access_id': '09960614-8574-4e03-89cf-7cf267b0bd08'
1687 }
1688 access_rules = [access]
1689 self._mock_powerscale_api.modify_smb_share_access.return_value = True
1690 rule_map = self.storage_connection.snapshot_update_access(
1691 self.mock_context,
1692 snapshot,
1693 access_rules,
1694 add_rules=None,
1695 delete_rules=None,
1696 share_server=None)
1697 expected_rule_map = {
1698 '09960614-8574-4e03-89cf-7cf267b0bd08': {
1699 'state': 'active'
1700 }
1701 }
1702 self.assertEqual(expected_rule_map, rule_map)
1704 def test_create_snapshot_with_mount_support(self):
1705 snapshot_name = "snapshot01"
1706 snapshot_path = '/ifs/home/admin'
1707 share = {"name": self.SHARE_NAME, "share_proto": 'NFS',
1708 "mount_snapshot_support": True}
1709 snapshot = {'name': snapshot_name, 'share_name': snapshot_path,
1710 'share': share}
1711 self.storage_connection.create_snapshot(self.mock_context, snapshot,
1712 None)
1713 self._mock_powerscale_api.create_snapshot.assert_called_with(
1714 snapshot_name, snapshot_path)
1716 def test_create_share_nfs_with_mount_point_name(self):
1717 share_path = self.SHARE_DIR
1718 mount_point_name = "/my_custom_share"
1719 alias_path = mount_point_name
1720 self._mock_powerscale_api.create_nfs_export.return_value = True
1721 self._mock_powerscale_api.create_nfs_export_aliases.return_value = True
1723 self.assertFalse(self._mock_powerscale_api.create_directory.called)
1724 self.assertFalse(self._mock_powerscale_api.create_nfs_export.called)
1725 self.assertFalse(
1726 self._mock_powerscale_api.create_nfs_export_aliases.called)
1727 share = {
1728 "name": self.SHARE_NAME,
1729 "share_proto": 'NFS',
1730 "size": 8,
1731 "mount_point_name": "my_custom_share",
1732 'share_type_id': 'fake_id',
1733 }
1734 location = self.storage_connection.create_share(
1735 self.mock_context, share, None)
1736 original_path = '%s:%s' % (self.POWERSCALE_ADDR, share_path)
1737 alias_export_path = '%s:%s' % (self.POWERSCALE_ADDR, alias_path)
1738 expected_location = [
1739 {
1740 'is_admin_only': False,
1741 'metadata': {'preferred': False},
1742 'path': original_path,
1743 },
1744 {
1745 'is_admin_only': False,
1746 'metadata': {'preferred': True},
1747 'path': alias_export_path,
1748 }
1749 ]
1750 self.assertEqual(expected_location, location)
1751 self._mock_powerscale_api.create_directory.assert_called_once_with(
1752 share_path, False)
1753 self._mock_powerscale_api.create_nfs_export.assert_called_once_with(
1754 share_path)
1755 (self._mock_powerscale_api.create_nfs_export_aliases.
1756 assert_called_once_with(mount_point_name, share_path))
1757 self._mock_powerscale_api.quota_create.assert_called_once_with(
1758 share_path, 'directory', 8 * units.Gi)
1760 def test_failed_to_create_share_nfs_with_mount_point_name(self):
1761 self._mock_powerscale_api.create_nfs_export.return_value = True
1762 (self._mock_powerscale_api.
1763 create_nfs_export_aliases).return_value = False
1764 self.assertFalse(self._mock_powerscale_api.create_directory.called)
1765 self.assertFalse(self._mock_powerscale_api.create_nfs_export.called)
1766 self.assertFalse(
1767 self._mock_powerscale_api.create_nfs_export_aliases.called)
1768 share = {
1769 "name": self.SHARE_NAME,
1770 "share_proto": 'NFS',
1771 "size": 8,
1772 "mount_point_name": "my_custom_share",
1773 }
1774 self.assertRaises(exception.ShareBackendException,
1775 self.storage_connection.create_share,
1776 self.mock_context, share,
1777 share_server=None)
1779 def test_create_share_cifs_with_mount_point_name(self):
1780 self._mock_powerscale_api.create_smb_share.return_value = True
1781 share = {
1782 "name": self.SHARE_NAME,
1783 "share_proto": 'CIFS',
1784 "size": 8,
1785 "mount_point_name": "custom_smb",
1786 'share_type_id': 'fake_id',
1787 }
1788 location = self.storage_connection.create_share(
1789 self.mock_context, share, None)
1791 path = '\\\\{0}\\{1}'.format(self.POWERSCALE_ADDR, "custom_smb")
1792 expected_location = [{
1793 'is_admin_only': False,
1794 'metadata': {'preferred': True},
1795 'path': path,
1796 }]
1797 self.assertEqual(expected_location, location)
1798 self._mock_powerscale_api.create_smb_share.assert_called_once_with(
1799 "custom_smb", self.SHARE_DIR)
1801 def test_delete_share_nfs_with_mount_point_alias_deleted(self):
1802 share = {
1803 "name": self.SHARE_NAME,
1804 "share_proto": "NFS",
1805 "mount_point_name": "my_custom_share",
1806 }
1807 fake_share_id = 42
1808 (self._mock_powerscale_api.
1809 lookup_nfs_export).return_value = fake_share_id
1810 self._mock_powerscale_api.delete_nfs_share.return_value = True
1811 self.storage_connection._check_valid_aliases = mock.MagicMock(
1812 return_value=True)
1813 self._mock_powerscale_api.delete_nfs_export_aliases.return_value = True
1814 self.storage_connection.delete_share(self.mock_context, share, None)
1815 self._mock_powerscale_api.lookup_nfs_export.assert_called_once_with(
1816 self.storage_connection._get_container_path(share)
1817 )
1818 (self._mock_powerscale_api.
1819 delete_nfs_share.assert_called_once_with(fake_share_id))
1820 (self._mock_powerscale_api.
1821 delete_nfs_export_aliases.assert_called_once_with("/my_custom_share"))
1823 def test_delete_invalid_share_nfs_with_mount_point_alias_deleted(self):
1824 share = {
1825 "name": self.SHARE_NAME,
1826 "share_proto": "NFS",
1827 "mount_point_name": "my_custom_share",
1828 }
1829 fake_share_id = 42
1830 (self._mock_powerscale_api.
1831 lookup_nfs_export).return_value = fake_share_id
1832 self._mock_powerscale_api.delete_nfs_share.return_value = True
1833 self.storage_connection._check_valid_aliases = mock.MagicMock(
1834 return_value=False)
1835 self.storage_connection.delete_share(self.mock_context, share, None)
1836 self._mock_powerscale_api.lookup_nfs_export.assert_called_once_with(
1837 self.storage_connection._get_container_path(share)
1838 )
1839 (self._mock_powerscale_api.
1840 delete_nfs_share.assert_called_once_with(fake_share_id))
1841 (self._mock_powerscale_api.
1842 delete_nfs_export_aliases.assert_not_called())
1844 def test_failed_to_delete_share_nfs_with_mount_point_alias_deleted(self):
1845 share = {
1846 "name": self.SHARE_NAME,
1847 "share_proto": "NFS",
1848 "mount_point_name": "my_custom_share",
1849 }
1850 fake_share_id = 42
1851 (self._mock_powerscale_api.
1852 lookup_nfs_export).return_value = fake_share_id
1853 self._mock_powerscale_api.delete_nfs_share.return_value = True
1854 self.storage_connection._check_valid_aliases = mock.MagicMock(
1855 return_value=True)
1856 (self._mock_powerscale_api.
1857 delete_nfs_export_aliases).return_value = False
1858 self.assertRaises(exception.ShareBackendException,
1859 self.storage_connection.delete_share,
1860 self.mock_context, share,
1861 share_server=None)
1863 def test_delete_share_cifs_with_mount_point_name(self):
1864 self.assertFalse(self._mock_powerscale_api.delete_smb_share.called)
1865 share = {"name": self.SHARE_NAME, "share_proto": 'CIFS',
1866 "mount_point_name": "my_custom_share", }
1867 self._mock_powerscale_api.lookup_smb_share.return_value = {
1868 'id': self.SHARE_NAME,
1869 'path': '/ifs/manila-test/share-foo',
1870 }
1871 container_path = '/ifs/manila-test/share-foo'
1872 self.storage_connection._get_container_path = mock.MagicMock(
1873 return_value=container_path)
1874 self.storage_connection.delete_share(self.mock_context, share, None)
1875 self._mock_powerscale_api.delete_smb_share.assert_called_with(
1876 'my_custom_share')
1878 def test_delete_invalid_share_cifs_with_mount_point_name(self):
1879 self.assertFalse(self._mock_powerscale_api.delete_smb_share.called)
1880 share = {"name": self.SHARE_NAME, "share_proto": 'CIFS',
1881 "mount_point_name": "my_custom_share", }
1882 self._mock_powerscale_api.lookup_smb_share.return_value = {
1883 'id': self.SHARE_NAME,
1884 'path': '/ifs/manila-test/share-foo-test',
1885 }
1886 container_path = '/ifs/manila-test/share-foo'
1887 self.storage_connection._get_container_path = mock.MagicMock(
1888 return_value=container_path)
1889 self.storage_connection.delete_share(self.mock_context, share, None)
1890 self._mock_powerscale_api.delete_smb_share.assert_not_called()
1892 def test_ensure_shares_nfs_share_exists_with_mount_point_name(self):
1893 share = {
1894 'id': '123',
1895 'share_proto': 'NFS',
1896 'name': 'my_share',
1897 "mount_point_name": "my_custom_share",
1898 }
1899 container_path = '/ifs/my_share'
1900 location = ['10.0.0.1:/ifs/my_share',
1901 '10.0.0.1:/my_custom_share']
1902 self.storage_connection._get_container_path = mock.MagicMock(
1903 return_value=container_path)
1904 self._mock_powerscale_api.lookup_nfs_export.return_value = '123'
1905 result = self.storage_connection.ensure_shares(None,
1906 [share])
1907 expected_result = {
1908 '123': {
1909 'export_locations': location,
1910 'status': 'available',
1911 'reapply_access_rules': True,
1912 }
1913 }
1914 self.assertEqual(result, expected_result)
1916 def test_ensure_shares_cifs_share_exists_with_mount_point_name(self):
1917 share = {
1918 'id': '123',
1919 'share_proto': 'CIFS',
1920 'name': 'my_share',
1921 "mount_point_name": "my_custom_share",
1922 }
1923 location = '\\\\10.0.0.1\\my_custom_share'
1924 self._mock_powerscale_api.lookup_smb_share.return_value = share
1926 result = self.storage_connection.ensure_shares(None,
1927 [share])
1928 expected_result = {
1929 '123': {
1930 'export_locations': [location],
1931 'status': 'available',
1932 'reapply_access_rules': True,
1933 }
1934 }
1935 self.assertEqual(result, expected_result)
1937 def test_check_valid_aliases_success(self):
1938 mount_point_name = '/my_alias'
1939 container_path = '/ifs/manila/share-123'
1940 self._mock_powerscale_api.get_nfs_export_aliases.return_value = {
1941 'path': container_path
1942 }
1943 result = self.storage_connection._check_valid_aliases(
1944 mount_point_name, container_path)
1945 self.assertTrue(result)
1946 (self._mock_powerscale_api.
1947 get_nfs_export_aliases.assert_called_once_with(mount_point_name))
1949 def test_check_valid_aliases_path_mismatch(self):
1950 mount_point_name = '/my_alias'
1951 container_path = '/ifs/manila/share-123'
1952 self._mock_powerscale_api.get_nfs_export_aliases.return_value = {
1953 'path': '/ifs/manila/other-share'
1954 }
1955 result = self.storage_connection._check_valid_aliases(
1956 mount_point_name, container_path)
1957 self.assertFalse(result)
1958 (self._mock_powerscale_api.
1959 get_nfs_export_aliases.assert_called_once_with(mount_point_name))