"Fossies" - the Fresh Open Source Software Archive 
Member "manila-8.1.4/manila/tests/share/drivers/netapp/dataontap/cluster_mode/test_lib_base.py" (19 Nov 2020, 236116 Bytes) of package /linux/misc/openstack/manila-8.1.4.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the latest
Fossies "Diffs" side-by-side code changes report for "test_lib_base.py":
8.1.3_vs_8.1.4.
1 # Copyright (c) 2015 Clinton Knight. All rights reserved.
2 # Copyright (c) 2015 Tom Barron. 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.
15 """
16 Unit tests for the NetApp Data ONTAP cDOT base storage driver library.
17 """
18
19 import copy
20 import json
21 import math
22 import socket
23 import time
24
25 import ddt
26 import mock
27 from oslo_log import log
28 from oslo_service import loopingcall
29 from oslo_utils import timeutils
30 from oslo_utils import units
31 from oslo_utils import uuidutils
32
33 from manila.common import constants
34 from manila import exception
35 from manila.share.drivers.netapp.dataontap.client import api as netapp_api
36 from manila.share.drivers.netapp.dataontap.client import client_cmode
37 from manila.share.drivers.netapp.dataontap.cluster_mode import data_motion
38 from manila.share.drivers.netapp.dataontap.cluster_mode import lib_base
39 from manila.share.drivers.netapp.dataontap.cluster_mode import performance
40 from manila.share.drivers.netapp.dataontap.protocols import cifs_cmode
41 from manila.share.drivers.netapp.dataontap.protocols import nfs_cmode
42 from manila.share.drivers.netapp import utils as na_utils
43 from manila.share import share_types
44 from manila.share import utils as share_utils
45 from manila import test
46 from manila.tests import fake_share
47 from manila.tests.share.drivers.netapp.dataontap import fakes as fake
48 from manila.tests import utils
49
50
51 def fake_replica(**kwargs):
52 return fake_share.fake_replica(for_manager=True, **kwargs)
53
54
55 @ddt.ddt
56 class NetAppFileStorageLibraryTestCase(test.TestCase):
57
58 def setUp(self):
59 super(NetAppFileStorageLibraryTestCase, self).setUp()
60
61 self.mock_object(na_utils, 'validate_driver_instantiation')
62 self.mock_object(na_utils, 'setup_tracing')
63
64 # Mock loggers as themselves to allow logger arg validation
65 mock_logger = log.getLogger('mock_logger')
66 self.mock_object(lib_base.LOG,
67 'info',
68 mock.Mock(side_effect=mock_logger.info))
69 self.mock_object(lib_base.LOG,
70 'warning',
71 mock.Mock(side_effect=mock_logger.warning))
72 self.mock_object(lib_base.LOG,
73 'error',
74 mock.Mock(side_effect=mock_logger.error))
75 self.mock_object(lib_base.LOG,
76 'debug',
77 mock.Mock(side_effect=mock_logger.debug))
78
79 kwargs = {
80 'configuration': fake.get_config_cmode(),
81 'private_storage': mock.Mock(),
82 'app_version': fake.APP_VERSION
83 }
84 self.library = lib_base.NetAppCmodeFileStorageLibrary(fake.DRIVER_NAME,
85 **kwargs)
86 self.library._client = mock.Mock()
87 self.library._perf_library = mock.Mock()
88 self.client = self.library._client
89 self.context = mock.Mock()
90 self.fake_replica = copy.deepcopy(fake.SHARE)
91 self.fake_replica_2 = copy.deepcopy(fake.SHARE)
92 self.fake_replica_2['id'] = fake.SHARE_ID2
93 self.fake_replica_2['replica_state'] = (
94 constants.REPLICA_STATE_OUT_OF_SYNC)
95 self.mock_dm_session = mock.Mock()
96 self.mock_object(data_motion, "DataMotionSession",
97 mock.Mock(return_value=self.mock_dm_session))
98 self.mock_object(data_motion, 'get_client_for_backend')
99
100 def _mock_api_error(self, code='fake', message='fake'):
101 return mock.Mock(side_effect=netapp_api.NaApiError(code=code,
102 message=message))
103
104 def test_init(self):
105 self.assertEqual(fake.DRIVER_NAME, self.library.driver_name)
106 self.assertEqual(1, na_utils.validate_driver_instantiation.call_count)
107 self.assertEqual(1, na_utils.setup_tracing.call_count)
108 self.assertListEqual([], self.library._licenses)
109 self.assertDictEqual({}, self.library._clients)
110 self.assertDictEqual({}, self.library._ssc_stats)
111 self.assertIsNotNone(self.library._app_version)
112
113 def test_do_setup(self):
114 mock_get_api_client = self.mock_object(self.library, '_get_api_client')
115 self.mock_object(
116 performance, 'PerformanceLibrary',
117 mock.Mock(return_value='fake_perf_library'))
118 self.mock_object(
119 self.library._client, 'check_for_cluster_credentials',
120 mock.Mock(return_value=True))
121 self.mock_object(
122 self.library, '_check_snaprestore_license',
123 mock.Mock(return_value=True))
124 self.mock_object(
125 self.library,
126 '_get_licenses',
127 mock.Mock(return_value=fake.LICENSES))
128 self.library.do_setup(self.context)
129
130 self.assertEqual(fake.LICENSES, self.library._licenses)
131 mock_get_api_client.assert_called_once_with()
132 (self.library._client.check_for_cluster_credentials.
133 assert_called_once_with())
134 self.assertEqual('fake_perf_library', self.library._perf_library)
135 self.mock_object(self.library._client,
136 'check_for_cluster_credentials',
137 mock.Mock(return_value=True))
138 self.mock_object(
139 self.library, '_check_snaprestore_license',
140 mock.Mock(return_value=True))
141 mock_set_cluster_info = self.mock_object(
142 self.library, '_set_cluster_info')
143 self.library.do_setup(self.context)
144 mock_set_cluster_info.assert_called_once()
145
146 def test_set_cluster_info(self):
147 self.library._set_cluster_info()
148 self.assertTrue(self.library._cluster_info['nve_support'],
149 fake.CLUSTER_NODES)
150
151 def test_check_for_setup_error(self):
152 mock_start_periodic_tasks = self.mock_object(self.library,
153 '_start_periodic_tasks')
154 self.library.check_for_setup_error()
155
156 mock_start_periodic_tasks.assert_called_once_with()
157
158 def test_get_vserver(self):
159 self.assertRaises(NotImplementedError, self.library._get_vserver)
160
161 def test_get_api_client(self):
162
163 client_kwargs = fake.CLIENT_KWARGS.copy()
164
165 # First call should proceed normally.
166 mock_client_constructor = self.mock_object(client_cmode,
167 'NetAppCmodeClient')
168 client1 = self.library._get_api_client()
169 self.assertIsNotNone(client1)
170 mock_client_constructor.assert_called_once_with(**client_kwargs)
171
172 # Second call should yield the same object.
173 mock_client_constructor = self.mock_object(client_cmode,
174 'NetAppCmodeClient')
175 client2 = self.library._get_api_client()
176 self.assertEqual(client1, client2)
177 self.assertFalse(mock_client_constructor.called)
178
179 def test_get_api_client_with_vserver(self):
180
181 client_kwargs = fake.CLIENT_KWARGS.copy()
182 client_kwargs['vserver'] = fake.VSERVER1
183
184 # First call should proceed normally.
185 mock_client_constructor = self.mock_object(client_cmode,
186 'NetAppCmodeClient')
187 client1 = self.library._get_api_client(vserver=fake.VSERVER1)
188 self.assertIsNotNone(client1)
189 mock_client_constructor.assert_called_once_with(**client_kwargs)
190
191 # Second call should yield the same object.
192 mock_client_constructor = self.mock_object(client_cmode,
193 'NetAppCmodeClient')
194 client2 = self.library._get_api_client(vserver=fake.VSERVER1)
195 self.assertEqual(client1, client2)
196 self.assertFalse(mock_client_constructor.called)
197
198 # A different vserver should work normally without caching.
199 mock_client_constructor = self.mock_object(client_cmode,
200 'NetAppCmodeClient')
201 client3 = self.library._get_api_client(vserver=fake.VSERVER2)
202 self.assertNotEqual(client1, client3)
203 client_kwargs['vserver'] = fake.VSERVER2
204 mock_client_constructor.assert_called_once_with(**client_kwargs)
205
206 def test_get_licenses_both_protocols(self):
207 self.library._have_cluster_creds = True
208 self.mock_object(self.client,
209 'get_licenses',
210 mock.Mock(return_value=fake.LICENSES))
211
212 result = self.library._get_licenses()
213
214 self.assertSequenceEqual(fake.LICENSES, result)
215 self.assertEqual(0, lib_base.LOG.error.call_count)
216 self.assertEqual(1, lib_base.LOG.info.call_count)
217
218 def test_get_licenses_one_protocol(self):
219 self.library._have_cluster_creds = True
220 licenses = list(fake.LICENSES)
221 licenses.remove('nfs')
222 self.mock_object(self.client,
223 'get_licenses',
224 mock.Mock(return_value=licenses))
225
226 result = self.library._get_licenses()
227
228 self.assertListEqual(licenses, result)
229 self.assertEqual(0, lib_base.LOG.error.call_count)
230 self.assertEqual(1, lib_base.LOG.info.call_count)
231
232 def test_get_licenses_no_protocols(self):
233 self.library._have_cluster_creds = True
234 licenses = list(fake.LICENSES)
235 licenses.remove('nfs')
236 licenses.remove('cifs')
237 self.mock_object(self.client,
238 'get_licenses',
239 mock.Mock(return_value=licenses))
240
241 result = self.library._get_licenses()
242
243 self.assertListEqual(licenses, result)
244 self.assertEqual(1, lib_base.LOG.error.call_count)
245 self.assertEqual(1, lib_base.LOG.info.call_count)
246
247 def test_get_licenses_no_cluster_creds(self):
248 self.library._have_cluster_creds = False
249
250 result = self.library._get_licenses()
251
252 self.assertListEqual([], result)
253 self.assertEqual(1, lib_base.LOG.debug.call_count)
254
255 def test_start_periodic_tasks(self):
256
257 mock_update_ssc_info = self.mock_object(self.library,
258 '_update_ssc_info')
259 mock_handle_ems_logging = self.mock_object(self.library,
260 '_handle_ems_logging')
261 mock_handle_housekeeping_tasks = self.mock_object(
262 self.library, '_handle_housekeeping_tasks')
263 mock_ssc_periodic_task = mock.Mock()
264 mock_ems_periodic_task = mock.Mock()
265 mock_housekeeping_periodic_task = mock.Mock()
266 mock_loopingcall = self.mock_object(
267 loopingcall,
268 'FixedIntervalLoopingCall',
269 mock.Mock(side_effect=[mock_ssc_periodic_task,
270 mock_ems_periodic_task,
271 mock_housekeeping_periodic_task]))
272
273 self.library._start_periodic_tasks()
274
275 self.assertTrue(mock_update_ssc_info.called)
276 self.assertFalse(mock_handle_ems_logging.called)
277 self.assertFalse(mock_housekeeping_periodic_task.called)
278 mock_loopingcall.assert_has_calls(
279 [mock.call(mock_update_ssc_info),
280 mock.call(mock_handle_ems_logging),
281 mock.call(mock_handle_housekeeping_tasks)])
282 self.assertTrue(mock_ssc_periodic_task.start.called)
283 self.assertTrue(mock_ems_periodic_task.start.called)
284 self.assertTrue(mock_housekeeping_periodic_task.start.called)
285
286 def test_get_backend_share_name(self):
287
288 result = self.library._get_backend_share_name(fake.SHARE_ID)
289 expected = (fake.VOLUME_NAME_TEMPLATE %
290 {'share_id': fake.SHARE_ID.replace('-', '_')})
291
292 self.assertEqual(expected, result)
293
294 def test_get_backend_snapshot_name(self):
295
296 result = self.library._get_backend_snapshot_name(fake.SNAPSHOT_ID)
297 expected = 'share_snapshot_' + fake.SNAPSHOT_ID.replace('-', '_')
298
299 self.assertEqual(expected, result)
300
301 def test_get_backend_cg_snapshot_name(self):
302
303 result = self.library._get_backend_cg_snapshot_name(fake.SNAPSHOT_ID)
304 expected = 'share_cg_snapshot_' + fake.SNAPSHOT_ID.replace('-', '_')
305
306 self.assertEqual(expected, result)
307
308 def test_get_aggregate_space_cluster_creds(self):
309
310 self.library._have_cluster_creds = True
311 self.mock_object(self.library,
312 '_find_matching_aggregates',
313 mock.Mock(return_value=fake.AGGREGATES))
314 self.mock_object(self.library._client,
315 'get_cluster_aggregate_capacities',
316 mock.Mock(return_value=fake.AGGREGATE_CAPACITIES))
317
318 result = self.library._get_aggregate_space()
319
320 (self.library._client.get_cluster_aggregate_capacities.
321 assert_called_once_with(fake.AGGREGATES))
322 self.assertDictEqual(fake.AGGREGATE_CAPACITIES, result)
323
324 def test_get_aggregate_space_no_cluster_creds(self):
325
326 self.library._have_cluster_creds = False
327 self.mock_object(self.library,
328 '_find_matching_aggregates',
329 mock.Mock(return_value=fake.AGGREGATES))
330 self.mock_object(self.library._client,
331 'get_vserver_aggregate_capacities',
332 mock.Mock(return_value=fake.AGGREGATE_CAPACITIES))
333
334 result = self.library._get_aggregate_space()
335
336 (self.library._client.get_vserver_aggregate_capacities.
337 assert_called_once_with(fake.AGGREGATES))
338 self.assertDictEqual(fake.AGGREGATE_CAPACITIES, result)
339
340 def test_check_snaprestore_license_admin_notfound(self):
341 self.library._have_cluster_creds = True
342 licenses = list(fake.LICENSES)
343 licenses.remove('snaprestore')
344 self.mock_object(self.client,
345 'get_licenses',
346 mock.Mock(return_value=licenses))
347 result = self.library._check_snaprestore_license()
348 self.assertIs(False, result)
349
350 def test_check_snaprestore_license_admin_found(self):
351 self.library._have_cluster_creds = True
352 self.library._licenses = fake.LICENSES
353 result = self.library._check_snaprestore_license()
354 self.assertIs(True, result)
355
356 def test_check_snaprestore_license_svm_scoped_notfound(self):
357 self.library._have_cluster_creds = False
358 self.mock_object(self.library._client,
359 'restore_snapshot',
360 mock.Mock(side_effect=netapp_api.NaApiError(
361 code=netapp_api.EAPIERROR,
362 message=fake.NO_SNAPRESTORE_LICENSE)))
363 result = self.library._check_snaprestore_license()
364 self.assertIs(False, result)
365
366 def test_check_snaprestore_license_svm_scoped_found(self):
367 self.library._have_cluster_creds = False
368 self.mock_object(self.library._client,
369 'restore_snapshot',
370 mock.Mock(side_effect=netapp_api.NaApiError(
371 code=netapp_api.EAPIERROR,
372 message='Other error')))
373 result = self.library._check_snaprestore_license()
374 self.assertIs(True, result)
375
376 def test_check_snaprestore_license_svm_scoped_found_exception(self):
377 self.mock_object(lib_base.LOG, 'exception')
378 self.library._have_cluster_creds = False
379 self.mock_object(self.library._client,
380 'restore_snapshot',
381 mock.Mock(return_value=None))
382
383 self.assertRaises(
384 exception.NetAppException,
385 self.library._check_snaprestore_license)
386 lib_base.LOG.exception.assert_called_once()
387
388 def test_get_aggregate_node_cluster_creds(self):
389
390 self.library._have_cluster_creds = True
391 self.mock_object(self.library._client,
392 'get_node_for_aggregate',
393 mock.Mock(return_value=fake.CLUSTER_NODE))
394
395 result = self.library._get_aggregate_node(fake.AGGREGATE)
396
397 (self.library._client.get_node_for_aggregate.
398 assert_called_once_with(fake.AGGREGATE))
399 self.assertEqual(fake.CLUSTER_NODE, result)
400
401 def test_get_aggregate_node_no_cluster_creds(self):
402
403 self.library._have_cluster_creds = False
404 self.mock_object(self.library._client, 'get_node_for_aggregate')
405
406 result = self.library._get_aggregate_node(fake.AGGREGATE)
407
408 self.assertFalse(self.library._client.get_node_for_aggregate.called)
409 self.assertIsNone(result)
410
411 def test_get_default_filter_function(self):
412
413 result = self.library.get_default_filter_function()
414
415 self.assertEqual(self.library.DEFAULT_FILTER_FUNCTION, result)
416
417 def test_get_default_goodness_function(self):
418
419 result = self.library.get_default_goodness_function()
420
421 self.assertEqual(self.library.DEFAULT_GOODNESS_FUNCTION, result)
422
423 def test_get_share_stats(self):
424
425 mock_get_pools = self.mock_object(
426 self.library, '_get_pools',
427 mock.Mock(return_value=fake.POOLS))
428
429 result = self.library.get_share_stats(filter_function='filter',
430 goodness_function='goodness')
431
432 expected = {
433 'share_backend_name': fake.BACKEND_NAME,
434 'driver_name': fake.DRIVER_NAME,
435 'vendor_name': 'NetApp',
436 'driver_version': '1.0',
437 'netapp_storage_family': 'ontap_cluster',
438 'storage_protocol': 'NFS_CIFS',
439 'pools': fake.POOLS,
440 'share_group_stats': {'consistent_snapshot_support': 'host'},
441 }
442 self.assertDictEqual(expected, result)
443 mock_get_pools.assert_called_once_with(filter_function='filter',
444 goodness_function='goodness')
445
446 def test_get_share_stats_with_replication(self):
447
448 self.library.configuration.replication_domain = "fake_domain"
449 mock_get_pools = self.mock_object(
450 self.library, '_get_pools',
451 mock.Mock(return_value=fake.POOLS))
452
453 result = self.library.get_share_stats(filter_function='filter',
454 goodness_function='goodness')
455
456 expected = {
457 'share_backend_name': fake.BACKEND_NAME,
458 'driver_name': fake.DRIVER_NAME,
459 'vendor_name': 'NetApp',
460 'driver_version': '1.0',
461 'netapp_storage_family': 'ontap_cluster',
462 'storage_protocol': 'NFS_CIFS',
463 'replication_type': 'dr',
464 'replication_domain': 'fake_domain',
465 'pools': fake.POOLS,
466 'share_group_stats': {'consistent_snapshot_support': 'host'},
467 }
468 self.assertDictEqual(expected, result)
469 mock_get_pools.assert_called_once_with(filter_function='filter',
470 goodness_function='goodness')
471
472 def test_get_share_server_pools(self):
473
474 self.mock_object(self.library,
475 '_get_pools',
476 mock.Mock(return_value=fake.POOLS))
477
478 result = self.library.get_share_server_pools(fake.SHARE_SERVER)
479
480 self.assertListEqual(fake.POOLS, result)
481
482 def test_get_pools(self):
483
484 self.mock_object(
485 self.library, '_get_aggregate_space',
486 mock.Mock(return_value=fake.AGGREGATE_CAPACITIES))
487 self.library._have_cluster_creds = True
488 self.library._revert_to_snapshot_support = True
489 self.library._cluster_info = fake.CLUSTER_INFO
490 self.library._ssc_stats = fake.SSC_INFO
491 self.library._perf_library.get_node_utilization_for_pool = (
492 mock.Mock(side_effect=[30.0, 42.0]))
493
494 result = self.library._get_pools(filter_function='filter',
495 goodness_function='goodness')
496
497 self.assertListEqual(fake.POOLS, result)
498
499 def test_get_pools_vserver_creds(self):
500
501 self.mock_object(
502 self.library, '_get_aggregate_space',
503 mock.Mock(return_value=fake.AGGREGATE_CAPACITIES_VSERVER_CREDS))
504 self.library._have_cluster_creds = False
505 self.library._revert_to_snapshot_support = True
506 self.library._cluster_info = fake.CLUSTER_INFO
507 self.library._ssc_stats = fake.SSC_INFO_VSERVER_CREDS
508 self.library._perf_library.get_node_utilization_for_pool = (
509 mock.Mock(side_effect=[50.0, 50.0]))
510
511 result = self.library._get_pools()
512
513 self.assertListEqual(fake.POOLS_VSERVER_CREDS, result)
514
515 def test_handle_ems_logging(self):
516
517 self.mock_object(self.library,
518 '_build_ems_log_message_0',
519 mock.Mock(return_value=fake.EMS_MESSAGE_0))
520 self.mock_object(self.library,
521 '_build_ems_log_message_1',
522 mock.Mock(return_value=fake.EMS_MESSAGE_1))
523
524 self.library._handle_ems_logging()
525
526 self.library._client.send_ems_log_message.assert_has_calls([
527 mock.call(fake.EMS_MESSAGE_0),
528 mock.call(fake.EMS_MESSAGE_1),
529 ])
530
531 def test_build_ems_log_message_0(self):
532
533 self.mock_object(socket,
534 'gethostname',
535 mock.Mock(return_value=fake.HOST_NAME))
536
537 result = self.library._build_ems_log_message_0()
538
539 self.assertDictEqual(fake.EMS_MESSAGE_0, result)
540
541 def test_build_ems_log_message_1(self):
542
543 pool_info = {
544 'pools': {
545 'vserver': 'fake_vserver',
546 'aggregates': ['aggr1', 'aggr2'],
547 },
548 }
549 self.mock_object(socket,
550 'gethostname',
551 mock.Mock(return_value=fake.HOST_NAME))
552 self.mock_object(self.library,
553 '_get_ems_pool_info',
554 mock.Mock(return_value=pool_info))
555
556 result = self.library._build_ems_log_message_1()
557
558 self.assertDictEqual(pool_info,
559 json.loads(result['event-description']))
560 result['event-description'] = ''
561 self.assertDictEqual(fake.EMS_MESSAGE_1, result)
562
563 def test_get_ems_pool_info(self):
564 self.assertRaises(NotImplementedError,
565 self.library._get_ems_pool_info)
566
567 def test_find_matching_aggregates(self):
568 self.assertRaises(NotImplementedError,
569 self.library._find_matching_aggregates)
570
571 @ddt.data(('NFS', nfs_cmode.NetAppCmodeNFSHelper),
572 ('nfs', nfs_cmode.NetAppCmodeNFSHelper),
573 ('CIFS', cifs_cmode.NetAppCmodeCIFSHelper),
574 ('cifs', cifs_cmode.NetAppCmodeCIFSHelper))
575 @ddt.unpack
576 def test_get_helper(self, protocol, helper_type):
577
578 fake_share = fake.SHARE.copy()
579 fake_share['share_proto'] = protocol
580 mock_check_license_for_protocol = self.mock_object(
581 self.library, '_check_license_for_protocol')
582
583 result = self.library._get_helper(fake_share)
584
585 mock_check_license_for_protocol.assert_called_once_with(
586 protocol.lower())
587 self.assertEqual(helper_type, type(result))
588
589 def test_get_helper_invalid_protocol(self):
590
591 fake_share = fake.SHARE.copy()
592 fake_share['share_proto'] = 'iSCSI'
593 self.mock_object(self.library, '_check_license_for_protocol')
594
595 self.assertRaises(exception.NetAppException,
596 self.library._get_helper,
597 fake_share)
598
599 def test_check_license_for_protocol_no_cluster_creds(self):
600
601 self.library._have_cluster_creds = False
602
603 result = self.library._check_license_for_protocol('fake_protocol')
604
605 self.assertIsNone(result)
606
607 def test_check_license_for_protocol_have_license(self):
608
609 self.library._have_cluster_creds = True
610 self.library._licenses = ['base', 'fake_protocol']
611
612 result = self.library._check_license_for_protocol('FAKE_PROTOCOL')
613
614 self.assertIsNone(result)
615
616 def test_check_license_for_protocol_newly_licensed_protocol(self):
617
618 self.library._have_cluster_creds = True
619 self.mock_object(self.library,
620 '_get_licenses',
621 mock.Mock(return_value=['base', 'nfs']))
622 self.library._licenses = ['base']
623
624 result = self.library._check_license_for_protocol('NFS')
625
626 self.assertIsNone(result)
627 self.assertTrue(self.library._get_licenses.called)
628
629 def test_check_license_for_protocol_unlicensed_protocol(self):
630
631 self.library._have_cluster_creds = True
632 self.mock_object(self.library,
633 '_get_licenses',
634 mock.Mock(return_value=['base']))
635 self.library._licenses = ['base']
636
637 self.assertRaises(exception.NetAppException,
638 self.library._check_license_for_protocol,
639 'NFS')
640
641 def test_get_pool_has_pool(self):
642 result = self.library.get_pool(fake.SHARE)
643 self.assertEqual(fake.POOL_NAME, result)
644 self.assertFalse(self.client.get_aggregate_for_volume.called)
645
646 def test_get_pool_no_pool(self):
647
648 fake_share = copy.deepcopy(fake.SHARE)
649 fake_share['host'] = '%(host)s@%(backend)s' % {
650 'host': fake.HOST_NAME, 'backend': fake.BACKEND_NAME}
651 self.client.get_aggregate_for_volume.return_value = fake.POOL_NAME
652
653 result = self.library.get_pool(fake_share)
654
655 self.assertEqual(fake.POOL_NAME, result)
656 self.assertTrue(self.client.get_aggregate_for_volume.called)
657
658 def test_get_pool_raises(self):
659
660 fake_share = copy.deepcopy(fake.SHARE)
661 fake_share['host'] = '%(host)s@%(backend)s' % {
662 'host': fake.HOST_NAME, 'backend': fake.BACKEND_NAME}
663 self.client.get_aggregate_for_volume.side_effect = (
664 exception.NetAppException)
665
666 self.assertRaises(exception.NetAppException,
667 self.library.get_pool,
668 fake_share)
669
670 def test_create_share(self):
671
672 vserver_client = mock.Mock()
673 self.mock_object(self.library,
674 '_get_vserver',
675 mock.Mock(return_value=(fake.VSERVER1,
676 vserver_client)))
677 mock_allocate_container = self.mock_object(self.library,
678 '_allocate_container')
679 mock_create_export = self.mock_object(
680 self.library,
681 '_create_export',
682 mock.Mock(return_value='fake_export_location'))
683
684 result = self.library.create_share(self.context,
685 fake.SHARE,
686 share_server=fake.SHARE_SERVER)
687
688 mock_allocate_container.assert_called_once_with(fake.SHARE,
689 fake.VSERVER1,
690 vserver_client)
691 mock_create_export.assert_called_once_with(fake.SHARE,
692 fake.SHARE_SERVER,
693 fake.VSERVER1,
694 vserver_client)
695 self.assertEqual('fake_export_location', result)
696
697 def test_create_share_from_snapshot(self):
698
699 vserver_client = mock.Mock()
700 self.mock_object(self.library,
701 '_get_vserver',
702 mock.Mock(return_value=(fake.VSERVER1,
703 vserver_client)))
704 mock_allocate_container_from_snapshot = self.mock_object(
705 self.library,
706 '_allocate_container_from_snapshot')
707 mock_create_export = self.mock_object(
708 self.library,
709 '_create_export',
710 mock.Mock(return_value='fake_export_location'))
711
712 result = self.library.create_share_from_snapshot(
713 self.context,
714 fake.SHARE,
715 fake.SNAPSHOT,
716 share_server=fake.SHARE_SERVER)
717
718 mock_allocate_container_from_snapshot.assert_called_once_with(
719 fake.SHARE,
720 fake.SNAPSHOT,
721 fake.VSERVER1,
722 vserver_client)
723 mock_create_export.assert_called_once_with(fake.SHARE,
724 fake.SHARE_SERVER,
725 fake.VSERVER1,
726 vserver_client)
727 self.assertEqual('fake_export_location', result)
728
729 @ddt.data(False, True)
730 def test_allocate_container(self, hide_snapdir):
731
732 provisioning_options = copy.deepcopy(fake.PROVISIONING_OPTIONS)
733 provisioning_options['hide_snapdir'] = hide_snapdir
734 self.mock_object(self.library, '_get_backend_share_name', mock.Mock(
735 return_value=fake.SHARE_NAME))
736 self.mock_object(share_utils, 'extract_host', mock.Mock(
737 return_value=fake.POOL_NAME))
738 mock_get_provisioning_opts = self.mock_object(
739 self.library, '_get_provisioning_options_for_share',
740 mock.Mock(return_value=provisioning_options))
741 vserver_client = mock.Mock()
742
743 self.library._allocate_container(fake.SHARE_INSTANCE,
744 fake.VSERVER1,
745 vserver_client)
746
747 mock_get_provisioning_opts.assert_called_once_with(
748 fake.SHARE_INSTANCE, fake.VSERVER1, replica=False)
749
750 vserver_client.create_volume.assert_called_once_with(
751 fake.POOL_NAME, fake.SHARE_NAME, fake.SHARE['size'],
752 thin_provisioned=True, snapshot_policy='default',
753 language='en-US', dedup_enabled=True, split=True, encrypt=False,
754 compression_enabled=False, max_files=5000, snapshot_reserve=8)
755
756 if hide_snapdir:
757 vserver_client.set_volume_snapdir_access.assert_called_once_with(
758 fake.SHARE_NAME, hide_snapdir)
759 else:
760 vserver_client.set_volume_snapdir_access.assert_not_called()
761
762 def test_remap_standard_boolean_extra_specs(self):
763
764 extra_specs = copy.deepcopy(fake.OVERLAPPING_EXTRA_SPEC)
765
766 result = self.library._remap_standard_boolean_extra_specs(extra_specs)
767
768 self.assertDictEqual(fake.REMAPPED_OVERLAPPING_EXTRA_SPEC, result)
769
770 def test_allocate_container_as_replica(self):
771 self.mock_object(self.library, '_get_backend_share_name', mock.Mock(
772 return_value=fake.SHARE_NAME))
773 self.mock_object(share_utils, 'extract_host', mock.Mock(
774 return_value=fake.POOL_NAME))
775 mock_get_provisioning_opts = self.mock_object(
776 self.library, '_get_provisioning_options_for_share',
777 mock.Mock(return_value=copy.deepcopy(fake.PROVISIONING_OPTIONS)))
778 vserver_client = mock.Mock()
779
780 self.library._allocate_container(fake.SHARE_INSTANCE, fake.VSERVER1,
781 vserver_client, replica=True)
782
783 mock_get_provisioning_opts.assert_called_once_with(
784 fake.SHARE_INSTANCE, fake.VSERVER1, replica=True)
785
786 vserver_client.create_volume.assert_called_once_with(
787 fake.POOL_NAME, fake.SHARE_NAME, fake.SHARE['size'],
788 thin_provisioned=True, snapshot_policy='default',
789 language='en-US', dedup_enabled=True, split=True,
790 compression_enabled=False, max_files=5000, encrypt=False,
791 snapshot_reserve=8, volume_type='dp')
792
793 def test_allocate_container_no_pool_name(self):
794 self.mock_object(self.library, '_get_backend_share_name', mock.Mock(
795 return_value=fake.SHARE_NAME))
796 self.mock_object(share_utils, 'extract_host', mock.Mock(
797 return_value=None))
798 self.mock_object(self.library, '_check_extra_specs_validity')
799 self.mock_object(self.library, '_get_provisioning_options')
800 vserver_client = mock.Mock()
801
802 self.assertRaises(exception.InvalidHost,
803 self.library._allocate_container,
804 fake.SHARE_INSTANCE, fake.VSERVER1, vserver_client)
805
806 self.library._get_backend_share_name.assert_called_once_with(
807 fake.SHARE_INSTANCE['id'])
808 share_utils.extract_host.assert_called_once_with(
809 fake.SHARE_INSTANCE['host'], level='pool')
810 self.assertEqual(0,
811 self.library._check_extra_specs_validity.call_count)
812 self.assertEqual(0, self.library._get_provisioning_options.call_count)
813
814 def test_check_extra_specs_validity(self):
815 boolean_extra_spec_keys = list(
816 self.library.BOOLEAN_QUALIFIED_EXTRA_SPECS_MAP)
817 mock_bool_check = self.mock_object(
818 self.library, '_check_boolean_extra_specs_validity')
819 mock_string_check = self.mock_object(
820 self.library, '_check_string_extra_specs_validity')
821
822 self.library._check_extra_specs_validity(
823 fake.SHARE_INSTANCE, fake.EXTRA_SPEC)
824
825 mock_bool_check.assert_called_once_with(
826 fake.SHARE_INSTANCE, fake.EXTRA_SPEC, boolean_extra_spec_keys)
827 mock_string_check.assert_called_once_with(
828 fake.SHARE_INSTANCE, fake.EXTRA_SPEC)
829
830 def test_check_extra_specs_validity_empty_spec(self):
831 result = self.library._check_extra_specs_validity(
832 fake.SHARE_INSTANCE, fake.EMPTY_EXTRA_SPEC)
833
834 self.assertIsNone(result)
835
836 def test_check_extra_specs_validity_invalid_value(self):
837 self.assertRaises(
838 exception.Invalid, self.library._check_extra_specs_validity,
839 fake.SHARE_INSTANCE, fake.INVALID_EXTRA_SPEC)
840
841 def test_check_string_extra_specs_validity(self):
842 result = self.library._check_string_extra_specs_validity(
843 fake.SHARE_INSTANCE, fake.EXTRA_SPEC)
844
845 self.assertIsNone(result)
846
847 def test_check_string_extra_specs_validity_empty_spec(self):
848 result = self.library._check_string_extra_specs_validity(
849 fake.SHARE_INSTANCE, fake.EMPTY_EXTRA_SPEC)
850
851 self.assertIsNone(result)
852
853 def test_check_string_extra_specs_validity_invalid_value(self):
854 self.assertRaises(
855 exception.NetAppException,
856 self.library._check_string_extra_specs_validity,
857 fake.SHARE_INSTANCE, fake.INVALID_MAX_FILE_EXTRA_SPEC)
858
859 def test_check_boolean_extra_specs_validity_invalid_value(self):
860 self.assertRaises(
861 exception.Invalid,
862 self.library._check_boolean_extra_specs_validity,
863 fake.SHARE_INSTANCE, fake.INVALID_EXTRA_SPEC,
864 list(self.library.BOOLEAN_QUALIFIED_EXTRA_SPECS_MAP))
865
866 def test_check_extra_specs_validity_invalid_combination(self):
867 self.assertRaises(
868 exception.Invalid,
869 self.library._check_boolean_extra_specs_validity,
870 fake.SHARE_INSTANCE, fake.INVALID_EXTRA_SPEC_COMBO,
871 list(self.library.BOOLEAN_QUALIFIED_EXTRA_SPECS_MAP))
872
873 @ddt.data({'extra_specs': fake.EXTRA_SPEC, 'is_replica': False},
874 {'extra_specs': fake.EXTRA_SPEC_WITH_QOS, 'is_replica': True},
875 {'extra_specs': fake.EXTRA_SPEC, 'is_replica': False},
876 {'extra_specs': fake.EXTRA_SPEC_WITH_QOS, 'is_replica': True})
877 @ddt.unpack
878 def test_get_provisioning_options_for_share(self, extra_specs, is_replica):
879
880 qos = True if fake.QOS_EXTRA_SPEC in extra_specs else False
881 mock_get_extra_specs_from_share = self.mock_object(
882 share_types, 'get_extra_specs_from_share',
883 mock.Mock(return_value=extra_specs))
884 mock_remap_standard_boolean_extra_specs = self.mock_object(
885 self.library, '_remap_standard_boolean_extra_specs',
886 mock.Mock(return_value=extra_specs))
887 mock_check_extra_specs_validity = self.mock_object(
888 self.library, '_check_extra_specs_validity')
889 mock_get_provisioning_options = self.mock_object(
890 self.library, '_get_provisioning_options',
891 mock.Mock(return_value=fake.PROVISIONING_OPTIONS))
892 mock_get_normalized_qos_specs = self.mock_object(
893 self.library, '_get_normalized_qos_specs',
894 mock.Mock(return_value={fake.QOS_NORMALIZED_SPEC: 3000}))
895 mock_create_qos_policy_group = self.mock_object(
896 self.library, '_create_qos_policy_group', mock.Mock(
897 return_value=fake.QOS_POLICY_GROUP_NAME))
898
899 result = self.library._get_provisioning_options_for_share(
900 fake.SHARE_INSTANCE, fake.VSERVER1, replica=is_replica)
901
902 if qos and is_replica:
903 expected_provisioning_opts = fake.PROVISIONING_OPTIONS
904 self.assertFalse(mock_create_qos_policy_group.called)
905 else:
906 expected_provisioning_opts = fake.PROVISIONING_OPTIONS_WITH_QOS
907 mock_create_qos_policy_group.assert_called_once_with(
908 fake.SHARE_INSTANCE, fake.VSERVER1,
909 {fake.QOS_NORMALIZED_SPEC: 3000})
910
911 self.assertEqual(expected_provisioning_opts, result)
912 mock_get_extra_specs_from_share.assert_called_once_with(
913 fake.SHARE_INSTANCE)
914 mock_remap_standard_boolean_extra_specs.assert_called_once_with(
915 extra_specs)
916 mock_check_extra_specs_validity.assert_called_once_with(
917 fake.SHARE_INSTANCE, extra_specs)
918 mock_get_provisioning_options.assert_called_once_with(extra_specs)
919 mock_get_normalized_qos_specs.assert_called_once_with(extra_specs)
920
921 def test_get_provisioning_options_implicit_false(self):
922 result = self.library._get_provisioning_options(
923 fake.EMPTY_EXTRA_SPEC)
924
925 expected = {
926 'language': None,
927 'max_files': None,
928 'snapshot_policy': None,
929 'thin_provisioned': False,
930 'compression_enabled': False,
931 'dedup_enabled': False,
932 'split': False,
933 'encrypt': False,
934 'hide_snapdir': False,
935 }
936
937 self.assertEqual(expected, result)
938
939 def test_get_boolean_provisioning_options(self):
940 result = self.library._get_boolean_provisioning_options(
941 fake.SHORT_BOOLEAN_EXTRA_SPEC,
942 self.library.BOOLEAN_QUALIFIED_EXTRA_SPECS_MAP)
943
944 self.assertEqual(fake.PROVISIONING_OPTIONS_BOOLEAN, result)
945
946 def test_get_boolean_provisioning_options_missing_spec(self):
947 result = self.library._get_boolean_provisioning_options(
948 fake.SHORT_BOOLEAN_EXTRA_SPEC,
949 self.library.BOOLEAN_QUALIFIED_EXTRA_SPECS_MAP)
950
951 self.assertEqual(fake.PROVISIONING_OPTIONS_BOOLEAN, result)
952
953 def test_get_boolean_provisioning_options_implicit_false(self):
954 expected = {
955 'thin_provisioned': False,
956 'dedup_enabled': False,
957 'compression_enabled': False,
958 'split': False,
959 'hide_snapdir': False,
960 }
961
962 result = self.library._get_boolean_provisioning_options(
963 fake.EMPTY_EXTRA_SPEC,
964 self.library.BOOLEAN_QUALIFIED_EXTRA_SPECS_MAP)
965
966 self.assertEqual(expected, result)
967
968 def test_get_string_provisioning_options(self):
969 result = self.library._get_string_provisioning_options(
970 fake.STRING_EXTRA_SPEC,
971 self.library.STRING_QUALIFIED_EXTRA_SPECS_MAP)
972
973 self.assertEqual(fake.PROVISIONING_OPTIONS_STRING, result)
974
975 def test_get_string_provisioning_options_missing_spec(self):
976 result = self.library._get_string_provisioning_options(
977 fake.SHORT_STRING_EXTRA_SPEC,
978 self.library.STRING_QUALIFIED_EXTRA_SPECS_MAP)
979
980 self.assertEqual(fake.PROVISIONING_OPTIONS_STRING_MISSING_SPECS,
981 result)
982
983 def test_get_string_provisioning_options_implicit_false(self):
984 result = self.library._get_string_provisioning_options(
985 fake.EMPTY_EXTRA_SPEC,
986 self.library.STRING_QUALIFIED_EXTRA_SPECS_MAP)
987
988 self.assertEqual(fake.PROVISIONING_OPTIONS_STRING_DEFAULT, result)
989
990 @ddt.data({}, {'foo': 'bar'}, {'netapp:maxiops': '3000'},
991 {'qos': True, 'netapp:absiops': '3000'},
992 {'qos': True, 'netapp:maxiops:': '3000'})
993 def test_get_normalized_qos_specs_no_qos_specs(self, extra_specs):
994 if 'qos' in extra_specs:
995 self.assertRaises(exception.NetAppException,
996 self.library._get_normalized_qos_specs,
997 extra_specs)
998 else:
999 self.assertDictMatch(
1000 {}, self.library._get_normalized_qos_specs(extra_specs))
1001
1002 @ddt.data({'qos': True, 'netapp:maxiops': '3000', 'netapp:maxbps': '9000'},
1003 {'qos': True, 'netapp:maxiopspergib': '1000',
1004 'netapp:maxiops': '1000'})
1005 def test_get_normalized_qos_specs_multiple_qos_specs(self, extra_specs):
1006 self.assertRaises(exception.NetAppException,
1007 self.library._get_normalized_qos_specs,
1008 extra_specs)
1009
1010 @ddt.data({'qos': True, 'netapp:maxIOPS': '3000'},
1011 {'qos': True, 'netapp:MAxBPs': '3000', 'clem': 'son'},
1012 {'qos': True, 'netapp:maxbps': '3000', 'tig': 'ers'},
1013 {'qos': True, 'netapp:MAXiopSPerGib': '3000', 'kin': 'gsof'},
1014 {'qos': True, 'netapp:maxiopspergib': '3000', 'coll': 'ege'},
1015 {'qos': True, 'netapp:maxBPSperGiB': '3000', 'foot': 'ball'})
1016 def test_get_normalized_qos_specs(self, extra_specs):
1017 expected_normalized_spec = {
1018 key.lower().split('netapp:')[1]: value
1019 for key, value in extra_specs.items() if 'netapp:' in key
1020 }
1021
1022 qos_specs = self.library._get_normalized_qos_specs(extra_specs)
1023
1024 self.assertDictMatch(expected_normalized_spec, qos_specs)
1025 self.assertEqual(1, len(qos_specs))
1026
1027 @ddt.data({'qos': {'maxiops': '3000'}, 'expected': '3000iops'},
1028 {'qos': {'maxbps': '3000'}, 'expected': '3000B/s'},
1029 {'qos': {'maxbpspergib': '3000'}, 'expected': '12000B/s'},
1030 {'qos': {'maxiopspergib': '3000'}, 'expected': '12000iops'})
1031 @ddt.unpack
1032 def test_get_max_throughput(self, qos, expected):
1033
1034 throughput = self.library._get_max_throughput(4, qos)
1035
1036 self.assertEqual(expected, throughput)
1037
1038 def test_create_qos_policy_group(self):
1039 mock_qos_policy_create = self.mock_object(
1040 self.library._client, 'qos_policy_group_create')
1041
1042 self.library._create_qos_policy_group(
1043 fake.SHARE, fake.VSERVER1, {'maxiops': '3000'})
1044
1045 expected_policy_name = 'qos_share_' + fake.SHARE['id'].replace(
1046 '-', '_')
1047 mock_qos_policy_create.assert_called_once_with(
1048 expected_policy_name, fake.VSERVER1, max_throughput='3000iops')
1049
1050 def test_check_if_max_files_is_valid_with_negative_integer(self):
1051 self.assertRaises(exception.NetAppException,
1052 self.library._check_if_max_files_is_valid,
1053 fake.SHARE, -1)
1054
1055 def test_check_if_max_files_is_valid_with_string(self):
1056 self.assertRaises(ValueError,
1057 self.library._check_if_max_files_is_valid,
1058 fake.SHARE, 'abc')
1059
1060 def test_allocate_container_no_pool(self):
1061
1062 vserver_client = mock.Mock()
1063 fake_share_inst = copy.deepcopy(fake.SHARE_INSTANCE)
1064 fake_share_inst['host'] = fake_share_inst['host'].split('#')[0]
1065
1066 self.assertRaises(exception.InvalidHost,
1067 self.library._allocate_container,
1068 fake_share_inst,
1069 fake.VSERVER1,
1070 vserver_client)
1071
1072 def test_check_aggregate_extra_specs_validity(self):
1073
1074 self.library._have_cluster_creds = True
1075 self.library._ssc_stats = fake.SSC_INFO
1076
1077 result = self.library._check_aggregate_extra_specs_validity(
1078 fake.AGGREGATES[0], fake.EXTRA_SPEC)
1079
1080 self.assertIsNone(result)
1081
1082 def test_check_aggregate_extra_specs_validity_no_match(self):
1083
1084 self.library._have_cluster_creds = True
1085 self.library._ssc_stats = fake.SSC_INFO
1086
1087 self.assertRaises(exception.NetAppException,
1088 self.library._check_aggregate_extra_specs_validity,
1089 fake.AGGREGATES[1],
1090 fake.EXTRA_SPEC)
1091
1092 @ddt.data({'provider_location': None, 'size': 50, 'hide_snapdir': True},
1093 {'provider_location': 'fake_location', 'size': 30,
1094 'hide_snapdir': False},
1095 {'provider_location': 'fake_location', 'size': 20,
1096 'hide_snapdir': True})
1097 @ddt.unpack
1098 def test_allocate_container_from_snapshot(
1099 self, provider_location, size, hide_snapdir):
1100
1101 provisioning_options = copy.deepcopy(fake.PROVISIONING_OPTIONS)
1102 provisioning_options['hide_snapdir'] = hide_snapdir
1103 mock_get_provisioning_opts = self.mock_object(
1104 self.library, '_get_provisioning_options_for_share',
1105 mock.Mock(return_value=provisioning_options))
1106 vserver = fake.VSERVER1
1107 vserver_client = mock.Mock()
1108 original_snapshot_size = 20
1109
1110 fake_share_inst = copy.deepcopy(fake.SHARE_INSTANCE)
1111 fake_share_inst['size'] = size
1112 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
1113 fake_snapshot['provider_location'] = provider_location
1114 fake_snapshot['size'] = original_snapshot_size
1115
1116 self.library._allocate_container_from_snapshot(fake_share_inst,
1117 fake_snapshot,
1118 vserver,
1119 vserver_client)
1120
1121 share_name = self.library._get_backend_share_name(
1122 fake_share_inst['id'])
1123 parent_share_name = self.library._get_backend_share_name(
1124 fake_snapshot['share_id'])
1125 parent_snapshot_name = self.library._get_backend_snapshot_name(
1126 fake_snapshot['id']) if not provider_location else 'fake_location'
1127 mock_get_provisioning_opts.assert_called_once_with(
1128 fake_share_inst, fake.VSERVER1)
1129 vserver_client.create_volume_clone.assert_called_once_with(
1130 share_name, parent_share_name, parent_snapshot_name,
1131 thin_provisioned=True, snapshot_policy='default',
1132 language='en-US', dedup_enabled=True, split=True, encrypt=False,
1133 compression_enabled=False, max_files=5000)
1134 if size > original_snapshot_size:
1135 vserver_client.set_volume_size.assert_called_once_with(
1136 share_name, size)
1137 else:
1138 vserver_client.set_volume_size.assert_not_called()
1139
1140 if hide_snapdir:
1141 vserver_client.set_volume_snapdir_access.assert_called_once_with(
1142 fake.SHARE_INSTANCE_NAME, hide_snapdir)
1143 else:
1144 vserver_client.set_volume_snapdir_access.assert_not_called()
1145
1146 def test_share_exists(self):
1147
1148 vserver_client = mock.Mock()
1149 vserver_client.volume_exists.return_value = True
1150
1151 result = self.library._share_exists(fake.SHARE_NAME, vserver_client)
1152
1153 self.assertTrue(result)
1154
1155 def test_share_exists_not_found(self):
1156
1157 vserver_client = mock.Mock()
1158 vserver_client.volume_exists.return_value = False
1159
1160 result = self.library._share_exists(fake.SHARE_NAME, vserver_client)
1161
1162 self.assertFalse(result)
1163
1164 def test_delete_share(self):
1165
1166 vserver_client = mock.Mock()
1167 self.mock_object(self.library,
1168 '_get_vserver',
1169 mock.Mock(return_value=(fake.VSERVER1,
1170 vserver_client)))
1171 mock_share_exists = self.mock_object(self.library,
1172 '_share_exists',
1173 mock.Mock(return_value=True))
1174 mock_remove_export = self.mock_object(self.library, '_remove_export')
1175 mock_deallocate_container = self.mock_object(self.library,
1176 '_deallocate_container')
1177
1178 self.library.delete_share(self.context,
1179 fake.SHARE,
1180 share_server=fake.SHARE_SERVER)
1181
1182 share_name = self.library._get_backend_share_name(fake.SHARE['id'])
1183 qos_policy_name = self.library._get_backend_qos_policy_group_name(
1184 fake.SHARE['id'])
1185 mock_share_exists.assert_called_once_with(share_name, vserver_client)
1186 mock_remove_export.assert_called_once_with(fake.SHARE, vserver_client)
1187 mock_deallocate_container.assert_called_once_with(share_name,
1188 vserver_client)
1189 (self.library._client.mark_qos_policy_group_for_deletion
1190 .assert_called_once_with(qos_policy_name))
1191 self.assertEqual(0, lib_base.LOG.info.call_count)
1192
1193 @ddt.data(exception.InvalidInput(reason='fake_reason'),
1194 exception.VserverNotSpecified(),
1195 exception.VserverNotFound(vserver='fake_vserver'))
1196 def test_delete_share_no_share_server(self, get_vserver_exception):
1197
1198 self.mock_object(self.library,
1199 '_get_vserver',
1200 mock.Mock(side_effect=get_vserver_exception))
1201 mock_share_exists = self.mock_object(self.library,
1202 '_share_exists',
1203 mock.Mock(return_value=False))
1204 mock_remove_export = self.mock_object(self.library, '_remove_export')
1205 mock_deallocate_container = self.mock_object(self.library,
1206 '_deallocate_container')
1207
1208 self.library.delete_share(self.context,
1209 fake.SHARE,
1210 share_server=fake.SHARE_SERVER)
1211
1212 self.assertFalse(mock_share_exists.called)
1213 self.assertFalse(mock_remove_export.called)
1214 self.assertFalse(mock_deallocate_container.called)
1215 self.assertFalse(
1216 self.library._client.mark_qos_policy_group_for_deletion.called)
1217 self.assertEqual(1, lib_base.LOG.warning.call_count)
1218
1219 def test_delete_share_not_found(self):
1220
1221 vserver_client = mock.Mock()
1222 self.mock_object(self.library,
1223 '_get_vserver',
1224 mock.Mock(return_value=(fake.VSERVER1,
1225 vserver_client)))
1226 mock_share_exists = self.mock_object(self.library,
1227 '_share_exists',
1228 mock.Mock(return_value=False))
1229 mock_remove_export = self.mock_object(self.library, '_remove_export')
1230 mock_deallocate_container = self.mock_object(self.library,
1231 '_deallocate_container')
1232
1233 self.library.delete_share(self.context,
1234 fake.SHARE,
1235 share_server=fake.SHARE_SERVER)
1236
1237 share_name = self.library._get_backend_share_name(fake.SHARE['id'])
1238 mock_share_exists.assert_called_once_with(share_name, vserver_client)
1239 self.assertFalse(mock_remove_export.called)
1240 self.assertFalse(mock_deallocate_container.called)
1241 self.assertFalse(
1242 self.library._client.mark_qos_policy_group_for_deletion.called)
1243 self.assertEqual(1, lib_base.LOG.info.call_count)
1244
1245 def test_deallocate_container(self):
1246
1247 vserver_client = mock.Mock()
1248
1249 self.library._deallocate_container(fake.SHARE_NAME, vserver_client)
1250
1251 vserver_client.unmount_volume.assert_called_with(fake.SHARE_NAME,
1252 force=True)
1253 vserver_client.offline_volume.assert_called_with(fake.SHARE_NAME)
1254 vserver_client.delete_volume.assert_called_with(fake.SHARE_NAME)
1255
1256 def test_create_export(self):
1257
1258 protocol_helper = mock.Mock()
1259 callback = (lambda export_address, export_path='fake_export_path':
1260 ':'.join([export_address, export_path]))
1261 protocol_helper.create_share.return_value = callback
1262 self.mock_object(self.library,
1263 '_get_helper',
1264 mock.Mock(return_value=protocol_helper))
1265 vserver_client = mock.Mock()
1266 vserver_client.get_network_interfaces.return_value = fake.LIFS
1267 fake_interface_addresses_with_metadata = copy.deepcopy(
1268 fake.INTERFACE_ADDRESSES_WITH_METADATA)
1269 mock_get_export_addresses_with_metadata = self.mock_object(
1270 self.library, '_get_export_addresses_with_metadata',
1271 mock.Mock(return_value=fake_interface_addresses_with_metadata))
1272
1273 result = self.library._create_export(fake.SHARE,
1274 fake.SHARE_SERVER,
1275 fake.VSERVER1,
1276 vserver_client)
1277
1278 self.assertEqual(fake.NFS_EXPORTS, result)
1279 mock_get_export_addresses_with_metadata.assert_called_once_with(
1280 fake.SHARE, fake.SHARE_SERVER, fake.LIFS)
1281 protocol_helper.create_share.assert_called_once_with(
1282 fake.SHARE, fake.SHARE_NAME, clear_current_export_policy=True)
1283
1284 def test_create_export_lifs_not_found(self):
1285
1286 self.mock_object(self.library, '_get_helper')
1287 vserver_client = mock.Mock()
1288 vserver_client.get_network_interfaces.return_value = []
1289
1290 self.assertRaises(exception.NetAppException,
1291 self.library._create_export,
1292 fake.SHARE,
1293 fake.SHARE_SERVER,
1294 fake.VSERVER1,
1295 vserver_client)
1296
1297 def test_get_export_addresses_with_metadata(self):
1298
1299 mock_get_aggregate_node = self.mock_object(
1300 self.library, '_get_aggregate_node',
1301 mock.Mock(return_value=fake.CLUSTER_NODES[0]))
1302 mock_get_admin_addresses_for_share_server = self.mock_object(
1303 self.library, '_get_admin_addresses_for_share_server',
1304 mock.Mock(return_value=[fake.LIF_ADDRESSES[1]]))
1305
1306 result = self.library._get_export_addresses_with_metadata(
1307 fake.SHARE, fake.SHARE_SERVER, fake.LIFS)
1308
1309 self.assertEqual(fake.INTERFACE_ADDRESSES_WITH_METADATA, result)
1310 mock_get_aggregate_node.assert_called_once_with(fake.POOL_NAME)
1311 mock_get_admin_addresses_for_share_server.assert_called_once_with(
1312 fake.SHARE_SERVER)
1313
1314 def test_get_export_addresses_with_metadata_node_unknown(self):
1315
1316 mock_get_aggregate_node = self.mock_object(
1317 self.library, '_get_aggregate_node',
1318 mock.Mock(return_value=None))
1319 mock_get_admin_addresses_for_share_server = self.mock_object(
1320 self.library, '_get_admin_addresses_for_share_server',
1321 mock.Mock(return_value=[fake.LIF_ADDRESSES[1]]))
1322
1323 result = self.library._get_export_addresses_with_metadata(
1324 fake.SHARE, fake.SHARE_SERVER, fake.LIFS)
1325
1326 expected = copy.deepcopy(fake.INTERFACE_ADDRESSES_WITH_METADATA)
1327 for key, value in expected.items():
1328 value['preferred'] = False
1329
1330 self.assertEqual(expected, result)
1331 mock_get_aggregate_node.assert_called_once_with(fake.POOL_NAME)
1332 mock_get_admin_addresses_for_share_server.assert_called_once_with(
1333 fake.SHARE_SERVER)
1334
1335 def test_get_admin_addresses_for_share_server(self):
1336
1337 result = self.library._get_admin_addresses_for_share_server(
1338 fake.SHARE_SERVER)
1339
1340 self.assertEqual([fake.ADMIN_NETWORK_ALLOCATIONS[0]['ip_address']],
1341 result)
1342
1343 def test_get_admin_addresses_for_share_server_no_share_server(self):
1344
1345 result = self.library._get_admin_addresses_for_share_server(None)
1346
1347 self.assertEqual([], result)
1348
1349 @ddt.data(True, False)
1350 def test_sort_export_locations_by_preferred_paths(self, reverse):
1351
1352 export_locations = copy.copy(fake.NFS_EXPORTS)
1353 if reverse:
1354 export_locations.reverse()
1355
1356 result = self.library._sort_export_locations_by_preferred_paths(
1357 export_locations)
1358
1359 self.assertEqual(fake.NFS_EXPORTS, result)
1360
1361 def test_remove_export(self):
1362
1363 protocol_helper = mock.Mock()
1364 protocol_helper.get_target.return_value = 'fake_target'
1365 self.mock_object(self.library,
1366 '_get_helper',
1367 mock.Mock(return_value=protocol_helper))
1368 vserver_client = mock.Mock()
1369
1370 self.library._remove_export(fake.SHARE, vserver_client)
1371
1372 protocol_helper.set_client.assert_called_once_with(vserver_client)
1373 protocol_helper.get_target.assert_called_once_with(fake.SHARE)
1374 protocol_helper.delete_share.assert_called_once_with(fake.SHARE,
1375 fake.SHARE_NAME)
1376
1377 def test_remove_export_target_not_found(self):
1378
1379 protocol_helper = mock.Mock()
1380 protocol_helper.get_target.return_value = None
1381 self.mock_object(self.library,
1382 '_get_helper',
1383 mock.Mock(return_value=protocol_helper))
1384 vserver_client = mock.Mock()
1385
1386 self.library._remove_export(fake.SHARE, vserver_client)
1387
1388 protocol_helper.set_client.assert_called_once_with(vserver_client)
1389 protocol_helper.get_target.assert_called_once_with(fake.SHARE)
1390 self.assertFalse(protocol_helper.delete_share.called)
1391
1392 def test_create_snapshot(self):
1393
1394 vserver_client = mock.Mock()
1395 self.mock_object(self.library,
1396 '_get_vserver',
1397 mock.Mock(return_value=(fake.VSERVER1,
1398 vserver_client)))
1399
1400 model_update = self.library.create_snapshot(
1401 self.context, fake.SNAPSHOT, share_server=fake.SHARE_SERVER)
1402
1403 share_name = self.library._get_backend_share_name(
1404 fake.SNAPSHOT['share_id'])
1405 snapshot_name = self.library._get_backend_snapshot_name(
1406 fake.SNAPSHOT['id'])
1407 vserver_client.create_snapshot.assert_called_once_with(share_name,
1408 snapshot_name)
1409 self.assertEqual(snapshot_name, model_update['provider_location'])
1410
1411 @ddt.data(True, False)
1412 def test_revert_to_snapshot(self, use_snap_provider_location):
1413
1414 vserver_client = mock.Mock()
1415 self.mock_object(self.library,
1416 '_get_vserver',
1417 mock.Mock(return_value=(fake.VSERVER1,
1418 vserver_client)))
1419 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
1420 if use_snap_provider_location:
1421 fake_snapshot['provider_location'] = 'fake-provider-location'
1422 else:
1423 del fake_snapshot['provider_location']
1424
1425 result = self.library.revert_to_snapshot(
1426 self.context, fake_snapshot, share_server=fake.SHARE_SERVER)
1427
1428 self.assertIsNone(result)
1429 share_name = self.library._get_backend_share_name(
1430 fake_snapshot['share_id'])
1431 snapshot_name = (self.library._get_backend_snapshot_name(
1432 fake_snapshot['id']) if not use_snap_provider_location
1433 else 'fake-provider-location')
1434 vserver_client.restore_snapshot.assert_called_once_with(share_name,
1435 snapshot_name)
1436
1437 def test_delete_snapshot(self):
1438
1439 vserver_client = mock.Mock()
1440 self.mock_object(self.library,
1441 '_get_vserver',
1442 mock.Mock(return_value=(fake.VSERVER1,
1443 vserver_client)))
1444 mock_delete_snapshot = self.mock_object(self.library,
1445 '_delete_snapshot')
1446
1447 self.library.delete_snapshot(self.context,
1448 fake.SNAPSHOT,
1449 share_server=fake.SHARE_SERVER)
1450
1451 share_name = self.library._get_backend_share_name(
1452 fake.SNAPSHOT['share_id'])
1453 snapshot_name = self.library._get_backend_snapshot_name(
1454 fake.SNAPSHOT['id'])
1455 mock_delete_snapshot.assert_called_once_with(
1456 vserver_client, share_name, snapshot_name)
1457
1458 def test_delete_snapshot_with_provider_location(self):
1459 vserver_client = mock.Mock()
1460 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
1461 self.mock_object(self.library,
1462 '_get_vserver',
1463 mock.Mock(return_value=(fake.VSERVER1,
1464 vserver_client)))
1465 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
1466 fake_snapshot['provider_location'] = 'fake_provider_location'
1467
1468 self.library.delete_snapshot(self.context,
1469 fake_snapshot,
1470 share_server=fake.SHARE_SERVER)
1471
1472 share_name = self.library._get_backend_share_name(
1473 fake_snapshot['share_id'])
1474 vserver_client.delete_snapshot.assert_called_once_with(
1475 share_name, fake_snapshot['provider_location'])
1476
1477 @ddt.data(exception.InvalidInput(reason='fake_reason'),
1478 exception.VserverNotSpecified(),
1479 exception.VserverNotFound(vserver='fake_vserver'))
1480 def test_delete_snapshot_no_share_server(self, get_vserver_exception):
1481
1482 self.mock_object(self.library,
1483 '_get_vserver',
1484 mock.Mock(side_effect=get_vserver_exception))
1485 mock_delete_snapshot = self.mock_object(self.library,
1486 '_delete_snapshot')
1487
1488 self.library.delete_snapshot(self.context,
1489 fake.SNAPSHOT,
1490 share_server=fake.SHARE_SERVER)
1491
1492 self.assertFalse(mock_delete_snapshot.called)
1493
1494 def test_delete_snapshot_not_found(self):
1495
1496 vserver_client = mock.Mock()
1497 self.mock_object(self.library,
1498 '_get_vserver',
1499 mock.Mock(return_value=(fake.VSERVER1,
1500 vserver_client)))
1501 mock_delete_snapshot = self.mock_object(
1502 self.library, '_delete_snapshot',
1503 mock.Mock(side_effect=exception.SnapshotResourceNotFound(
1504 name=fake.SNAPSHOT_NAME)))
1505
1506 self.library.delete_snapshot(self.context,
1507 fake.SNAPSHOT,
1508 share_server=fake.SHARE_SERVER)
1509
1510 share_name = self.library._get_backend_share_name(
1511 fake.SNAPSHOT['share_id'])
1512 snapshot_name = self.library._get_backend_snapshot_name(
1513 fake.SNAPSHOT['id'])
1514 mock_delete_snapshot.assert_called_once_with(
1515 vserver_client, share_name, snapshot_name)
1516
1517 def test_delete_snapshot_not_unique(self):
1518
1519 vserver_client = mock.Mock()
1520 self.mock_object(self.library,
1521 '_get_vserver',
1522 mock.Mock(return_value=(fake.VSERVER1,
1523 vserver_client)))
1524 mock_delete_snapshot = self.mock_object(
1525 self.library, '_delete_snapshot',
1526 mock.Mock(side_effect=exception.NetAppException()))
1527
1528 self.assertRaises(exception.NetAppException,
1529 self.library.delete_snapshot,
1530 self.context,
1531 fake.SNAPSHOT,
1532 share_server=fake.SHARE_SERVER)
1533
1534 share_name = self.library._get_backend_share_name(
1535 fake.SNAPSHOT['share_id'])
1536 snapshot_name = self.library._get_backend_snapshot_name(
1537 fake.SNAPSHOT['id'])
1538 mock_delete_snapshot.assert_called_once_with(
1539 vserver_client, share_name, snapshot_name)
1540
1541 def test__delete_snapshot(self):
1542
1543 vserver_client = mock.Mock()
1544 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
1545
1546 self.library._delete_snapshot(vserver_client,
1547 fake.SHARE_NAME,
1548 fake.SNAPSHOT_NAME)
1549
1550 vserver_client.delete_snapshot.assert_called_once_with(
1551 fake.SHARE_NAME, fake.SNAPSHOT_NAME)
1552 self.assertFalse(vserver_client.get_clone_children_for_snapshot.called)
1553 self.assertFalse(vserver_client.split_volume_clone.called)
1554 self.assertFalse(vserver_client.soft_delete_snapshot.called)
1555
1556 def test__delete_snapshot_busy_volume_clone(self):
1557
1558 vserver_client = mock.Mock()
1559 vserver_client.get_snapshot.return_value = (
1560 fake.CDOT_SNAPSHOT_BUSY_VOLUME_CLONE)
1561 vserver_client.get_clone_children_for_snapshot.return_value = (
1562 fake.CDOT_CLONE_CHILDREN)
1563
1564 self.library._delete_snapshot(vserver_client,
1565 fake.SHARE_NAME,
1566 fake.SNAPSHOT_NAME)
1567
1568 self.assertFalse(vserver_client.delete_snapshot.called)
1569 vserver_client.get_clone_children_for_snapshot.assert_called_once_with(
1570 fake.SHARE_NAME, fake.SNAPSHOT_NAME)
1571 vserver_client.split_volume_clone.assert_has_calls([
1572 mock.call(fake.CDOT_CLONE_CHILD_1),
1573 mock.call(fake.CDOT_CLONE_CHILD_2),
1574 ])
1575 vserver_client.soft_delete_snapshot.assert_called_once_with(
1576 fake.SHARE_NAME, fake.SNAPSHOT_NAME)
1577
1578 def test__delete_snapshot_busy_snapmirror(self):
1579
1580 vserver_client = mock.Mock()
1581 vserver_client.get_snapshot.return_value = (
1582 fake.CDOT_SNAPSHOT_BUSY_SNAPMIRROR)
1583
1584 self.assertRaises(exception.ShareSnapshotIsBusy,
1585 self.library._delete_snapshot,
1586 vserver_client,
1587 fake.SHARE_NAME,
1588 fake.SNAPSHOT_NAME)
1589
1590 self.assertFalse(vserver_client.delete_snapshot.called)
1591 self.assertFalse(vserver_client.get_clone_children_for_snapshot.called)
1592 self.assertFalse(vserver_client.split_volume_clone.called)
1593 self.assertFalse(vserver_client.soft_delete_snapshot.called)
1594
1595 @ddt.data(None, fake.VSERVER1)
1596 def test_manage_existing(self, fake_vserver):
1597
1598 vserver_client = mock.Mock()
1599 mock__get_vserver = self.mock_object(
1600 self.library, '_get_vserver',
1601 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
1602 mock_manage_container = self.mock_object(
1603 self.library,
1604 '_manage_container',
1605 mock.Mock(return_value=fake.SHARE_SIZE))
1606 mock_create_export = self.mock_object(
1607 self.library,
1608 '_create_export',
1609 mock.Mock(return_value=fake.NFS_EXPORTS))
1610
1611 result = self.library.manage_existing(fake.SHARE, {},
1612 share_server=fake_vserver)
1613
1614 expected = {
1615 'size': fake.SHARE_SIZE,
1616 'export_locations': fake.NFS_EXPORTS
1617 }
1618
1619 mock__get_vserver.assert_called_once_with(share_server=fake_vserver)
1620 mock_manage_container.assert_called_once_with(fake.SHARE,
1621 fake.VSERVER1,
1622 vserver_client)
1623
1624 mock_create_export.assert_called_once_with(fake.SHARE,
1625 fake_vserver,
1626 fake.VSERVER1,
1627 vserver_client)
1628 self.assertDictEqual(expected, result)
1629
1630 @ddt.data(None, fake.VSERVER1)
1631 def test_unmanage(self, fake_vserver):
1632
1633 result = self.library.unmanage(fake.SHARE, share_server=fake_vserver)
1634
1635 self.assertIsNone(result)
1636
1637 @ddt.data(True, False)
1638 def test_manage_container_with_qos(self, qos):
1639
1640 vserver_client = mock.Mock()
1641 qos_policy_group_name = fake.QOS_POLICY_GROUP_NAME if qos else None
1642 extra_specs = fake.EXTRA_SPEC_WITH_QOS if qos else fake.EXTRA_SPEC
1643 provisioning_opts = self.library._get_provisioning_options(extra_specs)
1644 if qos:
1645 provisioning_opts['qos_policy_group'] = fake.QOS_POLICY_GROUP_NAME
1646
1647 share_to_manage = copy.deepcopy(fake.SHARE)
1648 share_to_manage['export_location'] = fake.EXPORT_LOCATION
1649
1650 mock_helper = mock.Mock()
1651 mock_helper.get_share_name_for_share.return_value = fake.FLEXVOL_NAME
1652 self.mock_object(self.library,
1653 '_get_helper',
1654 mock.Mock(return_value=mock_helper))
1655
1656 mock_get_volume_to_manage = self.mock_object(
1657 vserver_client,
1658 'get_volume_to_manage',
1659 mock.Mock(return_value=fake.FLEXVOL_TO_MANAGE))
1660 mock_validate_volume_for_manage = self.mock_object(
1661 self.library,
1662 '_validate_volume_for_manage')
1663 self.mock_object(share_types,
1664 'get_extra_specs_from_share',
1665 mock.Mock(return_value=extra_specs))
1666 mock_check_extra_specs_validity = self.mock_object(
1667 self.library,
1668 '_check_extra_specs_validity')
1669 mock_check_aggregate_extra_specs_validity = self.mock_object(
1670 self.library,
1671 '_check_aggregate_extra_specs_validity')
1672 mock_modify_or_create_qos_policy = self.mock_object(
1673 self.library, '_modify_or_create_qos_for_existing_share',
1674 mock.Mock(return_value=qos_policy_group_name))
1675
1676 result = self.library._manage_container(share_to_manage,
1677 fake.VSERVER1,
1678 vserver_client)
1679
1680 mock_get_volume_to_manage.assert_called_once_with(
1681 fake.POOL_NAME, fake.FLEXVOL_NAME)
1682 mock_check_extra_specs_validity.assert_called_once_with(
1683 share_to_manage, extra_specs)
1684 mock_check_aggregate_extra_specs_validity.assert_called_once_with(
1685 fake.POOL_NAME, extra_specs)
1686 vserver_client.unmount_volume.assert_called_once_with(
1687 fake.FLEXVOL_NAME)
1688 vserver_client.set_volume_name.assert_called_once_with(
1689 fake.FLEXVOL_NAME, fake.SHARE_NAME)
1690 vserver_client.mount_volume.assert_called_once_with(
1691 fake.SHARE_NAME)
1692 vserver_client.modify_volume.assert_called_once_with(
1693 fake.POOL_NAME, fake.SHARE_NAME, **provisioning_opts)
1694 mock_modify_or_create_qos_policy.assert_called_once_with(
1695 share_to_manage, extra_specs, fake.VSERVER1, vserver_client)
1696 mock_validate_volume_for_manage.assert_called()
1697
1698 original_data = {
1699 'original_name': fake.FLEXVOL_TO_MANAGE['name'],
1700 'original_junction_path': fake.FLEXVOL_TO_MANAGE['junction-path'],
1701 }
1702 self.library.private_storage.update.assert_called_once_with(
1703 fake.SHARE['id'], original_data)
1704
1705 expected_size = int(
1706 math.ceil(float(fake.FLEXVOL_TO_MANAGE['size']) / units.Gi))
1707 self.assertEqual(expected_size, result)
1708
1709 def test_manage_container_invalid_export_location(self):
1710
1711 vserver_client = mock.Mock()
1712
1713 share_to_manage = copy.deepcopy(fake.SHARE)
1714 share_to_manage['export_location'] = fake.EXPORT_LOCATION
1715
1716 mock_helper = mock.Mock()
1717 mock_helper.get_share_name_for_share.return_value = None
1718 self.mock_object(self.library,
1719 '_get_helper',
1720 mock.Mock(return_value=mock_helper))
1721
1722 self.assertRaises(exception.ManageInvalidShare,
1723 self.library._manage_container,
1724 share_to_manage,
1725 fake.VSERVER1,
1726 vserver_client)
1727
1728 def test_manage_container_not_found(self):
1729
1730 vserver_client = mock.Mock()
1731
1732 share_to_manage = copy.deepcopy(fake.SHARE)
1733 share_to_manage['export_location'] = fake.EXPORT_LOCATION
1734
1735 mock_helper = mock.Mock()
1736 mock_helper.get_share_name_for_share.return_value = fake.FLEXVOL_NAME
1737 self.mock_object(self.library,
1738 '_get_helper',
1739 mock.Mock(return_value=mock_helper))
1740
1741 self.mock_object(vserver_client,
1742 'get_volume_to_manage',
1743 mock.Mock(return_value=None))
1744
1745 self.assertRaises(exception.ManageInvalidShare,
1746 self.library._manage_container,
1747 share_to_manage,
1748 fake.VSERVER1,
1749 vserver_client)
1750
1751 def test_manage_container_invalid_extra_specs(self):
1752
1753 vserver_client = mock.Mock()
1754
1755 share_to_manage = copy.deepcopy(fake.SHARE)
1756 share_to_manage['export_location'] = fake.EXPORT_LOCATION
1757
1758 mock_helper = mock.Mock()
1759 mock_helper.get_share_name_for_share.return_value = fake.FLEXVOL_NAME
1760 self.mock_object(self.library,
1761 '_get_helper',
1762 mock.Mock(return_value=mock_helper))
1763
1764 self.mock_object(vserver_client,
1765 'get_volume_to_manage',
1766 mock.Mock(return_value=fake.FLEXVOL_TO_MANAGE))
1767 self.mock_object(self.library, '_validate_volume_for_manage')
1768 self.mock_object(share_types,
1769 'get_extra_specs_from_share',
1770 mock.Mock(return_value=fake.EXTRA_SPEC))
1771 self.mock_object(self.library,
1772 '_check_extra_specs_validity',
1773 mock.Mock(side_effect=exception.NetAppException))
1774
1775 self.assertRaises(exception.ManageExistingShareTypeMismatch,
1776 self.library._manage_container,
1777 share_to_manage,
1778 fake.VSERVER1,
1779 vserver_client)
1780
1781 def test_validate_volume_for_manage(self):
1782
1783 vserver_client = mock.Mock()
1784 vserver_client.volume_has_luns = mock.Mock(return_value=False)
1785 vserver_client.volume_has_junctioned_volumes = mock.Mock(
1786 return_value=False)
1787 vserver_client.volume_has_snapmirror_relationships = mock.Mock(
1788 return_value=False)
1789
1790 result = self.library._validate_volume_for_manage(
1791 fake.FLEXVOL_TO_MANAGE, vserver_client)
1792
1793 self.assertIsNone(result)
1794
1795 @ddt.data({
1796 'attribute': 'type',
1797 'value': 'dp',
1798 }, {
1799 'attribute': 'style',
1800 'value': 'infinitevol',
1801 })
1802 @ddt.unpack
1803 def test_validate_volume_for_manage_invalid_volume(self, attribute, value):
1804
1805 flexvol_to_manage = copy.deepcopy(fake.FLEXVOL_TO_MANAGE)
1806 flexvol_to_manage[attribute] = value
1807
1808 vserver_client = mock.Mock()
1809 vserver_client.volume_has_luns = mock.Mock(return_value=False)
1810 vserver_client.volume_has_junctioned_volumes = mock.Mock(
1811 return_value=False)
1812 vserver_client.volume_has_snapmirror_relationships = mock.Mock(
1813 return_value=False)
1814
1815 self.assertRaises(exception.ManageInvalidShare,
1816 self.library._validate_volume_for_manage,
1817 flexvol_to_manage,
1818 vserver_client)
1819
1820 def test_validate_volume_for_manage_luns_present(self):
1821
1822 vserver_client = mock.Mock()
1823 vserver_client.volume_has_luns = mock.Mock(return_value=True)
1824 vserver_client.volume_has_junctioned_volumes = mock.Mock(
1825 return_value=False)
1826 vserver_client.volume_has_snapmirror_relationships = mock.Mock(
1827 return_value=False)
1828
1829 self.assertRaises(exception.ManageInvalidShare,
1830 self.library._validate_volume_for_manage,
1831 fake.FLEXVOL_TO_MANAGE,
1832 vserver_client)
1833
1834 def test_validate_volume_for_manage_junctioned_volumes_present(self):
1835
1836 vserver_client = mock.Mock()
1837 vserver_client.volume_has_luns = mock.Mock(return_value=False)
1838 vserver_client.volume_has_junctioned_volumes = mock.Mock(
1839 return_value=True)
1840 vserver_client.volume_has_snapmirror_relationships = mock.Mock(
1841 return_value=False)
1842
1843 self.assertRaises(exception.ManageInvalidShare,
1844 self.library._validate_volume_for_manage,
1845 fake.FLEXVOL_TO_MANAGE,
1846 vserver_client)
1847
1848 @ddt.data(None, fake.VSERVER1)
1849 def test_manage_existing_snapshot(self, fake_vserver):
1850
1851 vserver_client = mock.Mock()
1852 mock_get_vserver = self.mock_object(
1853 self.library, '_get_vserver',
1854 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
1855 vserver_client.get_volume.return_value = fake.FLEXVOL_TO_MANAGE
1856 vserver_client.volume_has_snapmirror_relationships.return_value = False
1857 result = self.library.manage_existing_snapshot(
1858 fake.SNAPSHOT_TO_MANAGE, {}, share_server=fake_vserver)
1859
1860 share_name = self.library._get_backend_share_name(
1861 fake.SNAPSHOT['share_id'])
1862 new_snapshot_name = self.library._get_backend_snapshot_name(
1863 fake.SNAPSHOT['id'])
1864 mock_get_vserver.assert_called_once_with(share_server=fake_vserver)
1865 (vserver_client.volume_has_snapmirror_relationships.
1866 assert_called_once_with(fake.FLEXVOL_TO_MANAGE))
1867 vserver_client.rename_snapshot.assert_called_once_with(
1868 share_name, fake.SNAPSHOT_NAME, new_snapshot_name)
1869 self.library.private_storage.update.assert_called_once_with(
1870 fake.SNAPSHOT['id'], {'original_name': fake.SNAPSHOT_NAME})
1871 self.assertEqual({'size': 2, 'provider_location': new_snapshot_name},
1872 result)
1873
1874 def test_manage_existing_snapshot_no_snapshot_name(self):
1875
1876 vserver_client = mock.Mock()
1877 self.mock_object(self.library,
1878 '_get_vserver',
1879 mock.Mock(return_value=(fake.VSERVER1,
1880 vserver_client)))
1881 vserver_client.get_volume.return_value = fake.FLEXVOL_TO_MANAGE
1882 vserver_client.volume_has_snapmirror_relationships.return_value = False
1883 fake_snapshot = copy.deepcopy(fake.SNAPSHOT_TO_MANAGE)
1884 fake_snapshot['provider_location'] = ''
1885
1886 self.assertRaises(exception.ManageInvalidShareSnapshot,
1887 self.library.manage_existing_snapshot,
1888 fake_snapshot, {})
1889
1890 @ddt.data(netapp_api.NaApiError,
1891 exception.NetAppException)
1892 def test_manage_existing_snapshot_get_volume_error(self, exception_type):
1893
1894 vserver_client = mock.Mock()
1895 self.mock_object(self.library,
1896 '_get_vserver',
1897 mock.Mock(return_value=(fake.VSERVER1,
1898 vserver_client)))
1899 vserver_client.get_volume.side_effect = exception_type
1900 self.mock_object(self.client,
1901 'volume_has_snapmirror_relationships',
1902 mock.Mock(return_value=False))
1903
1904 self.assertRaises(exception.ShareNotFound,
1905 self.library.manage_existing_snapshot,
1906 fake.SNAPSHOT_TO_MANAGE, {})
1907
1908 def test_manage_existing_snapshot_mirrors_present(self):
1909
1910 vserver_client = mock.Mock()
1911 self.mock_object(self.library,
1912 '_get_vserver',
1913 mock.Mock(return_value=(fake.VSERVER1,
1914 vserver_client)))
1915 vserver_client.get_volume.return_value = fake.FLEXVOL_TO_MANAGE
1916 vserver_client.volume_has_snapmirror_relationships.return_value = True
1917
1918 self.assertRaises(exception.ManageInvalidShareSnapshot,
1919 self.library.manage_existing_snapshot,
1920 fake.SNAPSHOT_TO_MANAGE, {})
1921
1922 def test_manage_existing_snapshot_rename_snapshot_error(self):
1923
1924 vserver_client = mock.Mock()
1925 self.mock_object(self.library,
1926 '_get_vserver',
1927 mock.Mock(return_value=(fake.VSERVER1,
1928 vserver_client)))
1929 vserver_client.get_volume.return_value = fake.FLEXVOL_TO_MANAGE
1930 vserver_client.volume_has_snapmirror_relationships.return_value = False
1931 vserver_client.rename_snapshot.side_effect = netapp_api.NaApiError
1932
1933 self.assertRaises(exception.ManageInvalidShareSnapshot,
1934 self.library.manage_existing_snapshot,
1935 fake.SNAPSHOT_TO_MANAGE, {})
1936
1937 @ddt.data(None, fake.VSERVER1)
1938 def test_unmanage_snapshot(self, fake_vserver):
1939
1940 result = self.library.unmanage_snapshot(fake.SNAPSHOT, fake_vserver)
1941
1942 self.assertIsNone(result)
1943
1944 def test_validate_volume_for_manage_snapmirror_relationships_present(self):
1945
1946 vserver_client = mock.Mock()
1947 vserver_client.volume_has_luns.return_value = False
1948 vserver_client.volume_has_junctioned_volumes.return_value = False
1949 vserver_client.volume_has_snapmirror_relationships.return_value = True
1950
1951 self.assertRaises(exception.ManageInvalidShare,
1952 self.library._validate_volume_for_manage,
1953 fake.FLEXVOL_TO_MANAGE,
1954 vserver_client)
1955
1956 def test_create_consistency_group_from_cgsnapshot(self):
1957
1958 vserver_client = mock.Mock()
1959 mock_get_vserver = self.mock_object(
1960 self.library, '_get_vserver',
1961 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
1962 mock_allocate_container_from_snapshot = self.mock_object(
1963 self.library, '_allocate_container_from_snapshot')
1964 mock_create_export = self.mock_object(
1965 self.library, '_create_export',
1966 mock.Mock(side_effect=[['loc3'], ['loc4']]))
1967
1968 result = self.library.create_consistency_group_from_cgsnapshot(
1969 self.context,
1970 fake.CONSISTENCY_GROUP_DEST,
1971 fake.CG_SNAPSHOT,
1972 share_server=fake.SHARE_SERVER)
1973
1974 share_update_list = [
1975 {'id': fake.SHARE_ID3, 'export_locations': ['loc3']},
1976 {'id': fake.SHARE_ID4, 'export_locations': ['loc4']}
1977 ]
1978 expected = (None, share_update_list)
1979 self.assertEqual(expected, result)
1980
1981 mock_allocate_container_from_snapshot.assert_has_calls([
1982 mock.call(fake.COLLATED_CGSNAPSHOT_INFO[0]['share'],
1983 fake.COLLATED_CGSNAPSHOT_INFO[0]['snapshot'],
1984 fake.VSERVER1,
1985 vserver_client,
1986 mock.ANY),
1987 mock.call(fake.COLLATED_CGSNAPSHOT_INFO[1]['share'],
1988 fake.COLLATED_CGSNAPSHOT_INFO[1]['snapshot'],
1989 fake.VSERVER1,
1990 vserver_client,
1991 mock.ANY),
1992 ])
1993 mock_create_export.assert_has_calls([
1994 mock.call(fake.COLLATED_CGSNAPSHOT_INFO[0]['share'],
1995 fake.SHARE_SERVER,
1996 fake.VSERVER1,
1997 vserver_client),
1998 mock.call(fake.COLLATED_CGSNAPSHOT_INFO[1]['share'],
1999 fake.SHARE_SERVER,
2000 fake.VSERVER1,
2001 vserver_client),
2002 ])
2003 mock_get_vserver.assert_called_once_with(
2004 share_server=fake.SHARE_SERVER)
2005
2006 def test_create_consistency_group_from_cgsnapshot_no_members(self):
2007
2008 vserver_client = mock.Mock()
2009 mock_get_vserver = self.mock_object(
2010 self.library, '_get_vserver',
2011 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
2012 mock_allocate_container_from_snapshot = self.mock_object(
2013 self.library, '_allocate_container_from_snapshot')
2014 mock_create_export = self.mock_object(
2015 self.library, '_create_export',
2016 mock.Mock(side_effect=[['loc3'], ['loc4']]))
2017
2018 fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
2019 fake_cg_snapshot['share_group_snapshot_members'] = []
2020
2021 result = self.library.create_consistency_group_from_cgsnapshot(
2022 self.context,
2023 fake.CONSISTENCY_GROUP_DEST,
2024 fake_cg_snapshot,
2025 share_server=fake.SHARE_SERVER)
2026
2027 self.assertEqual((None, None), result)
2028
2029 self.assertFalse(mock_allocate_container_from_snapshot.called)
2030 self.assertFalse(mock_create_export.called)
2031 mock_get_vserver.assert_called_once_with(
2032 share_server=fake.SHARE_SERVER)
2033
2034 def test_collate_cg_snapshot_info(self):
2035
2036 result = self.library._collate_cg_snapshot_info(
2037 fake.CONSISTENCY_GROUP_DEST, fake.CG_SNAPSHOT)
2038
2039 self.assertEqual(fake.COLLATED_CGSNAPSHOT_INFO, result)
2040
2041 def test_collate_cg_snapshot_info_invalid(self):
2042
2043 fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
2044 fake_cg_snapshot['share_group_snapshot_members'] = []
2045
2046 self.assertRaises(exception.InvalidShareGroup,
2047 self.library._collate_cg_snapshot_info,
2048 fake.CONSISTENCY_GROUP_DEST, fake_cg_snapshot)
2049
2050 def test_create_cgsnapshot(self):
2051
2052 vserver_client = mock.Mock()
2053 mock_get_vserver = self.mock_object(
2054 self.library, '_get_vserver',
2055 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
2056
2057 result = self.library.create_cgsnapshot(
2058 self.context,
2059 fake.CG_SNAPSHOT,
2060 share_server=fake.SHARE_SERVER)
2061
2062 share_names = [
2063 self.library._get_backend_share_name(
2064 fake.CG_SNAPSHOT_MEMBER_1['share_id']),
2065 self.library._get_backend_share_name(
2066 fake.CG_SNAPSHOT_MEMBER_2['share_id'])
2067 ]
2068 snapshot_name = self.library._get_backend_cg_snapshot_name(
2069 fake.CG_SNAPSHOT['id'])
2070 vserver_client.create_cg_snapshot.assert_called_once_with(
2071 share_names, snapshot_name)
2072 self.assertEqual((None, None), result)
2073 mock_get_vserver.assert_called_once_with(
2074 share_server=fake.SHARE_SERVER)
2075
2076 def test_create_cgsnapshot_no_members(self):
2077
2078 vserver_client = mock.Mock()
2079 mock_get_vserver = self.mock_object(
2080 self.library, '_get_vserver',
2081 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
2082
2083 fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
2084 fake_cg_snapshot['share_group_snapshot_members'] = []
2085
2086 result = self.library.create_cgsnapshot(
2087 self.context,
2088 fake_cg_snapshot,
2089 share_server=fake.SHARE_SERVER)
2090
2091 self.assertFalse(vserver_client.create_cg_snapshot.called)
2092 self.assertEqual((None, None), result)
2093 mock_get_vserver.assert_called_once_with(
2094 share_server=fake.SHARE_SERVER)
2095
2096 def test_delete_cgsnapshot(self):
2097
2098 vserver_client = mock.Mock()
2099 mock_get_vserver = self.mock_object(
2100 self.library, '_get_vserver',
2101 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
2102 mock_delete_snapshot = self.mock_object(self.library,
2103 '_delete_snapshot')
2104
2105 result = self.library.delete_cgsnapshot(
2106 self.context,
2107 fake.CG_SNAPSHOT,
2108 share_server=fake.SHARE_SERVER)
2109
2110 share_names = [
2111 self.library._get_backend_share_name(
2112 fake.CG_SNAPSHOT_MEMBER_1['share_id']),
2113 self.library._get_backend_share_name(
2114 fake.CG_SNAPSHOT_MEMBER_2['share_id'])
2115 ]
2116 snapshot_name = self.library._get_backend_cg_snapshot_name(
2117 fake.CG_SNAPSHOT['id'])
2118
2119 mock_delete_snapshot.assert_has_calls([
2120 mock.call(vserver_client, share_names[0], snapshot_name),
2121 mock.call(vserver_client, share_names[1], snapshot_name)
2122 ])
2123 self.assertEqual((None, None), result)
2124 mock_get_vserver.assert_called_once_with(
2125 share_server=fake.SHARE_SERVER)
2126
2127 def test_delete_cgsnapshot_no_members(self):
2128
2129 vserver_client = mock.Mock()
2130 mock_get_vserver = self.mock_object(
2131 self.library, '_get_vserver',
2132 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
2133 mock_delete_snapshot = self.mock_object(self.library,
2134 '_delete_snapshot')
2135
2136 fake_cg_snapshot = copy.deepcopy(fake.CG_SNAPSHOT)
2137 fake_cg_snapshot['share_group_snapshot_members'] = []
2138
2139 result = self.library.delete_cgsnapshot(
2140 self.context,
2141 fake_cg_snapshot,
2142 share_server=fake.SHARE_SERVER)
2143
2144 self.assertFalse(mock_delete_snapshot.called)
2145 self.assertEqual((None, None), result)
2146 mock_get_vserver.assert_called_once_with(
2147 share_server=fake.SHARE_SERVER)
2148
2149 def test_delete_cgsnapshot_snapshots_not_found(self):
2150
2151 vserver_client = mock.Mock()
2152 mock_get_vserver = self.mock_object(
2153 self.library, '_get_vserver',
2154 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
2155 mock_delete_snapshot = self.mock_object(
2156 self.library, '_delete_snapshot',
2157 mock.Mock(side_effect=exception.SnapshotResourceNotFound(
2158 name='fake')))
2159
2160 result = self.library.delete_cgsnapshot(
2161 self.context,
2162 fake.CG_SNAPSHOT,
2163 share_server=fake.SHARE_SERVER)
2164
2165 share_names = [
2166 self.library._get_backend_share_name(
2167 fake.CG_SNAPSHOT_MEMBER_1['share_id']),
2168 self.library._get_backend_share_name(
2169 fake.CG_SNAPSHOT_MEMBER_2['share_id'])
2170 ]
2171 snapshot_name = self.library._get_backend_cg_snapshot_name(
2172 fake.CG_SNAPSHOT['id'])
2173
2174 mock_delete_snapshot.assert_has_calls([
2175 mock.call(vserver_client, share_names[0], snapshot_name),
2176 mock.call(vserver_client, share_names[1], snapshot_name)
2177 ])
2178 self.assertEqual((None, None), result)
2179 mock_get_vserver.assert_called_once_with(
2180 share_server=fake.SHARE_SERVER)
2181
2182 @ddt.data(exception.InvalidInput(reason='fake_reason'),
2183 exception.VserverNotSpecified(),
2184 exception.VserverNotFound(vserver='fake_vserver'))
2185 def test_delete_cgsnapshot_no_share_server(self,
2186 get_vserver_exception):
2187
2188 mock_get_vserver = self.mock_object(
2189 self.library, '_get_vserver',
2190 mock.Mock(side_effect=get_vserver_exception))
2191
2192 result = self.library.delete_cgsnapshot(
2193 self.context,
2194 fake.EMPTY_CONSISTENCY_GROUP,
2195 share_server=fake.SHARE_SERVER)
2196
2197 self.assertEqual((None, None), result)
2198 self.assertEqual(1, lib_base.LOG.warning.call_count)
2199 mock_get_vserver.assert_called_once_with(
2200 share_server=fake.SHARE_SERVER)
2201
2202 def test_adjust_qos_policy_with_volume_resize_no_cluster_creds(self):
2203 self.library._have_cluster_creds = False
2204 self.mock_object(share_types, 'get_extra_specs_from_share')
2205
2206 retval = self.library._adjust_qos_policy_with_volume_resize(
2207 fake.SHARE, 10, mock.Mock())
2208
2209 self.assertIsNone(retval)
2210 share_types.get_extra_specs_from_share.assert_not_called()
2211
2212 def test_adjust_qos_policy_with_volume_resize_no_qos_on_share(self):
2213 self.library._have_cluster_creds = True
2214 self.mock_object(share_types, 'get_extra_specs_from_share')
2215 vserver_client = mock.Mock()
2216 self.mock_object(vserver_client, 'get_volume',
2217 mock.Mock(return_value=fake.FLEXVOL_WITHOUT_QOS))
2218
2219 retval = self.library._adjust_qos_policy_with_volume_resize(
2220 fake.SHARE, 10, vserver_client)
2221
2222 self.assertIsNone(retval)
2223 share_types.get_extra_specs_from_share.assert_not_called()
2224
2225 def test_adjust_qos_policy_with_volume_resize_no_size_dependent_qos(self):
2226 self.library._have_cluster_creds = True
2227 self.mock_object(share_types, 'get_extra_specs_from_share',
2228 mock.Mock(return_value=fake.EXTRA_SPEC_WITH_QOS))
2229 vserver_client = mock.Mock()
2230 self.mock_object(vserver_client, 'get_volume',
2231 mock.Mock(return_value=fake.FLEXVOL_WITH_QOS))
2232 self.mock_object(self.library, '_get_max_throughput')
2233 self.mock_object(self.library._client, 'qos_policy_group_modify')
2234
2235 retval = self.library._adjust_qos_policy_with_volume_resize(
2236 fake.SHARE, 10, vserver_client)
2237
2238 self.assertIsNone(retval)
2239 share_types.get_extra_specs_from_share.assert_called_once_with(
2240 fake.SHARE)
2241 self.library._get_max_throughput.assert_not_called()
2242 self.library._client.qos_policy_group_modify.assert_not_called()
2243
2244 def test_adjust_qos_policy_with_volume_resize(self):
2245 self.library._have_cluster_creds = True
2246 self.mock_object(
2247 share_types, 'get_extra_specs_from_share',
2248 mock.Mock(return_value=fake.EXTRA_SPEC_WITH_SIZE_DEPENDENT_QOS))
2249 vserver_client = mock.Mock()
2250 self.mock_object(vserver_client, 'get_volume',
2251 mock.Mock(return_value=fake.FLEXVOL_WITH_QOS))
2252 self.mock_object(self.library._client, 'qos_policy_group_modify')
2253
2254 retval = self.library._adjust_qos_policy_with_volume_resize(
2255 fake.SHARE, 10, vserver_client)
2256
2257 expected_max_throughput = '10000B/s'
2258 self.assertIsNone(retval)
2259 share_types.get_extra_specs_from_share.assert_called_once_with(
2260 fake.SHARE)
2261 self.library._client.qos_policy_group_modify.assert_called_once_with(
2262 fake.QOS_POLICY_GROUP_NAME, expected_max_throughput)
2263
2264 def test_extend_share(self):
2265
2266 vserver_client = mock.Mock()
2267 self.mock_object(self.library,
2268 '_get_vserver',
2269 mock.Mock(return_value=(fake.VSERVER1,
2270 vserver_client)))
2271 mock_adjust_qos_policy = self.mock_object(
2272 self.library, '_adjust_qos_policy_with_volume_resize')
2273
2274 mock_set_volume_size = self.mock_object(vserver_client,
2275 'set_volume_size')
2276 new_size = fake.SHARE['size'] * 2
2277
2278 self.library.extend_share(fake.SHARE, new_size)
2279
2280 mock_set_volume_size.assert_called_once_with(fake.SHARE_NAME, new_size)
2281 mock_adjust_qos_policy.assert_called_once_with(
2282 fake.SHARE, new_size, vserver_client)
2283
2284 def test_shrink_share(self):
2285
2286 vserver_client = mock.Mock()
2287 self.mock_object(self.library,
2288 '_get_vserver',
2289 mock.Mock(return_value=(fake.VSERVER1,
2290 vserver_client)))
2291 mock_adjust_qos_policy = self.mock_object(
2292 self.library, '_adjust_qos_policy_with_volume_resize')
2293 mock_set_volume_size = self.mock_object(vserver_client,
2294 'set_volume_size')
2295 new_size = fake.SHARE['size'] - 1
2296
2297 self.library.shrink_share(fake.SHARE, new_size)
2298
2299 mock_set_volume_size.assert_called_once_with(fake.SHARE_NAME, new_size)
2300 mock_adjust_qos_policy.assert_called_once_with(
2301 fake.SHARE, new_size, vserver_client)
2302
2303 def test_shrinking_possible_data_loss(self):
2304
2305 naapi_error = self._mock_api_error(code=netapp_api.EVOLOPNOTSUPP,
2306 message='Possible data loss')
2307
2308 vserver_client = mock.Mock()
2309 self.mock_object(self.library,
2310 '_get_vserver',
2311 mock.Mock(return_value=(fake.VSERVER1,
2312 vserver_client)))
2313
2314 mock_set_volume_size = self.mock_object(
2315 vserver_client, 'set_volume_size', naapi_error)
2316
2317 new_size = fake.SHARE['size'] - 1
2318
2319 self.assertRaises(exception.ShareShrinkingPossibleDataLoss,
2320 self.library.shrink_share,
2321 fake.SHARE, new_size)
2322
2323 self.library._get_vserver.assert_called_once_with(share_server=None)
2324 mock_set_volume_size.assert_called_once_with(fake.SHARE_NAME, new_size)
2325
2326 def test_update_access(self):
2327
2328 vserver_client = mock.Mock()
2329 mock_get_vserver = self.mock_object(
2330 self.library, '_get_vserver',
2331 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
2332 protocol_helper = mock.Mock()
2333 protocol_helper.update_access.return_value = None
2334 self.mock_object(self.library,
2335 '_get_helper',
2336 mock.Mock(return_value=protocol_helper))
2337 mock_share_exists = self.mock_object(self.library,
2338 '_share_exists',
2339 mock.Mock(return_value=True))
2340
2341 self.library.update_access(self.context,
2342 fake.SHARE,
2343 [fake.SHARE_ACCESS],
2344 [],
2345 [],
2346 share_server=fake.SHARE_SERVER)
2347
2348 mock_get_vserver.assert_called_once_with(
2349 share_server=fake.SHARE_SERVER)
2350 share_name = self.library._get_backend_share_name(fake.SHARE['id'])
2351 mock_share_exists.assert_called_once_with(share_name, vserver_client)
2352 protocol_helper.set_client.assert_called_once_with(vserver_client)
2353 protocol_helper.update_access.assert_called_once_with(
2354 fake.SHARE, fake.SHARE_NAME, [fake.SHARE_ACCESS])
2355
2356 @ddt.data(exception.InvalidInput(reason='fake_reason'),
2357 exception.VserverNotSpecified(),
2358 exception.VserverNotFound(vserver='fake_vserver'))
2359 def test_update_access_no_share_server(self, get_vserver_exception):
2360
2361 mock_get_vserver = self.mock_object(
2362 self.library, '_get_vserver',
2363 mock.Mock(side_effect=get_vserver_exception))
2364 protocol_helper = mock.Mock()
2365 protocol_helper.update_access.return_value = None
2366 self.mock_object(self.library,
2367 '_get_helper',
2368 mock.Mock(return_value=protocol_helper))
2369 mock_share_exists = self.mock_object(self.library, '_share_exists')
2370
2371 self.library.update_access(self.context,
2372 fake.SHARE,
2373 [fake.SHARE_ACCESS],
2374 [],
2375 [],
2376 share_server=fake.SHARE_SERVER)
2377
2378 mock_get_vserver.assert_called_once_with(
2379 share_server=fake.SHARE_SERVER)
2380 self.assertFalse(mock_share_exists.called)
2381 self.assertFalse(protocol_helper.set_client.called)
2382 self.assertFalse(protocol_helper.update_access.called)
2383
2384 def test_update_access_share_not_found(self):
2385
2386 vserver_client = mock.Mock()
2387 mock_get_vserver = self.mock_object(
2388 self.library, '_get_vserver',
2389 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
2390 protocol_helper = mock.Mock()
2391 protocol_helper.update_access.return_value = None
2392 self.mock_object(self.library,
2393 '_get_helper',
2394 mock.Mock(return_value=protocol_helper))
2395 mock_share_exists = self.mock_object(self.library,
2396 '_share_exists',
2397 mock.Mock(return_value=False))
2398
2399 self.assertRaises(exception.ShareResourceNotFound,
2400 self.library.update_access,
2401 self.context,
2402 fake.SHARE,
2403 [fake.SHARE_ACCESS],
2404 [],
2405 [],
2406 share_server=fake.SHARE_SERVER)
2407
2408 mock_get_vserver.assert_called_once_with(
2409 share_server=fake.SHARE_SERVER)
2410 share_name = self.library._get_backend_share_name(fake.SHARE['id'])
2411 mock_share_exists.assert_called_once_with(share_name, vserver_client)
2412 self.assertFalse(protocol_helper.set_client.called)
2413 self.assertFalse(protocol_helper.update_access.called)
2414
2415 def test_update_access_to_active_replica(self):
2416 fake_share = copy.deepcopy(fake.SHARE)
2417 fake_share['replica_state'] = constants.REPLICA_STATE_ACTIVE
2418 vserver_client = mock.Mock()
2419 mock_get_vserver = self.mock_object(
2420 self.library, '_get_vserver',
2421 mock.Mock(return_value=(fake.VSERVER1, vserver_client)))
2422 protocol_helper = mock.Mock()
2423 protocol_helper.update_access.return_value = None
2424 self.mock_object(self.library,
2425 '_get_helper',
2426 mock.Mock(return_value=protocol_helper))
2427 mock_share_exists = self.mock_object(self.library,
2428 '_share_exists',
2429 mock.Mock(return_value=True))
2430
2431 self.library.update_access(self.context,
2432 fake_share,
2433 [fake.SHARE_ACCESS],
2434 [],
2435 [],
2436 share_server=fake.SHARE_SERVER)
2437
2438 mock_get_vserver.assert_called_once_with(
2439 share_server=fake.SHARE_SERVER)
2440 share_name = self.library._get_backend_share_name(fake.SHARE['id'])
2441 mock_share_exists.assert_called_once_with(share_name, vserver_client)
2442 protocol_helper.set_client.assert_called_once_with(vserver_client)
2443 protocol_helper.update_access.assert_called_once_with(
2444 fake.SHARE, fake.SHARE_NAME, [fake.SHARE_ACCESS])
2445
2446 def test_update_access_to_in_sync_replica(self):
2447 fake_share = copy.deepcopy(fake.SHARE)
2448 fake_share['replica_state'] = constants.REPLICA_STATE_IN_SYNC
2449 self.library.update_access(self.context,
2450 fake_share,
2451 [fake.SHARE_ACCESS],
2452 [],
2453 [],
2454 share_server=fake.SHARE_SERVER)
2455
2456 def test_setup_server(self):
2457 self.assertRaises(NotImplementedError,
2458 self.library.setup_server,
2459 fake.NETWORK_INFO)
2460
2461 def test_teardown_server(self):
2462 self.assertRaises(NotImplementedError,
2463 self.library.teardown_server,
2464 fake.SHARE_SERVER['backend_details'])
2465
2466 def test_get_network_allocations_number(self):
2467 self.assertRaises(NotImplementedError,
2468 self.library.get_network_allocations_number)
2469
2470 def test_update_ssc_info(self):
2471
2472 self.mock_object(self.library,
2473 '_find_matching_aggregates',
2474 mock.Mock(return_value=fake.AGGREGATES))
2475 mock_update_ssc_aggr_info = self.mock_object(self.library,
2476 '_update_ssc_aggr_info')
2477
2478 self.library._update_ssc_info()
2479
2480 expected = {
2481 fake.AGGREGATES[0]: {
2482 'netapp_aggregate': fake.AGGREGATES[0],
2483 },
2484 fake.AGGREGATES[1]: {
2485 'netapp_aggregate': fake.AGGREGATES[1],
2486 }
2487 }
2488
2489 self.assertDictEqual(expected, self.library._ssc_stats)
2490 self.assertTrue(mock_update_ssc_aggr_info.called)
2491
2492 def test_update_ssc_info_no_aggregates(self):
2493
2494 self.mock_object(self.library,
2495 '_find_matching_aggregates',
2496 mock.Mock(return_value=[]))
2497 mock_update_ssc_aggr_info = self.mock_object(self.library,
2498 '_update_ssc_aggr_info')
2499
2500 self.library._update_ssc_info()
2501
2502 self.assertDictEqual({}, self.library._ssc_stats)
2503 self.assertFalse(mock_update_ssc_aggr_info.called)
2504
2505 def test_update_ssc_aggr_info(self):
2506
2507 self.library._have_cluster_creds = True
2508 mock_get_aggregate = self.mock_object(
2509 self.client, 'get_aggregate',
2510 mock.Mock(side_effect=fake.SSC_AGGREGATES))
2511 mock_get_aggregate_disk_types = self.mock_object(
2512 self.client, 'get_aggregate_disk_types',
2513 mock.Mock(side_effect=fake.SSC_DISK_TYPES))
2514 ssc_stats = {
2515 fake.AGGREGATES[0]: {
2516 'netapp_aggregate': fake.AGGREGATES[0],
2517 },
2518 fake.AGGREGATES[1]: {
2519 'netapp_aggregate': fake.AGGREGATES[1],
2520 },
2521 }
2522
2523 self.library._update_ssc_aggr_info(fake.AGGREGATES, ssc_stats)
2524
2525 self.assertDictEqual(fake.SSC_INFO, ssc_stats)
2526 mock_get_aggregate.assert_has_calls([
2527 mock.call(fake.AGGREGATES[0]),
2528 mock.call(fake.AGGREGATES[1]),
2529 ])
2530 mock_get_aggregate_disk_types.assert_has_calls([
2531 mock.call(fake.AGGREGATES[0]),
2532 mock.call(fake.AGGREGATES[1]),
2533 ])
2534
2535 def test_update_ssc_aggr_info_not_found(self):
2536
2537 self.library._have_cluster_creds = True
2538 self.mock_object(self.client,
2539 'get_aggregate',
2540 mock.Mock(return_value={}))
2541 self.mock_object(self.client,
2542 'get_aggregate_disk_types',
2543 mock.Mock(return_value=None))
2544 ssc_stats = {
2545 fake.AGGREGATES[0]: {},
2546 fake.AGGREGATES[1]: {},
2547 }
2548
2549 self.library._update_ssc_aggr_info(fake.AGGREGATES, ssc_stats)
2550
2551 expected = {
2552 fake.AGGREGATES[0]: {
2553 'netapp_raid_type': None,
2554 'netapp_disk_type': None,
2555 'netapp_hybrid_aggregate': None,
2556 },
2557 fake.AGGREGATES[1]: {
2558 'netapp_raid_type': None,
2559 'netapp_disk_type': None,
2560 'netapp_hybrid_aggregate': None,
2561 }
2562 }
2563 self.assertDictEqual(expected, ssc_stats)
2564
2565 def test_update_ssc_aggr_info_no_cluster_creds(self):
2566
2567 self.library._have_cluster_creds = False
2568 ssc_stats = {}
2569
2570 self.library._update_ssc_aggr_info(fake.AGGREGATES, ssc_stats)
2571
2572 self.assertDictEqual({}, ssc_stats)
2573 self.assertFalse(self.library._client.get_aggregate_raid_types.called)
2574
2575 def test_create_replica(self):
2576 self.mock_object(self.library,
2577 '_allocate_container')
2578 mock_dm_session = mock.Mock()
2579 self.mock_object(data_motion, "DataMotionSession",
2580 mock.Mock(return_value=mock_dm_session))
2581 self.mock_object(data_motion, 'get_client_for_backend')
2582 self.mock_object(mock_dm_session, 'get_vserver_from_share',
2583 mock.Mock(return_value=fake.VSERVER1))
2584 expected_model_update = {
2585 'export_locations': [],
2586 'replica_state': constants.REPLICA_STATE_OUT_OF_SYNC,
2587 'access_rules_status': constants.STATUS_ACTIVE,
2588 }
2589
2590 model_update = self.library.create_replica(
2591 None, [fake.SHARE], fake.SHARE, [], [],
2592 share_server=None)
2593
2594 self.assertDictMatch(expected_model_update, model_update)
2595 mock_dm_session.create_snapmirror.assert_called_once_with(fake.SHARE,
2596 fake.SHARE)
2597 data_motion.get_client_for_backend.assert_called_once_with(
2598 fake.BACKEND_NAME, vserver_name=fake.VSERVER1)
2599
2600 def test_create_replica_with_share_server(self):
2601 self.mock_object(self.library,
2602 '_allocate_container',
2603 mock.Mock())
2604 mock_dm_session = mock.Mock()
2605 self.mock_object(data_motion, "DataMotionSession",
2606 mock.Mock(return_value=mock_dm_session))
2607 self.mock_object(data_motion, 'get_client_for_backend')
2608 self.mock_object(mock_dm_session, 'get_vserver_from_share',
2609 mock.Mock(return_value=fake.VSERVER1))
2610
2611 expected_model_update = {
2612 'export_locations': [],
2613 'replica_state': constants.REPLICA_STATE_OUT_OF_SYNC,
2614 'access_rules_status': constants.STATUS_ACTIVE,
2615 }
2616
2617 model_update = self.library.create_replica(
2618 None, [fake.SHARE], fake.SHARE, [], [],
2619 share_server=fake.SHARE_SERVER)
2620
2621 self.assertDictMatch(expected_model_update, model_update)
2622 mock_dm_session.create_snapmirror.assert_called_once_with(fake.SHARE,
2623 fake.SHARE)
2624 data_motion.get_client_for_backend.assert_called_once_with(
2625 fake.BACKEND_NAME, vserver_name=fake.VSERVER1)
2626
2627 def test_delete_replica(self):
2628
2629 active_replica = fake_replica(
2630 replica_state=constants.REPLICA_STATE_ACTIVE)
2631 replica_1 = fake_replica(
2632 replica_state=constants.REPLICA_STATE_IN_SYNC,
2633 host=fake.MANILA_HOST_NAME)
2634 replica_2 = fake_replica(
2635 replica_state=constants.REPLICA_STATE_OUT_OF_SYNC)
2636 replica_list = [active_replica, replica_1, replica_2]
2637
2638 self.mock_object(self.library,
2639 '_deallocate_container',
2640 mock.Mock())
2641 self.mock_object(self.library,
2642 '_share_exists',
2643 mock.Mock(return_value=False))
2644 mock_dm_session = mock.Mock()
2645 self.mock_object(data_motion, "DataMotionSession",
2646 mock.Mock(return_value=mock_dm_session))
2647 self.mock_object(data_motion, 'get_client_for_backend')
2648 self.mock_object(mock_dm_session, 'get_vserver_from_share',
2649 mock.Mock(return_value=fake.VSERVER1))
2650
2651 result = self.library.delete_replica(None,
2652 replica_list,
2653 replica_1,
2654 [],
2655 share_server=None)
2656 self.assertIsNone(result)
2657 mock_dm_session.delete_snapmirror.assert_has_calls([
2658 mock.call(active_replica, replica_1),
2659 mock.call(replica_2, replica_1),
2660 mock.call(replica_1, replica_2),
2661 mock.call(replica_1, active_replica)],
2662 any_order=True)
2663 self.assertEqual(4, mock_dm_session.delete_snapmirror.call_count)
2664 data_motion.get_client_for_backend.assert_called_with(
2665 fake.BACKEND_NAME, vserver_name=mock.ANY)
2666 self.assertEqual(1, data_motion.get_client_for_backend.call_count)
2667
2668 def test_delete_replica_with_share_server(self):
2669
2670 active_replica = fake_replica(
2671 replica_state=constants.REPLICA_STATE_ACTIVE)
2672 replica = fake_replica(replica_state=constants.REPLICA_STATE_IN_SYNC,
2673 host=fake.MANILA_HOST_NAME)
2674 replica_list = [active_replica, replica]
2675
2676 self.mock_object(self.library,
2677 '_deallocate_container',
2678 mock.Mock())
2679 self.mock_object(self.library,
2680 '_share_exists',
2681 mock.Mock(return_value=False))
2682 mock_dm_session = mock.Mock()
2683 self.mock_object(data_motion, "DataMotionSession",
2684 mock.Mock(return_value=mock_dm_session))
2685 self.mock_object(data_motion, 'get_client_for_backend')
2686 self.mock_object(mock_dm_session, 'get_vserver_from_share',
2687 mock.Mock(return_value=fake.VSERVER1))
2688
2689 result = self.library.delete_replica(None,
2690 replica_list,
2691 replica,
2692 [],
2693 share_server=fake.SHARE_SERVER)
2694 self.assertIsNone(result)
2695 mock_dm_session.delete_snapmirror.assert_has_calls([
2696 mock.call(active_replica, replica),
2697 mock.call(replica, active_replica)],
2698 any_order=True)
2699 data_motion.get_client_for_backend.assert_called_once_with(
2700 fake.BACKEND_NAME, vserver_name=fake.VSERVER1)
2701
2702 def test_delete_replica_share_absent_on_backend(self):
2703 active_replica = fake_replica(
2704 replica_state=constants.REPLICA_STATE_ACTIVE)
2705 replica = fake_replica(replica_state=constants.REPLICA_STATE_IN_SYNC,
2706 host=fake.MANILA_HOST_NAME)
2707 replica_list = [active_replica, replica]
2708
2709 self.mock_object(self.library,
2710 '_deallocate_container',
2711 mock.Mock())
2712 self.mock_object(self.library,
2713 '_share_exists',
2714 mock.Mock(return_value=False))
2715 mock_dm_session = mock.Mock()
2716 self.mock_object(data_motion,
2717 "DataMotionSession",
2718 mock.Mock(return_value=mock_dm_session))
2719 self.mock_object(data_motion, 'get_client_for_backend')
2720 self.mock_object(mock_dm_session,
2721 'get_vserver_from_share',
2722 mock.Mock(return_value=fake.VSERVER1))
2723
2724 result = self.library.delete_replica(None,
2725 replica_list,
2726 replica,
2727 [],
2728 share_server=None)
2729
2730 self.assertIsNone(result)
2731 self.assertFalse(self.library._deallocate_container.called)
2732 mock_dm_session.delete_snapmirror.assert_has_calls([
2733 mock.call(active_replica, replica),
2734 mock.call(replica, active_replica)],
2735 any_order=True)
2736 data_motion.get_client_for_backend.assert_called_with(
2737 fake.BACKEND_NAME, vserver_name=mock.ANY)
2738 self.assertEqual(1, data_motion.get_client_for_backend.call_count)
2739
2740 def test_update_replica_state_no_snapmirror_share_creating(self):
2741 vserver_client = mock.Mock()
2742 self.mock_object(vserver_client, 'volume_exists',
2743 mock.Mock(return_value=True))
2744 self.mock_object(self.library,
2745 '_get_vserver',
2746 mock.Mock(return_value=(fake.VSERVER1,
2747 vserver_client)))
2748 self.mock_dm_session.get_snapmirrors = mock.Mock(return_value=[])
2749
2750 replica = copy.deepcopy(fake.SHARE)
2751 replica['status'] = constants.STATUS_CREATING
2752
2753 result = self.library.update_replica_state(
2754 None, [replica], replica, None, [], share_server=None)
2755
2756 self.assertFalse(self.mock_dm_session.create_snapmirror.called)
2757 self.assertEqual(constants.STATUS_OUT_OF_SYNC, result)
2758
2759 def test_update_replica_state_share_reverting_to_snapshot(self):
2760 vserver_client = mock.Mock()
2761 self.mock_object(vserver_client, 'volume_exists',
2762 mock.Mock(return_value=True))
2763 self.mock_object(self.library,
2764 '_get_vserver',
2765 mock.Mock(return_value=(fake.VSERVER1,
2766 vserver_client)))
2767 self.mock_dm_session.get_snapmirrors = mock.Mock(return_value=[])
2768
2769 replica = copy.deepcopy(fake.SHARE)
2770 replica['status'] = constants.STATUS_REVERTING
2771
2772 result = self.library.update_replica_state(
2773 None, [replica], replica, None, [], share_server=None)
2774
2775 self.assertFalse(self.mock_dm_session.get_snapmirrors.called)
2776 self.assertFalse(self.mock_dm_session.create_snapmirror.called)
2777 self.assertIsNone(result)
2778
2779 def test_update_replica_state_no_snapmirror_create_failed(self):
2780 vserver_client = mock.Mock()
2781 self.mock_object(vserver_client, 'volume_exists',
2782 mock.Mock(return_value=True))
2783 self.mock_object(self.library,
2784 '_get_vserver',
2785 mock.Mock(return_value=(fake.VSERVER1,
2786 vserver_client)))
2787 self.mock_dm_session.get_snapmirrors = mock.Mock(return_value=[])
2788 self.mock_dm_session.create_snapmirror.side_effect = (
2789 netapp_api.NaApiError(code=0))
2790
2791 replica = copy.deepcopy(fake.SHARE)
2792 replica['status'] = constants.REPLICA_STATE_OUT_OF_SYNC
2793
2794 result = self.library.update_replica_state(
2795 None, [replica], replica, None, [], share_server=None)
2796
2797 self.assertTrue(self.mock_dm_session.create_snapmirror.called)
2798 self.assertEqual(constants.STATUS_ERROR, result)
2799
2800 @ddt.data(constants.STATUS_ERROR, constants.STATUS_AVAILABLE)
2801 def test_update_replica_state_no_snapmirror(self, status):
2802 vserver_client = mock.Mock()
2803 self.mock_object(vserver_client, 'volume_exists',
2804 mock.Mock(return_value=True))
2805 self.mock_object(self.library,
2806 '_get_vserver',
2807 mock.Mock(return_value=(fake.VSERVER1,
2808 vserver_client)))
2809 self.mock_dm_session.get_snapmirrors = mock.Mock(return_value=[])
2810
2811 replica = copy.deepcopy(fake.SHARE)
2812 replica['status'] = status
2813
2814 result = self.library.update_replica_state(
2815 None, [replica], replica, None, [], share_server=None)
2816
2817 self.assertEqual(1, self.mock_dm_session.create_snapmirror.call_count)
2818 self.assertEqual(constants.STATUS_OUT_OF_SYNC, result)
2819
2820 def test_update_replica_state_broken_snapmirror(self):
2821 fake_snapmirror = {
2822 'mirror-state': 'broken-off',
2823 'relationship-status': 'idle',
2824 'source-vserver': fake.VSERVER2,
2825 'source-volume': 'fake_volume',
2826 'last-transfer-end-timestamp': '%s' % float(time.time() - 10000)
2827 }
2828 vserver_client = mock.Mock()
2829 self.mock_object(vserver_client, 'volume_exists',
2830 mock.Mock(return_value=True))
2831 self.mock_object(self.library,
2832 '_get_vserver',
2833 mock.Mock(return_value=(fake.VSERVER1,
2834 vserver_client)))
2835 self.mock_dm_session.get_snapmirrors = mock.Mock(
2836 return_value=[fake_snapmirror])
2837
2838 result = self.library.update_replica_state(None, [fake.SHARE],
2839 fake.SHARE, None, [],
2840 share_server=None)
2841
2842 vserver_client.resync_snapmirror.assert_called_once_with(
2843 fake.VSERVER2, 'fake_volume', fake.VSERVER1, fake.SHARE['name']
2844 )
2845
2846 self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC, result)
2847
2848 def test_update_replica_state_snapmirror_still_initializing(self):
2849 fake_snapmirror = {
2850 'mirror-state': 'uninitialized',
2851 'relationship-status': 'transferring',
2852 'source-vserver': fake.VSERVER2,
2853 'source-volume': 'fake_volume',
2854 'last-transfer-end-timestamp': '%s' % float(time.time() - 10000)
2855 }
2856 vserver_client = mock.Mock()
2857 self.mock_object(vserver_client, 'volume_exists',
2858 mock.Mock(return_value=True))
2859 self.mock_object(self.library,
2860 '_get_vserver',
2861 mock.Mock(return_value=(fake.VSERVER1,
2862 vserver_client)))
2863 self.mock_dm_session.get_snapmirrors = mock.Mock(
2864 return_value=[fake_snapmirror])
2865
2866 result = self.library.update_replica_state(None, [fake.SHARE],
2867 fake.SHARE, None, [],
2868 share_server=None)
2869
2870 self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC, result)
2871
2872 def test_update_replica_state_fail_to_get_snapmirrors(self):
2873 vserver_client = mock.Mock()
2874 self.mock_object(vserver_client, 'volume_exists',
2875 mock.Mock(return_value=True))
2876 self.mock_object(self.library,
2877 '_get_vserver',
2878 mock.Mock(return_value=(fake.VSERVER1,
2879 vserver_client)))
2880 self.mock_dm_session.get_snapmirrors.side_effect = (
2881 netapp_api.NaApiError(code=0))
2882
2883 result = self.library.update_replica_state(None, [fake.SHARE],
2884 fake.SHARE, None, [],
2885 share_server=None)
2886 self.assertTrue(self.mock_dm_session.get_snapmirrors.called)
2887 self.assertEqual(constants.STATUS_ERROR, result)
2888
2889 def test_update_replica_state_broken_snapmirror_resync_error(self):
2890 fake_snapmirror = {
2891 'mirror-state': 'broken-off',
2892 'relationship-status': 'idle',
2893 'source-vserver': fake.VSERVER2,
2894 'source-volume': 'fake_volume',
2895 'last-transfer-end-timestamp': '%s' % float(time.time() - 10000)
2896 }
2897 vserver_client = mock.Mock()
2898 self.mock_object(vserver_client, 'volume_exists',
2899 mock.Mock(return_value=True))
2900 self.mock_object(self.library,
2901 '_get_vserver',
2902 mock.Mock(return_value=(fake.VSERVER1,
2903 vserver_client)))
2904 self.mock_dm_session.get_snapmirrors = mock.Mock(
2905 return_value=[fake_snapmirror])
2906 vserver_client.resync_snapmirror.side_effect = netapp_api.NaApiError
2907
2908 result = self.library.update_replica_state(None, [fake.SHARE],
2909 fake.SHARE, None, [],
2910 share_server=None)
2911
2912 vserver_client.resync_snapmirror.assert_called_once_with(
2913 fake.VSERVER2, 'fake_volume', fake.VSERVER1, fake.SHARE['name']
2914 )
2915
2916 self.assertEqual(constants.STATUS_ERROR, result)
2917
2918 def test_update_replica_state_stale_snapmirror(self):
2919 fake_snapmirror = {
2920 'mirror-state': 'snapmirrored',
2921 'last-transfer-end-timestamp': '%s' % float(
2922 timeutils.utcnow_ts() - 10000)
2923 }
2924 vserver_client = mock.Mock()
2925 self.mock_object(vserver_client, 'volume_exists',
2926 mock.Mock(return_value=True))
2927 self.mock_object(self.library,
2928 '_get_vserver',
2929 mock.Mock(return_value=(fake.VSERVER1,
2930 vserver_client)))
2931 self.mock_dm_session.get_snapmirrors = mock.Mock(
2932 return_value=[fake_snapmirror])
2933
2934 result = self.library.update_replica_state(None, [fake.SHARE],
2935 fake.SHARE, None, [],
2936 share_server=None)
2937
2938 self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC, result)
2939
2940 def test_update_replica_state_in_sync(self):
2941 fake_snapmirror = {
2942 'mirror-state': 'snapmirrored',
2943 'relationship-status': 'idle',
2944 'last-transfer-end-timestamp': '%s' % float(time.time())
2945 }
2946 vserver_client = mock.Mock()
2947 self.mock_object(vserver_client, 'volume_exists',
2948 mock.Mock(return_value=True))
2949 self.mock_object(self.library,
2950 '_get_vserver',
2951 mock.Mock(return_value=(fake.VSERVER1,
2952 vserver_client)))
2953 self.mock_dm_session.get_snapmirrors = mock.Mock(
2954 return_value=[fake_snapmirror])
2955
2956 result = self.library.update_replica_state(None, [fake.SHARE],
2957 fake.SHARE, None, [],
2958 share_server=None)
2959
2960 self.assertEqual(constants.REPLICA_STATE_IN_SYNC, result)
2961
2962 def test_update_replica_state_backend_volume_absent(self):
2963 vserver_client = mock.Mock()
2964 self.mock_object(vserver_client, 'volume_exists',
2965 mock.Mock(return_value=False))
2966 self.mock_object(self.library,
2967 '_get_vserver',
2968 mock.Mock(return_value=(fake.VSERVER1,
2969 vserver_client)))
2970
2971 self.assertRaises(exception.ShareResourceNotFound,
2972 self.library.update_replica_state,
2973 None, [fake.SHARE], fake.SHARE, None, [],
2974 share_server=None)
2975
2976 def test_update_replica_state_in_sync_with_snapshots(self):
2977 fake_snapmirror = {
2978 'mirror-state': 'snapmirrored',
2979 'relationship-status': 'idle',
2980 'last-transfer-end-timestamp': '%s' % float(time.time())
2981 }
2982 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
2983 fake_snapshot['share_id'] = fake.SHARE['id']
2984 snapshots = [{'share_replica_snapshot': fake_snapshot}]
2985 vserver_client = mock.Mock()
2986 self.mock_object(vserver_client, 'snapshot_exists', mock.Mock(
2987 return_value=True))
2988 self.mock_object(self.library,
2989 '_get_vserver',
2990 mock.Mock(return_value=(fake.VSERVER1,
2991 vserver_client)))
2992 self.mock_dm_session.get_snapmirrors = mock.Mock(
2993 return_value=[fake_snapmirror])
2994
2995 result = self.library.update_replica_state(None, [fake.SHARE],
2996 fake.SHARE, None, snapshots,
2997 share_server=None)
2998
2999 self.assertEqual(constants.REPLICA_STATE_IN_SYNC, result)
3000
3001 def test_update_replica_state_missing_snapshot(self):
3002 fake_snapmirror = {
3003 'mirror-state': 'snapmirrored',
3004 'relationship-status': 'idle',
3005 'last-transfer-end-timestamp': '%s' % float(time.time())
3006 }
3007 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3008 fake_snapshot['share_id'] = fake.SHARE['id']
3009 snapshots = [{'share_replica_snapshot': fake_snapshot}]
3010 vserver_client = mock.Mock()
3011 self.mock_object(vserver_client, 'snapshot_exists', mock.Mock(
3012 return_value=False))
3013 self.mock_object(self.library,
3014 '_get_vserver',
3015 mock.Mock(return_value=(fake.VSERVER1,
3016 vserver_client)))
3017 self.mock_dm_session.get_snapmirrors = mock.Mock(
3018 return_value=[fake_snapmirror])
3019
3020 result = self.library.update_replica_state(None, [fake.SHARE],
3021 fake.SHARE, None, snapshots,
3022 share_server=None)
3023
3024 self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC, result)
3025
3026 def test_promote_replica(self):
3027 self.mock_object(self.library,
3028 '_get_vserver',
3029 mock.Mock(return_value=(fake.VSERVER1,
3030 mock.Mock())))
3031 protocol_helper = mock.Mock()
3032 self.mock_object(self.library,
3033 '_get_helper',
3034 mock.Mock(return_value=protocol_helper))
3035 self.mock_object(self.library, '_create_export',
3036 mock.Mock(return_value='fake_export_location'))
3037 self.mock_object(self.library, '_unmount_orig_active_replica')
3038 self.mock_object(self.library, '_handle_qos_on_replication_change')
3039
3040 mock_dm_session = mock.Mock()
3041 self.mock_object(data_motion, "DataMotionSession",
3042 mock.Mock(return_value=mock_dm_session))
3043 self.mock_object(mock_dm_session, 'get_vserver_from_share',
3044 mock.Mock(return_value=fake.VSERVER1))
3045 self.mock_object(self.client, 'cleanup_demoted_replica')
3046
3047 replicas = self.library.promote_replica(
3048 None, [self.fake_replica, self.fake_replica_2],
3049 self.fake_replica_2, [], share_server=None)
3050
3051 mock_dm_session.change_snapmirror_source.assert_called_once_with(
3052 self.fake_replica, self.fake_replica, self.fake_replica_2,
3053 mock.ANY
3054 )
3055 self.assertEqual(2, len(replicas))
3056 actual_replica_1 = list(filter(
3057 lambda x: x['id'] == self.fake_replica['id'], replicas))[0]
3058 self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC,
3059 actual_replica_1['replica_state'])
3060 actual_replica_2 = list(filter(
3061 lambda x: x['id'] == self.fake_replica_2['id'], replicas))[0]
3062 self.assertEqual(constants.REPLICA_STATE_ACTIVE,
3063 actual_replica_2['replica_state'])
3064 self.assertEqual('fake_export_location',
3065 actual_replica_2['export_locations'])
3066 self.assertEqual(constants.STATUS_ACTIVE,
3067 actual_replica_2['access_rules_status'])
3068 self.library._unmount_orig_active_replica.assert_called_once_with(
3069 self.fake_replica, fake.VSERVER1)
3070 self.library._handle_qos_on_replication_change.assert_called_once()
3071 protocol_helper.cleanup_demoted_replica.assert_called_once_with(
3072 self.fake_replica, fake.SHARE['name'])
3073
3074 def test_promote_replica_cleanup_demoted_storage_error(self):
3075 self.mock_object(self.library,
3076 '_get_vserver',
3077 mock.Mock(return_value=(fake.VSERVER1,
3078 mock.Mock())))
3079 protocol_helper = mock.Mock()
3080 self.mock_object(self.library,
3081 '_get_helper',
3082 mock.Mock(return_value=protocol_helper))
3083 self.mock_object(self.library, '_create_export',
3084 mock.Mock(return_value='fake_export_location'))
3085 self.mock_object(self.library, '_unmount_orig_active_replica')
3086 self.mock_object(self.library, '_handle_qos_on_replication_change')
3087
3088 mock_dm_session = mock.Mock()
3089 self.mock_object(data_motion, "DataMotionSession",
3090 mock.Mock(return_value=mock_dm_session))
3091 self.mock_object(mock_dm_session, 'get_vserver_from_share',
3092 mock.Mock(return_value=fake.VSERVER1))
3093 self.mock_object(
3094 protocol_helper, 'cleanup_demoted_replica',
3095 mock.Mock(side_effect=exception.StorageCommunicationException))
3096 mock_log = self.mock_object(lib_base.LOG, 'exception')
3097
3098 self.library.promote_replica(
3099 None, [self.fake_replica, self.fake_replica_2],
3100 self.fake_replica_2, [], share_server=None)
3101
3102 mock_dm_session.change_snapmirror_source.assert_called_once_with(
3103 self.fake_replica, self.fake_replica, self.fake_replica_2,
3104 mock.ANY
3105 )
3106 protocol_helper.cleanup_demoted_replica.assert_called_once_with(
3107 self.fake_replica, fake.SHARE['name'])
3108 mock_log.assert_called_once()
3109
3110 def test_promote_replica_destination_unreachable(self):
3111 self.mock_object(self.library,
3112 '_get_vserver',
3113 mock.Mock(return_value=(fake.VSERVER1,
3114 mock.Mock())))
3115 self.mock_object(self.library,
3116 '_get_helper',
3117 mock.Mock(return_value=mock.Mock()))
3118 self.mock_object(self.library, '_unmount_orig_active_replica')
3119 self.mock_object(self.library, '_handle_qos_on_replication_change')
3120
3121 self.mock_object(self.library, '_create_export',
3122 mock.Mock(return_value='fake_export_location'))
3123 self.mock_object(
3124 self.library, '_convert_destination_replica_to_independent',
3125 mock.Mock(side_effect=exception.StorageCommunicationException))
3126
3127 replicas = self.library.promote_replica(
3128 None, [self.fake_replica, self.fake_replica_2],
3129 self.fake_replica_2, [], share_server=None)
3130
3131 self.assertEqual(1, len(replicas))
3132 actual_replica = replicas[0]
3133 self.assertEqual(constants.STATUS_ERROR,
3134 actual_replica['replica_state'])
3135 self.assertEqual(constants.STATUS_ERROR,
3136 actual_replica['status'])
3137 self.assertFalse(
3138 self.library._unmount_orig_active_replica.called)
3139 self.assertFalse(
3140 self.library._handle_qos_on_replication_change.called)
3141
3142 def test_promote_replica_more_than_two_replicas(self):
3143 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3144 fake_replica_3['id'] = fake.SHARE_ID3
3145 fake_replica_3['replica_state'] = constants.REPLICA_STATE_OUT_OF_SYNC
3146 self.mock_object(self.library,
3147 '_get_vserver',
3148 mock.Mock(return_value=(fake.VSERVER1,
3149 mock.Mock())))
3150 self.mock_object(self.library, '_unmount_orig_active_replica')
3151 self.mock_object(self.library, '_handle_qos_on_replication_change')
3152 self.mock_object(self.library,
3153 '_get_helper',
3154 mock.Mock(return_value=mock.Mock()))
3155
3156 self.mock_object(self.library, '_create_export',
3157 mock.Mock(return_value='fake_export_location'))
3158 mock_dm_session = mock.Mock()
3159 self.mock_object(data_motion, "DataMotionSession",
3160 mock.Mock(return_value=mock_dm_session))
3161 self.mock_object(mock_dm_session, 'get_vserver_from_share',
3162 mock.Mock(return_value=fake.VSERVER1))
3163
3164 replicas = self.library.promote_replica(
3165 None, [self.fake_replica, self.fake_replica_2, fake_replica_3],
3166 self.fake_replica_2, [], share_server=None)
3167
3168 mock_dm_session.change_snapmirror_source.assert_has_calls([
3169 mock.call(fake_replica_3, self.fake_replica, self.fake_replica_2,
3170 mock.ANY),
3171 mock.call(self.fake_replica, self.fake_replica,
3172 self.fake_replica_2, mock.ANY)
3173 ], any_order=True)
3174
3175 self.assertEqual(3, len(replicas))
3176 actual_replica_1 = list(filter(
3177 lambda x: x['id'] == self.fake_replica['id'], replicas))[0]
3178 self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC,
3179 actual_replica_1['replica_state'])
3180 actual_replica_2 = list(filter(
3181 lambda x: x['id'] == self.fake_replica_2['id'], replicas))[0]
3182 self.assertEqual(constants.REPLICA_STATE_ACTIVE,
3183 actual_replica_2['replica_state'])
3184 self.assertEqual('fake_export_location',
3185 actual_replica_2['export_locations'])
3186 actual_replica_3 = list(filter(
3187 lambda x: x['id'] == fake_replica_3['id'], replicas))[0]
3188 self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC,
3189 actual_replica_3['replica_state'])
3190 self.library._unmount_orig_active_replica.assert_called_once_with(
3191 self.fake_replica, fake.VSERVER1)
3192 self.library._handle_qos_on_replication_change.assert_called_once()
3193
3194 def test_promote_replica_with_access_rules(self):
3195 self.mock_object(self.library,
3196 '_get_vserver',
3197 mock.Mock(return_value=(fake.VSERVER1,
3198 mock.Mock())))
3199 self.mock_object(self.library, '_unmount_orig_active_replica')
3200 self.mock_object(self.library, '_handle_qos_on_replication_change')
3201 mock_helper = mock.Mock()
3202 self.mock_object(self.library,
3203 '_get_helper',
3204 mock.Mock(return_value=mock_helper))
3205 self.mock_object(self.library, '_create_export',
3206 mock.Mock(return_value='fake_export_location'))
3207
3208 mock_dm_session = mock.Mock()
3209 self.mock_object(data_motion, "DataMotionSession",
3210 mock.Mock(return_value=mock_dm_session))
3211 self.mock_object(mock_dm_session, 'get_vserver_from_share',
3212 mock.Mock(return_value=fake.VSERVER1))
3213
3214 replicas = self.library.promote_replica(
3215 None, [self.fake_replica, self.fake_replica_2],
3216 self.fake_replica_2, [fake.SHARE_ACCESS], share_server=None)
3217
3218 mock_dm_session.change_snapmirror_source.assert_has_calls([
3219 mock.call(self.fake_replica, self.fake_replica,
3220 self.fake_replica_2, mock.ANY)
3221 ], any_order=True)
3222 self.assertEqual(2, len(replicas))
3223 share_name = self.library._get_backend_share_name(
3224 self.fake_replica_2['id'])
3225 mock_helper.update_access.assert_called_once_with(self.fake_replica_2,
3226 share_name,
3227 [fake.SHARE_ACCESS])
3228 self.library._unmount_orig_active_replica.assert_called_once_with(
3229 self.fake_replica, fake.VSERVER1)
3230 self.library._handle_qos_on_replication_change.assert_called_once()
3231
3232 def test_unmount_orig_active_replica(self):
3233 self.mock_object(share_utils, 'extract_host', mock.Mock(
3234 return_value=fake.MANILA_HOST_NAME))
3235 self.mock_object(data_motion, 'get_client_for_backend')
3236 self.mock_object(self.library, '_get_backend_share_name', mock.Mock(
3237 return_value=fake.SHARE_NAME))
3238
3239 result = self.library._unmount_orig_active_replica(fake.SHARE)
3240 self.assertIsNone(result)
3241
3242 @ddt.data({'extra_specs': {'netapp:snapshot_policy': 'none'},
3243 'have_cluster_creds': True},
3244 # Test Case 2 isn't possible input
3245 {'extra_specs': {'qos': True, 'netapp:maxiops': '3000'},
3246 'have_cluster_creds': False})
3247 @ddt.unpack
3248 def test_handle_qos_on_replication_change_nothing_to_handle(
3249 self, extra_specs, have_cluster_creds):
3250
3251 self.library._have_cluster_creds = have_cluster_creds
3252 self.mock_object(lib_base.LOG, 'exception')
3253 self.mock_object(lib_base.LOG, 'info')
3254 self.mock_object(share_types, 'get_extra_specs_from_share',
3255 mock.Mock(return_value=extra_specs))
3256
3257 retval = self.library._handle_qos_on_replication_change(
3258 self.mock_dm_session, self.fake_replica_2, self.fake_replica,
3259 share_server=fake.SHARE_SERVER)
3260
3261 self.assertIsNone(retval)
3262 lib_base.LOG.exception.assert_not_called()
3263 lib_base.LOG.info.assert_not_called()
3264
3265 def test_handle_qos_on_replication_change_exception(self):
3266 self.library._have_cluster_creds = True
3267 extra_specs = {'qos': True, fake.QOS_EXTRA_SPEC: '3000'}
3268 vserver_client = mock.Mock()
3269 self.mock_object(lib_base.LOG, 'exception')
3270 self.mock_object(lib_base.LOG, 'info')
3271 self.mock_object(share_types, 'get_extra_specs_from_share',
3272 mock.Mock(return_value=extra_specs))
3273 self.mock_object(self.library, '_get_vserver', mock.Mock(
3274 return_value=(fake.VSERVER1, vserver_client)))
3275 self.mock_object(self.library._client, 'qos_policy_group_exists',
3276 mock.Mock(return_value=True))
3277 self.mock_object(self.library._client, 'qos_policy_group_modify',
3278 mock.Mock(side_effect=netapp_api.NaApiError))
3279
3280 retval = self.library._handle_qos_on_replication_change(
3281 self.mock_dm_session, self.fake_replica_2, self.fake_replica,
3282 share_server=fake.SHARE_SERVER)
3283
3284 self.assertIsNone(retval)
3285 (self.mock_dm_session.remove_qos_on_old_active_replica
3286 .assert_called_once_with(self.fake_replica))
3287 lib_base.LOG.exception.assert_called_once()
3288 lib_base.LOG.info.assert_not_called()
3289 vserver_client.set_qos_policy_group_for_volume.assert_not_called()
3290
3291 def test_handle_qos_on_replication_change_modify_existing_policy(self):
3292 self.library._have_cluster_creds = True
3293 extra_specs = {'qos': True, fake.QOS_EXTRA_SPEC: '3000'}
3294 vserver_client = mock.Mock()
3295 volume_name_on_backend = self.library._get_backend_share_name(
3296 self.fake_replica_2['id'])
3297 self.mock_object(lib_base.LOG, 'exception')
3298 self.mock_object(lib_base.LOG, 'info')
3299 self.mock_object(share_types, 'get_extra_specs_from_share',
3300 mock.Mock(return_value=extra_specs))
3301 self.mock_object(self.library, '_get_vserver', mock.Mock(
3302 return_value=(fake.VSERVER1, vserver_client)))
3303 self.mock_object(self.library._client, 'qos_policy_group_exists',
3304 mock.Mock(return_value=True))
3305 self.mock_object(self.library._client, 'qos_policy_group_modify')
3306 self.mock_object(self.library, '_create_qos_policy_group')
3307
3308 retval = self.library._handle_qos_on_replication_change(
3309 self.mock_dm_session, self.fake_replica_2, self.fake_replica,
3310 share_server=fake.SHARE_SERVER)
3311
3312 self.assertIsNone(retval)
3313 self.library._client.qos_policy_group_modify.assert_called_once_with(
3314 'qos_' + volume_name_on_backend, '3000iops')
3315 vserver_client.set_qos_policy_group_for_volume.assert_called_once_with(
3316 volume_name_on_backend, 'qos_' + volume_name_on_backend)
3317 self.library._create_qos_policy_group.assert_not_called()
3318 lib_base.LOG.exception.assert_not_called()
3319 lib_base.LOG.info.assert_called_once()
3320
3321 def test_handle_qos_on_replication_change_create_new_policy(self):
3322 self.library._have_cluster_creds = True
3323 extra_specs = {'qos': True, fake.QOS_EXTRA_SPEC: '3000'}
3324 vserver_client = mock.Mock()
3325 self.mock_object(lib_base.LOG, 'exception')
3326 self.mock_object(lib_base.LOG, 'info')
3327 self.mock_object(share_types, 'get_extra_specs_from_share',
3328 mock.Mock(return_value=extra_specs))
3329 self.mock_object(self.library, '_get_vserver', mock.Mock(
3330 return_value=(fake.VSERVER1, vserver_client)))
3331 self.mock_object(self.library._client, 'qos_policy_group_exists',
3332 mock.Mock(return_value=False))
3333 self.mock_object(self.library._client, 'qos_policy_group_modify')
3334 self.mock_object(self.library, '_create_qos_policy_group')
3335
3336 retval = self.library._handle_qos_on_replication_change(
3337 self.mock_dm_session, self.fake_replica_2, self.fake_replica,
3338 share_server=fake.SHARE_SERVER)
3339
3340 self.assertIsNone(retval)
3341 self.library._create_qos_policy_group.assert_called_once_with(
3342 self.fake_replica_2, fake.VSERVER1, {'maxiops': '3000'})
3343 self.library._client.qos_policy_group_modify.assert_not_called()
3344 lib_base.LOG.exception.assert_not_called()
3345 lib_base.LOG.info.assert_called_once()
3346
3347 def test_convert_destination_replica_to_independent(self):
3348 self.mock_object(self.library,
3349 '_get_vserver',
3350 mock.Mock(return_value=(fake.VSERVER1,
3351 mock.Mock())))
3352 self.mock_object(self.library,
3353 '_get_helper',
3354 mock.Mock(return_value=mock.Mock()))
3355 self.mock_object(self.library, '_create_export',
3356 mock.Mock(return_value='fake_export_location'))
3357
3358 replica = self.library._convert_destination_replica_to_independent(
3359 None, self.mock_dm_session, self.fake_replica,
3360 self.fake_replica_2, [], share_server=None)
3361
3362 self.mock_dm_session.update_snapmirror.assert_called_once_with(
3363 self.fake_replica, self.fake_replica_2)
3364 self.mock_dm_session.break_snapmirror.assert_called_once_with(
3365 self.fake_replica, self.fake_replica_2)
3366
3367 self.assertEqual('fake_export_location',
3368 replica['export_locations'])
3369 self.assertEqual(constants.REPLICA_STATE_ACTIVE,
3370 replica['replica_state'])
3371
3372 def test_convert_destination_replica_to_independent_update_failed(self):
3373 self.mock_object(self.library,
3374 '_get_vserver',
3375 mock.Mock(return_value=(fake.VSERVER1,
3376 mock.Mock())))
3377 self.mock_object(self.library,
3378 '_get_helper',
3379 mock.Mock(return_value=mock.Mock()))
3380 self.mock_object(self.library, '_create_export',
3381 mock.Mock(return_value='fake_export_location'))
3382 self.mock_object(
3383 self.mock_dm_session, 'update_snapmirror',
3384 mock.Mock(side_effect=exception.StorageCommunicationException))
3385
3386 replica = self.library._convert_destination_replica_to_independent(
3387 None, self.mock_dm_session, self.fake_replica,
3388 self.fake_replica_2, [], share_server=None)
3389
3390 self.mock_dm_session.update_snapmirror.assert_called_once_with(
3391 self.fake_replica, self.fake_replica_2)
3392 self.mock_dm_session.break_snapmirror.assert_called_once_with(
3393 self.fake_replica, self.fake_replica_2)
3394
3395 self.assertEqual('fake_export_location',
3396 replica['export_locations'])
3397 self.assertEqual(constants.REPLICA_STATE_ACTIVE,
3398 replica['replica_state'])
3399
3400 def test_promote_replica_fail_to_set_access_rules(self):
3401 fake_helper = mock.Mock()
3402 fake_helper.update_access.side_effect = Exception
3403 fake_access_rules = [
3404 {'access_to': "0.0.0.0",
3405 'access_level': constants.ACCESS_LEVEL_RO},
3406 {'access_to': "10.10.10.10",
3407 'access_level': constants.ACCESS_LEVEL_RW},
3408 ]
3409 self.mock_object(self.library,
3410 '_get_vserver',
3411 mock.Mock(return_value=(fake.VSERVER1,
3412 mock.Mock())))
3413 self.mock_object(self.library, '_handle_qos_on_replication_change')
3414 self.mock_object(self.library,
3415 '_get_helper',
3416 mock.Mock(return_value=fake_helper))
3417 self.mock_object(self.library, '_create_export',
3418 mock.Mock(return_value='fake_export_location'))
3419
3420 replicas = self.library.promote_replica(
3421 None, [self.fake_replica, self.fake_replica_2],
3422 self.fake_replica_2, fake_access_rules, share_server=None)
3423
3424 self.mock_dm_session.change_snapmirror_source.assert_called_once_with(
3425 self.fake_replica, self.fake_replica, self.fake_replica_2,
3426 mock.ANY
3427 )
3428
3429 self.assertEqual(2, len(replicas))
3430 actual_replica_1 = list(filter(
3431 lambda x: x['id'] == self.fake_replica['id'], replicas))[0]
3432 self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC,
3433 actual_replica_1['replica_state'])
3434 actual_replica_2 = list(filter(
3435 lambda x: x['id'] == self.fake_replica_2['id'], replicas))[0]
3436 self.assertEqual(constants.REPLICA_STATE_ACTIVE,
3437 actual_replica_2['replica_state'])
3438 self.assertEqual('fake_export_location',
3439 actual_replica_2['export_locations'])
3440 self.assertEqual(constants.SHARE_INSTANCE_RULES_SYNCING,
3441 actual_replica_2['access_rules_status'])
3442 self.library._handle_qos_on_replication_change.assert_called_once()
3443
3444 def test_convert_destination_replica_to_independent_with_access_rules(
3445 self):
3446 fake_helper = mock.Mock()
3447 fake_helper.update_access.side_effect = Exception
3448 fake_access_rules = [
3449 {'access_to': "0.0.0.0",
3450 'access_level': constants.ACCESS_LEVEL_RO},
3451 {'access_to': "10.10.10.10",
3452 'access_level': constants.ACCESS_LEVEL_RW},
3453 ]
3454 self.mock_object(self.library,
3455 '_get_vserver',
3456 mock.Mock(return_value=(fake.VSERVER1,
3457 mock.Mock())))
3458 self.mock_object(self.library,
3459 '_get_helper',
3460 mock.Mock(return_value=fake_helper))
3461 self.mock_object(self.library, '_create_export',
3462 mock.Mock(return_value='fake_export_location'))
3463
3464 replica = self.library._convert_destination_replica_to_independent(
3465 None, self.mock_dm_session, self.fake_replica,
3466 self.fake_replica_2, fake_access_rules, share_server=None)
3467
3468 self.mock_dm_session.update_snapmirror.assert_called_once_with(
3469 self.fake_replica, self.fake_replica_2)
3470 self.mock_dm_session.break_snapmirror.assert_called_once_with(
3471 self.fake_replica, self.fake_replica_2)
3472
3473 self.assertEqual('fake_export_location',
3474 replica['export_locations'])
3475 self.assertEqual(constants.REPLICA_STATE_ACTIVE,
3476 replica['replica_state'])
3477 self.assertEqual(constants.SHARE_INSTANCE_RULES_SYNCING,
3478 replica['access_rules_status'])
3479
3480 def test_convert_destination_replica_to_independent_failed_access_rules(
3481 self):
3482 fake_helper = mock.Mock()
3483 fake_access_rules = [
3484 {'access_to': "0.0.0.0",
3485 'access_level': constants.ACCESS_LEVEL_RO},
3486 {'access_to': "10.10.10.10",
3487 'access_level': constants.ACCESS_LEVEL_RW},
3488 ]
3489 self.mock_object(self.library,
3490 '_get_vserver',
3491 mock.Mock(return_value=(fake.VSERVER1,
3492 mock.Mock())))
3493 self.mock_object(self.library,
3494 '_get_helper',
3495 mock.Mock(return_value=fake_helper))
3496 self.mock_object(self.library, '_create_export',
3497 mock.Mock(return_value='fake_export_location'))
3498
3499 replica = self.library._convert_destination_replica_to_independent(
3500 None, self.mock_dm_session, self.fake_replica,
3501 self.fake_replica_2, fake_access_rules, share_server=None)
3502
3503 self.mock_dm_session.update_snapmirror.assert_called_once_with(
3504 self.fake_replica, self.fake_replica_2)
3505 self.mock_dm_session.break_snapmirror.assert_called_once_with(
3506 self.fake_replica, self.fake_replica_2)
3507
3508 fake_helper.assert_has_calls([
3509 mock.call.set_client(mock.ANY),
3510 mock.call.update_access(mock.ANY, mock.ANY, fake_access_rules),
3511 ])
3512
3513 self.assertEqual('fake_export_location',
3514 replica['export_locations'])
3515 self.assertEqual(constants.REPLICA_STATE_ACTIVE,
3516 replica['replica_state'])
3517 self.assertEqual(constants.STATUS_ACTIVE,
3518 replica['access_rules_status'])
3519
3520 def test_safe_change_replica_source(self):
3521 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3522 fake_replica_3['id'] = fake.SHARE_ID3
3523 fake_replica_3['replica_state'] = constants.REPLICA_STATE_OUT_OF_SYNC
3524 replica = self.library._safe_change_replica_source(
3525 self.mock_dm_session, self.fake_replica, self.fake_replica_2,
3526 fake_replica_3, [self.fake_replica, self.fake_replica_2,
3527 fake_replica_3]
3528 )
3529 self.assertEqual([], replica['export_locations'])
3530 self.assertEqual(constants.REPLICA_STATE_OUT_OF_SYNC,
3531 replica['replica_state'])
3532
3533 def test_safe_change_replica_source_destination_unreachable(self):
3534 self.mock_dm_session.change_snapmirror_source.side_effect = (
3535 exception.StorageCommunicationException
3536 )
3537
3538 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3539 fake_replica_3['id'] = fake.SHARE_ID3
3540 fake_replica_3['replica_state'] = constants.REPLICA_STATE_OUT_OF_SYNC
3541 replica = self.library._safe_change_replica_source(
3542 self.mock_dm_session, self.fake_replica, self.fake_replica_2,
3543 fake_replica_3, [self.fake_replica, self.fake_replica_2,
3544 fake_replica_3]
3545 )
3546 self.assertEqual([], replica['export_locations'])
3547 self.assertEqual(constants.STATUS_ERROR,
3548 replica['replica_state'])
3549 self.assertEqual(constants.STATUS_ERROR,
3550 replica['status'])
3551
3552 def test_safe_change_replica_source_error(self):
3553 self.mock_dm_session.change_snapmirror_source.side_effect = (
3554 netapp_api.NaApiError(code=0)
3555 )
3556
3557 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3558 fake_replica_3['id'] = fake.SHARE_ID3
3559 fake_replica_3['replica_state'] = constants.REPLICA_STATE_OUT_OF_SYNC
3560 replica = self.library._safe_change_replica_source(
3561 self.mock_dm_session, self.fake_replica, self.fake_replica_2,
3562 fake_replica_3, [self.fake_replica, self.fake_replica_2,
3563 fake_replica_3]
3564 )
3565 self.assertEqual([], replica['export_locations'])
3566 self.assertEqual(constants.STATUS_ERROR,
3567 replica['replica_state'])
3568
3569 def test_create_replicated_snapshot(self):
3570 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3571 fake_replica_3['id'] = fake.SHARE_ID3
3572 replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
3573 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3574 fake_snapshot['share_id'] = self.fake_replica['id']
3575 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
3576 fake_snapshot_2['id'] = uuidutils.generate_uuid()
3577 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
3578 fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
3579 fake_snapshot_3['id'] = uuidutils.generate_uuid()
3580 fake_snapshot_3['share_id'] = fake_replica_3['id']
3581 snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
3582
3583 vserver_client = mock.Mock()
3584 self.mock_object(self.library,
3585 '_get_vserver',
3586 mock.Mock(return_value=(fake.VSERVER1,
3587 vserver_client)))
3588
3589 model_list = self.library.create_replicated_snapshot(
3590 self.context, replica_list, snapshot_list,
3591 share_server=fake.SHARE_SERVER)
3592
3593 share_name = self.library._get_backend_share_name(
3594 fake_snapshot['share_id'])
3595 snapshot_name = self.library._get_backend_snapshot_name(
3596 fake_snapshot['id'])
3597 vserver_client.create_snapshot.assert_called_once_with(share_name,
3598 snapshot_name)
3599 self.assertEqual(3, len(model_list))
3600 for snapshot in model_list:
3601 self.assertEqual(snapshot['provider_location'], snapshot_name)
3602 actual_active_snapshot = list(filter(
3603 lambda x: x['id'] == fake_snapshot['id'], model_list))[0]
3604 self.assertEqual(constants.STATUS_AVAILABLE,
3605 actual_active_snapshot['status'])
3606 actual_non_active_snapshot_list = list(filter(
3607 lambda x: x['id'] != fake_snapshot['id'], model_list))
3608 for snapshot in actual_non_active_snapshot_list:
3609 self.assertEqual(constants.STATUS_CREATING, snapshot['status'])
3610 self.mock_dm_session.update_snapmirror.assert_has_calls(
3611 [mock.call(self.fake_replica, self.fake_replica_2),
3612 mock.call(self.fake_replica, fake_replica_3)],
3613 any_order=True
3614 )
3615
3616 def test_create_replicated_snapshot_with_creating_replica(self):
3617 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3618 fake_replica_3['id'] = fake.SHARE_ID3
3619 fake_replica_3['host'] = None
3620 replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
3621 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3622 fake_snapshot['share_id'] = self.fake_replica['id']
3623 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
3624 fake_snapshot_2['id'] = uuidutils.generate_uuid()
3625 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
3626 fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
3627 fake_snapshot_3['id'] = uuidutils.generate_uuid()
3628 fake_snapshot_3['share_id'] = fake_replica_3['id']
3629 snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
3630
3631 vserver_client = mock.Mock()
3632 self.mock_object(self.library,
3633 '_get_vserver',
3634 mock.Mock(return_value=(fake.VSERVER1,
3635 vserver_client)))
3636
3637 model_list = self.library.create_replicated_snapshot(
3638 self.context, replica_list, snapshot_list,
3639 share_server=fake.SHARE_SERVER)
3640
3641 share_name = self.library._get_backend_share_name(
3642 fake_snapshot['share_id'])
3643 snapshot_name = self.library._get_backend_snapshot_name(
3644 fake_snapshot['id'])
3645 vserver_client.create_snapshot.assert_called_once_with(share_name,
3646 snapshot_name)
3647 self.assertEqual(3, len(model_list))
3648 for snapshot in model_list:
3649 self.assertEqual(snapshot['provider_location'], snapshot_name)
3650 actual_active_snapshot = list(filter(
3651 lambda x: x['id'] == fake_snapshot['id'], model_list))[0]
3652 self.assertEqual(constants.STATUS_AVAILABLE,
3653 actual_active_snapshot['status'])
3654 actual_non_active_snapshot_list = list(filter(
3655 lambda x: x['id'] != fake_snapshot['id'], model_list))
3656 for snapshot in actual_non_active_snapshot_list:
3657 self.assertEqual(constants.STATUS_CREATING, snapshot['status'])
3658 self.mock_dm_session.update_snapmirror.assert_has_calls(
3659 [mock.call(self.fake_replica, self.fake_replica_2)],
3660 any_order=True
3661 )
3662
3663 def test_create_replicated_snapshot_no_snapmirror(self):
3664 self.mock_dm_session.update_snapmirror.side_effect = [
3665 None,
3666 netapp_api.NaApiError(code=netapp_api.EOBJECTNOTFOUND)
3667 ]
3668 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3669 fake_replica_3['id'] = fake.SHARE_ID3
3670 replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
3671 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3672 fake_snapshot['share_id'] = self.fake_replica['id']
3673 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
3674 fake_snapshot_2['id'] = uuidutils.generate_uuid()
3675 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
3676 fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
3677 fake_snapshot_3['id'] = uuidutils.generate_uuid()
3678 fake_snapshot_3['share_id'] = fake_replica_3['id']
3679 snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
3680
3681 vserver_client = mock.Mock()
3682 self.mock_object(self.library,
3683 '_get_vserver',
3684 mock.Mock(return_value=(fake.VSERVER1,
3685 vserver_client)))
3686
3687 model_list = self.library.create_replicated_snapshot(
3688 self.context, replica_list, snapshot_list,
3689 share_server=fake.SHARE_SERVER)
3690
3691 share_name = self.library._get_backend_share_name(
3692 fake_snapshot['share_id'])
3693 snapshot_name = self.library._get_backend_snapshot_name(
3694 fake_snapshot['id'])
3695 vserver_client.create_snapshot.assert_called_once_with(share_name,
3696 snapshot_name)
3697 self.assertEqual(3, len(model_list))
3698 for snapshot in model_list:
3699 self.assertEqual(snapshot['provider_location'], snapshot_name)
3700 actual_active_snapshot = list(filter(
3701 lambda x: x['id'] == fake_snapshot['id'], model_list))[0]
3702 self.assertEqual(constants.STATUS_AVAILABLE,
3703 actual_active_snapshot['status'])
3704 actual_non_active_snapshot_list = list(filter(
3705 lambda x: x['id'] != fake_snapshot['id'], model_list))
3706 for snapshot in actual_non_active_snapshot_list:
3707 self.assertEqual(constants.STATUS_CREATING, snapshot['status'])
3708 self.mock_dm_session.update_snapmirror.assert_has_calls(
3709 [mock.call(self.fake_replica, self.fake_replica_2),
3710 mock.call(self.fake_replica, fake_replica_3)],
3711 any_order=True
3712 )
3713
3714 def test_create_replicated_snapshot_update_error(self):
3715 self.mock_dm_session.update_snapmirror.side_effect = [
3716 None,
3717 netapp_api.NaApiError()
3718 ]
3719 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3720 fake_replica_3['id'] = fake.SHARE_ID3
3721 replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
3722 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3723 fake_snapshot['share_id'] = self.fake_replica['id']
3724 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
3725 fake_snapshot_2['id'] = uuidutils.generate_uuid()
3726 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
3727 fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
3728 fake_snapshot_3['id'] = uuidutils.generate_uuid()
3729 fake_snapshot_3['share_id'] = fake_replica_3['id']
3730 snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
3731
3732 vserver_client = mock.Mock()
3733 self.mock_object(self.library,
3734 '_get_vserver',
3735 mock.Mock(return_value=(fake.VSERVER1,
3736 vserver_client)))
3737
3738 self.assertRaises(netapp_api.NaApiError,
3739 self.library.create_replicated_snapshot,
3740 self.context, replica_list, snapshot_list,
3741 share_server=fake.SHARE_SERVER)
3742
3743 def test_delete_replicated_snapshot(self):
3744 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3745 fake_replica_3['id'] = fake.SHARE_ID3
3746 replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
3747 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3748 fake_snapshot['share_id'] = self.fake_replica['id']
3749 share_name = self.library._get_backend_share_name(
3750 fake_snapshot['share_id'])
3751 snapshot_name = self.library._get_backend_snapshot_name(
3752 fake_snapshot['id'])
3753 fake_snapshot['provider_location'] = snapshot_name
3754 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
3755 fake_snapshot_2['id'] = uuidutils.generate_uuid()
3756 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
3757 fake_snapshot_2['provider_location'] = snapshot_name
3758 fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
3759 fake_snapshot_3['id'] = uuidutils.generate_uuid()
3760 fake_snapshot_3['share_id'] = fake_replica_3['id']
3761 fake_snapshot_3['provider_location'] = snapshot_name
3762
3763 snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
3764
3765 vserver_client = mock.Mock()
3766 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
3767 self.mock_object(self.library,
3768 '_get_vserver',
3769 mock.Mock(return_value=(fake.VSERVER1,
3770 vserver_client)))
3771
3772 self.library.delete_replicated_snapshot(
3773 self.context, replica_list, snapshot_list,
3774 share_server=fake.SHARE_SERVER)
3775
3776 vserver_client.delete_snapshot.assert_called_once_with(share_name,
3777 snapshot_name)
3778
3779 self.mock_dm_session.update_snapmirror.assert_has_calls(
3780 [mock.call(self.fake_replica, self.fake_replica_2),
3781 mock.call(self.fake_replica, fake_replica_3)],
3782 any_order=True
3783 )
3784
3785 def test_delete_replicated_snapshot_replica_still_creating(self):
3786 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3787 fake_replica_3['id'] = fake.SHARE_ID3
3788 fake_replica_3['host'] = None
3789 replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
3790 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3791 fake_snapshot['share_id'] = self.fake_replica['id']
3792 share_name = self.library._get_backend_share_name(
3793 fake_snapshot['share_id'])
3794 snapshot_name = self.library._get_backend_snapshot_name(
3795 fake_snapshot['id'])
3796 fake_snapshot['provider_location'] = snapshot_name
3797 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
3798 fake_snapshot_2['id'] = uuidutils.generate_uuid()
3799 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
3800 fake_snapshot_2['provider_location'] = snapshot_name
3801 fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
3802 fake_snapshot_3['id'] = uuidutils.generate_uuid()
3803 fake_snapshot_3['share_id'] = fake_replica_3['id']
3804 fake_snapshot_3['provider_location'] = snapshot_name
3805
3806 snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
3807
3808 vserver_client = mock.Mock()
3809 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
3810 self.mock_object(self.library,
3811 '_get_vserver',
3812 mock.Mock(return_value=(fake.VSERVER1,
3813 vserver_client)))
3814
3815 self.library.delete_replicated_snapshot(
3816 self.context, replica_list, snapshot_list,
3817 share_server=fake.SHARE_SERVER)
3818
3819 vserver_client.delete_snapshot.assert_called_once_with(share_name,
3820 snapshot_name)
3821
3822 self.mock_dm_session.update_snapmirror.assert_has_calls(
3823 [mock.call(self.fake_replica, self.fake_replica_2)],
3824 any_order=True
3825 )
3826
3827 def test_delete_replicated_snapshot_missing_snapmirror(self):
3828 self.mock_dm_session.update_snapmirror.side_effect = [
3829 None,
3830 netapp_api.NaApiError(code=netapp_api.EOBJECTNOTFOUND)
3831 ]
3832 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3833 fake_replica_3['id'] = fake.SHARE_ID3
3834 replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
3835 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3836 fake_snapshot['share_id'] = self.fake_replica['id']
3837 share_name = self.library._get_backend_share_name(
3838 fake_snapshot['share_id'])
3839 snapshot_name = self.library._get_backend_snapshot_name(
3840 fake_snapshot['id'])
3841 fake_snapshot['provider_location'] = snapshot_name
3842 fake_snapshot['busy'] = False
3843
3844 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
3845 fake_snapshot_2['id'] = uuidutils.generate_uuid()
3846 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
3847 fake_snapshot_2['provider_location'] = snapshot_name
3848 fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
3849 fake_snapshot_3['id'] = uuidutils.generate_uuid()
3850 fake_snapshot_3['share_id'] = fake_replica_3['id']
3851 fake_snapshot_3['provider_location'] = snapshot_name
3852
3853 snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
3854
3855 vserver_client = mock.Mock()
3856 vserver_client.get_snapshot.return_value = fake_snapshot
3857 self.mock_object(self.library,
3858 '_get_vserver',
3859 mock.Mock(return_value=(fake.VSERVER1,
3860 vserver_client)))
3861
3862 self.library.delete_replicated_snapshot(
3863 self.context, replica_list, snapshot_list,
3864 share_server=fake.SHARE_SERVER)
3865
3866 vserver_client.delete_snapshot.assert_called_once_with(share_name,
3867 snapshot_name)
3868
3869 self.mock_dm_session.update_snapmirror.assert_has_calls(
3870 [mock.call(self.fake_replica, self.fake_replica_2),
3871 mock.call(self.fake_replica, fake_replica_3)],
3872 any_order=True
3873 )
3874
3875 def test_delete_replicated_snapshot_update_error(self):
3876 self.mock_dm_session.update_snapmirror.side_effect = [
3877 None,
3878 netapp_api.NaApiError()
3879 ]
3880 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
3881 fake_replica_3['id'] = fake.SHARE_ID3
3882 replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
3883 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3884 fake_snapshot['share_id'] = self.fake_replica['id']
3885 snapshot_name = self.library._get_backend_snapshot_name(
3886 fake_snapshot['id'])
3887 fake_snapshot['provider_location'] = snapshot_name
3888 fake_snapshot['busy'] = False
3889
3890 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
3891 fake_snapshot_2['id'] = uuidutils.generate_uuid()
3892 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
3893 fake_snapshot_2['provider_location'] = snapshot_name
3894 fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
3895 fake_snapshot_3['id'] = uuidutils.generate_uuid()
3896 fake_snapshot_3['share_id'] = fake_replica_3['id']
3897 fake_snapshot_3['provider_location'] = snapshot_name
3898
3899 snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
3900
3901 vserver_client = mock.Mock()
3902 vserver_client.get_snapshot.return_value = fake_snapshot
3903 self.mock_object(self.library,
3904 '_get_vserver',
3905 mock.Mock(return_value=(fake.VSERVER1,
3906 vserver_client)))
3907
3908 self.assertRaises(netapp_api.NaApiError,
3909 self.library.delete_replicated_snapshot,
3910 self.context, replica_list, snapshot_list,
3911 share_server=fake.SHARE_SERVER)
3912
3913 def test_update_replicated_snapshot_still_creating(self):
3914 vserver_client = mock.Mock()
3915 vserver_client.snapshot_exists.return_value = False
3916 self.mock_object(self.library,
3917 '_get_vserver',
3918 mock.Mock(return_value=(fake.VSERVER1,
3919 vserver_client)))
3920 replica_list = [self.fake_replica, self.fake_replica_2]
3921 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3922 fake_snapshot['status'] = constants.STATUS_CREATING
3923 fake_snapshot['share_id'] = self.fake_replica_2['id']
3924 snapshot_name = self.library._get_backend_snapshot_name(
3925 fake_snapshot['id'])
3926 fake_snapshot['provider_location'] = snapshot_name
3927
3928 model_update = self.library.update_replicated_snapshot(
3929 replica_list, self.fake_replica_2, [fake_snapshot], fake_snapshot)
3930
3931 self.assertIsNone(model_update)
3932 self.mock_dm_session.update_snapmirror.assert_called_once_with(
3933 self.fake_replica, self.fake_replica_2
3934 )
3935
3936 def test_update_replicated_snapshot_still_creating_no_host(self):
3937 self.fake_replica_2['host'] = None
3938 vserver_client = mock.Mock()
3939 vserver_client.snapshot_exists.return_value = False
3940 self.mock_object(self.library,
3941 '_get_vserver',
3942 mock.Mock(return_value=(fake.VSERVER1,
3943 vserver_client)))
3944 replica_list = [self.fake_replica, self.fake_replica_2]
3945 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3946 fake_snapshot['status'] = constants.STATUS_CREATING
3947 fake_snapshot['share_id'] = self.fake_replica_2['id']
3948 snapshot_name = self.library._get_backend_snapshot_name(
3949 fake_snapshot['id'])
3950 fake_snapshot['provider_location'] = snapshot_name
3951
3952 model_update = self.library.update_replicated_snapshot(
3953 replica_list, self.fake_replica_2, [fake_snapshot], fake_snapshot)
3954
3955 self.assertIsNone(model_update)
3956 self.mock_dm_session.update_snapmirror.assert_called_once_with(
3957 self.fake_replica, self.fake_replica_2
3958 )
3959
3960 def test_update_replicated_snapshot_no_snapmirror(self):
3961 vserver_client = mock.Mock()
3962 vserver_client.snapshot_exists.return_value = False
3963 self.mock_dm_session.update_snapmirror.side_effect = (
3964 netapp_api.NaApiError(code=netapp_api.EOBJECTNOTFOUND)
3965 )
3966 self.mock_object(self.library,
3967 '_get_vserver',
3968 mock.Mock(return_value=(fake.VSERVER1,
3969 vserver_client)))
3970 replica_list = [self.fake_replica, self.fake_replica_2]
3971 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3972 fake_snapshot['status'] = constants.STATUS_CREATING
3973 fake_snapshot['share_id'] = self.fake_replica_2['id']
3974 snapshot_name = self.library._get_backend_snapshot_name(
3975 fake_snapshot['id'])
3976 fake_snapshot['provider_location'] = snapshot_name
3977
3978 model_update = self.library.update_replicated_snapshot(
3979 replica_list, self.fake_replica_2, [fake_snapshot], fake_snapshot)
3980
3981 self.assertIsNone(model_update)
3982 self.mock_dm_session.update_snapmirror.assert_called_once_with(
3983 self.fake_replica, self.fake_replica_2
3984 )
3985
3986 def test_update_replicated_snapshot_update_error(self):
3987 vserver_client = mock.Mock()
3988 vserver_client.snapshot_exists.return_value = False
3989 self.mock_dm_session.update_snapmirror.side_effect = (
3990 netapp_api.NaApiError()
3991 )
3992 self.mock_object(self.library,
3993 '_get_vserver',
3994 mock.Mock(return_value=(fake.VSERVER1,
3995 vserver_client)))
3996 replica_list = [self.fake_replica, self.fake_replica_2]
3997 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
3998 fake_snapshot['status'] = constants.STATUS_CREATING
3999 fake_snapshot['share_id'] = self.fake_replica_2['id']
4000 snapshot_name = self.library._get_backend_snapshot_name(
4001 fake_snapshot['id'])
4002 fake_snapshot['provider_location'] = snapshot_name
4003
4004 self.assertRaises(netapp_api.NaApiError,
4005 self.library.update_replicated_snapshot,
4006 replica_list, self.fake_replica_2,
4007 [fake_snapshot], fake_snapshot)
4008
4009 def test_update_replicated_snapshot_still_deleting(self):
4010 vserver_client = mock.Mock()
4011 vserver_client.snapshot_exists.return_value = True
4012 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
4013 self.mock_object(self.library,
4014 '_get_vserver',
4015 mock.Mock(return_value=(fake.VSERVER1,
4016 vserver_client)))
4017
4018 replica_list = [self.fake_replica]
4019 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
4020 fake_snapshot['status'] = constants.STATUS_DELETING
4021 fake_snapshot['share_id'] = self.fake_replica['id']
4022 snapshot_name = self.library._get_backend_snapshot_name(
4023 fake_snapshot['id'])
4024 fake_snapshot['provider_location'] = snapshot_name
4025
4026 model_update = self.library.update_replicated_snapshot(
4027 replica_list, self.fake_replica, [fake_snapshot], fake_snapshot)
4028
4029 self.assertIsNone(model_update)
4030
4031 def test_update_replicated_snapshot_created(self):
4032 vserver_client = mock.Mock()
4033 vserver_client.snapshot_exists.return_value = True
4034 self.mock_object(self.library,
4035 '_get_vserver',
4036 mock.Mock(return_value=(fake.VSERVER1,
4037 vserver_client)))
4038 replica_list = [self.fake_replica]
4039 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
4040 fake_snapshot['status'] = constants.STATUS_CREATING
4041 fake_snapshot['share_id'] = self.fake_replica['id']
4042 snapshot_name = self.library._get_backend_snapshot_name(
4043 fake_snapshot['id'])
4044 fake_snapshot['provider_location'] = snapshot_name
4045
4046 model_update = self.library.update_replicated_snapshot(
4047 replica_list, self.fake_replica, [fake_snapshot], fake_snapshot)
4048
4049 self.assertEqual(constants.STATUS_AVAILABLE, model_update['status'])
4050 self.assertEqual(snapshot_name, model_update['provider_location'])
4051
4052 def test_update_replicated_snapshot_created_no_provider_location(self):
4053 vserver_client = mock.Mock()
4054 vserver_client.snapshot_exists.return_value = True
4055 self.mock_object(self.library,
4056 '_get_vserver',
4057 mock.Mock(return_value=(fake.VSERVER1,
4058 vserver_client)))
4059 replica_list = [self.fake_replica, self.fake_replica_2]
4060 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
4061 fake_snapshot['status'] = constants.STATUS_ACTIVE
4062 fake_snapshot['share_id'] = self.fake_replica['id']
4063 snapshot_name = self.library._get_backend_snapshot_name(
4064 fake_snapshot['id'])
4065 fake_snapshot['provider_location'] = snapshot_name
4066 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
4067 fake_snapshot_2['status'] = constants.STATUS_CREATING
4068 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
4069
4070 model_update = self.library.update_replicated_snapshot(
4071 replica_list, self.fake_replica_2,
4072 [fake_snapshot, fake_snapshot_2], fake_snapshot_2)
4073
4074 self.assertEqual(constants.STATUS_AVAILABLE, model_update['status'])
4075 self.assertEqual(snapshot_name, model_update['provider_location'])
4076
4077 def test_update_replicated_snapshot_deleted(self):
4078 vserver_client = mock.Mock()
4079 vserver_client.snapshot_exists.return_value = False
4080 self.mock_object(self.library,
4081 '_get_vserver',
4082 mock.Mock(return_value=(fake.VSERVER1,
4083 vserver_client)))
4084 replica_list = [self.fake_replica]
4085 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
4086 fake_snapshot['status'] = constants.STATUS_DELETING
4087 fake_snapshot['share_id'] = self.fake_replica['id']
4088 snapshot_name = self.library._get_backend_snapshot_name(
4089 fake_snapshot['id'])
4090 fake_snapshot['provider_location'] = snapshot_name
4091
4092 self.assertRaises(exception.SnapshotResourceNotFound,
4093 self.library.update_replicated_snapshot,
4094 replica_list, self.fake_replica, [fake_snapshot],
4095 fake_snapshot)
4096
4097 def test_update_replicated_snapshot_no_provider_locations(self):
4098 vserver_client = mock.Mock()
4099 vserver_client.snapshot_exists.return_value = True
4100 self.mock_object(self.library,
4101 '_get_vserver',
4102 mock.Mock(return_value=(fake.VSERVER1,
4103 vserver_client)))
4104 replica_list = [self.fake_replica]
4105 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
4106 fake_snapshot['status'] = constants.STATUS_CREATING
4107 fake_snapshot['share_id'] = self.fake_replica['id']
4108 fake_snapshot['provider_location'] = None
4109
4110 model_update = self.library.update_replicated_snapshot(
4111 replica_list, self.fake_replica, [fake_snapshot], fake_snapshot)
4112
4113 self.assertIsNone(model_update)
4114
4115 def _get_fake_replicas_and_snapshots(self):
4116
4117 fake_replica_3 = copy.deepcopy(self.fake_replica_2)
4118 fake_replica_3['id'] = fake.SHARE_ID3
4119 fake_snapshot = copy.deepcopy(fake.SNAPSHOT)
4120 fake_snapshot['share_id'] = self.fake_replica['id']
4121 snapshot_name = self.library._get_backend_snapshot_name(
4122 fake_snapshot['id'])
4123 fake_snapshot['provider_location'] = snapshot_name
4124 fake_snapshot_2 = copy.deepcopy(fake.SNAPSHOT)
4125 fake_snapshot_2['id'] = uuidutils.generate_uuid()
4126 fake_snapshot_2['share_id'] = self.fake_replica_2['id']
4127 fake_snapshot_2['provider_location'] = snapshot_name
4128 fake_snapshot_3 = copy.deepcopy(fake.SNAPSHOT)
4129 fake_snapshot_3['id'] = uuidutils.generate_uuid()
4130 fake_snapshot_3['share_id'] = fake_replica_3['id']
4131 fake_snapshot_3['provider_location'] = snapshot_name
4132 replica_list = [self.fake_replica, self.fake_replica_2, fake_replica_3]
4133 snapshot_list = [fake_snapshot, fake_snapshot_2, fake_snapshot_3]
4134 return replica_list, snapshot_list
4135
4136 @ddt.data(True, False)
4137 def test_revert_to_replicated_snapshot(self, use_snap_provider_location):
4138
4139 replica_list, snapshot_list = self._get_fake_replicas_and_snapshots()
4140 fake_replica, fake_replica_2, fake_replica_3 = replica_list
4141 fake_snapshot, fake_snapshot_2, fake_snapshot_3 = snapshot_list
4142
4143 if not use_snap_provider_location:
4144 del fake_snapshot['provider_location']
4145 del fake_snapshot_2['provider_location']
4146 del fake_snapshot_3['provider_location']
4147
4148 share_name = self.library._get_backend_share_name(
4149 fake_snapshot['share_id'])
4150 snapshot_name = self.library._get_backend_snapshot_name(
4151 fake_snapshot['id'])
4152
4153 vserver_client = mock.Mock()
4154 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
4155 vserver_client.list_snapmirror_snapshots.return_value = ['sm_snap']
4156 self.mock_object(self.library,
4157 '_get_vserver',
4158 mock.Mock(return_value=(fake.VSERVER1,
4159 vserver_client)))
4160
4161 self.library.revert_to_replicated_snapshot(
4162 self.context, self.fake_replica, replica_list, fake_snapshot,
4163 snapshot_list, share_server=fake.SHARE_SERVER)
4164
4165 vserver_client.get_snapshot.assert_called_once_with(
4166 share_name, snapshot_name)
4167 vserver_client.list_snapmirror_snapshots.assert_called_once_with(
4168 share_name)
4169 vserver_client.delete_snapshot.assert_called_once_with(
4170 share_name, 'sm_snap', ignore_owners=True)
4171 vserver_client.restore_snapshot.assert_called_once_with(
4172 share_name, snapshot_name)
4173
4174 self.mock_dm_session.break_snapmirror.assert_has_calls(
4175 [mock.call(self.fake_replica, self.fake_replica_2, mount=False),
4176 mock.call(self.fake_replica, fake_replica_3, mount=False)],
4177 any_order=True)
4178 self.mock_dm_session.resync_snapmirror.assert_has_calls(
4179 [mock.call(self.fake_replica, self.fake_replica_2),
4180 mock.call(self.fake_replica, fake_replica_3)],
4181 any_order=True)
4182
4183 def test_revert_to_replicated_snapshot_not_found(self):
4184
4185 replica_list, snapshot_list = self._get_fake_replicas_and_snapshots()
4186 fake_snapshot, fake_snapshot_2, fake_snapshot_3 = snapshot_list
4187 share_name = self.library._get_backend_share_name(
4188 fake_snapshot['share_id'])
4189 snapshot_name = self.library._get_backend_snapshot_name(
4190 fake_snapshot['id'])
4191
4192 vserver_client = mock.Mock()
4193 vserver_client.get_snapshot.side_effect = netapp_api.NaApiError
4194 vserver_client.list_snapmirror_snapshots.return_value = ['sm_snap']
4195 self.mock_object(self.library,
4196 '_get_vserver',
4197 mock.Mock(return_value=(fake.VSERVER1,
4198 vserver_client)))
4199
4200 self.assertRaises(
4201 netapp_api.NaApiError, self.library.revert_to_replicated_snapshot,
4202 self.context, self.fake_replica, replica_list, fake_snapshot,
4203 snapshot_list, share_server=fake.SHARE_SERVER)
4204
4205 vserver_client.get_snapshot.assert_called_once_with(
4206 share_name, snapshot_name)
4207 self.assertFalse(vserver_client.list_snapmirror_snapshots.called)
4208 self.assertFalse(vserver_client.delete_snapshot.called)
4209 self.assertFalse(vserver_client.restore_snapshot.called)
4210 self.assertFalse(self.mock_dm_session.break_snapmirror.called)
4211 self.assertFalse(self.mock_dm_session.resync_snapmirror.called)
4212
4213 def test_revert_to_replicated_snapshot_snapmirror_break_error(self):
4214
4215 replica_list, snapshot_list = self._get_fake_replicas_and_snapshots()
4216 fake_snapshot, fake_snapshot_2, fake_snapshot_3 = snapshot_list
4217
4218 vserver_client = mock.Mock()
4219 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
4220 vserver_client.list_snapmirror_snapshots.return_value = ['sm_snap']
4221 self.mock_object(self.library,
4222 '_get_vserver',
4223 mock.Mock(return_value=(fake.VSERVER1,
4224 vserver_client)))
4225 self.mock_dm_session.break_snapmirror.side_effect = (
4226 netapp_api.NaApiError)
4227
4228 self.assertRaises(
4229 netapp_api.NaApiError, self.library.revert_to_replicated_snapshot,
4230 self.context, self.fake_replica, replica_list, fake_snapshot,
4231 snapshot_list, share_server=fake.SHARE_SERVER)
4232
4233 def test_revert_to_replicated_snapshot_snapmirror_break_not_found(self):
4234
4235 replica_list, snapshot_list = self._get_fake_replicas_and_snapshots()
4236 fake_replica, fake_replica_2, fake_replica_3 = replica_list
4237 fake_snapshot, fake_snapshot_2, fake_snapshot_3 = snapshot_list
4238 share_name = self.library._get_backend_share_name(
4239 fake_snapshot['share_id'])
4240 snapshot_name = self.library._get_backend_snapshot_name(
4241 fake_snapshot['id'])
4242
4243 vserver_client = mock.Mock()
4244 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
4245 vserver_client.list_snapmirror_snapshots.return_value = ['sm_snap']
4246 self.mock_object(self.library,
4247 '_get_vserver',
4248 mock.Mock(return_value=(fake.VSERVER1,
4249 vserver_client)))
4250 self.mock_dm_session.break_snapmirror.side_effect = (
4251 netapp_api.NaApiError(code=netapp_api.EOBJECTNOTFOUND))
4252
4253 self.library.revert_to_replicated_snapshot(
4254 self.context, self.fake_replica, replica_list, fake_snapshot,
4255 snapshot_list, share_server=fake.SHARE_SERVER)
4256
4257 vserver_client.get_snapshot.assert_called_once_with(
4258 share_name, snapshot_name)
4259 vserver_client.list_snapmirror_snapshots.assert_called_once_with(
4260 share_name)
4261 vserver_client.delete_snapshot.assert_called_once_with(
4262 share_name, 'sm_snap', ignore_owners=True)
4263 vserver_client.restore_snapshot.assert_called_once_with(
4264 share_name, snapshot_name)
4265
4266 self.mock_dm_session.break_snapmirror.assert_has_calls(
4267 [mock.call(self.fake_replica, self.fake_replica_2, mount=False),
4268 mock.call(self.fake_replica, fake_replica_3, mount=False)],
4269 any_order=True)
4270 self.mock_dm_session.resync_snapmirror.assert_has_calls(
4271 [mock.call(self.fake_replica, self.fake_replica_2),
4272 mock.call(self.fake_replica, fake_replica_3)],
4273 any_order=True)
4274
4275 def test_revert_to_replicated_snapshot_snapmirror_resync_error(self):
4276
4277 replica_list, snapshot_list = self._get_fake_replicas_and_snapshots()
4278 fake_snapshot, fake_snapshot_2, fake_snapshot_3 = snapshot_list
4279
4280 vserver_client = mock.Mock()
4281 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
4282 vserver_client.list_snapmirror_snapshots.return_value = ['sm_snap']
4283 self.mock_object(self.library,
4284 '_get_vserver',
4285 mock.Mock(return_value=(fake.VSERVER1,
4286 vserver_client)))
4287 self.mock_dm_session.resync_snapmirror.side_effect = (
4288 netapp_api.NaApiError)
4289
4290 self.assertRaises(
4291 netapp_api.NaApiError, self.library.revert_to_replicated_snapshot,
4292 self.context, self.fake_replica, replica_list, fake_snapshot,
4293 snapshot_list, share_server=fake.SHARE_SERVER)
4294
4295 def test_revert_to_replicated_snapshot_snapmirror_resync_not_found(self):
4296
4297 replica_list, snapshot_list = self._get_fake_replicas_and_snapshots()
4298 fake_replica, fake_replica_2, fake_replica_3 = replica_list
4299 fake_snapshot, fake_snapshot_2, fake_snapshot_3 = snapshot_list
4300 share_name = self.library._get_backend_share_name(
4301 fake_snapshot['share_id'])
4302 snapshot_name = self.library._get_backend_snapshot_name(
4303 fake_snapshot['id'])
4304
4305 vserver_client = mock.Mock()
4306 vserver_client.get_snapshot.return_value = fake.CDOT_SNAPSHOT
4307 vserver_client.list_snapmirror_snapshots.return_value = ['sm_snap']
4308 self.mock_object(self.library,
4309 '_get_vserver',
4310 mock.Mock(return_value=(fake.VSERVER1,
4311 vserver_client)))
4312 self.mock_dm_session.resync_snapmirror.side_effect = (
4313 netapp_api.NaApiError(code=netapp_api.EOBJECTNOTFOUND))
4314
4315 self.library.revert_to_replicated_snapshot(
4316 self.context, self.fake_replica, replica_list, fake_snapshot,
4317 snapshot_list, share_server=fake.SHARE_SERVER)
4318
4319 vserver_client.get_snapshot.assert_called_once_with(
4320 share_name, snapshot_name)
4321 vserver_client.list_snapmirror_snapshots.assert_called_once_with(
4322 share_name)
4323 vserver_client.delete_snapshot.assert_called_once_with(
4324 share_name, 'sm_snap', ignore_owners=True)
4325 vserver_client.restore_snapshot.assert_called_once_with(
4326 share_name, snapshot_name)
4327
4328 self.mock_dm_session.break_snapmirror.assert_has_calls(
4329 [mock.call(self.fake_replica, self.fake_replica_2, mount=False),
4330 mock.call(self.fake_replica, fake_replica_3, mount=False)],
4331 any_order=True)
4332 self.mock_dm_session.resync_snapmirror.assert_has_calls(
4333 [mock.call(self.fake_replica, self.fake_replica_2),
4334 mock.call(self.fake_replica, fake_replica_3)],
4335 any_order=True)
4336
4337 def test_migration_check_compatibility_no_cluster_credentials(self):
4338 self.library._have_cluster_creds = False
4339 self.mock_object(data_motion, 'get_backend_configuration')
4340 mock_warning_log = self.mock_object(lib_base.LOG, 'warning')
4341
4342 migration_compatibility = self.library.migration_check_compatibility(
4343 self.context, fake_share.fake_share_instance(),
4344 fake_share.fake_share_instance(), share_server=None,
4345 destination_share_server=fake.SHARE_SERVER)
4346
4347 expected_compatibility = {
4348 'compatible': False,
4349 'writable': False,
4350 'nondisruptive': False,
4351 'preserve_metadata': False,
4352 'preserve_snapshots': False,
4353 }
4354 self.assertDictMatch(expected_compatibility, migration_compatibility)
4355 mock_warning_log.assert_called_once()
4356 self.assertFalse(data_motion.get_backend_configuration.called)
4357
4358 @ddt.data((None, exception.NetAppException),
4359 (exception.Invalid, None))
4360 @ddt.unpack
4361 def test_migration_check_compatibility_extra_specs_invalid(
4362 self, side_effect_1, side_effect_2):
4363 self.library._have_cluster_creds = True
4364 self.mock_object(self.library, '_get_backend_share_name',
4365 mock.Mock(return_value=fake.SHARE_NAME))
4366 mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
4367 self.mock_object(share_types, 'get_extra_specs_from_share')
4368 self.mock_object(self.library, '_check_extra_specs_validity',
4369 mock.Mock(side_effect=side_effect_1))
4370 self.mock_object(self.library,
4371 '_check_aggregate_extra_specs_validity',
4372 mock.Mock(side_effect=side_effect_2))
4373 self.mock_object(data_motion, 'get_backend_configuration')
4374
4375 migration_compatibility = self.library.migration_check_compatibility(
4376 self.context, fake_share.fake_share_instance(),
4377 fake_share.fake_share_instance(), share_server=fake.SHARE_SERVER,
4378 destination_share_server=None)
4379
4380 expected_compatibility = {
4381 'compatible': False,
4382 'writable': False,
4383 'nondisruptive': False,
4384 'preserve_metadata': False,
4385 'preserve_snapshots': False,
4386 }
4387 self.assertDictMatch(expected_compatibility, migration_compatibility)
4388 mock_exception_log.assert_called_once()
4389 self.assertFalse(data_motion.get_backend_configuration.called)
4390
4391 def test_migration_check_compatibility_destination_not_configured(self):
4392 self.library._have_cluster_creds = True
4393 self.mock_object(self.library, '_get_backend_share_name',
4394 mock.Mock(return_value=fake.SHARE_NAME))
4395 self.mock_object(
4396 data_motion, 'get_backend_configuration',
4397 mock.Mock(side_effect=exception.BadConfigurationException))
4398 self.mock_object(self.library, '_get_vserver')
4399 mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
4400 self.mock_object(share_utils, 'extract_host', mock.Mock(
4401 return_value='destination_backend'))
4402 self.mock_object(share_types, 'get_extra_specs_from_share')
4403 self.mock_object(self.library, '_check_extra_specs_validity')
4404 self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
4405 mock_vserver_compatibility_check = self.mock_object(
4406 self.library, '_check_destination_vserver_for_vol_move')
4407 self.mock_object(self.library, '_get_dest_flexvol_encryption_value',
4408 mock.Mock(return_value=False))
4409
4410 migration_compatibility = self.library.migration_check_compatibility(
4411 self.context, fake_share.fake_share_instance(),
4412 fake_share.fake_share_instance(), share_server=fake.SHARE_SERVER,
4413 destination_share_server=None)
4414
4415 expected_compatibility = {
4416 'compatible': False,
4417 'writable': False,
4418 'nondisruptive': False,
4419 'preserve_metadata': False,
4420 'preserve_snapshots': False,
4421 }
4422 self.assertDictMatch(expected_compatibility, migration_compatibility)
4423 mock_exception_log.assert_called_once()
4424 data_motion.get_backend_configuration.assert_called_once_with(
4425 'destination_backend')
4426 self.assertFalse(mock_vserver_compatibility_check.called)
4427 self.assertFalse(self.library._get_vserver.called)
4428
4429 @ddt.data(
4430 utils.annotated(
4431 'dest_share_server_not_expected',
4432 (('src_vserver', None), exception.InvalidParameterValue)),
4433 utils.annotated(
4434 'src_share_server_not_expected',
4435 (exception.InvalidParameterValue, ('dest_vserver', None))))
4436 def test_migration_check_compatibility_errors(self, side_effects):
4437 self.library._have_cluster_creds = True
4438 self.mock_object(share_types, 'get_extra_specs_from_share')
4439 self.mock_object(self.library, '_check_extra_specs_validity')
4440 self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
4441 self.mock_object(self.library, '_get_backend_share_name',
4442 mock.Mock(return_value=fake.SHARE_NAME))
4443 self.mock_object(data_motion, 'get_backend_configuration')
4444 self.mock_object(self.library, '_get_vserver',
4445 mock.Mock(side_effect=side_effects))
4446 mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
4447 self.mock_object(share_utils, 'extract_host', mock.Mock(
4448 return_value='destination_backend'))
4449 mock_compatibility_check = self.mock_object(
4450 self.client, 'check_volume_move')
4451
4452 migration_compatibility = self.library.migration_check_compatibility(
4453 self.context, fake_share.fake_share_instance(),
4454 fake_share.fake_share_instance(), share_server=fake.SHARE_SERVER,
4455 destination_share_server=None)
4456
4457 expected_compatibility = {
4458 'compatible': False,
4459 'writable': False,
4460 'nondisruptive': False,
4461 'preserve_metadata': False,
4462 'preserve_snapshots': False,
4463 }
4464 self.assertDictMatch(expected_compatibility, migration_compatibility)
4465 mock_exception_log.assert_called_once()
4466 data_motion.get_backend_configuration.assert_called_once_with(
4467 'destination_backend')
4468 self.assertFalse(mock_compatibility_check.called)
4469
4470 def test_migration_check_compatibility_incompatible_vservers(self):
4471 self.library._have_cluster_creds = True
4472 self.mock_object(share_types, 'get_extra_specs_from_share')
4473 self.mock_object(self.library, '_check_extra_specs_validity')
4474 self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
4475 self.mock_object(self.library, '_get_backend_share_name',
4476 mock.Mock(return_value=fake.SHARE_NAME))
4477 self.mock_object(data_motion, 'get_backend_configuration')
4478 mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
4479 get_vserver_returns = [
4480 (fake.VSERVER1, mock.Mock()),
4481 (fake.VSERVER2, mock.Mock()),
4482 ]
4483 self.mock_object(self.library, '_get_vserver',
4484 mock.Mock(side_effect=get_vserver_returns))
4485 self.mock_object(share_utils, 'extract_host', mock.Mock(
4486 side_effect=['destination_backend', 'destination_pool']))
4487 mock_move_check = self.mock_object(self.client, 'check_volume_move')
4488
4489 migration_compatibility = self.library.migration_check_compatibility(
4490 self.context, fake_share.fake_share_instance(),
4491 fake_share.fake_share_instance(), share_server=fake.SHARE_SERVER,
4492 destination_share_server='dst_srv')
4493
4494 expected_compatibility = {
4495 'compatible': False,
4496 'writable': False,
4497 'nondisruptive': False,
4498 'preserve_metadata': False,
4499 'preserve_snapshots': False,
4500 }
4501 self.assertDictMatch(expected_compatibility, migration_compatibility)
4502 mock_exception_log.assert_called_once()
4503 data_motion.get_backend_configuration.assert_called_once_with(
4504 'destination_backend')
4505 self.assertFalse(mock_move_check.called)
4506 self.library._get_vserver.assert_has_calls(
4507 [mock.call(share_server=fake.SHARE_SERVER),
4508 mock.call(share_server='dst_srv')])
4509
4510 def test_migration_check_compatibility_client_error(self):
4511 self.library._have_cluster_creds = True
4512 self.mock_object(share_types, 'get_extra_specs_from_share')
4513 self.mock_object(self.library, '_check_extra_specs_validity')
4514 self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
4515 self.mock_object(self.library, '_get_backend_share_name',
4516 mock.Mock(return_value=fake.SHARE_NAME))
4517 mock_exception_log = self.mock_object(lib_base.LOG, 'exception')
4518 self.mock_object(data_motion, 'get_backend_configuration')
4519 self.mock_object(self.library, '_get_vserver',
4520 mock.Mock(return_value=(fake.VSERVER1, mock.Mock())))
4521 self.mock_object(share_utils, 'extract_host', mock.Mock(
4522 side_effect=['destination_backend', 'destination_pool']))
4523 mock_move_check = self.mock_object(
4524 self.client, 'check_volume_move',
4525 mock.Mock(side_effect=netapp_api.NaApiError))
4526 self.mock_object(self.library, '_get_dest_flexvol_encryption_value',
4527 mock.Mock(return_value=False))
4528
4529 migration_compatibility = self.library.migration_check_compatibility(
4530 self.context, fake_share.fake_share_instance(),
4531 fake_share.fake_share_instance(), share_server=fake.SHARE_SERVER,
4532 destination_share_server='dst_srv')
4533
4534 expected_compatibility = {
4535 'compatible': False,
4536 'writable': False,
4537 'nondisruptive': False,
4538 'preserve_metadata': False,
4539 'preserve_snapshots': False,
4540 }
4541 self.assertDictMatch(expected_compatibility, migration_compatibility)
4542 mock_exception_log.assert_called_once()
4543 data_motion.get_backend_configuration.assert_called_once_with(
4544 'destination_backend')
4545 mock_move_check.assert_called_once_with(
4546 fake.SHARE_NAME, fake.VSERVER1, 'destination_pool',
4547 encrypt_destination=False)
4548 self.library._get_vserver.assert_has_calls(
4549 [mock.call(share_server=fake.SHARE_SERVER),
4550 mock.call(share_server='dst_srv')])
4551
4552 def test_migration_check_compatibility(self):
4553 self.library._have_cluster_creds = True
4554 self.mock_object(share_types, 'get_extra_specs_from_share')
4555 self.mock_object(self.library, '_check_extra_specs_validity')
4556 self.mock_object(self.library, '_check_aggregate_extra_specs_validity')
4557 self.mock_object(self.library, '_get_backend_share_name',
4558 mock.Mock(return_value=fake.SHARE_NAME))
4559 self.mock_object(data_motion, 'get_backend_configuration')
4560 self.mock_object(self.library, '_get_vserver',
4561 mock.Mock(return_value=(fake.VSERVER1, mock.Mock())))
4562 self.mock_object(share_utils, 'extract_host', mock.Mock(
4563 side_effect=['destination_backend', 'destination_pool']))
4564 mock_move_check = self.mock_object(self.client, 'check_volume_move')
4565 self.mock_object(self.library, '_get_dest_flexvol_encryption_value',
4566 mock.Mock(return_value=False))
4567
4568 migration_compatibility = self.library.migration_check_compatibility(
4569 self.context, fake_share.fake_share_instance(),
4570 fake_share.fake_share_instance(), share_server=fake.SHARE_SERVER,
4571 destination_share_server='dst_srv')
4572
4573 expected_compatibility = {
4574 'compatible': True,
4575 'writable': True,
4576 'nondisruptive': True,
4577 'preserve_metadata': True,
4578 'preserve_snapshots': True,
4579 }
4580 self.assertDictMatch(expected_compatibility, migration_compatibility)
4581 data_motion.get_backend_configuration.assert_called_once_with(
4582 'destination_backend')
4583 mock_move_check.assert_called_once_with(
4584 fake.SHARE_NAME, fake.VSERVER1, 'destination_pool',
4585 encrypt_destination=False)
4586 self.library._get_vserver.assert_has_calls(
4587 [mock.call(share_server=fake.SHARE_SERVER),
4588 mock.call(share_server='dst_srv')])
4589
4590 def test_migration_check_compatibility_destination_type_is_encrypted(self):
4591 self.library._have_cluster_creds = True
4592 self.mock_object(self.library, '_get_backend_share_name',
4593 mock.Mock(return_value=fake.SHARE_NAME))
4594 self.mock_object(data_motion