Coverage for manila/tests/share/drivers/zfssa/test_zfssashare.py: 100%
243 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) 2014, Oracle and/or its affiliates. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14"""
15Unit tests for Oracle's ZFSSA Manila driver.
16"""
17from unittest import mock
19from oslo_config import cfg
20from oslo_utils import units
22from manila import context
23from manila import exception
24from manila.share import configuration as conf
25from manila.share.drivers.zfssa import zfssashare
26from manila import test
27from manila.tests import fake_zfssa
30CONF = cfg.CONF
33class ZFSSAShareDriverTestCase(test.TestCase):
34 """Tests ZFSSAShareDriver."""
36 share = {
37 'id': 'fakeid',
38 'name': 'fakename',
39 'size': 1,
40 'share_proto': 'NFS',
41 'export_location': '/mnt/nfs/volume-00002',
42 }
44 share2 = {
45 'id': 'fakeid2',
46 'name': 'fakename2',
47 'size': 4,
48 'share_proto': 'CIFS',
49 'export_location': '/mnt/nfs/volume-00003',
50 'space_data': 3006477107
51 }
53 snapshot = {
54 'id': 'fakesnapshotid',
55 'share_name': 'fakename',
56 'share_id': 'fakeid',
57 'name': 'fakesnapshotname',
58 'share_size': 1,
59 'share_proto': 'NFS',
60 }
62 access = {
63 'id': 'fakeaccid',
64 'access_type': 'ip',
65 'access_to': '10.0.0.2',
66 'state': 'active',
67 }
69 @mock.patch.object(zfssashare, 'factory_zfssa')
70 def setUp(self, _factory_zfssa):
71 super(ZFSSAShareDriverTestCase, self).setUp()
72 self._create_fake_config()
73 lcfg = self.configuration
74 self.mountpoint = '/export/' + lcfg.zfssa_nas_mountpoint
75 _factory_zfssa.return_value = fake_zfssa.FakeZFSSA()
76 _factory_zfssa.set_host(lcfg.zfssa_host)
77 _factory_zfssa.login(lcfg.zfssa_auth_user)
78 self._context = context.get_admin_context()
79 self._driver = zfssashare.ZFSSAShareDriver(False, configuration=lcfg)
80 self._driver.do_setup(self._context)
82 self.fake_proto_share = {
83 'id': self.share['id'],
84 'share_proto': 'fake_proto',
85 'export_locations': [{'path': self.share['export_location']}],
86 }
88 self.test_share = {
89 'id': self.share['id'],
90 'share_proto': 'NFS',
91 'export_locations': [{'path': self.share['export_location']}],
92 }
94 self.test_share2 = {
95 'id': self.share2['id'],
96 'share_proto': 'CIFS',
97 'export_locations': [{'path': self.share2['export_location']}],
98 }
100 self.driver_options = {'zfssa_name': self.share['name']}
102 def _create_fake_config(self):
103 def _safe_get(opt):
104 return getattr(self.configuration, opt)
106 self.configuration = mock.Mock(spec=conf.Configuration)
107 self.configuration.safe_get = mock.Mock(side_effect=_safe_get)
108 self.configuration.zfssa_host = '1.1.1.1'
109 self.configuration.zfssa_data_ip = '1.1.1.1'
110 self.configuration.zfssa_auth_user = 'user'
111 self.configuration.zfssa_auth_password = 'passwd'
112 self.configuration.zfssa_pool = 'pool'
113 self.configuration.zfssa_project = 'project'
114 self.configuration.zfssa_nas_mountpoint = 'project'
115 self.configuration.zfssa_nas_checksum = 'fletcher4'
116 self.configuration.zfssa_nas_logbias = 'latency'
117 self.configuration.zfssa_nas_compression = 'off'
118 self.configuration.zfssa_nas_vscan = 'false'
119 self.configuration.zfssa_nas_rstchown = 'true'
120 self.configuration.zfssa_nas_quota_snap = 'true'
121 self.configuration.zfssa_rest_timeout = 60
122 self.configuration.network_config_group = 'fake_network_config_group'
123 self.configuration.admin_network_config_group = (
124 'fake_admin_network_config_group')
125 self.configuration.driver_handles_share_servers = False
126 self.configuration.zfssa_manage_policy = 'strict'
128 def test_create_share(self):
129 self.mock_object(self._driver.zfssa, 'create_share')
130 self.mock_object(self._driver, '_export_location')
131 lcfg = self.configuration
132 arg = {
133 'host': lcfg.zfssa_data_ip,
134 'mountpoint': self.mountpoint,
135 'name': self.share['id'],
136 }
137 location = ("%(host)s:%(mountpoint)s/%(name)s" % arg)
138 self._driver._export_location.return_value = location
139 arg = self._driver.create_arg(self.share['size'])
140 arg.update(self._driver.default_args)
141 arg.update({'name': self.share['id']})
142 ret = self._driver.create_share(self._context, self.share)
143 self._driver.zfssa.create_share.assert_called_with(lcfg.zfssa_pool,
144 lcfg.zfssa_project,
145 arg)
146 self.assertEqual(location, ret)
147 self.assertEqual(1, self._driver.zfssa.create_share.call_count)
148 self.assertEqual(1, self._driver._export_location.call_count)
150 def test_create_share_from_snapshot(self):
151 self.mock_object(self._driver.zfssa, 'clone_snapshot')
152 self.mock_object(self._driver, '_export_location')
153 lcfg = self.configuration
154 arg = {
155 'host': lcfg.zfssa_data_ip,
156 'mountpoint': self.mountpoint,
157 'name': self.share['id'],
158 }
159 location = ("%(host)s:%(mountpoint)s/%(name)s" % arg)
160 self._driver._export_location.return_value = location
161 arg = self._driver.create_arg(self.share['size'])
162 details = {
163 'share': self.share['id'],
164 'project': lcfg.zfssa_project,
165 }
166 arg.update(details)
167 ret = self._driver.create_share_from_snapshot(self._context,
168 self.share,
169 self.snapshot)
170 self.assertEqual(location, ret)
171 self.assertEqual(1, self._driver.zfssa.clone_snapshot.call_count)
172 self.assertEqual(1, self._driver._export_location.call_count)
173 self._driver.zfssa.clone_snapshot.assert_called_with(
174 lcfg.zfssa_pool,
175 lcfg.zfssa_project,
176 self.snapshot,
177 self.share,
178 arg)
180 def test_delete_share(self):
181 self.mock_object(self._driver.zfssa, 'delete_share')
182 self._driver.delete_share(self._context, self.share)
183 self.assertEqual(1, self._driver.zfssa.delete_share.call_count)
184 lcfg = self.configuration
185 self._driver.zfssa.delete_share.assert_called_with(lcfg.zfssa_pool,
186 lcfg.zfssa_project,
187 self.share['id'])
189 def test_create_snapshot(self):
190 self.mock_object(self._driver.zfssa, 'create_snapshot')
191 lcfg = self.configuration
192 self._driver.create_snapshot(self._context, self.snapshot)
193 self.assertEqual(1, self._driver.zfssa.create_snapshot.call_count)
194 self._driver.zfssa.create_snapshot.assert_called_with(
195 lcfg.zfssa_pool,
196 lcfg.zfssa_project,
197 self.snapshot['share_id'],
198 self.snapshot['id'])
200 def test_delete_snapshot(self):
201 self.mock_object(self._driver.zfssa, 'delete_snapshot')
202 self._driver.delete_snapshot(self._context, self.snapshot)
203 self.assertEqual(1, self._driver.zfssa.delete_snapshot.call_count)
205 def test_delete_snapshot_negative(self):
206 self.mock_object(self._driver.zfssa, 'has_clones')
207 self._driver.zfssa.has_clones.return_value = True
208 self.assertRaises(exception.ShareSnapshotIsBusy,
209 self._driver.delete_snapshot,
210 self._context,
211 self.snapshot)
213 def test_ensure_share(self):
214 self.mock_object(self._driver.zfssa, 'get_share')
215 lcfg = self.configuration
216 self._driver.ensure_share(self._context, self.share)
217 self.assertEqual(1, self._driver.zfssa.get_share.call_count)
218 self._driver.zfssa.get_share.assert_called_with(
219 lcfg.zfssa_pool,
220 lcfg.zfssa_project,
221 self.share['id'])
223 self._driver.zfssa.get_share.return_value = None
224 self.assertRaises(exception.ManilaException,
225 self._driver.ensure_share,
226 self._context,
227 self.share)
229 def test_allow_access(self):
230 self.mock_object(self._driver.zfssa, 'allow_access_nfs')
231 lcfg = self.configuration
232 self._driver.allow_access(self._context, self.share, self.access)
233 self.assertEqual(1, self._driver.zfssa.allow_access_nfs.call_count)
234 self._driver.zfssa.allow_access_nfs.assert_called_with(
235 lcfg.zfssa_pool,
236 lcfg.zfssa_project,
237 self.share['id'],
238 self.access)
240 def test_deny_access(self):
241 self.mock_object(self._driver.zfssa, 'deny_access_nfs')
242 lcfg = self.configuration
243 self._driver.deny_access(self._context, self.share, self.access)
244 self.assertEqual(1, self._driver.zfssa.deny_access_nfs.call_count)
245 self._driver.zfssa.deny_access_nfs.assert_called_with(
246 lcfg.zfssa_pool,
247 lcfg.zfssa_project,
248 self.share['id'],
249 self.access)
251 def test_extend_share_negative(self):
252 self.mock_object(self._driver.zfssa, 'modify_share')
253 new_size = 3
254 # Not enough space in project, expect an exception:
255 self.mock_object(self._driver.zfssa, 'get_project_stats')
256 self._driver.zfssa.get_project_stats.return_value = 1 * units.Gi
258 self.assertRaises(exception.ShareExtendingError,
259 self._driver.extend_share,
260 self.share,
261 new_size)
263 def test_extend_share(self):
264 self.mock_object(self._driver.zfssa, 'modify_share')
265 new_size = 3
266 lcfg = self.configuration
267 self.mock_object(self._driver.zfssa, 'get_project_stats')
268 self._driver.zfssa.get_project_stats.return_value = 10 * units.Gi
270 arg = self._driver.create_arg(new_size)
271 self._driver.extend_share(self.share, new_size)
273 self.assertEqual(1, self._driver.zfssa.modify_share.call_count)
274 self._driver.zfssa.modify_share.assert_called_with(
275 lcfg.zfssa_pool,
276 lcfg.zfssa_project,
277 self.share['id'],
278 arg)
280 def test_shrink_share_negative(self):
281 self.mock_object(self._driver.zfssa, 'modify_share')
282 # Used space is larger than 2GB
283 new_size = 2
284 self.mock_object(self._driver.zfssa, 'get_share')
285 self._driver.zfssa.get_share.return_value = self.share2
287 self.assertRaises(exception.ShareShrinkingPossibleDataLoss,
288 self._driver.shrink_share,
289 self.share2,
290 new_size)
292 def test_shrink_share(self):
293 self.mock_object(self._driver.zfssa, 'modify_share')
294 new_size = 3
295 lcfg = self.configuration
296 self.mock_object(self._driver.zfssa, 'get_share')
297 self._driver.zfssa.get_share.return_value = self.share2
299 arg = self._driver.create_arg(new_size)
300 self._driver.shrink_share(self.share2, new_size)
302 self.assertEqual(1, self._driver.zfssa.modify_share.call_count)
303 self._driver.zfssa.modify_share.assert_called_with(
304 lcfg.zfssa_pool,
305 lcfg.zfssa_project,
306 self.share2['id'],
307 arg)
309 def test_manage_invalid_option(self):
310 self.mock_object(self._driver, '_get_share_details')
312 # zfssa_name not in driver_options:
313 self.assertRaises(exception.ShareBackendException,
314 self._driver.manage_existing,
315 self.share,
316 {})
318 def test_manage_no_share_details(self):
319 self.mock_object(self._driver, '_get_share_details')
320 self._driver._get_share_details.side_effect = (
321 exception.ShareResourceNotFound(share_id=self.share['name']))
323 self.assertRaises(exception.ShareResourceNotFound,
324 self._driver.manage_existing,
325 self.share,
326 self.driver_options)
328 def test_manage_invalid_size(self):
329 details = {
330 'quota': 10, # 10 bytes
331 'reservation': 10,
332 }
333 self.mock_object(self._driver, '_get_share_details')
334 self._driver._get_share_details.return_value = details
336 self.mock_object(self._driver.zfssa, 'get_project_stats')
337 self._driver.zfssa.get_project_stats.return_value = 900
339 # Share size is less than 1GB, but there is not enough free space
340 self.assertRaises(exception.ManageInvalidShare,
341 self._driver.manage_existing,
342 self.test_share,
343 self.driver_options)
345 def test_manage_invalid_protocol(self):
346 self.mock_object(self._driver, '_get_share_details')
347 self._driver._get_share_details.return_value = {
348 'quota': self.share['size'] * units.Gi,
349 'reservation': self.share['size'] * units.Gi,
350 'custom:manila_managed': False,
351 }
353 self.assertRaises(exception.ManageInvalidShare,
354 self._driver.manage_existing,
355 self.fake_proto_share,
356 self.driver_options)
358 def test_manage_unmanage_no_schema(self):
359 self.mock_object(self._driver, '_get_share_details')
360 self._driver._get_share_details.return_value = {}
362 # Share does not have custom:manila_managed property
363 # Test manage_existing():
364 self.assertRaises(exception.ManageInvalidShare,
365 self._driver.manage_existing,
366 self.test_share,
367 self.driver_options)
369 # Test unmanage():
370 self.assertRaises(exception.UnmanageInvalidShare,
371 self._driver.unmanage,
372 self.test_share)
374 def test_manage_round_up_size(self):
375 details = {
376 'quota': 100,
377 'reservation': 50,
378 'custom:manila_managed': False,
379 }
380 self.mock_object(self._driver, '_get_share_details')
381 self._driver._get_share_details.return_value = details
383 self.mock_object(self._driver.zfssa, 'get_project_stats')
384 self._driver.zfssa.get_project_stats.return_value = 1 * units.Gi
386 ret = self._driver.manage_existing(self.test_share,
387 self.driver_options)
389 # Expect share size is 1GB
390 self.assertEqual(1, ret['size'])
392 def test_manage_not_enough_space(self):
393 details = {
394 'quota': 3.5 * units.Gi,
395 'reservation': 3.5 * units.Gi,
396 'custom:manila_managed': False,
397 }
398 self.mock_object(self._driver, '_get_share_details')
399 self._driver._get_share_details.return_value = details
401 self.mock_object(self._driver.zfssa, 'get_project_stats')
402 self._driver.zfssa.get_project_stats.return_value = 0.1 * units.Gi
404 self.assertRaises(exception.ManageInvalidShare,
405 self._driver.manage_existing,
406 self.test_share,
407 self.driver_options)
409 def test_manage_unmanage_NFS(self):
410 lcfg = self.configuration
411 details = {
412 # Share size is 1GB
413 'quota': self.share['size'] * units.Gi,
414 'reservation': self.share['size'] * units.Gi,
415 'custom:manila_managed': False,
416 }
417 arg = {
418 'host': lcfg.zfssa_data_ip,
419 'mountpoint': self.share['export_location'],
420 'name': self.share['id'],
421 }
422 export_loc = "%(host)s:%(mountpoint)s/%(name)s" % arg
423 self.mock_object(self._driver, '_get_share_details')
424 self._driver._get_share_details.return_value = details
426 ret = self._driver.manage_existing(self.test_share,
427 self.driver_options)
429 self.assertEqual(export_loc, ret['export_locations'])
430 self.assertEqual(1, ret['size'])
432 def test_manage_unmanage_CIFS(self):
433 lcfg = self.configuration
434 details = {
435 # Share size is 1GB
436 'quota': self.share2['size'] * units.Gi,
437 'reservation': self.share2['size'] * units.Gi,
438 'custom:manila_managed': False,
439 }
440 arg = {
441 'host': lcfg.zfssa_data_ip,
442 'name': self.share2['id'],
443 }
444 export_loc = "\\\\%(host)s\\%(name)s" % arg
445 self.mock_object(self._driver, '_get_share_details')
446 self._driver._get_share_details.return_value = details
448 ret = self._driver.manage_existing(self.test_share2,
449 self.driver_options)
451 self.assertEqual(export_loc, ret['export_locations'])
452 self.assertEqual(4, ret['size'])
454 def test_unmanage_NFS(self):
455 self.mock_object(self._driver.zfssa, 'modify_share')
456 lcfg = self.configuration
457 details = {
458 'quota': self.share['size'] * units.Gi,
459 'reservation': self.share['size'] * units.Gi,
460 'custom:manila_managed': True,
461 }
463 arg = {
464 'custom:manila_managed': False,
465 'sharenfs': 'off',
466 }
468 self.mock_object(self._driver, '_get_share_details')
469 self._driver._get_share_details.return_value = details
471 self._driver.unmanage(self.test_share)
473 self._driver.zfssa.modify_share.assert_called_with(
474 lcfg.zfssa_pool,
475 lcfg.zfssa_project,
476 self.test_share['id'],
477 arg)
479 def test_unmanage_CIFS(self):
480 self.mock_object(self._driver.zfssa, 'modify_share')
481 lcfg = self.configuration
482 details = {
483 'quota': self.share2['size'] * units.Gi,
484 'reservation': self.share2['size'] * units.Gi,
485 'custom:manila_managed': True,
486 }
488 arg = {
489 'custom:manila_managed': False,
490 'sharesmb': 'off',
491 }
493 self.mock_object(self._driver, '_get_share_details')
494 self._driver._get_share_details.return_value = details
496 self._driver.unmanage(self.test_share2)
498 self._driver.zfssa.modify_share.assert_called_with(
499 lcfg.zfssa_pool,
500 lcfg.zfssa_project,
501 self.test_share2['id'],
502 arg)
504 def test_verify_share_to_manage_loose_policy(self):
505 # Temporarily change policy to loose
506 self.configuration.zfssa_manage_policy = 'loose'
508 ret = self._driver._verify_share_to_manage('sharename', {})
510 self.assertIsNone(ret)
511 # Change it back to strict
512 self.configuration.zfssa_manage_policy = 'strict'
514 def test_verify_share_to_manage_no_property(self):
515 self.configuration.zfssa_manage_policy = 'strict'
516 self.assertRaises(exception.ManageInvalidShare,
517 self._driver._verify_share_to_manage,
518 'sharename',
519 {})
521 def test_verify_share_to_manage_alredy_managed(self):
522 details = {'custom:manila_managed': True}
524 self.assertRaises(exception.ManageInvalidShare,
525 self._driver._verify_share_to_manage,
526 'sharename',
527 details)