Coverage for manila/tests/share/drivers/test_generic.py: 99%
892 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 NetApp, Inc.
2# Copyright (c) 2015 Mirantis, Inc.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
17"""Unit tests for the Generic driver module."""
19import os
20import time
21from unittest import mock
23import ddt
24from oslo_concurrency import processutils
25from oslo_config import cfg
27from manila.common import constants as const
28from manila import compute
29from manila import context
30from manila import exception
31import manila.share.configuration
32from manila.share.drivers import generic
33from manila.share import share_types
34from manila import ssh_utils
35from manila import test
36from manila.tests import fake_compute
37from manila.tests import fake_service_instance
38from manila.tests import fake_share
39from manila.tests import fake_volume
40from manila import utils
41from manila import volume
44CONF = cfg.CONF
47def get_fake_manage_share():
48 return {
49 'id': 'fake',
50 'share_proto': 'NFS',
51 'share_type_id': 'fake',
52 'export_locations': [
53 {'path': '10.0.0.1:/foo/fake/path'},
54 {'path': '11.0.0.1:/bar/fake/path'},
55 ],
56 }
59def get_fake_snap_dict():
60 snap_dict = {
61 'status': 'available',
62 'project_id': '13c0be6290934bd98596cfa004650049',
63 'user_id': 'a0314a441ca842019b0952224aa39192',
64 'description': None,
65 'deleted': '0',
66 'created_at': '2015-08-10 00:05:58',
67 'updated_at': '2015-08-10 00:05:58',
68 'consistency_group_id': None,
69 'deleted_at': None,
70 'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',
71 'name': None,
72 }
73 return snap_dict
76def get_fake_access_rule(access_to, access_level, access_type='ip'):
77 return {
78 'access_type': access_type,
79 'access_to': access_to,
80 'access_level': access_level,
81 }
84@ddt.ddt
85class GenericShareDriverTestCase(test.TestCase):
86 """Tests GenericShareDriver."""
88 def setUp(self):
89 super(GenericShareDriverTestCase, self).setUp()
90 self._context = context.get_admin_context()
91 self._execute = mock.Mock(return_value=('', ''))
93 self._helper_cifs = mock.Mock()
94 self._helper_nfs = mock.Mock()
95 CONF.set_default('driver_handles_share_servers', True)
96 self.fake_conf = manila.share.configuration.Configuration(None)
98 self.fake_private_storage = mock.Mock()
99 self.mock_object(self.fake_private_storage, 'get',
100 mock.Mock(return_value=None))
102 with mock.patch.object(
103 generic.service_instance,
104 'ServiceInstanceManager',
105 fake_service_instance.FakeServiceInstanceManager):
106 self._driver = generic.GenericShareDriver(
107 private_storage=self.fake_private_storage,
108 execute=self._execute, configuration=self.fake_conf)
109 self._driver.service_tenant_id = 'service tenant id'
110 self._driver.service_network_id = 'service network id'
111 self._driver.compute_api = fake_compute.API()
112 self._driver.volume_api = fake_volume.API()
113 self._driver.share_networks_locks = {}
114 self._driver.get_service_instance = mock.Mock()
115 self._driver.share_networks_servers = {}
116 self._driver.admin_context = self._context
118 self.fake_sn = {"id": "fake_sn_id"}
119 self.fake_net_info = {
120 "id": "fake_srv_id",
121 "share_network_id": "fake_sn_id"
122 }
123 fsim = fake_service_instance.FakeServiceInstanceManager()
124 sim = mock.Mock(return_value=fsim)
125 self._driver.instance_manager = sim
126 self._driver.service_instance_manager = sim
127 self.fake_server = sim._create_service_instance(
128 context="fake", instance_name="fake",
129 share_network_id=self.fake_sn["id"], old_server_ip="fake")
131 self.mock_object(utils, 'synchronized',
132 mock.Mock(return_value=lambda f: f))
133 self.mock_object(generic.os.path, 'exists',
134 mock.Mock(return_value=True))
135 self._driver._helpers = {
136 'CIFS': self._helper_cifs,
137 'NFS': self._helper_nfs,
138 }
139 self.share = fake_share.fake_share(share_proto='NFS')
140 self.server = {
141 'instance_id': 'fake_instance_id',
142 'ip': 'fake_ip',
143 'username': 'fake_username',
144 'password': 'fake_password',
145 'pk_path': 'fake_pk_path',
146 'backend_details': {
147 'ip': '1.2.3.4',
148 'public_address': 'fake_public_address',
149 'instance_id': 'fake',
150 'service_ip': 'fake_ip',
151 },
152 'availability_zone': 'fake_az',
153 }
154 self.access = fake_share.fake_access()
155 self.snapshot = fake_share.fake_snapshot()
156 self.mock_object(time, 'sleep')
157 self.mock_debug_log = self.mock_object(generic.LOG, 'debug')
158 self.mock_warning_log = self.mock_object(generic.LOG, 'warning')
159 self.mock_error_log = self.mock_object(generic.LOG, 'error')
160 self.mock_exception_log = self.mock_object(generic.LOG, 'exception')
162 @ddt.data(True, False)
163 def test_do_setup_with_dhss(self, dhss):
164 CONF.set_default('driver_handles_share_servers', dhss)
165 fake_server = {'id': 'fake_server_id'}
166 self.mock_object(volume, 'API')
167 self.mock_object(compute, 'API')
168 self.mock_object(self._driver, '_setup_helpers')
169 self.mock_object(
170 self._driver,
171 '_is_share_server_active', mock.Mock(return_value=True))
172 self.mock_object(
173 self._driver.service_instance_manager,
174 'get_common_server', mock.Mock(return_value=fake_server))
176 self._driver.do_setup(self._context)
178 volume.API.assert_called_once_with()
179 compute.API.assert_called_once_with()
180 self._driver._setup_helpers.assert_called_once_with()
181 if not dhss:
182 (self._driver.service_instance_manager.get_common_server.
183 assert_called_once_with())
184 self._driver._is_share_server_active.assert_called_once_with(
185 self._context, fake_server)
186 else:
187 self.assertFalse(
188 self._driver.service_instance_manager.get_common_server.called)
189 self.assertFalse(self._driver._is_share_server_active.called)
191 @mock.patch('time.sleep')
192 def test_do_setup_dhss_false_server_avail_after_retry(self, mock_sleep):
193 # This tests the scenario in which the common share server cannot be
194 # retrieved during the first attempt, is not active during the second,
195 # becoming active during the third attempt.
196 CONF.set_default('driver_handles_share_servers', False)
197 fake_server = {'id': 'fake_server_id'}
198 self.mock_object(volume, 'API')
199 self.mock_object(compute, 'API')
200 self.mock_object(self._driver, '_setup_helpers')
201 self.mock_object(
202 self._driver,
203 '_is_share_server_active', mock.Mock(side_effect=[False, True]))
204 self.mock_object(
205 self._driver.service_instance_manager,
206 'get_common_server',
207 mock.Mock(side_effect=[exception.ManilaException,
208 fake_server,
209 fake_server]))
211 self._driver.do_setup(self._context)
213 volume.API.assert_called_once_with()
214 compute.API.assert_called_once_with()
215 self._driver._setup_helpers.assert_called_once_with()
216 (self._driver.service_instance_manager.get_common_server.
217 assert_has_calls([mock.call()] * 3))
218 self._driver._is_share_server_active.assert_has_calls(
219 [mock.call(self._context, fake_server)] * 2)
220 mock_sleep.assert_has_calls([mock.call(5)] * 2)
222 def test_setup_helpers(self):
223 self._driver._helpers = {}
224 CONF.set_default('share_helpers', ['NFS=fakenfs'])
225 self.mock_object(generic.importutils, 'import_class',
226 mock.Mock(return_value=self._helper_nfs))
227 self._driver._setup_helpers()
228 generic.importutils.import_class.assert_has_calls([
229 mock.call('fakenfs')
230 ])
231 self._helper_nfs.assert_called_once_with(
232 self._execute,
233 self._driver._ssh_exec,
234 self.fake_conf
235 )
236 self.assertEqual(1, len(self._driver._helpers))
238 def test_setup_helpers_no_helpers(self):
239 self._driver._helpers = {}
240 CONF.set_default('share_helpers', [])
241 self.assertRaises(exception.ManilaException,
242 self._driver._setup_helpers)
244 def test_create_share(self):
245 volume = 'fake_volume'
246 volume2 = 'fake_volume2'
247 self.mock_object(self._driver, '_allocate_container',
248 mock.Mock(return_value=volume))
249 self.mock_object(self._driver, '_attach_volume',
250 mock.Mock(return_value=volume2))
251 self.mock_object(self._driver, '_format_device')
252 self.mock_object(self._driver, '_mount_device')
254 result = self._driver.create_share(
255 self._context, self.share, share_server=self.server)
257 self.assertEqual(self._helper_nfs.create_exports.return_value, result)
258 self._driver._allocate_container.assert_called_once_with(
259 self._driver.admin_context, self.share, snapshot=None)
260 self._driver._attach_volume.assert_called_once_with(
261 self._driver.admin_context, self.share,
262 self.server['backend_details']['instance_id'],
263 volume)
264 self._driver._format_device.assert_called_once_with(
265 self.server['backend_details'], volume2)
266 self._driver._mount_device.assert_called_once_with(
267 self.share, self.server['backend_details'], volume2)
269 def test_create_share_exception(self):
270 share = fake_share.fake_share(share_network_id=None)
271 self.assertRaises(exception.ManilaException, self._driver.create_share,
272 self._context, share)
274 def test_create_share_invalid_helper(self):
275 self._driver._helpers = {'CIFS': self._helper_cifs}
276 self.assertRaises(exception.InvalidShare, self._driver.create_share,
277 self._context, self.share, share_server=self.server)
279 def test_is_device_file_available(self):
280 volume = {'mountpoint': 'fake_mount_point'}
281 self.mock_object(self._driver, '_ssh_exec',
282 mock.Mock(return_value=None))
284 self._driver._is_device_file_available(self.server, volume)
286 self._driver._ssh_exec.assert_called_once_with(
287 self.server, ['sudo', 'test', '-b', volume['mountpoint']])
289 def test_format_device(self):
290 volume = {'mountpoint': 'fake_mount_point'}
291 self.mock_object(self._driver, '_ssh_exec',
292 mock.Mock(return_value=('', '')))
293 self.mock_object(self._driver, '_is_device_file_available')
295 self._driver._format_device(self.server, volume)
297 self._driver._is_device_file_available.assert_called_once_with(
298 self.server, volume)
299 self._driver._ssh_exec.assert_called_once_with(
300 self.server,
301 ['sudo', 'mkfs.%s' % self.fake_conf.share_volume_fstype,
302 volume['mountpoint']])
304 def test_mount_device_not_present(self):
305 server = {'instance_id': 'fake_server_id'}
306 mount_path = self._driver._get_mount_path(self.share)
307 volume = {'mountpoint': 'fake_mount_point'}
308 device_path = volume['mountpoint']
309 self.mock_object(self._driver, '_is_device_mounted',
310 mock.Mock(return_value=False))
311 self.mock_object(self._driver, '_add_mount_permanently')
312 self.mock_object(self._driver, '_ssh_exec',
313 mock.Mock(return_value=('', '')))
315 self._driver._mount_device(self.share, server, volume)
317 self._driver._is_device_mounted.assert_called_once_with(
318 mount_path, server, volume)
319 self._driver._add_mount_permanently.assert_called_once_with(
320 self.share.id, device_path, server)
321 self._driver._ssh_exec.assert_called_once_with(
322 server, (
323 'sudo', 'mkdir', '-p', mount_path,
324 '&&', 'sudo', 'mount', volume['mountpoint'], mount_path,
325 '&&', 'sudo', 'chmod', '777', mount_path,
326 '&&', 'sudo', 'umount', mount_path,
327 '&&', 'sudo', 'e2fsck', '-y', '-f', volume['mountpoint'],
328 '&&', 'sudo', 'tune2fs', '-U', 'random', volume['mountpoint'],
329 '&&', 'sudo', 'mount', volume['mountpoint'], mount_path,
330 ),
331 )
333 def test_mount_device_present(self):
334 mount_path = '/fake/mount/path'
335 volume = {'mountpoint': 'fake_mount_point'}
336 self.mock_object(self._driver, '_is_device_mounted',
337 mock.Mock(return_value=True))
338 self.mock_object(self._driver, '_get_mount_path',
339 mock.Mock(return_value=mount_path))
340 self.mock_object(generic.LOG, 'warning')
342 self._driver._mount_device(self.share, self.server, volume)
344 self._driver._get_mount_path.assert_called_once_with(self.share)
345 self._driver._is_device_mounted.assert_called_once_with(
346 mount_path, self.server, volume)
347 generic.LOG.warning.assert_called_once_with(mock.ANY, mock.ANY)
349 def test_mount_device_exception_raised(self):
350 volume = {'mountpoint': 'fake_mount_point'}
352 self.mock_object(
353 self._driver, '_is_device_mounted',
354 mock.Mock(side_effect=exception.ProcessExecutionError))
356 self.assertRaises(
357 exception.ShareBackendException,
358 self._driver._mount_device,
359 self.share,
360 self.server,
361 volume,
362 )
363 self._driver._is_device_mounted.assert_called_once_with(
364 self._driver._get_mount_path(self.share), self.server, volume)
366 def test_unmount_device_present(self):
367 mount_path = '/fake/mount/path'
368 self.mock_object(self._driver, '_is_device_mounted',
369 mock.Mock(return_value=True))
370 self.mock_object(self._driver, '_remove_mount_permanently')
371 self.mock_object(self._driver, '_get_mount_path',
372 mock.Mock(return_value=mount_path))
373 self.mock_object(self._driver, '_ssh_exec',
374 mock.Mock(return_value=('', '')))
376 self._driver._unmount_device(self.share, self.server)
378 self._driver._get_mount_path.assert_called_once_with(self.share)
379 self._driver._is_device_mounted.assert_called_once_with(
380 mount_path, self.server)
381 self._driver._remove_mount_permanently.assert_called_once_with(
382 self.share.id, self.server)
383 self._driver._ssh_exec.assert_called_once_with(
384 self.server,
385 ['sudo', 'umount', mount_path, '&&', 'sudo', 'rmdir', mount_path],
386 )
388 def test_unmount_device_retry_once(self):
389 self.counter = 0
391 def _side_effect(*args):
392 self.counter += 1
393 if self.counter < 2:
394 raise exception.ProcessExecutionError
396 mount_path = '/fake/mount/path'
397 self.mock_object(self._driver, '_is_device_mounted',
398 mock.Mock(return_value=True))
399 self.mock_object(self._driver, '_remove_mount_permanently')
400 self.mock_object(self._driver, '_get_mount_path',
401 mock.Mock(return_value=mount_path))
402 self.mock_object(self._driver, '_ssh_exec',
403 mock.Mock(side_effect=_side_effect))
405 self._driver._unmount_device(self.share, self.server)
407 self.assertEqual(1, time.sleep.call_count)
408 self.assertEqual([mock.call(self.share) for i in range(2)],
409 self._driver._get_mount_path.mock_calls)
410 self.assertEqual([mock.call(mount_path,
411 self.server) for i in range(2)],
412 self._driver._is_device_mounted.mock_calls)
413 self._driver._remove_mount_permanently.assert_called_once_with(
414 self.share.id, self.server)
415 self.assertEqual(
416 [mock.call(self.server, ['sudo', 'umount', mount_path,
417 '&&', 'sudo', 'rmdir', mount_path])
418 for i in range(2)],
419 self._driver._ssh_exec.mock_calls,
420 )
422 def test_unmount_device_not_present(self):
423 mount_path = '/fake/mount/path'
424 self.mock_object(self._driver, '_is_device_mounted',
425 mock.Mock(return_value=False))
426 self.mock_object(self._driver, '_get_mount_path',
427 mock.Mock(return_value=mount_path))
428 self.mock_object(generic.LOG, 'warning')
430 self._driver._unmount_device(self.share, self.server)
432 self._driver._get_mount_path.assert_called_once_with(self.share)
433 self._driver._is_device_mounted.assert_called_once_with(
434 mount_path, self.server)
435 generic.LOG.warning.assert_called_once_with(mock.ANY, mock.ANY)
437 def test_is_device_mounted_true(self):
438 volume = {'mountpoint': 'fake_mount_point', 'id': 'fake_id'}
439 mount_path = '/fake/mount/path'
440 mounts = "%(dev)s on %(path)s" % {'dev': volume['mountpoint'],
441 'path': mount_path}
442 self.mock_object(self._driver, '_ssh_exec',
443 mock.Mock(return_value=(mounts, '')))
445 result = self._driver._is_device_mounted(
446 mount_path, self.server, volume)
448 self._driver._ssh_exec.assert_called_once_with(
449 self.server, ['sudo', 'mount'])
450 self.assertTrue(result)
452 def test_is_device_mounted_true_no_volume_provided(self):
453 mount_path = '/fake/mount/path'
454 mounts = "/fake/dev/path on %(path)s type fake" % {'path': mount_path}
455 self.mock_object(self._driver, '_ssh_exec',
456 mock.Mock(return_value=(mounts, '')))
458 result = self._driver._is_device_mounted(mount_path, self.server)
460 self._driver._ssh_exec.assert_called_once_with(
461 self.server, ['sudo', 'mount'])
462 self.assertTrue(result)
464 def test_is_device_mounted_false(self):
465 mount_path = '/fake/mount/path'
466 volume = {'mountpoint': 'fake_mount_point', 'id': 'fake_id'}
467 mounts = "%(dev)s on %(path)s" % {'dev': '/fake',
468 'path': mount_path}
469 self.mock_object(self._driver, '_ssh_exec',
470 mock.Mock(return_value=(mounts, '')))
472 result = self._driver._is_device_mounted(
473 mount_path, self.server, volume)
475 self._driver._ssh_exec.assert_called_once_with(
476 self.server, ['sudo', 'mount'])
477 self.assertFalse(result)
479 def test_is_device_mounted_false_no_volume_provided(self):
480 mount_path = '/fake/mount/path'
481 mounts = "%(path)s" % {'path': 'fake'}
482 self.mock_object(self._driver, '_ssh_exec',
483 mock.Mock(return_value=(mounts, '')))
484 self.mock_object(self._driver, '_get_mount_path',
485 mock.Mock(return_value=mount_path))
487 result = self._driver._is_device_mounted(mount_path, self.server)
489 self._driver._ssh_exec.assert_called_once_with(
490 self.server, ['sudo', 'mount'])
491 self.assertFalse(result)
493 def test_add_mount_permanently(self):
494 device_path = '/fake/mount/path'
495 device_uuid = 'fake_disk_uuid'
496 formated_device_uuid = f"UUID={device_uuid}"
497 self.mock_object(self._driver, '_ssh_exec',
498 mock.Mock(return_value=(device_uuid, '')))
499 self._driver._add_mount_permanently(self.share.id, device_path,
500 self.server)
501 self._driver._ssh_exec.assert_has_calls([
502 mock.call(
503 self.server,
504 ['grep', self.share.id, const.MOUNT_FILE_TEMP,
505 '|', 'sudo', 'tee', '-a', const.MOUNT_FILE]),
506 mock.call(self.server, ['lsblk', '-o', 'uuid',
507 '-n', device_path]),
508 mock.call(
509 self.server,
510 ['sudo', 'sed', '-i', "s@{}@{}@".format(device_path,
511 formated_device_uuid), const.MOUNT_FILE]),
512 mock.call(self.server, ['sudo', 'mount', '-a'])
513 ])
515 def test_add_mount_permanently_raise_error_on_add(self):
516 device_path = 'fake_device_path'
517 self.mock_object(
518 self._driver, '_ssh_exec',
519 mock.Mock(side_effect=exception.ProcessExecutionError))
520 self.assertRaises(
521 exception.ShareBackendException,
522 self._driver._add_mount_permanently,
523 self.share.id,
524 device_path,
525 self.server
526 )
527 self._driver._ssh_exec.assert_called_once_with(
528 self.server,
529 ['grep', self.share.id, const.MOUNT_FILE_TEMP,
530 '|', 'sudo', 'tee', '-a', const.MOUNT_FILE],
531 )
533 def test_remove_mount_permanently(self):
534 self.mock_object(self._driver, '_ssh_exec')
535 self._driver._remove_mount_permanently(self.share.id, self.server)
536 self._driver._ssh_exec.assert_called_once_with(
537 self.server,
538 ['sudo', 'sed', '-i', '\'/%s/d\'' % self.share.id,
539 const.MOUNT_FILE],
540 )
542 def test_remove_mount_permanently_raise_error_on_remove(self):
543 self.mock_object(
544 self._driver, '_ssh_exec',
545 mock.Mock(side_effect=exception.ProcessExecutionError))
546 self.assertRaises(
547 exception.ShareBackendException,
548 self._driver._remove_mount_permanently,
549 self.share.id,
550 self.server
551 )
552 self._driver._ssh_exec.assert_called_once_with(
553 self.server,
554 ['sudo', 'sed', '-i', '\'/%s/d\'' % self.share.id,
555 const.MOUNT_FILE],
556 )
558 def test_get_mount_path(self):
559 result = self._driver._get_mount_path(self.share)
560 self.assertEqual(os.path.join(CONF.share_mount_path,
561 self.share['name']), result)
563 def test_attach_volume_not_attached(self):
564 available_volume = fake_volume.FakeVolume()
565 attached_volume = fake_volume.FakeVolume(status='in-use')
566 self.mock_object(self._driver.compute_api, 'instance_volume_attach')
567 self.mock_object(self._driver.volume_api, 'get',
568 mock.Mock(return_value=attached_volume))
570 result = self._driver._attach_volume(self._context, self.share,
571 'fake_inst_id', available_volume)
573 (self._driver.compute_api.instance_volume_attach.
574 assert_called_once_with(self._context, 'fake_inst_id',
575 available_volume['id']))
576 self._driver.volume_api.get.assert_called_once_with(
577 self._context, attached_volume['id'])
578 self.assertEqual(attached_volume, result)
580 def test_attach_volume_attached_correct(self):
581 fake_server = fake_compute.FakeServer()
582 attached_volume = fake_volume.FakeVolume(status='in-use')
583 self.mock_object(self._driver.compute_api, 'instance_volumes_list',
584 mock.Mock(return_value=[attached_volume.id]))
586 result = self._driver._attach_volume(self._context, self.share,
587 fake_server, attached_volume)
589 self.assertEqual(attached_volume, result)
591 def test_attach_volume_attached_incorrect(self):
592 fake_server = fake_compute.FakeServer()
593 attached_volume = fake_volume.FakeVolume(status='in-use')
594 anoter_volume = fake_volume.FakeVolume(id='fake_id2', status='in-use')
595 self.mock_object(self._driver.compute_api, 'instance_volumes_list',
596 mock.Mock(return_value=[anoter_volume]))
597 self.assertRaises(exception.ManilaException,
598 self._driver._attach_volume, self._context,
599 self.share, fake_server, attached_volume)
601 @ddt.data(exception.ManilaException, exception.Invalid)
602 def test_attach_volume_failed_attach(self, side_effect):
603 fake_server = fake_compute.FakeServer()
604 available_volume = fake_volume.FakeVolume()
605 self.mock_object(self._driver.compute_api, 'instance_volume_attach',
606 mock.Mock(side_effect=side_effect))
607 self.assertRaises(exception.ManilaException,
608 self._driver._attach_volume,
609 self._context, self.share, fake_server,
610 available_volume)
611 self.assertEqual(
612 3, self._driver.compute_api.instance_volume_attach.call_count)
614 def test_attach_volume_attached_retry_correct(self):
615 fake_server = fake_compute.FakeServer()
616 attached_volume = fake_volume.FakeVolume(status='available')
617 in_use_volume = fake_volume.FakeVolume(status='in-use')
619 side_effect = [exception.Invalid("Fake"), attached_volume]
620 attach_mock = mock.Mock(side_effect=side_effect)
621 self.mock_object(self._driver.compute_api, 'instance_volume_attach',
622 attach_mock)
623 self.mock_object(self._driver.compute_api, 'instance_volumes_list',
624 mock.Mock(return_value=[attached_volume]))
625 self.mock_object(self._driver.volume_api, 'get',
626 mock.Mock(return_value=in_use_volume))
628 result = self._driver._attach_volume(self._context, self.share,
629 fake_server, attached_volume)
631 self.assertEqual(in_use_volume, result)
632 self.assertEqual(
633 2, self._driver.compute_api.instance_volume_attach.call_count)
635 def test_attach_volume_error(self):
636 fake_server = fake_compute.FakeServer()
637 available_volume = fake_volume.FakeVolume()
638 error_volume = fake_volume.FakeVolume(status='error')
639 self.mock_object(self._driver.compute_api, 'instance_volume_attach')
640 self.mock_object(self._driver.volume_api, 'get',
641 mock.Mock(return_value=error_volume))
642 self.assertRaises(exception.ManilaException,
643 self._driver._attach_volume,
644 self._context, self.share,
645 fake_server, available_volume)
647 def test_get_volume(self):
648 volume = fake_volume.FakeVolume(
649 name=CONF.volume_name_template % self.share['id'])
650 self.mock_object(self._driver.volume_api, 'get_all',
651 mock.Mock(return_value=[volume]))
652 result = self._driver._get_volume(self._context, self.share['id'])
653 self.assertEqual(volume, result)
654 self._driver.volume_api.get_all.assert_called_once_with(
655 self._context, {'all_tenants': True, 'name': volume['name']})
657 def test_get_volume_with_private_data(self):
658 volume = fake_volume.FakeVolume()
659 self.mock_object(self._driver.volume_api, 'get',
660 mock.Mock(return_value=volume))
661 self.mock_object(self.fake_private_storage, 'get',
662 mock.Mock(return_value=volume['id']))
664 result = self._driver._get_volume(self._context, self.share['id'])
666 self.assertEqual(volume, result)
667 self._driver.volume_api.get.assert_called_once_with(
668 self._context, volume['id'])
669 self.fake_private_storage.get.assert_called_once_with(
670 self.share['id'], 'volume_id'
671 )
673 def test_get_volume_none(self):
674 vol_name = (
675 self._driver.configuration.volume_name_template % self.share['id'])
676 self.mock_object(self._driver.volume_api, 'get_all',
677 mock.Mock(return_value=[]))
679 result = self._driver._get_volume(self._context, self.share['id'])
681 self.assertIsNone(result)
682 self._driver.volume_api.get_all.assert_called_once_with(
683 self._context, {'all_tenants': True, 'name': vol_name})
685 def test_get_volume_error(self):
686 volume = fake_volume.FakeVolume(
687 name=CONF.volume_name_template % self.share['id'])
688 self.mock_object(self._driver.volume_api, 'get_all',
689 mock.Mock(return_value=[volume, volume]))
690 self.assertRaises(exception.ManilaException,
691 self._driver._get_volume,
692 self._context, self.share['id'])
693 self._driver.volume_api.get_all.assert_called_once_with(
694 self._context, {'all_tenants': True, 'name': volume['name']})
696 def test_get_volume_snapshot(self):
697 volume_snapshot = fake_volume.FakeVolumeSnapshot(
698 name=self._driver.configuration.volume_snapshot_name_template %
699 self.snapshot['id'])
700 self.mock_object(self._driver.volume_api, 'get_all_snapshots',
701 mock.Mock(return_value=[volume_snapshot]))
702 result = self._driver._get_volume_snapshot(self._context,
703 self.snapshot['id'])
704 self.assertEqual(volume_snapshot, result)
705 self._driver.volume_api.get_all_snapshots.assert_called_once_with(
706 self._context, {'name': volume_snapshot['name']})
708 def test_get_volume_snapshot_with_private_data(self):
709 volume_snapshot = fake_volume.FakeVolumeSnapshot()
710 self.mock_object(self._driver.volume_api, 'get_snapshot',
711 mock.Mock(return_value=volume_snapshot))
712 self.mock_object(self.fake_private_storage, 'get',
713 mock.Mock(return_value=volume_snapshot['id']))
714 result = self._driver._get_volume_snapshot(self._context,
715 self.snapshot['id'])
716 self.assertEqual(volume_snapshot, result)
717 self._driver.volume_api.get_snapshot.assert_called_once_with(
718 self._context, volume_snapshot['id'])
719 self.fake_private_storage.get.assert_called_once_with(
720 self.snapshot['id'], 'volume_snapshot_id'
721 )
723 def test_get_volume_snapshot_none(self):
724 snap_name = (
725 self._driver.configuration.volume_snapshot_name_template %
726 self.share['id'])
727 self.mock_object(self._driver.volume_api, 'get_all_snapshots',
728 mock.Mock(return_value=[]))
729 result = self._driver._get_volume_snapshot(self._context,
730 self.share['id'])
731 self.assertIsNone(result)
732 self._driver.volume_api.get_all_snapshots.assert_called_once_with(
733 self._context, {'name': snap_name})
735 def test_get_volume_snapshot_error(self):
736 volume_snapshot = fake_volume.FakeVolumeSnapshot(
737 name=self._driver.configuration.volume_snapshot_name_template %
738 self.snapshot['id'])
739 self.mock_object(
740 self._driver.volume_api, 'get_all_snapshots',
741 mock.Mock(return_value=[volume_snapshot, volume_snapshot]))
742 self.assertRaises(
743 exception.ManilaException, self._driver._get_volume_snapshot,
744 self._context, self.snapshot['id'])
745 self._driver.volume_api.get_all_snapshots.assert_called_once_with(
746 self._context, {'name': volume_snapshot['name']})
748 def test_detach_volume(self):
749 available_volume = fake_volume.FakeVolume()
750 attached_volume = fake_volume.FakeVolume(status='in-use')
751 self.mock_object(self._driver, '_get_volume',
752 mock.Mock(return_value=attached_volume))
753 self.mock_object(self._driver.compute_api, 'instance_volumes_list',
754 mock.Mock(return_value=[attached_volume.id]))
755 self.mock_object(self._driver.compute_api, 'instance_volume_detach')
756 self.mock_object(self._driver.volume_api, 'get',
757 mock.Mock(return_value=available_volume))
759 self._driver._detach_volume(self._context, self.share,
760 self.server['backend_details'])
762 (self._driver.compute_api.instance_volume_detach.
763 assert_called_once_with(
764 self._context,
765 self.server['backend_details']['instance_id'],
766 available_volume['id']))
767 self._driver.volume_api.get.assert_called_once_with(
768 self._context, available_volume['id'])
770 def test_detach_volume_detached(self):
771 available_volume = fake_volume.FakeVolume()
772 attached_volume = fake_volume.FakeVolume(status='in-use')
773 self.mock_object(self._driver, '_get_volume',
774 mock.Mock(return_value=attached_volume))
775 self.mock_object(self._driver.compute_api, 'instance_volumes_list',
776 mock.Mock(return_value=[]))
777 self.mock_object(self._driver.volume_api, 'get',
778 mock.Mock(return_value=available_volume))
779 self.mock_object(self._driver.compute_api, 'instance_volume_detach')
781 self._driver._detach_volume(self._context, self.share,
782 self.server['backend_details'])
784 self.assertFalse(self._driver.volume_api.get.called)
785 self.assertFalse(
786 self._driver.compute_api.instance_volume_detach.called)
788 def test_allocate_container(self):
789 fake_vol = fake_volume.FakeVolume()
790 self.fake_conf.cinder_volume_type = 'fake_volume_type'
791 self.mock_object(self._driver.volume_api, 'create',
792 mock.Mock(return_value=fake_vol))
794 result = self._driver._allocate_container(self._context, self.share)
795 self.assertEqual(fake_vol, result)
796 self._driver.volume_api.create.assert_called_once_with(
797 self._context,
798 self.share['size'],
799 CONF.volume_name_template % self.share['id'],
800 '',
801 snapshot=None,
802 volume_type='fake_volume_type',
803 availability_zone=self.share['availability_zone'])
805 def test_allocate_container_with_snaphot(self):
806 fake_vol = fake_volume.FakeVolume()
807 fake_vol_snap = fake_volume.FakeVolumeSnapshot()
808 self.mock_object(self._driver, '_get_volume_snapshot',
809 mock.Mock(return_value=fake_vol_snap))
810 self.mock_object(self._driver.volume_api, 'create',
811 mock.Mock(return_value=fake_vol))
813 result = self._driver._allocate_container(self._context,
814 self.share,
815 self.snapshot)
816 self.assertEqual(fake_vol, result)
817 self._driver.volume_api.create.assert_called_once_with(
818 self._context,
819 self.share['size'],
820 CONF.volume_name_template % self.share['id'],
821 '',
822 snapshot=fake_vol_snap,
823 volume_type=None,
824 availability_zone=self.share['availability_zone'])
826 def test_deallocate_container(self):
827 fake_vol = fake_volume.FakeVolume()
828 self.mock_object(self._driver, '_get_volume',
829 mock.Mock(return_value=fake_vol))
830 self.mock_object(self._driver.volume_api, 'delete')
831 self.mock_object(self._driver.volume_api, 'get', mock.Mock(
832 side_effect=exception.VolumeNotFound(volume_id=fake_vol['id'])))
834 self._driver._deallocate_container(self._context, self.share)
836 self._driver._get_volume.assert_called_once_with(
837 self._context, self.share['id'])
838 self._driver.volume_api.delete.assert_called_once_with(
839 self._context, fake_vol['id'])
840 self._driver.volume_api.get.assert_called_once_with(
841 self._context, fake_vol['id'])
843 def test_deallocate_container_with_volume_not_found(self):
844 fake_vol = fake_volume.FakeVolume()
845 self.mock_object(self._driver, '_get_volume',
846 mock.Mock(side_effect=exception.VolumeNotFound(
847 volume_id=fake_vol['id'])))
848 self.mock_object(self._driver.volume_api, 'delete')
850 self._driver._deallocate_container(self._context, self.share)
852 self._driver._get_volume.assert_called_once_with(
853 self._context, self.share['id'])
854 self.assertFalse(self._driver.volume_api.delete.called)
856 def test_create_share_from_snapshot(self):
857 vol1 = 'fake_vol1'
858 vol2 = 'fake_vol2'
859 self.mock_object(self._driver, '_allocate_container',
860 mock.Mock(return_value=vol1))
861 self.mock_object(self._driver, '_attach_volume',
862 mock.Mock(return_value=vol2))
863 self.mock_object(self._driver, '_mount_device')
865 result = self._driver.create_share_from_snapshot(
866 self._context,
867 self.share,
868 self.snapshot,
869 share_server=self.server)
871 self.assertEqual(self._helper_nfs.create_exports.return_value, result)
872 self._driver._allocate_container.assert_called_once_with(
873 self._driver.admin_context, self.share, snapshot=self.snapshot)
874 self._driver._attach_volume.assert_called_once_with(
875 self._driver.admin_context, self.share,
876 self.server['backend_details']['instance_id'], vol1)
877 self._driver._mount_device.assert_called_once_with(
878 self.share, self.server['backend_details'], vol2)
879 self._helper_nfs.create_exports.assert_called_once_with(
880 self.server['backend_details'], self.share['name'])
882 def test_create_share_from_snapshot_invalid_helper(self):
883 self._driver._helpers = {'CIFS': self._helper_cifs}
884 self.assertRaises(exception.InvalidShare,
885 self._driver.create_share_from_snapshot,
886 self._context, self.share, self.snapshot,
887 share_server=self.server)
889 def test_delete_share_no_share_servers_handling(self):
890 self.mock_object(self._driver, '_deallocate_container')
891 self.mock_object(
892 self._driver.service_instance_manager,
893 'get_common_server', mock.Mock(return_value=self.server))
894 self.mock_object(
895 self._driver.service_instance_manager,
896 'ensure_service_instance', mock.Mock(return_value=False))
898 CONF.set_default('driver_handles_share_servers', False)
900 self._driver.delete_share(self._context, self.share)
902 (self._driver.service_instance_manager.get_common_server.
903 assert_called_once_with())
904 self._driver._deallocate_container.assert_called_once_with(
905 self._driver.admin_context, self.share)
906 (self._driver.service_instance_manager.ensure_service_instance.
907 assert_called_once_with(
908 self._context, self.server['backend_details']))
910 def test_delete_share(self):
911 self.mock_object(self._driver, '_unmount_device')
912 self.mock_object(self._driver, '_detach_volume')
913 self.mock_object(self._driver, '_deallocate_container')
915 self._driver.delete_share(
916 self._context, self.share, share_server=self.server)
918 self._helper_nfs.remove_exports.assert_called_once_with(
919 self.server['backend_details'], self.share['name'])
920 self._driver._unmount_device.assert_called_once_with(
921 self.share, self.server['backend_details'])
922 self._driver._detach_volume.assert_called_once_with(
923 self._driver.admin_context, self.share,
924 self.server['backend_details'])
925 self._driver._deallocate_container.assert_called_once_with(
926 self._driver.admin_context, self.share)
927 (self._driver.service_instance_manager.ensure_service_instance.
928 assert_called_once_with(
929 self._context, self.server['backend_details']))
931 def test_detach_volume_with_volume_not_found(self):
932 fake_vol = fake_volume.FakeVolume()
933 fake_server_details = mock.MagicMock()
934 self.mock_object(self._driver.compute_api, 'instance_volumes_list',
935 mock.Mock(return_value=[]))
937 self.mock_object(self._driver, '_get_volume',
938 mock.Mock(side_effect=exception.VolumeNotFound(
939 volume_id=fake_vol['id'])))
941 self._driver._detach_volume(self._context,
942 self.share,
943 fake_server_details)
945 (self._driver.compute_api.instance_volumes_list.
946 assert_called_once_with(self._driver.admin_context,
947 fake_server_details['instance_id']))
948 (self._driver._get_volume.
949 assert_called_once_with(self._driver.admin_context,
950 self.share['id']))
951 self.assertEqual(1, self.mock_warning_log.call_count)
953 def test_delete_share_without_share_server(self):
954 self.mock_object(self._driver, '_unmount_device')
955 self.mock_object(self._driver, '_detach_volume')
956 self.mock_object(self._driver, '_deallocate_container')
958 self._driver.delete_share(
959 self._context, self.share, share_server=None)
961 self.assertFalse(self._helper_nfs.remove_export.called)
962 self.assertFalse(self._driver._unmount_device.called)
963 self.assertFalse(self._driver._detach_volume.called)
964 self._driver._deallocate_container.assert_called_once_with(
965 self._driver.admin_context, self.share)
967 def test_delete_share_without_server_backend_details(self):
968 self.mock_object(self._driver, '_unmount_device')
969 self.mock_object(self._driver, '_detach_volume')
970 self.mock_object(self._driver, '_deallocate_container')
972 fake_share_server = {
973 'instance_id': 'fake_instance_id',
974 'ip': 'fake_ip',
975 'username': 'fake_username',
976 'password': 'fake_password',
977 'pk_path': 'fake_pk_path',
978 'backend_details': {}
979 }
981 self._driver.delete_share(
982 self._context, self.share, share_server=fake_share_server)
984 self.assertFalse(self._helper_nfs.remove_export.called)
985 self.assertFalse(self._driver._unmount_device.called)
986 self.assertFalse(self._driver._detach_volume.called)
987 self._driver._deallocate_container.assert_called_once_with(
988 self._driver.admin_context, self.share)
990 def test_delete_share_without_server_availability(self):
991 self.mock_object(self._driver, '_unmount_device')
992 self.mock_object(self._driver, '_detach_volume')
993 self.mock_object(self._driver, '_deallocate_container')
995 self.mock_object(
996 self._driver.service_instance_manager,
997 'ensure_service_instance', mock.Mock(return_value=False))
998 self._driver.delete_share(
999 self._context, self.share, share_server=self.server)
1001 self.assertFalse(self._helper_nfs.remove_export.called)
1002 self.assertFalse(self._driver._unmount_device.called)
1003 self.assertFalse(self._driver._detach_volume.called)
1004 self._driver._deallocate_container.assert_called_once_with(
1005 self._driver.admin_context, self.share)
1006 (self._driver.service_instance_manager.ensure_service_instance.
1007 assert_called_once_with(
1008 self._context, self.server['backend_details']))
1010 def test_delete_share_invalid_helper(self):
1011 self._driver._helpers = {'CIFS': self._helper_cifs}
1012 self.assertRaises(exception.InvalidShare,
1013 self._driver.delete_share,
1014 self._context, self.share, share_server=self.server)
1016 def test_create_snapshot(self):
1017 fake_vol = fake_volume.FakeVolume()
1018 fake_vol_snap = fake_volume.FakeVolumeSnapshot(
1019 share_instance_id=fake_vol['id'])
1020 self.mock_object(self._driver, '_get_volume',
1021 mock.Mock(return_value=fake_vol))
1022 self.mock_object(self._driver.volume_api, 'create_snapshot_force',
1023 mock.Mock(return_value=fake_vol_snap))
1025 self._driver.create_snapshot(self._context, fake_vol_snap,
1026 share_server=self.server)
1028 self._driver._get_volume.assert_called_once_with(
1029 self._driver.admin_context, fake_vol_snap['share_instance_id'])
1030 self._driver.volume_api.create_snapshot_force.assert_called_once_with(
1031 self._context,
1032 fake_vol['id'],
1033 CONF.volume_snapshot_name_template % fake_vol_snap['id'],
1034 ''
1035 )
1037 def test_delete_snapshot(self):
1038 fake_vol_snap = fake_volume.FakeVolumeSnapshot()
1039 fake_vol_snap2 = {'id': 'fake_vol_snap2'}
1040 self.mock_object(self._driver, '_get_volume_snapshot',
1041 mock.Mock(return_value=fake_vol_snap2))
1042 self.mock_object(self._driver.volume_api, 'delete_snapshot')
1043 self.mock_object(
1044 self._driver.volume_api, 'get_snapshot',
1045 mock.Mock(side_effect=exception.VolumeSnapshotNotFound(
1046 snapshot_id=fake_vol_snap['id'])))
1048 self._driver.delete_snapshot(self._context, fake_vol_snap,
1049 share_server=self.server)
1051 self._driver._get_volume_snapshot.assert_called_once_with(
1052 self._driver.admin_context, fake_vol_snap['id'])
1053 self._driver.volume_api.delete_snapshot.assert_called_once_with(
1054 self._driver.admin_context, fake_vol_snap2['id'])
1055 self._driver.volume_api.get_snapshot.assert_called_once_with(
1056 self._driver.admin_context, fake_vol_snap2['id'])
1058 def test_ensure_share(self):
1059 vol1 = 'fake_vol1'
1060 vol2 = 'fake_vol2'
1061 self._helper_nfs.create_export.return_value = 'fakelocation'
1062 self.mock_object(self._driver, '_get_volume',
1063 mock.Mock(return_value=vol1))
1064 self.mock_object(self._driver, '_attach_volume',
1065 mock.Mock(return_value=vol2))
1066 self.mock_object(self._driver, '_mount_device')
1068 self._driver.ensure_share(
1069 self._context, self.share, share_server=self.server)
1071 self._driver._get_volume.assert_called_once_with(
1072 self._context, self.share['id'])
1073 self._driver._attach_volume.assert_called_once_with(
1074 self._context, self.share,
1075 self.server['backend_details']['instance_id'], vol1)
1076 self._driver._mount_device.assert_called_once_with(
1077 self.share, self.server['backend_details'], vol2)
1078 self._helper_nfs.create_exports.assert_called_once_with(
1079 self.server['backend_details'], self.share['name'], recreate=True)
1081 def test_ensure_share_volume_is_absent(self):
1082 self.mock_object(
1083 self._driver, '_get_volume', mock.Mock(return_value=None))
1084 self.mock_object(self._driver, '_attach_volume')
1086 self._driver.ensure_share(
1087 self._context, self.share, share_server=self.server)
1089 self._driver._get_volume.assert_called_once_with(
1090 self._context, self.share['id'])
1091 self.assertFalse(self._driver._attach_volume.called)
1093 def test_ensure_share_invalid_helper(self):
1094 self._driver._helpers = {'CIFS': self._helper_cifs}
1095 self.assertRaises(exception.InvalidShare, self._driver.ensure_share,
1096 self._context, self.share, share_server=self.server)
1098 @ddt.data(const.ACCESS_LEVEL_RW, const.ACCESS_LEVEL_RO)
1099 def test_update_access(self, access_level):
1101 # fakes
1102 access_rules = [get_fake_access_rule('1.1.1.1', access_level),
1103 get_fake_access_rule('2.2.2.2', access_level)]
1104 add_rules = [get_fake_access_rule('2.2.2.2', access_level), ]
1105 delete_rules = [get_fake_access_rule('3.3.3.3', access_level), ]
1107 # run
1108 self._driver.update_access(self._context, self.share, access_rules,
1109 add_rules=add_rules,
1110 delete_rules=delete_rules,
1111 update_rules=None,
1112 share_server=self.server)
1114 # asserts
1115 (self._driver._helpers[self.share['share_proto']].
1116 update_access.assert_called_once_with(
1117 self.server['backend_details'], self.share['name'],
1118 access_rules, add_rules=add_rules, delete_rules=delete_rules))
1120 @ddt.data(fake_share.fake_share(),
1121 fake_share.fake_share(share_proto='NFSBOGUS'),
1122 fake_share.fake_share(share_proto='CIFSBOGUS'))
1123 def test__get_helper_with_wrong_proto(self, share):
1124 self.assertRaises(exception.InvalidShare,
1125 self._driver._get_helper, share)
1127 def test__setup_server(self):
1128 sim = self._driver.instance_manager
1129 net_info = [{
1130 'server_id': 'fake',
1131 'neutron_net_id': 'fake-net-id',
1132 'neutron_subnet_id': 'fake-subnet-id',
1133 }]
1134 self._driver.setup_server(net_info)
1135 sim.set_up_service_instance.assert_called_once_with(
1136 self._context, net_info[0])
1138 def test__setup_server_revert(self):
1140 def raise_exception(*args, **kwargs):
1141 raise exception.ServiceInstanceException
1143 net_info = [{'server_id': 'fake',
1144 'neutron_net_id': 'fake-net-id',
1145 'neutron_subnet_id': 'fake-subnet-id'}]
1146 self.mock_object(self._driver.service_instance_manager,
1147 'set_up_service_instance',
1148 mock.Mock(side_effect=raise_exception))
1149 self.assertRaises(exception.ServiceInstanceException,
1150 self._driver.setup_server,
1151 net_info)
1153 def test__teardown_server(self):
1154 server_details = {
1155 'instance_id': 'fake_instance_id',
1156 'subnet_id': 'fake_subnet_id',
1157 'router_id': 'fake_router_id',
1158 }
1159 self._driver.teardown_server(server_details)
1160 (self._driver.service_instance_manager.delete_service_instance.
1161 assert_called_once_with(
1162 self._driver.admin_context, server_details))
1164 def test_ssh_exec_connection_not_exist(self):
1165 ssh_conn_timeout = 30
1166 CONF.set_default('ssh_conn_timeout', ssh_conn_timeout)
1167 ssh_output = 'fake_ssh_output'
1168 cmd = ['fake', 'command']
1169 ssh = mock.Mock()
1170 ssh.get_transport = mock.Mock()
1171 ssh.get_transport().is_active = mock.Mock(return_value=True)
1172 ssh_pool = mock.Mock()
1173 ssh_pool.create = mock.Mock(return_value=ssh)
1174 self.mock_object(ssh_utils,
1175 'SSHPool',
1176 mock.Mock(return_value=ssh_pool))
1177 self.mock_object(processutils, 'ssh_execute',
1178 mock.Mock(return_value=ssh_output))
1179 self._driver.ssh_connections = {}
1181 result = self._driver._ssh_exec(self.server, cmd)
1183 ssh_utils.SSHPool.assert_called_once_with(
1184 self.server['ip'], 22, ssh_conn_timeout, self.server['username'],
1185 self.server['password'], self.server['pk_path'], max_size=1)
1186 ssh_pool.create.assert_called_once_with()
1187 processutils.ssh_execute.assert_called_once_with(
1188 ssh, 'fake command', check_exit_code=True)
1189 ssh.get_transport().is_active.assert_called_once_with()
1190 self.assertEqual(
1191 self._driver.ssh_connections,
1192 {self.server['instance_id']: (ssh_pool, ssh)}
1193 )
1194 self.assertEqual(ssh_output, result)
1196 def test_ssh_exec_connection_exist(self):
1197 ssh_output = 'fake_ssh_output'
1198 cmd = ['fake', 'command']
1199 ssh = mock.Mock()
1200 ssh.get_transport = mock.Mock()
1201 ssh.get_transport().is_active = mock.Mock(side_effect=lambda: True)
1202 ssh_pool = mock.Mock()
1203 self.mock_object(processutils, 'ssh_execute',
1204 mock.Mock(return_value=ssh_output))
1205 self._driver.ssh_connections = {
1206 self.server['instance_id']: (ssh_pool, ssh)
1207 }
1209 result = self._driver._ssh_exec(self.server, cmd)
1211 processutils.ssh_execute.assert_called_once_with(
1212 ssh, 'fake command', check_exit_code=True)
1213 ssh.get_transport().is_active.assert_called_once_with()
1214 self.assertEqual(
1215 self._driver.ssh_connections,
1216 {self.server['instance_id']: (ssh_pool, ssh)}
1217 )
1218 self.assertEqual(ssh_output, result)
1220 def test_ssh_exec_connection_recreation(self):
1221 ssh_output = 'fake_ssh_output'
1222 cmd = ['fake', 'command']
1223 ssh = mock.Mock()
1224 ssh.get_transport = mock.Mock()
1225 ssh.get_transport().is_active = mock.Mock(side_effect=lambda: False)
1226 ssh_pool = mock.Mock()
1227 ssh_pool.create = mock.Mock(side_effect=lambda: ssh)
1228 ssh_pool.remove = mock.Mock()
1229 self.mock_object(processutils, 'ssh_execute',
1230 mock.Mock(return_value=ssh_output))
1231 self._driver.ssh_connections = {
1232 self.server['instance_id']: (ssh_pool, ssh)
1233 }
1235 result = self._driver._ssh_exec(self.server, cmd)
1237 processutils.ssh_execute.assert_called_once_with(
1238 ssh, 'fake command', check_exit_code=True)
1239 ssh.get_transport().is_active.assert_called_once_with()
1240 ssh_pool.create.assert_called_once_with()
1241 ssh_pool.remove.assert_called_once_with(ssh)
1242 self.assertEqual(
1243 self._driver.ssh_connections,
1244 {self.server['instance_id']: (ssh_pool, ssh)}
1245 )
1246 self.assertEqual(ssh_output, result)
1248 def test__ssh_exec_check_list_comprehensions_still_work(self):
1249 ssh_output = 'fake_ssh_output'
1250 cmd = ['fake', 'command spaced']
1251 ssh = mock.Mock()
1252 ssh_pool = mock.Mock()
1253 ssh_pool.create = mock.Mock(side_effect=lambda: ssh)
1254 ssh_pool.remove = mock.Mock()
1255 self.mock_object(processutils, 'ssh_execute',
1256 mock.Mock(return_value=ssh_output))
1257 self._driver.ssh_connections = {
1258 self.server['instance_id']: (ssh_pool, ssh)
1259 }
1261 self._driver._ssh_exec(self.server, cmd)
1263 processutils.ssh_execute.assert_called_once_with(
1264 ssh, 'fake "command spaced"', check_exit_code=True)
1266 def test_get_share_stats_refresh_false(self):
1267 self._driver._stats = {'fake_key': 'fake_value'}
1269 result = self._driver.get_share_stats(False)
1271 self.assertEqual(self._driver._stats, result)
1273 def test_get_share_stats_refresh_true(self):
1274 fake_stats = {'fake_key': 'fake_value'}
1275 self._driver._stats = fake_stats
1276 expected_keys = [
1277 'qos', 'driver_version', 'share_backend_name',
1278 'free_capacity_gb', 'total_capacity_gb',
1279 'driver_handles_share_servers',
1280 'reserved_percentage', 'reserved_snapshot_percentage',
1281 'reserved_share_extend_percentage',
1282 'vendor_name', 'storage_protocol',
1283 ]
1285 result = self._driver.get_share_stats(True)
1287 self.assertNotEqual(fake_stats, result)
1288 for key in expected_keys:
1289 self.assertIn(key, result)
1290 self.assertTrue(result['driver_handles_share_servers'])
1291 self.assertEqual('Open Source', result['vendor_name'])
1293 def _setup_manage_mocks(self,
1294 get_share_type_extra_specs='False',
1295 is_device_mounted=True,
1296 server_details=None):
1297 CONF.set_default('driver_handles_share_servers', False)
1299 self.mock_object(share_types, 'get_share_type_extra_specs',
1300 mock.Mock(return_value=get_share_type_extra_specs))
1302 self.mock_object(self._driver, '_is_device_mounted',
1303 mock.Mock(return_value=is_device_mounted))
1305 self.mock_object(self._driver, 'service_instance_manager')
1306 server = {'backend_details': server_details}
1307 self.mock_object(self._driver.service_instance_manager,
1308 'get_common_server',
1309 mock.Mock(return_value=server))
1311 def test_manage_invalid_protocol(self):
1312 share = {'share_proto': 'fake_proto'}
1313 self._setup_manage_mocks()
1315 self.assertRaises(exception.InvalidShare,
1316 self._driver.manage_existing, share, {})
1318 def test_manage_not_mounted_share(self):
1319 share = get_fake_manage_share()
1320 fake_path = '/foo/bar'
1321 self._setup_manage_mocks(is_device_mounted=False)
1322 self.mock_object(
1323 self._driver._helpers[share['share_proto']],
1324 'get_share_path_by_export_location',
1325 mock.Mock(return_value=fake_path))
1327 self.assertRaises(exception.ManageInvalidShare,
1328 self._driver.manage_existing, share, {})
1330 self.assertEqual(
1331 1,
1332 self._driver.service_instance_manager.get_common_server.call_count)
1333 self._driver._is_device_mounted.assert_called_once_with(
1334 fake_path, None)
1335 (self._driver._helpers[share['share_proto']].
1336 get_share_path_by_export_location.assert_called_once_with(
1337 None, share['export_locations'][0]['path']))
1339 def test_manage_share_not_attached_to_cinder_volume_invalid_size(self):
1340 share = get_fake_manage_share()
1341 server_details = {}
1342 fake_path = '/foo/bar'
1343 self._setup_manage_mocks(server_details=server_details)
1344 self.mock_object(self._driver, '_get_volume',
1345 mock.Mock(return_value=None))
1346 error = exception.ManageInvalidShare(reason="fake")
1347 self.mock_object(
1348 self._driver, '_get_mounted_share_size',
1349 mock.Mock(side_effect=error))
1350 self.mock_object(
1351 self._driver._helpers[share['share_proto']],
1352 'get_share_path_by_export_location',
1353 mock.Mock(return_value=fake_path))
1355 self.assertRaises(exception.ManageInvalidShare,
1356 self._driver.manage_existing, share, {})
1358 self._driver._get_mounted_share_size.assert_called_once_with(
1359 fake_path, server_details)
1360 (self._driver._helpers[share['share_proto']].
1361 get_share_path_by_export_location.assert_called_once_with(
1362 server_details, share['export_locations'][0]['path']))
1364 def test_manage_share_not_attached_to_cinder_volume(self):
1365 share = get_fake_manage_share()
1366 share_size = "fake"
1367 fake_path = '/foo/bar'
1368 fake_exports = ['foo', 'bar']
1369 server_details = {}
1370 self._setup_manage_mocks(server_details=server_details)
1371 self.mock_object(self._driver, '_get_volume')
1372 self.mock_object(self._driver, '_get_mounted_share_size',
1373 mock.Mock(return_value=share_size))
1374 self.mock_object(
1375 self._driver._helpers[share['share_proto']],
1376 'get_share_path_by_export_location',
1377 mock.Mock(return_value=fake_path))
1378 self.mock_object(
1379 self._driver._helpers[share['share_proto']],
1380 'get_exports_for_share',
1381 mock.Mock(return_value=fake_exports))
1383 result = self._driver.manage_existing(share, {})
1385 self.assertEqual(
1386 {'size': share_size, 'export_locations': fake_exports}, result)
1387 (self._driver._helpers[share['share_proto']].get_exports_for_share.
1388 assert_called_once_with(
1389 server_details, share['export_locations'][0]['path']))
1390 (self._driver._helpers[share['share_proto']].
1391 get_share_path_by_export_location.assert_called_once_with(
1392 server_details, share['export_locations'][0]['path']))
1393 self._driver._get_mounted_share_size.assert_called_once_with(
1394 fake_path, server_details)
1395 self.assertFalse(self._driver._get_volume.called)
1397 def test_manage_share_attached_to_cinder_volume_not_found(self):
1398 share = get_fake_manage_share()
1399 server_details = {}
1400 driver_options = {'volume_id': 'fake'}
1401 self._setup_manage_mocks(server_details=server_details)
1402 self.mock_object(
1403 self._driver.volume_api, 'get',
1404 mock.Mock(side_effect=exception.VolumeNotFound(volume_id="fake"))
1405 )
1407 self.assertRaises(exception.ManageInvalidShare,
1408 self._driver.manage_existing, share, driver_options)
1410 self._driver.volume_api.get.assert_called_once_with(
1411 mock.ANY, driver_options['volume_id'])
1413 def test_manage_share_attached_to_cinder_volume_not_mounted_to_srv(self):
1414 share = get_fake_manage_share()
1415 server_details = {'instance_id': 'fake'}
1416 driver_options = {'volume_id': 'fake'}
1417 volume = {'id': 'fake'}
1418 self._setup_manage_mocks(server_details=server_details)
1419 self.mock_object(self._driver.volume_api, 'get',
1420 mock.Mock(return_value=volume))
1421 self.mock_object(self._driver.compute_api, 'instance_volumes_list',
1422 mock.Mock(return_value=[]))
1424 self.assertRaises(exception.ManageInvalidShare,
1425 self._driver.manage_existing, share, driver_options)
1427 self._driver.volume_api.get.assert_called_once_with(
1428 mock.ANY, driver_options['volume_id'])
1429 self._driver.compute_api.instance_volumes_list.assert_called_once_with(
1430 mock.ANY, server_details['instance_id'])
1432 def test_manage_share_attached_to_cinder_volume(self):
1433 share = get_fake_manage_share()
1434 fake_size = 'foobar'
1435 fake_exports = ['foo', 'bar']
1436 server_details = {'instance_id': 'fake'}
1437 driver_options = {'volume_id': 'fake'}
1438 volume = {'id': 'fake', 'name': 'fake_volume_1', 'size': fake_size}
1439 self._setup_manage_mocks(server_details=server_details)
1440 self.mock_object(self._driver.volume_api, 'get',
1441 mock.Mock(return_value=volume))
1442 self._driver.volume_api.update = mock.Mock()
1443 self.mock_object(self._driver.compute_api, 'instance_volumes_list',
1444 mock.Mock(return_value=['fake']))
1445 self.mock_object(
1446 self._driver._helpers[share['share_proto']],
1447 'get_exports_for_share',
1448 mock.Mock(return_value=fake_exports))
1450 result = self._driver.manage_existing(share, driver_options)
1452 self.assertEqual(
1453 {'size': fake_size, 'export_locations': fake_exports}, result)
1454 (self._driver._helpers[share['share_proto']].get_exports_for_share.
1455 assert_called_once_with(
1456 server_details, share['export_locations'][0]['path']))
1457 expected_volume_update = {
1458 'name': self._driver._get_volume_name(share['id'])
1459 }
1460 self._driver.volume_api.update.assert_called_once_with(
1461 mock.ANY, volume['id'], expected_volume_update)
1462 self.fake_private_storage.update.assert_called_once_with(
1463 share['id'], {'volume_id': volume['id']}
1464 )
1466 def test_get_mounted_share_size(self):
1467 output = ("Filesystem blocks Used Available Capacity Mounted on\n"
1468 "/dev/fake 1G 1G 1G 4% /shares/share-fake")
1469 self.mock_object(self._driver, '_ssh_exec',
1470 mock.Mock(return_value=(output, '')))
1472 actual_result = self._driver._get_mounted_share_size('/fake/path', {})
1473 self.assertEqual(1, actual_result)
1475 @ddt.data("fake\nfake\n", "fake", "fake\n")
1476 def test_get_mounted_share_size_invalid_output(self, output):
1477 self.mock_object(self._driver, '_ssh_exec',
1478 mock.Mock(return_value=(output, '')))
1479 self.assertRaises(exception.ManageInvalidShare,
1480 self._driver._get_mounted_share_size,
1481 '/fake/path', {})
1483 def test_get_consumed_space(self):
1484 mount_path = "fake_path"
1485 server_details = {}
1486 index = 2
1487 valid_result = 1
1488 self.mock_object(self._driver, '_get_mount_stats_by_index',
1489 mock.Mock(return_value=valid_result * 1024))
1491 actual_result = self._driver._get_consumed_space(
1492 mount_path, server_details)
1494 self.assertEqual(valid_result, actual_result)
1495 self._driver._get_mount_stats_by_index.assert_called_once_with(
1496 mount_path, server_details, index, block_size='M'
1497 )
1499 def test_get_consumed_space_invalid(self):
1500 self.mock_object(
1501 self._driver,
1502 '_get_mount_stats_by_index',
1503 mock.Mock(side_effect=exception.ManilaException("fake"))
1504 )
1506 self.assertRaises(
1507 exception.InvalidShare,
1508 self._driver._get_consumed_space,
1509 "fake", "fake"
1510 )
1512 @ddt.data(100, 130, 123)
1513 def test_extend_share(self, volume_size):
1514 fake_volume = {
1515 "name": "fake",
1516 "size": volume_size,
1517 }
1518 fake_share = {
1519 'id': 'fake',
1520 'share_proto': 'NFS',
1521 'name': 'test_share',
1522 }
1523 new_size = 123
1524 srv_details = self.server['backend_details']
1525 self.mock_object(
1526 self._driver.service_instance_manager,
1527 'get_common_server',
1528 mock.Mock(return_value=self.server)
1529 )
1530 self.mock_object(self._driver, '_unmount_device')
1531 self.mock_object(self._driver, '_detach_volume')
1532 self.mock_object(self._driver, '_extend_volume')
1533 self.mock_object(self._driver, '_attach_volume')
1534 self.mock_object(self._driver, '_mount_device')
1535 self.mock_object(self._driver, '_resize_filesystem')
1536 self.mock_object(
1537 self._driver, '_get_volume',
1538 mock.Mock(return_value=fake_volume)
1539 )
1540 CONF.set_default('driver_handles_share_servers', False)
1542 self._driver.extend_share(fake_share, new_size)
1544 self.assertTrue(
1545 self._driver.service_instance_manager.get_common_server.called)
1546 self._driver._unmount_device.assert_called_once_with(
1547 fake_share, srv_details)
1548 self._driver._get_volume.assert_called_once_with(
1549 mock.ANY, fake_share['id'])
1551 if new_size > volume_size:
1552 self._driver._detach_volume.assert_called_once_with(
1553 mock.ANY, fake_share, srv_details)
1554 self._driver._extend_volume.assert_called_once_with(
1555 mock.ANY, fake_volume, new_size)
1556 self._driver._attach_volume.assert_called_once_with(
1557 mock.ANY, fake_share, srv_details['instance_id'], mock.ANY)
1558 else:
1559 self.assertFalse(self._driver._detach_volume.called)
1560 self.assertFalse(self._driver._extend_volume.called)
1561 self.assertFalse(self._driver._attach_volume.called)
1563 (self._helper_nfs.disable_access_for_maintenance.
1564 assert_called_once_with(srv_details, 'test_share'))
1565 (self._helper_nfs.restore_access_after_maintenance.
1566 assert_called_once_with(srv_details, 'test_share'))
1567 self.assertTrue(self._driver._resize_filesystem.called)
1569 def test_extend_volume(self):
1570 fake_volume = {'id': 'fake'}
1571 new_size = 123
1572 self.mock_object(self._driver.volume_api, 'extend')
1573 self.mock_object(self._driver.volume_api, 'wait_for_available_volume')
1575 self._driver._extend_volume(self._context, fake_volume, new_size)
1577 self._driver.volume_api.extend.assert_called_once_with(
1578 self._context, fake_volume['id'], new_size
1579 )
1580 m_wfav = self._driver.volume_api.wait_for_available_volume
1581 m_wfav.assert_called_once_with(
1582 fake_volume, mock.ANY, msg_timeout=mock.ANY, msg_error=mock.ANY,
1583 expected_size=new_size
1584 )
1586 def test_resize_filesystem(self):
1587 fake_server_details = {'fake': 'fake'}
1588 fake_volume = {'mountpoint': '/dev/fake'}
1589 self.mock_object(self._driver, '_ssh_exec')
1591 self._driver._resize_filesystem(
1592 fake_server_details, fake_volume, new_size=123)
1594 self._driver._ssh_exec.assert_any_call(
1595 fake_server_details, ['sudo', 'fsck', '-pf', '/dev/fake'])
1596 self._driver._ssh_exec.assert_any_call(
1597 fake_server_details,
1598 ['sudo', 'resize2fs', '/dev/fake', "%sG" % 123]
1599 )
1600 self.assertEqual(2, self._driver._ssh_exec.call_count)
1602 @ddt.data(
1603 {
1604 'source': processutils.ProcessExecutionError(
1605 stderr="resize2fs: New size smaller than minimum (123456)"),
1606 'target': exception.Invalid
1607 },
1608 {
1609 'source': processutils.ProcessExecutionError(stderr="fake_error"),
1610 'target': exception.ManilaException
1611 }
1612 )
1613 @ddt.unpack
1614 def test_resize_filesystem_invalid_new_size(self, source, target):
1615 fake_server_details = {'fake': 'fake'}
1616 fake_volume = {'mountpoint': '/dev/fake'}
1617 ssh_mock = mock.Mock(side_effect=["fake", source])
1618 self.mock_object(self._driver, '_ssh_exec', ssh_mock)
1620 self.assertRaises(
1621 target,
1622 self._driver._resize_filesystem,
1623 fake_server_details, fake_volume, new_size=123
1624 )
1626 def test_shrink_share_invalid_size(self):
1627 fake_share = {'id': 'fake', 'export_locations': [{'path': 'test'}]}
1628 new_size = 123
1629 self.mock_object(
1630 self._driver.service_instance_manager,
1631 'get_common_server',
1632 mock.Mock(return_value=self.server)
1633 )
1634 self.mock_object(self._driver, '_get_helper')
1635 self.mock_object(self._driver, '_get_consumed_space',
1636 mock.Mock(return_value=200))
1637 CONF.set_default('driver_handles_share_servers', False)
1639 self.assertRaises(
1640 exception.ShareShrinkingPossibleDataLoss,
1641 self._driver.shrink_share,
1642 fake_share,
1643 new_size
1644 )
1646 self._driver._get_helper.assert_called_once_with(fake_share)
1647 self._driver._get_consumed_space.assert_called_once_with(
1648 mock.ANY, self.server['backend_details'])
1650 def _setup_shrink_mocks(self):
1651 share = {'id': 'fake', 'export_locations': [{'path': 'test'}],
1652 'name': 'fake'}
1653 volume = {'id': 'fake'}
1654 new_size = 123
1655 server_details = self.server['backend_details']
1656 self.mock_object(
1657 self._driver.service_instance_manager,
1658 'get_common_server',
1659 mock.Mock(return_value=self.server)
1660 )
1661 helper = mock.Mock()
1662 self.mock_object(self._driver, '_get_helper',
1663 mock.Mock(return_value=helper))
1664 self.mock_object(self._driver, '_get_consumed_space',
1665 mock.Mock(return_value=100))
1666 self.mock_object(self._driver, '_get_volume',
1667 mock.Mock(return_value=volume))
1668 self.mock_object(self._driver, '_unmount_device')
1669 self.mock_object(self._driver, '_mount_device')
1670 CONF.set_default('driver_handles_share_servers', False)
1672 return share, volume, new_size, server_details, helper
1674 @ddt.data({'source': exception.Invalid("fake"),
1675 'target': exception.ShareShrinkingPossibleDataLoss},
1676 {'source': exception.ManilaException("fake"),
1677 'target': exception.Invalid})
1678 @ddt.unpack
1679 def test_shrink_share_error_on_resize_fs(self, source, target):
1680 share, vol, size, server_details, _ = self._setup_shrink_mocks()
1681 resize_mock = mock.Mock(side_effect=source)
1682 self.mock_object(self._driver, '_resize_filesystem', resize_mock)
1684 self.assertRaises(target, self._driver.shrink_share, share, size)
1686 resize_mock.assert_called_once_with(server_details, vol,
1687 new_size=size)
1689 def test_shrink_share(self):
1690 share, vol, size, server_details, helper = self._setup_shrink_mocks()
1691 self.mock_object(self._driver, '_resize_filesystem')
1693 self._driver.shrink_share(share, size)
1695 self._driver._get_helper.assert_called_once_with(share)
1696 self._driver._get_consumed_space.assert_called_once_with(
1697 mock.ANY, server_details)
1698 self._driver._get_volume.assert_called_once_with(mock.ANY, share['id'])
1699 self._driver._unmount_device.assert_called_once_with(share,
1700 server_details)
1701 self._driver._resize_filesystem(
1702 server_details, vol, new_size=size)
1703 self._driver._mount_device(share, server_details, vol)
1704 self.assertTrue(helper.disable_access_for_maintenance.called)
1705 self.assertTrue(helper.restore_access_after_maintenance.called)
1707 @ddt.data({'share_servers': [], 'result': None},
1708 {'share_servers': None, 'result': None},
1709 {'share_servers': ['fake'], 'result': 'fake'},
1710 {'share_servers': ['fake', 'test'], 'result': 'fake'})
1711 @ddt.unpack
1712 def tests_choose_share_server_compatible_with_share(self, share_servers,
1713 result):
1714 fake_share = "fake"
1716 actual_result = self._driver.choose_share_server_compatible_with_share(
1717 self._context, share_servers, fake_share
1718 )
1720 self.assertEqual(result, actual_result)
1722 def test_manage_snapshot_not_found(self):
1723 snapshot_instance = {'id': 'snap_instance_id',
1724 'provider_location': 'vol_snap_id'}
1725 driver_options = {}
1726 self.mock_object(
1727 self._driver.volume_api, 'get_snapshot',
1728 mock.Mock(side_effect=exception.VolumeSnapshotNotFound(
1729 snapshot_id='vol_snap_id')))
1731 self.assertRaises(exception.ManageInvalidShareSnapshot,
1732 self._driver.manage_existing_snapshot,
1733 snapshot_instance,
1734 driver_options)
1735 self._driver.volume_api.get_snapshot.assert_called_once_with(
1736 self._context, 'vol_snap_id')
1738 def test_manage_snapshot_valid(self):
1739 snapshot_instance = {'id': 'snap_instance_id',
1740 'provider_location': 'vol_snap_id'}
1741 volume_snapshot = {'id': 'vol_snap_id', 'size': 1}
1742 self.mock_object(self._driver.volume_api, 'get_snapshot',
1743 mock.Mock(return_value=volume_snapshot))
1744 ret_manage = self._driver.manage_existing_snapshot(
1745 snapshot_instance, {})
1747 self.assertEqual({'provider_location': 'vol_snap_id',
1748 'size': 1}, ret_manage)
1750 self._driver.volume_api.get_snapshot.assert_called_once_with(
1751 self._context, 'vol_snap_id')
1753 def test_unmanage_snapshot(self):
1754 snapshot_instance = {'id': 'snap_instance_id',
1755 'provider_location': 'vol_snap_id'}
1756 self.mock_object(self._driver.private_storage, 'delete')
1757 self._driver.unmanage_snapshot(snapshot_instance)
1759 self._driver.private_storage.delete.assert_called_once_with(
1760 'snap_instance_id')
1763@generic.ensure_server
1764def fake(driver_instance, context, share_server=None):
1765 return share_server
1768@ddt.ddt
1769class GenericDriverEnsureServerTestCase(test.TestCase):
1771 def setUp(self):
1772 super(GenericDriverEnsureServerTestCase, self).setUp()
1773 self._context = context.get_admin_context()
1774 self.server = {'id': 'fake_id', 'backend_details': {'foo': 'bar'}}
1775 self.dhss_false = type(
1776 'Fake', (object,), {'driver_handles_share_servers': False})
1777 self.dhss_true = type(
1778 'Fake', (object,), {'driver_handles_share_servers': True})
1780 def test_share_servers_are_not_handled_server_not_provided(self):
1781 self.dhss_false.service_instance_manager = mock.Mock()
1782 self.dhss_false.service_instance_manager.get_common_server = (
1783 mock.Mock(return_value=self.server))
1784 self.dhss_false.service_instance_manager.ensure_service_instance = (
1785 mock.Mock(return_value=True))
1787 actual = fake(self.dhss_false, self._context)
1789 self.assertEqual(self.server, actual)
1790 (self.dhss_false.service_instance_manager.
1791 get_common_server.assert_called_once_with())
1792 (self.dhss_false.service_instance_manager.ensure_service_instance.
1793 assert_called_once_with(
1794 self._context, self.server['backend_details']))
1796 @ddt.data({'id': 'without_details'},
1797 {'id': 'with_details', 'backend_details': {'foo': 'bar'}})
1798 def test_share_servers_are_not_handled_server_provided(self, server):
1799 self.assertRaises(
1800 exception.ManilaException,
1801 fake, self.dhss_false, self._context, share_server=server)
1803 def test_share_servers_are_handled_server_provided(self):
1804 self.dhss_true.service_instance_manager = mock.Mock()
1805 self.dhss_true.service_instance_manager.ensure_service_instance = (
1806 mock.Mock(return_value=True))
1808 actual = fake(self.dhss_true, self._context, share_server=self.server)
1810 self.assertEqual(self.server, actual)
1811 (self.dhss_true.service_instance_manager.ensure_service_instance.
1812 assert_called_once_with(
1813 self._context, self.server['backend_details']))
1815 def test_share_servers_are_handled_invalid_server_provided(self):
1816 server = {'id': 'without_details'}
1818 self.assertRaises(
1819 exception.ManilaException,
1820 fake, self.dhss_true, self._context, share_server=server)
1822 def test_share_servers_are_handled_server_not_provided(self):
1823 self.assertRaises(
1824 exception.ManilaException, fake, self.dhss_true, self._context)