Coverage for manila/tests/share/drivers/hitachi/hsp/test_driver.py: 100%
234 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) 2016 Hitachi Data Systems, Inc.
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_config import cfg
21from manila import exception
22import manila.share.configuration
23import manila.share.driver
24from manila.share.drivers.hitachi.hsp import driver
25from manila.share.drivers.hitachi.hsp import rest
26from manila import test
27from manila.tests import fake_share
28from manila.tests.share.drivers.hitachi.hsp import fakes
30from manila.common import constants
31from oslo_utils import units
33CONF = cfg.CONF
36@ddt.ddt
37class HitachiHSPTestCase(test.TestCase):
38 def setUp(self):
39 super(HitachiHSPTestCase, self).setUp()
40 CONF.set_default('driver_handles_share_servers', False)
41 CONF.hitachi_hsp_host = '172.24.47.190'
42 CONF.hitachi_hsp_username = 'hsp_user'
43 CONF.hitachi_hsp_password = 'hsp_password'
44 CONF.hitachi_hsp_job_timeout = 300
46 self.fake_el = [{
47 "path": CONF.hitachi_hsp_host + ":/fakeinstanceid",
48 "metadata": {},
49 "is_admin_only": False,
50 }]
51 self.fake_share = fake_share.fake_share(share_proto='nfs')
52 self.fake_share_instance = fake_share.fake_share_instance(
53 base_share=self.fake_share, export_locations=self.fake_el)
55 self.fake_conf = manila.share.configuration.Configuration(None)
56 self.fake_private_storage = mock.Mock()
57 self.mock_object(rest.HSPRestBackend, "get_cluster",
58 mock.Mock(return_value=fakes.hsp_cluster))
59 self._driver = driver.HitachiHSPDriver(
60 configuration=self.fake_conf,
61 private_storage=self.fake_private_storage)
62 self._driver.backend_name = "HSP"
63 self.mock_log = self.mock_object(driver, 'LOG')
65 @ddt.data(None, exception.HSPBackendException(
66 message="Duplicate NFS access rule exists."))
67 def test_update_access_add(self, add_rule):
68 access = {
69 'access_type': 'ip',
70 'access_to': '172.24.10.10',
71 'access_level': 'rw',
72 }
74 access_list = [access]
76 self.mock_object(rest.HSPRestBackend, "get_file_system",
77 mock.Mock(return_value=fakes.file_system))
78 self.mock_object(rest.HSPRestBackend, "get_share",
79 mock.Mock(return_value=fakes.share))
80 self.mock_object(rest.HSPRestBackend, "add_access_rule", mock.Mock(
81 side_effect=add_rule))
83 self._driver.update_access('context', self.fake_share_instance, [],
84 access_list, [], [])
86 self.assertTrue(self.mock_log.debug.called)
88 rest.HSPRestBackend.get_file_system.assert_called_once_with(
89 self.fake_share_instance['id'])
90 rest.HSPRestBackend.get_share.assert_called_once_with(
91 fakes.file_system['id'])
92 rest.HSPRestBackend.add_access_rule.assert_called_once_with(
93 fakes.share['id'], access['access_to'],
94 (access['access_level'] == constants.ACCESS_LEVEL_RW))
96 def test_update_access_add_exception(self):
97 access = {
98 'access_type': 'ip',
99 'access_to': '172.24.10.10',
100 'access_level': 'rw',
101 }
103 access_list = [access]
105 self.mock_object(rest.HSPRestBackend, "get_file_system",
106 mock.Mock(return_value=fakes.file_system))
107 self.mock_object(rest.HSPRestBackend, "get_share",
108 mock.Mock(return_value=fakes.share))
109 self.mock_object(rest.HSPRestBackend, "add_access_rule",
110 mock.Mock(side_effect=exception.HSPBackendException(
111 message="HSP Backend Exception: error adding "
112 "rule.")))
114 self.assertRaises(exception.HSPBackendException,
115 self._driver.update_access, 'context',
116 self.fake_share_instance, [], access_list, [], [])
118 rest.HSPRestBackend.get_file_system.assert_called_once_with(
119 self.fake_share_instance['id'])
120 rest.HSPRestBackend.get_share.assert_called_once_with(
121 fakes.file_system['id'])
122 rest.HSPRestBackend.add_access_rule.assert_called_once_with(
123 fakes.share['id'], access['access_to'],
124 (access['access_level'] == constants.ACCESS_LEVEL_RW))
126 def test_update_access_recovery(self):
127 access1 = {
128 'access_type': 'ip',
129 'access_to': '172.24.10.10',
130 'access_level': 'rw',
131 }
132 access2 = {
133 'access_type': 'ip',
134 'access_to': '188.100.20.10',
135 'access_level': 'ro',
136 }
138 access_list = [access1, access2]
140 self.mock_object(rest.HSPRestBackend, "get_file_system",
141 mock.Mock(return_value=fakes.file_system))
142 self.mock_object(rest.HSPRestBackend, "get_share",
143 mock.Mock(return_value=fakes.share))
144 self.mock_object(rest.HSPRestBackend, "get_access_rules",
145 mock.Mock(side_effect=[fakes.hsp_rules, []]))
146 self.mock_object(rest.HSPRestBackend, "delete_access_rule")
147 self.mock_object(rest.HSPRestBackend, "add_access_rule")
149 self._driver.update_access('context', self.fake_share_instance,
150 access_list, [], [], [])
152 self.assertTrue(self.mock_log.debug.called)
154 rest.HSPRestBackend.get_file_system.assert_called_once_with(
155 self.fake_share_instance['id'])
156 rest.HSPRestBackend.get_share.assert_called_once_with(
157 fakes.file_system['id'])
158 rest.HSPRestBackend.get_access_rules.assert_has_calls([
159 mock.call(fakes.share['id'])])
160 rest.HSPRestBackend.delete_access_rule.assert_called_once_with(
161 fakes.share['id'],
162 fakes.share['id'] + fakes.hsp_rules[0]['host-specification'])
163 rest.HSPRestBackend.add_access_rule.assert_has_calls([
164 mock.call(fakes.share['id'], access1['access_to'], True),
165 mock.call(fakes.share['id'], access2['access_to'], False)
166 ], any_order=True)
168 @ddt.data(None, exception.HSPBackendException(
169 message="No matching access rule found."))
170 def test_update_access_delete(self, delete_rule):
171 access1 = {
172 'access_type': 'ip',
173 'access_to': '172.24.44.200',
174 'access_level': 'rw',
175 }
176 access2 = {
177 'access_type': 'something',
178 'access_to': '188.100.20.10',
179 'access_level': 'ro',
180 }
182 delete_rules = [access1, access2]
184 self.mock_object(rest.HSPRestBackend, "get_file_system",
185 mock.Mock(return_value=fakes.file_system))
186 self.mock_object(rest.HSPRestBackend, "get_share",
187 mock.Mock(return_value=fakes.share))
188 self.mock_object(rest.HSPRestBackend, "delete_access_rule",
189 mock.Mock(side_effect=delete_rule))
190 self.mock_object(rest.HSPRestBackend, "get_access_rules",
191 mock.Mock(return_value=fakes.hsp_rules))
193 self._driver.update_access('context', self.fake_share_instance, [], [],
194 delete_rules, [])
196 self.assertTrue(self.mock_log.debug.called)
198 rest.HSPRestBackend.get_file_system.assert_called_once_with(
199 self.fake_share_instance['id'])
200 rest.HSPRestBackend.get_share.assert_called_once_with(
201 fakes.file_system['id'])
202 rest.HSPRestBackend.delete_access_rule.assert_called_once_with(
203 fakes.share['id'], fakes.hsp_rules[0]['name'])
204 rest.HSPRestBackend.get_access_rules.assert_called_once_with(
205 fakes.share['id'])
207 def test_update_access_delete_exception(self):
208 access1 = {
209 'access_type': 'ip',
210 'access_to': '172.24.10.10',
211 'access_level': 'rw',
212 }
213 access2 = {
214 'access_type': 'something',
215 'access_to': '188.100.20.10',
216 'access_level': 'ro',
217 }
219 delete_rules = [access1, access2]
221 self.mock_object(rest.HSPRestBackend, "get_file_system",
222 mock.Mock(return_value=fakes.file_system))
223 self.mock_object(rest.HSPRestBackend, "get_share",
224 mock.Mock(return_value=fakes.share))
225 self.mock_object(rest.HSPRestBackend, "delete_access_rule",
226 mock.Mock(side_effect=exception.HSPBackendException(
227 message="HSP Backend Exception: error deleting "
228 "rule.")))
229 self.mock_object(rest.HSPRestBackend, 'get_access_rules',
230 mock.Mock(return_value=[]))
232 self.assertRaises(exception.HSPBackendException,
233 self._driver.update_access, 'context',
234 self.fake_share_instance, [], [], delete_rules, [])
236 self.assertTrue(self.mock_log.debug.called)
238 rest.HSPRestBackend.get_file_system.assert_called_once_with(
239 self.fake_share_instance['id'])
240 rest.HSPRestBackend.get_share.assert_called_once_with(
241 fakes.file_system['id'])
242 rest.HSPRestBackend.delete_access_rule.assert_called_once_with(
243 fakes.share['id'], fakes.share['id'] + access1['access_to'])
244 rest.HSPRestBackend.get_access_rules.assert_called_once_with(
245 fakes.share['id'])
247 @ddt.data(True, False)
248 def test_update_access_ip_exception(self, is_recovery):
249 access = {
250 'access_type': 'something',
251 'access_to': '172.24.10.10',
252 'access_level': 'rw',
253 }
255 access_list = [access]
257 self.mock_object(rest.HSPRestBackend, "get_file_system",
258 mock.Mock(return_value=fakes.file_system))
259 self.mock_object(rest.HSPRestBackend, "get_share",
260 mock.Mock(return_value=fakes.share))
261 self.mock_object(rest.HSPRestBackend, "get_access_rules",
262 mock.Mock(return_value=fakes.hsp_rules))
264 if is_recovery:
265 access_args = [access_list, [], [], []]
266 else:
267 access_args = [[], access_list, [], []]
269 self.assertRaises(exception.InvalidShareAccess,
270 self._driver.update_access, 'context',
271 self.fake_share_instance, *access_args)
273 rest.HSPRestBackend.get_file_system.assert_called_once_with(
274 self.fake_share_instance['id'])
275 rest.HSPRestBackend.get_share.assert_called_once_with(
276 fakes.file_system['id'])
278 if is_recovery:
279 rest.HSPRestBackend.get_access_rules.assert_called_once_with(
280 fakes.share['id'])
282 def test_update_access_not_found_exception(self):
283 access_list = []
285 self.mock_object(rest.HSPRestBackend, "get_file_system", mock.Mock(
286 side_effect=exception.HSPItemNotFoundException(msg='fake')))
288 self.assertRaises(exception.ShareResourceNotFound,
289 self._driver.update_access, 'context',
290 self.fake_share_instance, access_list, [], [], [])
292 rest.HSPRestBackend.get_file_system.assert_called_once_with(
293 self.fake_share_instance['id'])
295 def test_create_share(self):
296 self.mock_object(rest.HSPRestBackend, "add_file_system", mock.Mock())
297 self.mock_object(rest.HSPRestBackend, "get_file_system",
298 mock.Mock(return_value=fakes.file_system))
299 self.mock_object(rest.HSPRestBackend, "add_share", mock.Mock())
301 result = self._driver.create_share('context', self.fake_share_instance)
303 self.assertEqual(self.fake_el, result)
304 self.assertTrue(self.mock_log.debug.called)
306 rest.HSPRestBackend.add_file_system.assert_called_once_with(
307 self.fake_share_instance['id'],
308 self.fake_share_instance['size'] * units.Gi)
309 rest.HSPRestBackend.get_file_system.assert_called_once_with(
310 self.fake_share_instance['id'])
311 rest.HSPRestBackend.add_share.assert_called_once_with(
312 self.fake_share_instance['id'], fakes.file_system['id'])
314 def test_create_share_export_error(self):
315 self.mock_object(rest.HSPRestBackend, "add_file_system", mock.Mock())
316 self.mock_object(rest.HSPRestBackend, "get_file_system",
317 mock.Mock(return_value=fakes.file_system))
318 self.mock_object(rest.HSPRestBackend, "add_share", mock.Mock(
319 side_effect=exception.HSPBackendException(msg='fake')))
320 self.mock_object(rest.HSPRestBackend, "delete_file_system",
321 mock.Mock())
323 self.assertRaises(exception.HSPBackendException,
324 self._driver.create_share, 'context',
325 self.fake_share_instance)
326 self.assertTrue(self.mock_log.debug.called)
327 self.assertTrue(self.mock_log.exception.called)
329 rest.HSPRestBackend.add_file_system.assert_called_once_with(
330 self.fake_share_instance['id'],
331 self.fake_share_instance['size'] * units.Gi)
332 rest.HSPRestBackend.get_file_system.assert_called_once_with(
333 self.fake_share_instance['id'])
334 rest.HSPRestBackend.add_share.assert_called_once_with(
335 self.fake_share_instance['id'], fakes.file_system['id'])
336 rest.HSPRestBackend.delete_file_system.assert_called_once_with(
337 fakes.file_system['id'])
339 def test_create_share_invalid_share_protocol(self):
340 self.assertRaises(exception.InvalidShare,
341 self._driver.create_share, 'context',
342 fakes.invalid_share)
344 @ddt.data(None, exception.HSPBackendException(
345 message="No matching access rule found."))
346 def test_delete_share(self, delete_rule):
347 self.mock_object(rest.HSPRestBackend, "get_file_system",
348 mock.Mock(return_value=fakes.file_system))
349 self.mock_object(rest.HSPRestBackend, "get_share",
350 mock.Mock(return_value=fakes.share))
351 self.mock_object(rest.HSPRestBackend, "delete_share")
352 self.mock_object(rest.HSPRestBackend, "delete_file_system")
353 self.mock_object(rest.HSPRestBackend, "get_access_rules",
354 mock.Mock(return_value=[fakes.hsp_rules[0]]))
355 self.mock_object(rest.HSPRestBackend, "delete_access_rule", mock.Mock(
356 side_effect=[exception.HSPBackendException(
357 message="No matching access rule found."), delete_rule]))
359 self._driver.delete_share('context', self.fake_share_instance)
361 self.assertTrue(self.mock_log.debug.called)
363 rest.HSPRestBackend.get_file_system.assert_called_once_with(
364 self.fake_share_instance['id'])
365 rest.HSPRestBackend.get_share.assert_called_once_with(
366 fakes.file_system['id'])
367 rest.HSPRestBackend.delete_share.assert_called_once_with(
368 fakes.share['id'])
369 rest.HSPRestBackend.delete_file_system.assert_called_once_with(
370 fakes.file_system['id'])
371 rest.HSPRestBackend.get_access_rules.assert_called_once_with(
372 fakes.share['id'])
373 rest.HSPRestBackend.delete_access_rule.assert_called_once_with(
374 fakes.share['id'], fakes.hsp_rules[0]['name'])
376 def test_delete_share_rule_exception(self):
377 self.mock_object(rest.HSPRestBackend, "get_file_system",
378 mock.Mock(return_value=fakes.file_system))
379 self.mock_object(rest.HSPRestBackend, "get_share",
380 mock.Mock(return_value=fakes.share))
381 self.mock_object(rest.HSPRestBackend, "get_access_rules",
382 mock.Mock(return_value=[fakes.hsp_rules[0]]))
383 self.mock_object(rest.HSPRestBackend, "delete_access_rule",
384 mock.Mock(side_effect=exception.HSPBackendException(
385 message="Internal Server Error.")))
387 self.assertRaises(exception.HSPBackendException,
388 self._driver.delete_share, 'context',
389 self.fake_share_instance)
391 self.assertTrue(self.mock_log.debug.called)
393 rest.HSPRestBackend.get_file_system.assert_called_once_with(
394 self.fake_share_instance['id'])
395 rest.HSPRestBackend.get_share.assert_called_once_with(
396 fakes.file_system['id'])
397 rest.HSPRestBackend.get_access_rules.assert_called_once_with(
398 fakes.share['id'])
399 rest.HSPRestBackend.delete_access_rule.assert_called_once_with(
400 fakes.share['id'], fakes.hsp_rules[0]['name'])
402 def test_delete_share_already_deleted(self):
403 self.mock_object(rest.HSPRestBackend, "get_file_system", mock.Mock(
404 side_effect=exception.HSPItemNotFoundException(msg='fake')))
406 self.mock_object(driver.LOG, "info")
408 self._driver.delete_share('context', self.fake_share_instance)
410 self.assertTrue(self.mock_log.info.called)
412 rest.HSPRestBackend.get_file_system.assert_called_once_with(
413 self.fake_share_instance['id'])
415 def test_extend_share(self):
416 new_size = 2
418 self.mock_object(rest.HSPRestBackend, "get_file_system",
419 mock.Mock(return_value=fakes.file_system))
420 self.mock_object(rest.HSPRestBackend, "resize_file_system",
421 mock.Mock())
423 self._driver.extend_share(self.fake_share_instance, new_size)
425 self.assertTrue(self.mock_log.info.called)
427 rest.HSPRestBackend.get_cluster.assert_called_once_with()
428 rest.HSPRestBackend.get_file_system.assert_called_once_with(
429 self.fake_share_instance['id'])
430 rest.HSPRestBackend.resize_file_system.assert_called_once_with(
431 fakes.file_system['id'], new_size * units.Gi)
433 def test_extend_share_with_no_available_space_in_fs(self):
434 new_size = 150
436 self.assertRaises(exception.HSPBackendException,
437 self._driver.extend_share, self.fake_share_instance,
438 new_size)
440 rest.HSPRestBackend.get_cluster.assert_called_once_with()
442 def test_shrink_share(self):
443 new_size = 70
445 self.mock_object(rest.HSPRestBackend, "get_file_system",
446 mock.Mock(return_value=fakes.file_system))
447 self.mock_object(rest.HSPRestBackend, "resize_file_system",
448 mock.Mock())
450 self._driver.shrink_share(self.fake_share_instance, new_size)
452 self.assertTrue(self.mock_log.info.called)
454 rest.HSPRestBackend.get_file_system.assert_called_once_with(
455 self.fake_share_instance['id'])
456 rest.HSPRestBackend.resize_file_system.assert_called_once_with(
457 fakes.file_system['id'], new_size * units.Gi)
459 def test_shrink_share_new_size_lower_than_usage(self):
460 new_size = 20
462 self.mock_object(rest.HSPRestBackend, "get_file_system",
463 mock.Mock(return_value=fakes.file_system))
465 self.assertRaises(exception.ShareShrinkingPossibleDataLoss,
466 self._driver.shrink_share, self.fake_share_instance,
467 new_size)
469 rest.HSPRestBackend.get_file_system.assert_called_once_with(
470 self.fake_share_instance['id'])
472 def test_manage_existing(self):
473 self.mock_object(self.fake_private_storage, "update")
474 self.mock_object(rest.HSPRestBackend, "get_share",
475 mock.Mock(return_value=fakes.share))
476 self.mock_object(rest.HSPRestBackend, "rename_file_system",
477 mock.Mock())
478 self.mock_object(rest.HSPRestBackend, "get_file_system",
479 mock.Mock(return_value=fakes.file_system))
481 result = self._driver.manage_existing(self.fake_share_instance,
482 'option')
484 expected = {
485 'size': fakes.file_system['properties']['quota'] / units.Gi,
486 'export_locations': self.fake_el,
487 }
489 self.assertTrue(self.mock_log.info.called)
490 self.assertEqual(expected, result)
492 rest.HSPRestBackend.get_share.assert_called_once_with(
493 name=self.fake_share_instance['id'])
494 rest.HSPRestBackend.rename_file_system.assert_called_once_with(
495 fakes.file_system['id'], self.fake_share_instance['id'])
496 rest.HSPRestBackend.get_file_system.assert_called_once_with(
497 self.fake_share_instance['id'])
499 def test_manage_existing_wrong_share_id(self):
500 self.mock_object(rest.HSPRestBackend, "get_share", mock.Mock(
501 side_effect=exception.HSPItemNotFoundException(msg='fake')))
503 self.assertRaises(exception.ManageInvalidShare,
504 self._driver.manage_existing,
505 self.fake_share_instance,
506 'option')
508 rest.HSPRestBackend.get_share.assert_called_once_with(
509 name=self.fake_share_instance['id'])
511 def test_unmanage(self):
512 self.mock_object(self.fake_private_storage, "get",
513 mock.Mock(
514 return_value='original_name'))
515 self.mock_object(self.fake_private_storage, "delete")
517 self._driver.unmanage(self.fake_share_instance)
519 self.assertTrue(self.mock_log.info.called)
521 def test__update_share_stats(self):
522 mock__update_share_stats = self.mock_object(
523 manila.share.driver.ShareDriver, '_update_share_stats')
524 self.mock_object(self.fake_private_storage, 'get', mock.Mock(
525 return_value={'provisioned': 0}
526 ))
528 self._driver._update_share_stats()
530 rest.HSPRestBackend.get_cluster.assert_called_once_with()
531 mock__update_share_stats.assert_called_once_with(fakes.stats_data)
532 self.assertTrue(self.mock_log.info.called)
534 def test_get_default_filter_function(self):
535 expected = "share.size >= 128"
537 actual = self._driver.get_default_filter_function()
539 self.assertEqual(expected, actual)