Coverage for manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py: 99%
3465 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright (c) 2014 Alex Meade. All rights reserved.
2# Copyright (c) 2015 Clinton Knight. All rights reserved.
3# Copyright (c) 2015 Tom Barron. All rights reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
17import copy
18import hashlib
19import time
20from unittest import mock
22import ddt
23from oslo_log import log
25from manila import exception
26from manila.share.drivers.netapp.dataontap.client import api as netapp_api
27from manila.share.drivers.netapp.dataontap.client import client_base
28from manila.share.drivers.netapp.dataontap.client import client_cmode
29from manila.share.drivers.netapp import utils as na_utils
30from manila import test
31from manila.tests.share.drivers.netapp.dataontap.client import fakes as fake
34@ddt.ddt
35class NetAppClientCmodeTestCase(test.TestCase):
37 def setUp(self):
38 super(NetAppClientCmodeTestCase, self).setUp()
40 # Mock loggers as themselves to allow logger arg validation
41 mock_logger = log.getLogger('mock_logger')
42 self.mock_object(client_cmode.LOG,
43 'error',
44 mock.Mock(side_effect=mock_logger.error))
45 self.mock_object(client_cmode.LOG,
46 'warning',
47 mock.Mock(side_effect=mock_logger.warning))
48 self.mock_object(client_cmode.LOG,
49 'debug',
50 mock.Mock(side_effect=mock_logger.debug))
52 self.mock_object(client_base.NetAppBaseClient,
53 'get_ontapi_version',
54 mock.Mock(return_value=(1, 20)))
56 self.mock_object(client_base.NetAppBaseClient,
57 'get_system_version',
58 mock.Mock(return_value={
59 'version-tuple': (8, 3, 0),
60 'version': fake.VERSION,
61 }))
63 self.client = client_cmode.NetAppCmodeClient(**fake.CONNECTION_INFO)
64 self.client.connection = mock.MagicMock()
66 self.vserver_client = client_cmode.NetAppCmodeClient(
67 **fake.CONNECTION_INFO)
68 self.vserver_client.set_vserver(fake.VSERVER_NAME)
69 self.vserver_client.connection = mock.MagicMock()
71 self.sleep_patcher = mock.patch.object(time, 'sleep', lambda s: None)
72 self.sleep_patcher.start()
73 self.addCleanup(self.sleep_patcher.stop)
75 def _mock_api_error(self, code='fake', message='fake'):
76 return mock.Mock(side_effect=netapp_api.NaApiError(code=code,
77 message=message))
79 def test_init_features_ontapi_1_21(self):
81 self.mock_object(client_base.NetAppBaseClient,
82 'get_ontapi_version',
83 mock.Mock(return_value=(1, 21)))
85 self.client._init_features()
87 self.assertFalse(self.client.features.BROADCAST_DOMAINS)
88 self.assertFalse(self.client.features.IPSPACES)
89 self.assertFalse(self.client.features.SUBNETS)
90 self.assertFalse(self.client.features.FLEXVOL_ENCRYPTION)
92 @ddt.data((1, 30), (1, 40), (2, 0))
93 def test_init_features_ontapi_1_30(self, ontapi_version):
95 self.mock_object(client_base.NetAppBaseClient,
96 'get_ontapi_version',
97 mock.Mock(return_value=ontapi_version))
99 self.client._init_features()
101 self.assertTrue(self.client.features.BROADCAST_DOMAINS)
102 self.assertTrue(self.client.features.IPSPACES)
103 self.assertTrue(self.client.features.SUBNETS)
105 @ddt.data((1, 110), (2, 0))
106 def test_init_features_ontap_1_110(self, ontapi_version):
108 self.mock_object(client_base.NetAppBaseClient,
109 'get_ontapi_version',
110 mock.Mock(return_value=ontapi_version))
112 self.client._init_features()
114 self.assertTrue(self.client.features.BROADCAST_DOMAINS)
115 self.assertTrue(self.client.features.IPSPACES)
116 self.assertTrue(self.client.features.SUBNETS)
117 self.assertTrue(self.client.features.FLEXVOL_ENCRYPTION)
119 @ddt.data(((9, 1, 0), fake.VERSION_NO_DARE), ((8, 3, 2), fake.VERSION))
120 @ddt.unpack
121 def test_is_nve_supported_unsupported_release_or_platform(self, gen, ver):
123 system_version = {'version-tuple': gen, 'version': ver}
124 self.mock_object(client_base.NetAppBaseClient,
125 'get_system_version',
126 mock.Mock(return_value=system_version))
127 self.mock_object(self.client,
128 'get_security_key_manager_nve_support',
129 mock.Mock(return_value=True))
130 self.mock_object(self.client,
131 'list_cluster_nodes',
132 mock.Mock(return_value=fake.NODE_NAMES))
134 result = self.client.is_nve_supported()
136 self.assertFalse(result)
138 def test_is_nve_supported_valid_platform_and_supported_release(self):
140 system_version = {
141 'version-tuple': (9, 1, 0),
142 'version': fake.VERSION,
143 }
144 self.mock_object(client_base.NetAppBaseClient,
145 'get_system_version',
146 mock.Mock(return_value=system_version))
147 self.mock_object(self.client,
148 'get_security_key_manager_nve_support',
149 mock.Mock(return_value=True))
150 self.mock_object(self.client,
151 'list_cluster_nodes',
152 mock.Mock(return_value=fake.NODE_NAMES))
154 result = self.client.is_nve_supported()
155 self.assertTrue(result)
157 def test_is_nve_supported_key_manager_not_enabled(self):
159 system_version = {
160 'version-tuple': (9, 1, 0),
161 'version': fake.VERSION,
162 }
163 self.mock_object(client_base.NetAppBaseClient,
164 'get_system_version',
165 mock.Mock(return_value=system_version))
166 self.mock_object(self.client,
167 'get_security_key_manager_nve_support',
168 mock.Mock(return_value=False))
169 self.mock_object(self.client,
170 'list_cluster_nodes',
171 mock.Mock(return_value=fake.NODE_NAMES))
173 result = self.client.is_nve_supported()
175 self.assertFalse(result)
177 def test_get_security_key_manager_nve_support_enabled(self):
178 api_response = netapp_api.NaElement(
179 fake.SECUTITY_KEY_MANAGER_NVE_SUPPORT_RESPONSE_TRUE)
180 self.mock_object(self.client,
181 'send_request',
182 mock.Mock(return_value=api_response))
184 result = self.client.get_security_key_manager_nve_support(
185 fake.NODE_NAME)
187 self.assertTrue(result)
188 api_args = {'node': fake.NODE_NAME}
189 self.client.send_request.assert_has_calls([
190 mock.call('security-key-manager-volume-encryption-supported',
191 api_args)])
193 def test_get_security_key_manager_nve_support_disabled(self):
194 api_response = netapp_api.NaElement(
195 fake.SECUTITY_KEY_MANAGER_NVE_SUPPORT_RESPONSE_FALSE)
196 self.mock_object(self.client,
197 'send_request',
198 mock.Mock(return_value=api_response))
200 result = self.client.get_security_key_manager_nve_support(
201 fake.NODE_NAME)
203 self.assertFalse(result)
204 api_args = {'node': fake.NODE_NAME}
205 self.client.send_request.assert_has_calls([
206 mock.call('security-key-manager-volume-encryption-supported',
207 api_args)])
209 def test_get_security_key_manager_nve_support_disabled_no_license(self):
210 self.mock_object(self.client,
211 'send_request',
212 self._mock_api_error())
214 result = self.client.get_security_key_manager_nve_support(
215 fake.NODE_NAME)
217 self.assertFalse(result)
219 api_args = {'node': fake.NODE_NAME}
220 self.client.send_request.assert_has_calls([
221 mock.call('security-key-manager-volume-encryption-supported',
222 api_args)])
224 @ddt.data((True, True, True), (False, None, False))
225 @ddt.unpack
226 def test_send_volume_move_request_success(self, validation_only,
227 encrypt_dst, fv_encryption):
228 self.mock_object(self.client, 'features',
229 mock.Mock(FLEXVOL_ENCRYPTION=fv_encryption))
230 self.client._send_volume_move_request(fake.ROOT_VOLUME_NAME,
231 fake.NODE_VSERVER_NAME,
232 fake.SHARE_AGGREGATE_NAME,
233 validation_only=validation_only,
234 encrypt_destination=encrypt_dst)
236 @ddt.data((True, True, False))
237 @ddt.unpack
238 def test_send_volume_move_request_failure(self, validation_only,
239 encrypt_dst, fv_encrypt):
240 self.mock_object(self.client, 'features',
241 mock.Mock(FLEXVOL_ENCRYPTION=fv_encrypt))
242 self.assertRaises(exception.NetAppException,
243 self.client._send_volume_move_request,
244 fake.ROOT_VOLUME_NAME,
245 fake.NODE_VSERVER_NAME,
246 fake.SHARE_AGGREGATE_NAME,
247 validation_only=validation_only,
248 encrypt_destination=encrypt_dst)
250 def test_invoke_vserver_api(self):
252 self.client._invoke_vserver_api('fake-api', 'fake_vserver')
254 self.client.connection.set_vserver.assert_has_calls(
255 [mock.call('fake_vserver')])
256 self.client.connection.invoke_successfully.assert_has_calls(
257 [mock.call('fake-api', True)])
259 def test_has_records(self):
260 self.assertTrue(self.client._has_records(
261 netapp_api.NaElement(fake.VSERVER_GET_ITER_RESPONSE)))
263 def test_has_records_not_found(self):
264 self.assertFalse(self.client._has_records(
265 netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)))
267 @ddt.data((fake.VSERVER_GET_ITER_RESPONSE, 1),
268 (fake.NO_RECORDS_RESPONSE, 0))
269 @ddt.unpack
270 def test_get_record_count(self, response, expected):
272 api_response = netapp_api.NaElement(response)
274 result = self.client._get_record_count(api_response)
276 self.assertEqual(expected, result)
278 def test_get_records_count_invalid(self):
280 api_response = netapp_api.NaElement(
281 fake.INVALID_GET_ITER_RESPONSE_NO_RECORDS)
283 self.assertRaises(exception.NetAppException,
284 self.client._get_record_count,
285 api_response)
287 def test_send_iter_request(self):
289 api_responses = [
290 netapp_api.NaElement(fake.STORAGE_DISK_GET_ITER_RESPONSE_PAGE_1),
291 netapp_api.NaElement(fake.STORAGE_DISK_GET_ITER_RESPONSE_PAGE_2),
292 netapp_api.NaElement(fake.STORAGE_DISK_GET_ITER_RESPONSE_PAGE_3),
293 ]
294 mock_send_request = self.mock_object(
295 self.client, 'send_request',
296 mock.Mock(side_effect=api_responses))
298 storage_disk_get_iter_args = {
299 'desired-attributes': {
300 'storage-disk-info': {
301 'disk-name': None,
302 }
303 }
304 }
305 result = self.client.send_iter_request(
306 'storage-disk-get-iter', api_args=storage_disk_get_iter_args,
307 max_page_length=10)
309 num_records = result.get_child_content('num-records')
310 self.assertEqual('28', num_records)
311 next_tag = result.get_child_content('next-tag')
312 self.assertEqual('', next_tag)
314 args1 = copy.deepcopy(storage_disk_get_iter_args)
315 args1['max-records'] = 10
316 args2 = copy.deepcopy(storage_disk_get_iter_args)
317 args2['max-records'] = 10
318 args2['tag'] = 'next_tag_1'
319 args3 = copy.deepcopy(storage_disk_get_iter_args)
320 args3['max-records'] = 10
321 args3['tag'] = 'next_tag_2'
323 mock_send_request.assert_has_calls([
324 mock.call('storage-disk-get-iter', args1, enable_tunneling=True),
325 mock.call('storage-disk-get-iter', args2, enable_tunneling=True),
326 mock.call('storage-disk-get-iter', args3, enable_tunneling=True),
327 ])
329 def test_send_iter_request_single_page(self):
331 api_response = netapp_api.NaElement(
332 fake.STORAGE_DISK_GET_ITER_RESPONSE)
333 mock_send_request = self.mock_object(
334 self.client, 'send_request',
335 mock.Mock(return_value=api_response))
337 storage_disk_get_iter_args = {
338 'desired-attributes': {
339 'storage-disk-info': {
340 'disk-name': None,
341 }
342 }
343 }
344 result = self.client.send_iter_request(
345 'storage-disk-get-iter', api_args=storage_disk_get_iter_args,
346 max_page_length=10)
348 num_records = result.get_child_content('num-records')
349 self.assertEqual('4', num_records)
351 args = copy.deepcopy(storage_disk_get_iter_args)
352 args['max-records'] = 10
354 mock_send_request.assert_has_calls([
355 mock.call('storage-disk-get-iter', args, enable_tunneling=True),
356 ])
358 def test_send_iter_request_not_found(self):
360 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
361 mock_send_request = self.mock_object(
362 self.client, 'send_request',
363 mock.Mock(return_value=api_response))
365 result = self.client.send_iter_request('storage-disk-get-iter')
367 num_records = result.get_child_content('num-records')
368 self.assertEqual('0', num_records)
370 args = {'max-records': client_cmode.DEFAULT_MAX_PAGE_LENGTH}
372 mock_send_request.assert_has_calls([
373 mock.call('storage-disk-get-iter', args, enable_tunneling=True),
374 ])
376 @ddt.data(fake.INVALID_GET_ITER_RESPONSE_NO_ATTRIBUTES,
377 fake.INVALID_GET_ITER_RESPONSE_NO_RECORDS)
378 def test_send_iter_request_invalid(self, fake_response):
380 api_response = netapp_api.NaElement(fake_response)
381 self.mock_object(self.client,
382 'send_request',
383 mock.Mock(return_value=api_response))
385 self.assertRaises(exception.NetAppException,
386 self.client.send_iter_request,
387 'storage-disk-get-iter')
389 def test_set_vserver(self):
390 self.client.set_vserver(fake.VSERVER_NAME)
391 self.client.connection.set_vserver.assert_has_calls(
392 [mock.call('fake_vserver')])
394 def test_vserver_exists(self):
396 api_response = netapp_api.NaElement(fake.VSERVER_GET_ITER_RESPONSE)
397 self.mock_object(self.client,
398 'send_iter_request',
399 mock.Mock(return_value=api_response))
401 vserver_get_args = {
402 'query': {'vserver-info': {'vserver-name': fake.VSERVER_NAME}},
403 'desired-attributes': {'vserver-info': {'vserver-name': None}}
404 }
406 result = self.client.vserver_exists(fake.VSERVER_NAME)
408 self.client.send_iter_request.assert_has_calls([
409 mock.call('vserver-get-iter', vserver_get_args,
410 enable_tunneling=False)])
411 self.assertTrue(result)
413 def test_vserver_exists_not_found(self):
415 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
416 self.mock_object(self.client,
417 'send_request',
418 mock.Mock(return_value=api_response))
420 result = self.client.vserver_exists(fake.VSERVER_NAME)
422 self.assertFalse(result)
424 @ddt.data(0, 65535, 270000)
425 def test_create_vserver_delete_retention_hours(self,
426 delete_retention_hours):
428 self.client.features.add_feature('DELETE_RETENTION_HOURS')
429 self.mock_object(self.client, 'send_request')
430 self.mock_object(self.client,
431 '_modify_security_cert',
432 mock.Mock())
434 vserver_create_args = {
435 'vserver-name': fake.VSERVER_NAME,
436 'root-volume-security-style': 'unix',
437 'root-volume-aggregate': fake.ROOT_VOLUME_AGGREGATE_NAME,
438 'root-volume': fake.ROOT_VOLUME_NAME,
439 'name-server-switch': {'nsswitch': 'file'},
440 'is-space-reporting-logical': 'false',
441 'is-space-enforcement-logical': 'false'
442 }
443 vserver_modify_args = {
444 'aggr-list': [{'aggr-name': aggr_name} for aggr_name
445 in fake.SHARE_AGGREGATE_NAMES],
446 'vserver-name': fake.VSERVER_NAME,
447 'volume-delete-retention-hours': str(delete_retention_hours),
448 }
450 self.client.create_vserver(fake.VSERVER_NAME,
451 fake.ROOT_VOLUME_AGGREGATE_NAME,
452 fake.ROOT_VOLUME_NAME,
453 fake.SHARE_AGGREGATE_NAMES,
454 None,
455 fake.SECURITY_CERT_LARGE_EXPIRE_DAYS,
456 delete_retention_hours,
457 False)
459 self.client.send_request.assert_has_calls([
460 mock.call('vserver-create', vserver_create_args),
461 mock.call('vserver-modify', vserver_modify_args)])
462 self.client._modify_security_cert.assert_called_with(
463 fake.VSERVER_NAME, fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
465 def test_create_vserver_no_ipspace(self):
467 self.client.features.add_feature('DELETE_RETENTION_HOURS')
468 self.mock_object(self.client, 'send_request')
469 self.mock_object(self.client,
470 '_modify_security_cert',
471 mock.Mock())
473 vserver_create_args = {
474 'vserver-name': fake.VSERVER_NAME,
475 'root-volume-security-style': 'unix',
476 'root-volume-aggregate': fake.ROOT_VOLUME_AGGREGATE_NAME,
477 'root-volume': fake.ROOT_VOLUME_NAME,
478 'name-server-switch': {'nsswitch': 'file'},
479 'is-space-reporting-logical': 'false',
480 'is-space-enforcement-logical': 'false'
481 }
482 vserver_modify_args = {
483 'aggr-list': [{'aggr-name': aggr_name} for aggr_name
484 in fake.SHARE_AGGREGATE_NAMES],
485 'vserver-name': fake.VSERVER_NAME,
486 'volume-delete-retention-hours': '16',
487 }
489 self.client.create_vserver(fake.VSERVER_NAME,
490 fake.ROOT_VOLUME_AGGREGATE_NAME,
491 fake.ROOT_VOLUME_NAME,
492 fake.SHARE_AGGREGATE_NAMES,
493 None,
494 fake.SECURITY_CERT_LARGE_EXPIRE_DAYS,
495 16,
496 False)
498 self.client.send_request.assert_has_calls([
499 mock.call('vserver-create', vserver_create_args),
500 mock.call('vserver-modify', vserver_modify_args)])
501 self.client._modify_security_cert.assert_called_with(
502 fake.VSERVER_NAME, fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
504 def test_create_vserver_with_ipspace(self):
506 self.client.features.add_feature('IPSPACES')
507 self.client.features.add_feature('DELETE_RETENTION_HOURS')
508 self.mock_object(self.client, 'send_request')
509 self.mock_object(self.client,
510 '_modify_security_cert',
511 mock.Mock())
513 vserver_create_args = {
514 'vserver-name': fake.VSERVER_NAME,
515 'root-volume-security-style': 'unix',
516 'root-volume-aggregate': fake.ROOT_VOLUME_AGGREGATE_NAME,
517 'root-volume': fake.ROOT_VOLUME_NAME,
518 'name-server-switch': {'nsswitch': 'file'},
519 'ipspace': fake.IPSPACE_NAME,
520 'is-space-reporting-logical': 'false',
521 'is-space-enforcement-logical': 'false'
522 }
523 vserver_modify_args = {
524 'aggr-list': [{'aggr-name': aggr_name} for aggr_name
525 in fake.SHARE_AGGREGATE_NAMES],
526 'volume-delete-retention-hours': '24',
527 'vserver-name': fake.VSERVER_NAME
528 }
530 self.client.create_vserver(fake.VSERVER_NAME,
531 fake.ROOT_VOLUME_AGGREGATE_NAME,
532 fake.ROOT_VOLUME_NAME,
533 fake.SHARE_AGGREGATE_NAMES,
534 fake.IPSPACE_NAME,
535 fake.SECURITY_CERT_LARGE_EXPIRE_DAYS,
536 24,
537 False)
539 self.client.send_request.assert_has_calls([
540 mock.call('vserver-create', vserver_create_args),
541 mock.call('vserver-modify', vserver_modify_args)])
542 self.client._modify_security_cert.assert_called_with(
543 fake.VSERVER_NAME, fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
545 def test__modify_security_cert(self):
547 certificate_create_args = {
548 'vserver': fake.VSERVER_NAME,
549 'common-name': fake.VSERVER_NAME,
550 'type': 'server',
551 'expire-days': fake.SECURITY_CERT_LARGE_EXPIRE_DAYS,
552 }
554 self.mock_object(self.client, 'send_request')
555 api_response = netapp_api.NaElement(fake.SECURITY_CERT_GET_RESPONSE)
556 self.mock_object(self.client,
557 'send_iter_request',
558 mock.Mock(return_value=api_response))
559 certificate_get_args = {
560 'query': {
561 'certificate-info': {
562 'vserver': fake.VSERVER_NAME,
563 'common-name': fake.VSERVER_NAME,
564 'certificate-authority': fake.VSERVER_NAME,
565 'type': 'server',
566 },
567 },
568 'desired-attributes': {
569 'certificate-info': {
570 'serial-number': None,
571 },
572 },
573 }
575 certificate_delete_args = {
576 'certificate-authority': fake.VSERVER_NAME,
577 'common-name': fake.VSERVER_NAME,
578 'serial-number': '12345',
579 'type': 'server',
580 'vserver': fake.VSERVER_NAME,
581 }
583 self.client._modify_security_cert(
584 fake.VSERVER_NAME,
585 fake.SECURITY_CERT_LARGE_EXPIRE_DAYS)
587 self.client.send_request.assert_has_calls([
588 mock.call(
589 'security-certificate-create', certificate_create_args),
590 mock.call(
591 'security-certificate-delete', certificate_delete_args)])
593 self.client.send_iter_request.assert_has_calls([
594 mock.call('security-certificate-get-iter', certificate_get_args)])
596 def test_create_vserver_dp_destination(self):
598 self.client.features.add_feature('IPSPACES')
599 self.client.features.add_feature('DELETE_RETENTION_HOURS')
600 self.mock_object(self.client, 'send_request')
602 vserver_create_args = {
603 'vserver-name': fake.VSERVER_NAME,
604 'ipspace': fake.IPSPACE_NAME,
605 'vserver-subtype': fake.VSERVER_TYPE_DP_DEST,
606 'is-space-reporting-logical': 'false',
607 'is-space-enforcement-logical': 'false'
608 }
609 vserver_modify_args = {
610 'aggr-list': [{'aggr-name': aggr_name} for aggr_name
611 in fake.SHARE_AGGREGATE_NAMES],
612 'volume-delete-retention-hours': '18',
613 'vserver-name': fake.VSERVER_NAME
614 }
616 self.client.create_vserver_dp_destination(
617 fake.VSERVER_NAME,
618 fake.SHARE_AGGREGATE_NAMES,
619 fake.IPSPACE_NAME,
620 18,
621 False)
623 self.client.send_request.assert_has_calls([
624 mock.call('vserver-create', vserver_create_args),
625 mock.call('vserver-modify', vserver_modify_args)])
627 def test_create_vserver_ipspaces_not_supported(self):
629 self.assertRaises(exception.NetAppException,
630 self.client.create_vserver,
631 fake.VSERVER_NAME,
632 fake.ROOT_VOLUME_AGGREGATE_NAME,
633 fake.ROOT_VOLUME_NAME,
634 fake.SHARE_AGGREGATE_NAMES,
635 fake.IPSPACE_NAME,
636 fake.SECURITY_CERT_LARGE_EXPIRE_DAYS,
637 10,
638 False)
640 def test_get_vserver_root_volume_name(self):
642 api_response = netapp_api.NaElement(
643 fake.VSERVER_GET_ROOT_VOLUME_NAME_RESPONSE)
644 self.mock_object(self.client,
645 'send_iter_request',
646 mock.Mock(return_value=api_response))
648 vserver_get_args = {
649 'query': {'vserver-info': {'vserver-name': fake.VSERVER_NAME}},
650 'desired-attributes': {'vserver-info': {'root-volume': None}}
651 }
653 result = self.client.get_vserver_root_volume_name(fake.VSERVER_NAME)
655 self.client.send_iter_request.assert_has_calls([
656 mock.call('vserver-get-iter', vserver_get_args)])
657 self.assertEqual(fake.ROOT_VOLUME_NAME, result)
659 def test_get_vserver_root_volume_name_not_found(self):
661 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
662 self.mock_object(self.client,
663 'send_iter_request',
664 mock.Mock(return_value=api_response))
666 self.assertRaises(exception.NetAppException,
667 self.client.get_vserver_root_volume_name,
668 fake.VSERVER_NAME)
670 def test_get_vserver_ipspace(self):
672 self.client.features.add_feature('IPSPACES')
673 api_response = netapp_api.NaElement(
674 fake.VSERVER_GET_IPSPACE_NAME_RESPONSE)
675 self.mock_object(self.client,
676 'send_iter_request',
677 mock.Mock(return_value=api_response))
679 result = self.client.get_vserver_ipspace(fake.VSERVER_NAME)
681 vserver_get_iter_args = {
682 'query': {
683 'vserver-info': {
684 'vserver-name': fake.VSERVER_NAME,
685 },
686 },
687 'desired-attributes': {
688 'vserver-info': {
689 'ipspace': None,
690 },
691 },
692 }
693 self.client.send_iter_request.assert_has_calls([
694 mock.call('vserver-get-iter', vserver_get_iter_args)])
695 self.assertEqual(fake.IPSPACE_NAME, result)
697 def test_get_vserver_ipspace_not_supported(self):
699 result = self.client.get_vserver_ipspace(fake.IPSPACE_NAME)
701 self.assertIsNone(result)
703 def test_get_vserver_ipspace_not_found(self):
705 self.client.features.add_feature('IPSPACES')
706 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
707 self.mock_object(self.client,
708 'send_iter_request',
709 mock.Mock(return_value=api_response))
711 self.assertRaises(exception.NetAppException,
712 self.client.get_vserver_ipspace,
713 fake.IPSPACE_NAME)
715 def test_ipspace_has_data_vservers(self):
717 self.client.features.add_feature('IPSPACES')
718 api_response = netapp_api.NaElement(fake.VSERVER_GET_ITER_RESPONSE)
719 self.mock_object(self.client,
720 'send_iter_request',
721 mock.Mock(return_value=api_response))
723 result = self.client.ipspace_has_data_vservers(fake.IPSPACE_NAME)
725 vserver_get_iter_args = {
726 'query': {
727 'vserver-info': {
728 'ipspace': fake.IPSPACE_NAME,
729 'vserver-type': 'data'
730 },
731 },
732 'desired-attributes': {
733 'vserver-info': {
734 'vserver-name': None,
735 },
736 },
737 }
738 self.client.send_iter_request.assert_has_calls([
739 mock.call('vserver-get-iter', vserver_get_iter_args)])
740 self.assertTrue(result)
742 def test_ipspace_has_data_vservers_not_supported(self):
744 result = self.client.ipspace_has_data_vservers(fake.IPSPACE_NAME)
746 self.assertFalse(result)
748 def test_ipspace_has_data_vservers_not_found(self):
750 self.client.features.add_feature('IPSPACES')
751 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
752 self.mock_object(self.client,
753 'send_request',
754 mock.Mock(return_value=api_response))
756 result = self.client.ipspace_has_data_vservers(fake.IPSPACE_NAME)
758 self.assertFalse(result)
760 def test_list_vservers(self):
762 api_response = netapp_api.NaElement(
763 fake.VSERVER_DATA_LIST_RESPONSE)
764 self.mock_object(self.client,
765 'send_iter_request',
766 mock.Mock(return_value=api_response))
768 result = self.client.list_vservers()
770 vserver_get_iter_args = {
771 'query': {
772 'vserver-info': {
773 'vserver-type': 'data'
774 }
775 },
776 'desired-attributes': {
777 'vserver-info': {
778 'vserver-name': None
779 }
780 }
781 }
782 self.client.send_iter_request.assert_has_calls([
783 mock.call('vserver-get-iter', vserver_get_iter_args)])
784 self.assertListEqual([fake.VSERVER_NAME], result)
786 def test_list_vservers_node_type(self):
788 api_response = netapp_api.NaElement(
789 fake.VSERVER_DATA_LIST_RESPONSE)
790 self.mock_object(self.client,
791 'send_iter_request',
792 mock.Mock(return_value=api_response))
794 result = self.client.list_vservers(vserver_type='node')
796 vserver_get_iter_args = {
797 'query': {
798 'vserver-info': {
799 'vserver-type': 'node'
800 }
801 },
802 'desired-attributes': {
803 'vserver-info': {
804 'vserver-name': None
805 }
806 }
807 }
808 self.client.send_iter_request.assert_has_calls([
809 mock.call('vserver-get-iter', vserver_get_iter_args)])
810 self.assertListEqual([fake.VSERVER_NAME], result)
812 def test_list_vservers_not_found(self):
814 api_response = netapp_api.NaElement(
815 fake.NO_RECORDS_RESPONSE)
816 self.mock_object(self.client,
817 'send_request',
818 mock.Mock(return_value=api_response))
820 result = self.client.list_vservers(vserver_type='data')
822 self.assertListEqual([], result)
824 def test_get_vserver_volume_count(self):
826 api_response = netapp_api.NaElement(fake.VOLUME_COUNT_RESPONSE)
827 self.mock_object(self.client,
828 'send_iter_request',
829 mock.Mock(return_value=api_response))
831 result = self.client.get_vserver_volume_count()
833 self.assertEqual(2, result)
835 def test_delete_vserver_no_volumes(self):
837 self.mock_object(self.client,
838 'get_vserver_info',
839 mock.Mock(return_value=fake.VSERVER_INFO))
840 self.mock_object(self.client,
841 'get_vserver_root_volume_name',
842 mock.Mock(return_value=fake.ROOT_VOLUME_NAME))
843 self.mock_object(self.vserver_client,
844 'get_vserver_volume_count',
845 mock.Mock(return_value=0))
846 self.mock_object(self.client, '_terminate_vserver_services')
847 self.mock_object(self.client, 'send_request')
849 self.client.delete_vserver(
850 fake.VSERVER_NAME,
851 self.vserver_client,
852 security_services=[fake.CIFS_SECURITY_SERVICE])
854 self.client._terminate_vserver_services.assert_called_with(
855 fake.VSERVER_NAME, self.vserver_client,
856 [fake.CIFS_SECURITY_SERVICE])
858 vserver_destroy_args = {'vserver-name': fake.VSERVER_NAME}
859 self.client.send_request.assert_has_calls([
860 mock.call('vserver-destroy', vserver_destroy_args)])
862 def test_delete_vserver_one_volume(self):
864 self.mock_object(self.client,
865 'get_vserver_info',
866 mock.Mock(return_value=fake.VSERVER_INFO))
867 self.mock_object(self.client,
868 'get_vserver_root_volume_name',
869 mock.Mock(return_value=fake.ROOT_VOLUME_NAME))
870 self.mock_object(self.vserver_client,
871 'get_vserver_volume_count',
872 mock.Mock(return_value=1))
873 self.mock_object(self.client, 'send_request')
874 self.mock_object(self.vserver_client, 'offline_volume')
875 self.mock_object(self.vserver_client, 'delete_volume')
877 self.client.delete_vserver(fake.VSERVER_NAME,
878 self.vserver_client)
880 self.vserver_client.offline_volume.assert_called_with(
881 fake.ROOT_VOLUME_NAME)
882 self.vserver_client.delete_volume.assert_called_with(
883 fake.ROOT_VOLUME_NAME)
885 vserver_destroy_args = {'vserver-name': fake.VSERVER_NAME}
886 self.client.send_request.assert_has_calls([
887 mock.call('vserver-destroy', vserver_destroy_args)])
889 def test_delete_vserver_one_volume_already_offline(self):
891 self.mock_object(self.client,
892 'get_vserver_info',
893 mock.Mock(return_value=fake.VSERVER_INFO))
894 self.mock_object(self.client,
895 'get_vserver_root_volume_name',
896 mock.Mock(return_value=fake.ROOT_VOLUME_NAME))
897 self.mock_object(self.vserver_client,
898 'get_vserver_volume_count',
899 mock.Mock(return_value=1))
900 self.mock_object(self.client, 'send_request')
901 self.mock_object(self.vserver_client,
902 'offline_volume',
903 self._mock_api_error(code=netapp_api.EVOLUMEOFFLINE))
905 self.mock_object(self.vserver_client, 'delete_volume')
907 self.client.delete_vserver(fake.VSERVER_NAME,
908 self.vserver_client)
910 self.vserver_client.offline_volume.assert_called_with(
911 fake.ROOT_VOLUME_NAME)
912 self.vserver_client.delete_volume.assert_called_with(
913 fake.ROOT_VOLUME_NAME)
915 vserver_destroy_args = {'vserver-name': fake.VSERVER_NAME}
916 self.client.send_request.assert_has_calls([
917 mock.call('vserver-destroy', vserver_destroy_args)])
918 self.assertEqual(1, client_cmode.LOG.error.call_count)
920 def test_delete_vserver_one_volume_api_error(self):
922 self.mock_object(self.client,
923 'get_vserver_info',
924 mock.Mock(return_value=fake.VSERVER_INFO))
925 self.mock_object(self.client,
926 'get_vserver_root_volume_name',
927 mock.Mock(return_value=fake.ROOT_VOLUME_NAME))
928 self.mock_object(self.vserver_client,
929 'get_vserver_volume_count',
930 mock.Mock(return_value=1))
931 self.mock_object(self.client, 'send_request')
932 self.mock_object(self.vserver_client,
933 'offline_volume',
934 self._mock_api_error())
935 self.mock_object(self.vserver_client, 'delete_volume')
937 self.assertRaises(netapp_api.NaApiError,
938 self.client.delete_vserver,
939 fake.VSERVER_NAME,
940 self.vserver_client)
942 def test_delete_vserver_multiple_volumes(self):
944 self.mock_object(self.client,
945 'get_vserver_info',
946 mock.Mock(return_value=fake.VSERVER_INFO))
947 self.mock_object(self.client,
948 'get_vserver_root_volume_name',
949 mock.Mock(return_value=fake.ROOT_VOLUME_NAME))
950 self.mock_object(self.vserver_client,
951 'get_vserver_volume_count',
952 mock.Mock(return_value=2))
954 self.assertRaises(exception.NetAppException,
955 self.client.delete_vserver,
956 fake.VSERVER_NAME,
957 self.vserver_client)
959 def test_delete_vserver_not_found(self):
961 self.mock_object(self.client,
962 'get_vserver_info',
963 mock.Mock(return_value=None))
965 self.client.delete_vserver(fake.VSERVER_NAME,
966 self.vserver_client)
968 self.assertEqual(1, client_cmode.LOG.error.call_count)
970 def test_terminate_vserver_services(self):
972 self.mock_object(self.vserver_client, 'send_request')
974 self.client._terminate_vserver_services(fake.VSERVER_NAME,
975 self.vserver_client,
976 [fake.CIFS_SECURITY_SERVICE])
978 cifs_server_delete_args = {
979 'admin-password': fake.CIFS_SECURITY_SERVICE['password'],
980 'admin-username': fake.CIFS_SECURITY_SERVICE['user'],
981 }
982 self.vserver_client.send_request.assert_has_calls([
983 mock.call('cifs-server-delete', cifs_server_delete_args)])
985 def test_terminate_vserver_services_cifs_not_found(self):
987 self.mock_object(self.vserver_client,
988 'send_request',
989 self._mock_api_error(
990 code=netapp_api.EOBJECTNOTFOUND))
992 self.client._terminate_vserver_services(fake.VSERVER_NAME,
993 self.vserver_client,
994 [fake.CIFS_SECURITY_SERVICE])
996 cifs_server_delete_args = {
997 'admin-password': fake.CIFS_SECURITY_SERVICE['password'],
998 'admin-username': fake.CIFS_SECURITY_SERVICE['user'],
999 }
1000 self.vserver_client.send_request.assert_has_calls([
1001 mock.call('cifs-server-delete', cifs_server_delete_args)])
1002 self.assertEqual(1, client_cmode.LOG.error.call_count)
1004 def test_terminate_vserver_services_api_error(self):
1006 side_effects = [netapp_api.NaApiError(code='fake'), None]
1007 self.mock_object(self.vserver_client,
1008 'send_request',
1009 mock.Mock(side_effect=side_effects))
1011 self.client._terminate_vserver_services(fake.VSERVER_NAME,
1012 self.vserver_client,
1013 [fake.CIFS_SECURITY_SERVICE])
1015 cifs_server_delete_args = {
1016 'admin-password': fake.CIFS_SECURITY_SERVICE['password'],
1017 'admin-username': fake.CIFS_SECURITY_SERVICE['user'],
1018 }
1019 cifs_server_delete_force_args = {
1020 'force-account-delete': 'true',
1021 }
1022 self.vserver_client.send_request.assert_has_calls([
1023 mock.call('cifs-server-delete', cifs_server_delete_args),
1024 mock.call('cifs-server-delete', cifs_server_delete_force_args)])
1025 self.assertEqual(0, client_cmode.LOG.error.call_count)
1027 def test_list_cluster_nodes(self):
1029 api_response = netapp_api.NaElement(
1030 fake.SYSTEM_NODE_GET_ITER_RESPONSE)
1031 self.mock_object(self.client,
1032 'send_request',
1033 mock.Mock(return_value=api_response))
1035 result = self.client.list_cluster_nodes()
1037 self.assertListEqual([fake.NODE_NAME], result)
1039 def test_list_cluster_nodes_not_found(self):
1041 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
1042 self.mock_object(self.client,
1043 'send_request',
1044 mock.Mock(return_value=api_response))
1046 result = self.client.list_cluster_nodes()
1048 self.assertListEqual([], result)
1050 def test_list_node_data_ports(self):
1052 self.mock_object(self.client,
1053 'get_node_data_ports',
1054 mock.Mock(return_value=fake.SPEED_SORTED_PORTS))
1056 result = self.client.list_node_data_ports(fake.NODE_NAME)
1058 self.assertSequenceEqual(fake.SPEED_SORTED_PORT_NAMES, result)
1060 def test_get_node_data_ports(self):
1062 api_response = netapp_api.NaElement(fake.NET_PORT_GET_ITER_RESPONSE)
1063 self.mock_object(self.client,
1064 'send_iter_request',
1065 mock.Mock(return_value=api_response))
1067 result = self.client.get_node_data_ports(fake.NODE_NAME)
1069 net_port_get_iter_args = {
1070 'query': {
1071 'net-port-info': {
1072 'node': fake.NODE_NAME,
1073 'link-status': 'up',
1074 'port-type': 'physical|if_group',
1075 'role': 'data',
1076 },
1077 },
1078 'desired-attributes': {
1079 'net-port-info': {
1080 'port': None,
1081 'node': None,
1082 'operational-speed': None,
1083 'ifgrp-port': None,
1084 },
1085 },
1086 }
1088 self.assertSequenceEqual(fake.SPEED_SORTED_PORTS, result)
1089 self.client.send_iter_request.assert_has_calls([
1090 mock.call('net-port-get-iter', net_port_get_iter_args)])
1092 def test_get_node_data_ports_not_found(self):
1094 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
1095 self.mock_object(self.client,
1096 'send_iter_request',
1097 mock.Mock(return_value=api_response))
1099 result = self.client.get_node_data_ports(fake.NODE_NAME)
1101 self.assertSequenceEqual([], result)
1103 def test_sort_data_ports_by_speed(self):
1105 result = self.client._sort_data_ports_by_speed(
1106 fake.UNSORTED_PORTS_ALL_SPEEDS)
1108 self.assertSequenceEqual(fake.SORTED_PORTS_ALL_SPEEDS, result)
1110 def test_list_root_aggregates(self):
1112 api_response = netapp_api.NaElement(
1113 fake.AGGR_GET_ITER_ROOT_AGGR_RESPONSE)
1114 self.mock_object(self.client,
1115 'send_iter_request',
1116 mock.Mock(return_value=api_response))
1118 result = self.client.list_root_aggregates()
1120 aggr_get_iter_args = {
1121 'desired-attributes': {
1122 'aggr-attributes': {
1123 'aggregate-name': None,
1124 'aggr-raid-attributes': {
1125 'has-local-root': None,
1126 'has-partner-root': None,
1127 },
1128 },
1129 }
1130 }
1131 self.assertSequenceEqual(fake.ROOT_AGGREGATE_NAMES, result)
1132 self.client.send_iter_request.assert_has_calls([
1133 mock.call('aggr-get-iter', aggr_get_iter_args)])
1135 def test_list_non_root_aggregates(self):
1137 api_response = netapp_api.NaElement(
1138 fake.AGGR_GET_ITER_NON_ROOT_AGGR_RESPONSE)
1139 self.mock_object(self.client,
1140 'send_iter_request',
1141 mock.Mock(return_value=api_response))
1143 result = self.client.list_non_root_aggregates()
1145 aggr_get_iter_args = {
1146 'query': {
1147 'aggr-attributes': {
1148 'aggr-raid-attributes': {
1149 'has-local-root': 'false',
1150 'has-partner-root': 'false',
1151 }
1152 },
1153 },
1154 'desired-attributes': {
1155 'aggr-attributes': {
1156 'aggregate-name': None,
1157 },
1158 },
1159 }
1160 self.assertSequenceEqual(fake.SHARE_AGGREGATE_NAMES, result)
1161 self.client.send_iter_request.assert_has_calls([
1162 mock.call('aggr-get-iter', aggr_get_iter_args)])
1164 def test_list_aggregates(self):
1166 api_response = netapp_api.NaElement(fake.AGGR_GET_NAMES_RESPONSE)
1167 self.mock_object(self.client,
1168 'send_iter_request',
1169 mock.Mock(return_value=api_response))
1171 result = self.client._list_aggregates()
1173 aggr_get_iter_args = {
1174 'desired-attributes': {
1175 'aggr-attributes': {
1176 'aggregate-name': None,
1177 },
1178 },
1179 }
1180 self.assertSequenceEqual(
1181 fake.ROOT_AGGREGATE_NAMES + fake.SHARE_AGGREGATE_NAMES, result)
1182 self.client.send_iter_request.assert_has_calls([
1183 mock.call('aggr-get-iter', aggr_get_iter_args)])
1185 def test_list_aggregates_not_found(self):
1187 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
1188 self.mock_object(self.client,
1189 'send_request',
1190 mock.Mock(return_value=api_response))
1192 self.assertRaises(exception.NetAppException,
1193 self.client._list_aggregates)
1195 def test_list_vserver_aggregates(self):
1197 self.mock_object(self.vserver_client,
1198 'get_vserver_aggregate_capacities',
1199 mock.Mock(return_value=fake.VSERVER_AGGREGATES))
1201 result = self.vserver_client.list_vserver_aggregates()
1203 self.assertListEqual(list(fake.VSERVER_AGGREGATES.keys()), result)
1205 def test_list_vserver_aggregates_none_found(self):
1207 self.mock_object(self.vserver_client,
1208 'get_vserver_aggregate_capacities',
1209 mock.Mock(return_value={}))
1211 result = self.vserver_client.list_vserver_aggregates()
1213 self.assertListEqual([], result)
1215 def test_create_network_interface(self):
1217 self.mock_object(self.client, 'send_request')
1219 lif_create_args = {
1220 'address': fake.IP_ADDRESS,
1221 'administrative-status': 'up',
1222 'data-protocols': [
1223 {'data-protocol': 'nfs'},
1224 {'data-protocol': 'cifs'}
1225 ],
1226 'home-node': fake.NODE_NAME,
1227 'home-port': fake.VLAN_PORT,
1228 'netmask': fake.NETMASK,
1229 'interface-name': fake.LIF_NAME,
1230 'role': 'data',
1231 'vserver': fake.VSERVER_NAME,
1232 }
1233 self.client.create_network_interface(fake.IP_ADDRESS,
1234 fake.NETMASK,
1235 fake.NODE_NAME,
1236 fake.VLAN_PORT,
1237 fake.VSERVER_NAME,
1238 fake.LIF_NAME)
1240 self.client.send_request.assert_called_once_with(
1241 'net-interface-create', lif_create_args)
1243 @ddt.data((None, True), (fake.VLAN, True), (None, False),
1244 (fake.VLAN, False))
1245 @ddt.unpack
1246 def test_create_port_and_broadcast_domain(self, fake_vlan,
1247 broadcast_domains_supported):
1249 self.client.features.add_feature(
1250 'BROADCAST_DOMAINS', broadcast_domains_supported)
1252 mock_create_vlan = self.mock_object(
1253 self.client, '_create_vlan')
1254 mock_ensure_broadcast = self.mock_object(
1255 self.client, '_ensure_broadcast_domain_for_port')
1257 result = self.client.create_port_and_broadcast_domain(
1258 fake.NODE_NAME, fake.PORT, fake_vlan, fake.MTU, fake.IPSPACE_NAME)
1260 if fake_vlan:
1261 mock_create_vlan.assert_called_once_with(
1262 fake.NODE_NAME, fake.PORT, fake_vlan)
1264 fake_home_port_name = (
1265 f'{fake.PORT}-{fake_vlan}' if fake_vlan else fake.PORT)
1266 if broadcast_domains_supported:
1267 mock_ensure_broadcast.assert_called_once_with(
1268 fake.NODE_NAME, fake_home_port_name, fake.MTU,
1269 ipspace=fake.IPSPACE_NAME)
1271 self.assertEqual(fake_home_port_name, result)
1273 def test_create_vlan(self):
1275 self.mock_object(self.client, 'send_request')
1277 vlan_create_args = {
1278 'vlan-info': {
1279 'parent-interface': fake.PORT,
1280 'node': fake.NODE_NAME,
1281 'vlanid': fake.VLAN
1282 }
1283 }
1284 self.client._create_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)
1286 self.client.send_request.assert_has_calls([
1287 mock.call('net-vlan-create', vlan_create_args)])
1289 def test_create_vlan_already_present(self):
1291 self.mock_object(self.client,
1292 'send_request',
1293 self._mock_api_error(code=netapp_api.EDUPLICATEENTRY))
1295 vlan_create_args = {
1296 'vlan-info': {
1297 'parent-interface': fake.PORT,
1298 'node': fake.NODE_NAME,
1299 'vlanid': fake.VLAN
1300 }
1301 }
1302 self.client._create_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)
1304 self.client.send_request.assert_has_calls([
1305 mock.call('net-vlan-create', vlan_create_args)])
1306 self.assertEqual(1, client_cmode.LOG.debug.call_count)
1308 def test_create_vlan_api_error(self):
1310 self.mock_object(self.client, 'send_request', self._mock_api_error())
1312 self.assertRaises(exception.NetAppException,
1313 self.client._create_vlan,
1314 fake.NODE_NAME,
1315 fake.PORT,
1316 fake.VLAN)
1318 def test_delete_vlan(self):
1320 self.mock_object(self.client, 'send_request')
1322 vlan_delete_args = {
1323 'vlan-info': {
1324 'parent-interface': fake.PORT,
1325 'node': fake.NODE_NAME,
1326 'vlanid': fake.VLAN
1327 }
1328 }
1329 self.client.delete_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)
1331 self.client.send_request.assert_has_calls([
1332 mock.call('net-vlan-delete', vlan_delete_args)])
1334 def test_delete_vlan_still_used(self):
1336 self.mock_object(self.client,
1337 'send_request',
1338 self._mock_api_error(code=netapp_api.EAPIERROR,
1339 message='Port already has a '
1340 'lif bound. '))
1342 vlan_delete_args = {
1343 'vlan-info': {
1344 'parent-interface': fake.PORT,
1345 'node': fake.NODE_NAME,
1346 'vlanid': fake.VLAN
1347 }
1348 }
1349 self.client.delete_vlan(fake.NODE_NAME, fake.PORT, fake.VLAN)
1351 self.client.send_request.assert_has_calls([
1352 mock.call('net-vlan-delete', vlan_delete_args)])
1353 self.assertEqual(1, client_cmode.LOG.debug.call_count)
1355 def test_delete_vlan_api_error(self):
1357 self.mock_object(self.client, 'send_request', self._mock_api_error())
1359 self.assertRaises(exception.NetAppException,
1360 self.client.delete_vlan,
1361 fake.NODE_NAME,
1362 fake.PORT,
1363 fake.VLAN)
1365 @ddt.data(('10.10.10.0/24', '10.10.10.1', False),
1366 ('fc00::/7', 'fe80::1', False),
1367 ('0.0.0.0/0', '10.10.10.1', True),
1368 ('::/0', 'fe80::1', True))
1369 @ddt.unpack
1370 def test_create_route(self, subnet, gateway, omit_destination):
1371 api_response = netapp_api.NaElement(
1372 fake.NET_ROUTES_CREATE_RESPONSE)
1373 expected_api_args = {
1374 'destination': subnet,
1375 'gateway': gateway,
1376 'return-record': 'true',
1377 }
1378 self.mock_object(
1379 self.client, 'send_request', mock.Mock(return_value=api_response))
1381 destination = None if omit_destination else subnet
1382 self.client.create_route(gateway, destination=destination)
1384 self.client.send_request.assert_called_once_with(
1385 'net-routes-create', expected_api_args)
1387 def test_create_route_duplicate(self):
1388 self.mock_object(client_cmode.LOG, 'debug')
1389 expected_api_args = {
1390 'destination': fake.SUBNET,
1391 'gateway': fake.GATEWAY,
1392 'return-record': 'true',
1393 }
1394 self.mock_object(
1395 self.client, 'send_request',
1396 mock.Mock(side_effect=self._mock_api_error(
1397 code=netapp_api.EAPIERROR, message='Duplicate route exists.')))
1399 self.client.create_route(fake.GATEWAY, destination=fake.SUBNET)
1401 self.client.send_request.assert_called_once_with(
1402 'net-routes-create', expected_api_args)
1403 self.assertEqual(1, client_cmode.LOG.debug.call_count)
1405 def test_create_route_api_error(self):
1406 expected_api_args = {
1407 'destination': fake.SUBNET,
1408 'gateway': fake.GATEWAY,
1409 'return-record': 'true',
1410 }
1411 self.mock_object(
1412 self.client, 'send_request',
1413 mock.Mock(side_effect=self._mock_api_error()))
1415 self.assertRaises(exception.NetAppException,
1416 self.client.create_route,
1417 fake.GATEWAY, destination=fake.SUBNET)
1419 self.client.send_request.assert_called_once_with(
1420 'net-routes-create', expected_api_args)
1422 def test_create_route_without_gateway(self):
1423 self.mock_object(self.client, 'send_request')
1424 self.client.create_route(None, destination=fake.SUBNET)
1425 self.assertFalse(self.client.send_request.called)
1427 def test_ensure_broadcast_domain_for_port_domain_match(self):
1429 port_info = {
1430 'ipspace': fake.IPSPACE_NAME,
1431 'broadcast-domain': fake.BROADCAST_DOMAIN,
1432 }
1433 self.mock_object(self.client,
1434 '_get_broadcast_domain_for_port',
1435 mock.Mock(return_value=port_info))
1436 self.mock_object(self.client,
1437 '_broadcast_domain_exists',
1438 mock.Mock(return_value=True))
1439 self.mock_object(self.client, '_create_broadcast_domain')
1440 self.mock_object(self.client, '_modify_broadcast_domain')
1441 self.mock_object(self.client, '_add_port_to_broadcast_domain')
1443 self.client._ensure_broadcast_domain_for_port(
1444 fake.NODE_NAME, fake.PORT, fake.MTU, ipspace=fake.IPSPACE_NAME)
1446 self.client._get_broadcast_domain_for_port.assert_called_once_with(
1447 fake.NODE_NAME, fake.PORT)
1448 self.client._modify_broadcast_domain.assert_called_once_with(
1449 fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME, fake.MTU)
1450 self.assertFalse(self.client._broadcast_domain_exists.called)
1451 self.assertFalse(self.client._create_broadcast_domain.called)
1452 self.assertFalse(self.client._add_port_to_broadcast_domain.called)
1454 @ddt.data(fake.IPSPACE_NAME, client_cmode.DEFAULT_IPSPACE)
1455 def test_ensure_broadcast_domain_for_port_other_domain(self, ipspace):
1457 port_info = {
1458 'ipspace': ipspace,
1459 'broadcast-domain': 'other_domain',
1460 }
1461 self.mock_object(self.client,
1462 '_get_broadcast_domain_for_port',
1463 mock.Mock(return_value=port_info))
1464 self.mock_object(self.client,
1465 '_broadcast_domain_exists',
1466 mock.Mock(return_value=True))
1467 self.mock_object(self.client, '_create_broadcast_domain')
1468 self.mock_object(self.client, '_modify_broadcast_domain')
1469 self.mock_object(self.client, '_remove_port_from_broadcast_domain')
1470 self.mock_object(self.client, '_add_port_to_broadcast_domain')
1472 self.client._ensure_broadcast_domain_for_port(
1473 fake.NODE_NAME, fake.PORT, ipspace=fake.IPSPACE_NAME, mtu=fake.MTU)
1475 self.client._get_broadcast_domain_for_port.assert_called_once_with(
1476 fake.NODE_NAME, fake.PORT)
1477 self.client._remove_port_from_broadcast_domain.assert_called_once_with(
1478 fake.NODE_NAME, fake.PORT, 'other_domain', ipspace)
1479 self.client._broadcast_domain_exists.assert_called_once_with(
1480 fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME)
1481 self.assertFalse(self.client._create_broadcast_domain.called)
1482 self.client._modify_broadcast_domain.assert_called_once_with(
1483 fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME, fake.MTU)
1484 self.client._add_port_to_broadcast_domain.assert_called_once_with(
1485 fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN,
1486 fake.IPSPACE_NAME)
1488 def test_ensure_broadcast_domain_for_port_no_domain(self):
1490 port_info = {
1491 'ipspace': fake.IPSPACE_NAME,
1492 'broadcast-domain': None,
1493 }
1494 self.mock_object(self.client,
1495 '_get_broadcast_domain_for_port',
1496 mock.Mock(return_value=port_info))
1497 self.mock_object(self.client,
1498 '_broadcast_domain_exists',
1499 mock.Mock(return_value=False))
1500 self.mock_object(self.client, '_create_broadcast_domain')
1501 self.mock_object(self.client, '_modify_broadcast_domain')
1502 self.mock_object(self.client, '_remove_port_from_broadcast_domain')
1503 self.mock_object(self.client, '_add_port_to_broadcast_domain')
1505 self.client._ensure_broadcast_domain_for_port(
1506 fake.NODE_NAME, fake.PORT, ipspace=fake.IPSPACE_NAME, mtu=fake.MTU)
1508 self.client._get_broadcast_domain_for_port.assert_called_once_with(
1509 fake.NODE_NAME, fake.PORT)
1510 self.assertFalse(self.client._remove_port_from_broadcast_domain.called)
1511 self.client._broadcast_domain_exists.assert_called_once_with(
1512 fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME)
1513 self.client._create_broadcast_domain.assert_called_once_with(
1514 fake.BROADCAST_DOMAIN, fake.IPSPACE_NAME, fake.MTU)
1515 self.assertFalse(self.client._modify_broadcast_domain.called)
1516 self.client._add_port_to_broadcast_domain.assert_called_once_with(
1517 fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN,
1518 fake.IPSPACE_NAME)
1520 def test_get_broadcast_domain_for_port(self):
1522 api_response = netapp_api.NaElement(
1523 fake.NET_PORT_GET_ITER_BROADCAST_DOMAIN_RESPONSE)
1524 self.mock_object(self.client,
1525 'send_iter_request',
1526 mock.Mock(return_value=api_response))
1528 net_port_get_iter_args = {
1529 'query': {
1530 'net-port-info': {
1531 'node': fake.NODE_NAME,
1532 'port': fake.PORT,
1533 },
1534 },
1535 'desired-attributes': {
1536 'net-port-info': {
1537 'broadcast-domain': None,
1538 'ipspace': None,
1539 },
1540 },
1541 }
1542 result = self.client._get_broadcast_domain_for_port(fake.NODE_NAME,
1543 fake.PORT)
1545 expected = {
1546 'broadcast-domain': fake.BROADCAST_DOMAIN,
1547 'ipspace': fake.IPSPACE_NAME,
1548 }
1549 self.client.send_iter_request.assert_has_calls([
1550 mock.call('net-port-get-iter', net_port_get_iter_args)])
1551 self.assertEqual(expected, result)
1553 def test_get_broadcast_domain_for_port_port_not_found(self):
1555 api_response = netapp_api.NaElement(
1556 fake.NO_RECORDS_RESPONSE)
1557 self.mock_object(self.client,
1558 'send_iter_request',
1559 mock.Mock(return_value=api_response))
1561 self.assertRaises(exception.NetAppException,
1562 self.client._get_broadcast_domain_for_port,
1563 fake.NODE_NAME,
1564 fake.PORT)
1566 def test_get_broadcast_domain_for_port_domain_not_found(self):
1568 api_response = netapp_api.NaElement(
1569 fake.NET_PORT_GET_ITER_BROADCAST_DOMAIN_MISSING_RESPONSE)
1570 self.mock_object(self.client,
1571 'send_iter_request',
1572 mock.Mock(return_value=api_response))
1574 result = self.client._get_broadcast_domain_for_port(fake.NODE_NAME,
1575 fake.PORT)
1577 expected = {
1578 'broadcast-domain': None,
1579 'ipspace': fake.IPSPACE_NAME,
1580 }
1581 self.assertEqual(expected, result)
1583 def test_broadcast_domain_exists(self):
1585 api_response = netapp_api.NaElement(
1586 fake.NET_PORT_BROADCAST_DOMAIN_GET_ITER_RESPONSE)
1587 self.mock_object(self.client,
1588 'send_iter_request',
1589 mock.Mock(return_value=api_response))
1591 result = self.client._broadcast_domain_exists(fake.BROADCAST_DOMAIN,
1592 fake.IPSPACE_NAME)
1594 net_port_broadcast_domain_get_iter_args = {
1595 'query': {
1596 'net-port-broadcast-domain-info': {
1597 'ipspace': fake.IPSPACE_NAME,
1598 'broadcast-domain': fake.BROADCAST_DOMAIN,
1599 },
1600 },
1601 'desired-attributes': {
1602 'net-port-broadcast-domain-info': None,
1603 },
1604 }
1605 self.client.send_iter_request.assert_has_calls([
1606 mock.call('net-port-broadcast-domain-get-iter',
1607 net_port_broadcast_domain_get_iter_args)])
1608 self.assertTrue(result)
1610 def test_broadcast_domain_exists_not_found(self):
1612 api_response = netapp_api.NaElement(
1613 fake.NO_RECORDS_RESPONSE)
1614 self.mock_object(self.client,
1615 'send_request',
1616 mock.Mock(return_value=api_response))
1618 result = self.client._broadcast_domain_exists(fake.BROADCAST_DOMAIN,
1619 fake.IPSPACE_NAME)
1621 self.assertFalse(result)
1623 def test_create_broadcast_domain(self):
1625 self.mock_object(self.client, 'send_request')
1627 result = self.client._create_broadcast_domain(fake.BROADCAST_DOMAIN,
1628 fake.IPSPACE_NAME,
1629 fake.MTU)
1631 net_port_broadcast_domain_create_args = {
1632 'ipspace': fake.IPSPACE_NAME,
1633 'broadcast-domain': fake.BROADCAST_DOMAIN,
1634 'mtu': fake.MTU,
1635 }
1636 self.assertIsNone(result)
1637 self.client.send_request.assert_has_calls([
1638 mock.call('net-port-broadcast-domain-create',
1639 net_port_broadcast_domain_create_args)])
1641 def test_modify_broadcast_domain(self):
1643 self.mock_object(self.client, 'send_request')
1645 result = self.client._modify_broadcast_domain(fake.BROADCAST_DOMAIN,
1646 fake.IPSPACE_NAME,
1647 fake.MTU)
1649 net_port_broadcast_domain_modify_args = {
1650 'ipspace': fake.IPSPACE_NAME,
1651 'broadcast-domain': fake.BROADCAST_DOMAIN,
1652 'mtu': fake.MTU,
1653 }
1654 self.assertIsNone(result)
1655 self.client.send_request.assert_called_once_with(
1656 'net-port-broadcast-domain-modify',
1657 net_port_broadcast_domain_modify_args)
1659 def test_delete_broadcast_domain(self):
1661 self.mock_object(self.client, 'send_request')
1663 result = self.client._delete_broadcast_domain(fake.BROADCAST_DOMAIN,
1664 fake.IPSPACE_NAME)
1666 net_port_broadcast_domain_delete_args = {
1667 'ipspace': fake.IPSPACE_NAME,
1668 'broadcast-domain': fake.BROADCAST_DOMAIN,
1669 }
1670 self.assertIsNone(result)
1671 self.client.send_request.assert_has_calls([
1672 mock.call('net-port-broadcast-domain-destroy',
1673 net_port_broadcast_domain_delete_args)])
1675 def test_delete_broadcast_domains_for_ipspace_not_found(self):
1677 self.mock_object(self.client,
1678 'get_ipspaces',
1679 mock.Mock(return_value=[]))
1680 self.mock_object(self.client, '_delete_broadcast_domain')
1682 self.client._delete_broadcast_domains_for_ipspace(fake.IPSPACE_NAME)
1684 self.client.get_ipspaces.assert_called_once_with(
1685 ipspace_name=fake.IPSPACE_NAME)
1686 self.assertFalse(self.client._delete_broadcast_domain.called)
1688 def test_delete_broadcast_domains_for_ipspace(self):
1690 self.mock_object(self.client,
1691 'get_ipspaces',
1692 mock.Mock(return_value=fake.IPSPACES))
1693 self.mock_object(self.client, '_delete_broadcast_domain')
1695 self.client._delete_broadcast_domains_for_ipspace(fake.IPSPACE_NAME)
1697 self.client.get_ipspaces.assert_called_once_with(
1698 ipspace_name=fake.IPSPACE_NAME)
1699 self.client._delete_broadcast_domain.assert_called_once_with(
1700 fake.IPSPACES[0]['broadcast-domains'][0], fake.IPSPACE_NAME)
1702 def test_add_port_to_broadcast_domain(self):
1704 self.mock_object(self.client, 'send_request')
1706 add_port_to_broadcast_domain_args = {
1707 'ipspace': fake.IPSPACE_NAME,
1708 'broadcast-domain': fake.BROADCAST_DOMAIN,
1709 'ports': {
1710 'net-qualified-port-name': ':'.join([fake.NODE_NAME,
1711 fake.VLAN_PORT])
1712 }
1713 }
1714 result = self.client._add_port_to_broadcast_domain(
1715 fake.NODE_NAME, fake.VLAN_PORT, fake.BROADCAST_DOMAIN,
1716 fake.IPSPACE_NAME)
1718 self.assertIsNone(result)
1719 self.client.send_request.assert_has_calls([
1720 mock.call('net-port-broadcast-domain-add-ports',
1721 add_port_to_broadcast_domain_args)])
1723 def test_add_port_to_broadcast_domain_already_present(self):
1725 self.mock_object(self.client, 'send_request', self._mock_api_error(
1726 code=netapp_api.
1727 E_VIFMGR_PORT_ALREADY_ASSIGNED_TO_BROADCAST_DOMAIN))
1729 result = self.client._add_port_to_broadcast_domain(
1730 fake.NODE_NAME, fake.VLAN_PORT, fake.BROADCAST_DOMAIN,
1731 fake.IPSPACE_NAME)
1733 self.assertIsNone(result)
1735 def test_add_port_to_broadcast_domain_api_error(self):
1737 self.mock_object(self.client, 'send_request', self._mock_api_error())
1739 self.assertRaises(exception.NetAppException,
1740 self.client._add_port_to_broadcast_domain,
1741 fake.NODE_NAME,
1742 fake.VLAN_PORT,
1743 fake.BROADCAST_DOMAIN,
1744 fake.IPSPACE_NAME)
1746 def test_remove_port_from_broadcast_domain(self):
1748 self.mock_object(self.client, 'send_request')
1750 result = self.client._remove_port_from_broadcast_domain(
1751 fake.NODE_NAME, fake.VLAN_PORT, fake.BROADCAST_DOMAIN,
1752 fake.IPSPACE_NAME)
1754 net_port_broadcast_domain_remove_ports_args = {
1755 'ipspace': fake.IPSPACE_NAME,
1756 'broadcast-domain': fake.BROADCAST_DOMAIN,
1757 'ports': {
1758 'net-qualified-port-name': ':'.join([fake.NODE_NAME,
1759 fake.VLAN_PORT])
1760 }
1761 }
1762 self.assertIsNone(result)
1763 self.client.send_request.assert_has_calls([
1764 mock.call('net-port-broadcast-domain-remove-ports',
1765 net_port_broadcast_domain_remove_ports_args)])
1767 def test_network_interface_exists(self):
1769 api_response = netapp_api.NaElement(
1770 fake.NET_INTERFACE_GET_ONE_RESPONSE)
1771 self.mock_object(self.client,
1772 'send_iter_request',
1773 mock.Mock(return_value=api_response))
1775 net_interface_get_args = {
1776 'query': {
1777 'net-interface-info': {
1778 'address': fake.IP_ADDRESS,
1779 'home-node': fake.NODE_NAME,
1780 'home-port': fake.VLAN_PORT,
1781 'netmask': fake.NETMASK,
1782 'vserver': fake.VSERVER_NAME}
1783 },
1784 'desired-attributes': {
1785 'net-interface-info': {
1786 'interface-name': None,
1787 }
1788 }
1789 }
1790 result = self.client.network_interface_exists(
1791 fake.VSERVER_NAME, fake.NODE_NAME, fake.PORT, fake.IP_ADDRESS,
1792 fake.NETMASK, fake.VLAN)
1794 self.client.send_iter_request.assert_has_calls([
1795 mock.call('net-interface-get-iter', net_interface_get_args)])
1796 self.assertTrue(result)
1798 def test_network_interface_exists_not_found(self):
1800 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
1801 self.mock_object(self.client,
1802 'send_iter_request',
1803 mock.Mock(return_value=api_response))
1805 net_interface_get_args = {
1806 'query': {
1807 'net-interface-info': {
1808 'address': fake.IP_ADDRESS,
1809 'home-node': fake.NODE_NAME,
1810 'home-port': fake.PORT,
1811 'netmask': fake.NETMASK,
1812 'vserver': fake.VSERVER_NAME}
1813 },
1814 'desired-attributes': {
1815 'net-interface-info': {
1816 'interface-name': None,
1817 }
1818 }
1819 }
1820 result = self.client.network_interface_exists(
1821 fake.VSERVER_NAME, fake.NODE_NAME, fake.PORT, fake.IP_ADDRESS,
1822 fake.NETMASK, None)
1823 self.client.send_iter_request.assert_has_calls([
1824 mock.call('net-interface-get-iter', net_interface_get_args)])
1825 self.assertFalse(result)
1827 def test_list_network_interfaces(self):
1829 api_response = netapp_api.NaElement(
1830 fake.NET_INTERFACE_GET_ITER_RESPONSE)
1831 self.mock_object(self.client,
1832 'send_iter_request',
1833 mock.Mock(return_value=api_response))
1835 net_interface_get_args = {
1836 'desired-attributes': {
1837 'net-interface-info': {
1838 'interface-name': None,
1839 }
1840 }
1841 }
1843 result = self.client.list_network_interfaces()
1845 self.client.send_iter_request.assert_has_calls([
1846 mock.call('net-interface-get-iter', net_interface_get_args)])
1847 self.assertSequenceEqual(fake.LIF_NAMES, result)
1849 def test_list_network_interfaces_not_found(self):
1851 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
1852 self.mock_object(self.client,
1853 'send_request',
1854 mock.Mock(return_value=api_response))
1856 result = self.client.list_network_interfaces()
1858 self.assertListEqual([], result)
1860 def test_get_network_interfaces(self):
1862 api_response = netapp_api.NaElement(
1863 fake.NET_INTERFACE_GET_ITER_RESPONSE)
1864 self.mock_object(self.client,
1865 'send_iter_request',
1866 mock.Mock(return_value=api_response))
1868 result = self.client.get_network_interfaces()
1870 self.client.send_iter_request.assert_has_calls([
1871 mock.call('net-interface-get-iter', None)])
1872 self.assertSequenceEqual(fake.LIFS, result)
1874 def test_get_network_interfaces_filtered_by_protocol(self):
1876 api_response = netapp_api.NaElement(
1877 fake.NET_INTERFACE_GET_ITER_RESPONSE_NFS)
1878 self.mock_object(self.client,
1879 'send_iter_request',
1880 mock.Mock(return_value=api_response))
1882 result = self.client.get_network_interfaces(protocols=['NFS'])
1884 net_interface_get_args = {
1885 'query': {
1886 'net-interface-info': {
1887 'data-protocols': {
1888 'data-protocol': 'nfs',
1889 }
1890 }
1891 }
1892 }
1894 self.client.send_iter_request.assert_has_calls([
1895 mock.call('net-interface-get-iter', net_interface_get_args)])
1896 self.assertListEqual(fake.NFS_LIFS, result)
1898 def test_get_network_interfaces_not_found(self):
1900 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
1901 self.mock_object(self.client,
1902 'send_iter_request',
1903 mock.Mock(return_value=api_response))
1905 result = self.client.get_network_interfaces()
1907 self.client.send_iter_request.assert_has_calls([
1908 mock.call('net-interface-get-iter', None)])
1909 self.assertListEqual([], result)
1911 def test_disable_network_interface(self):
1912 interface_name = fake.NETWORK_INTERFACES[0]['interface-name']
1913 vserver_name = fake.VSERVER_NAME
1914 expected_api_args = {
1915 'administrative-status': 'down',
1916 'interface-name': interface_name,
1917 'vserver': vserver_name,
1918 }
1920 self.mock_object(self.client, 'send_request')
1922 self.client.disable_network_interface(vserver_name, interface_name)
1924 self.client.send_request.assert_called_once_with(
1925 'net-interface-modify', expected_api_args)
1927 def test_delete_network_interface(self):
1928 interface_name = fake.NETWORK_INTERFACES[0]['interface-name']
1929 vserver_name = fake.VSERVER_NAME
1930 expected_api_args = {
1931 'interface-name': interface_name,
1932 'vserver': vserver_name,
1933 }
1935 self.mock_object(self.client, 'disable_network_interface')
1936 self.mock_object(self.client, 'send_request')
1938 self.client.delete_network_interface(vserver_name, interface_name)
1940 self.client.disable_network_interface.assert_called_once_with(
1941 vserver_name, interface_name)
1942 self.client.send_request.assert_called_once_with(
1943 'net-interface-delete', expected_api_args)
1945 def test_get_ipspaces(self):
1947 self.client.features.add_feature('IPSPACES')
1948 api_response = netapp_api.NaElement(
1949 fake.NET_IPSPACES_GET_ITER_RESPONSE)
1950 self.mock_object(self.client,
1951 'send_iter_request',
1952 mock.Mock(return_value=api_response))
1954 result = self.client.get_ipspaces(ipspace_name=fake.IPSPACE_NAME)
1956 net_ipspaces_get_iter_args = {
1957 'query': {
1958 'net-ipspaces-info': {
1959 'ipspace': fake.IPSPACE_NAME,
1960 },
1961 },
1962 }
1963 self.client.send_iter_request.assert_has_calls([
1964 mock.call('net-ipspaces-get-iter', net_ipspaces_get_iter_args)])
1965 self.assertEqual(fake.IPSPACES, result)
1967 def test_get_ipspaces_not_found(self):
1969 self.client.features.add_feature('IPSPACES')
1970 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
1971 self.mock_object(self.client,
1972 'send_iter_request',
1973 mock.Mock(return_value=api_response))
1975 result = self.client.get_ipspaces()
1977 net_ipspaces_get_iter_args = {}
1978 self.client.send_iter_request.assert_has_calls([
1979 mock.call('net-ipspaces-get-iter', net_ipspaces_get_iter_args)])
1980 self.assertEqual([], result)
1982 def test_get_ipspaces_not_supported(self):
1984 self.mock_object(self.client, 'send_iter_request')
1986 result = self.client.get_ipspaces()
1988 self.assertFalse(self.client.send_iter_request.called)
1989 self.assertEqual([], result)
1991 @ddt.data((fake.NET_IPSPACES_GET_ITER_RESPONSE, True),
1992 (fake.NO_RECORDS_RESPONSE, False))
1993 @ddt.unpack
1994 def test_ipspace_exists(self, api_response, expected):
1996 self.client.features.add_feature('IPSPACES')
1997 api_response = netapp_api.NaElement(api_response)
1998 self.mock_object(self.client,
1999 'send_iter_request',
2000 mock.Mock(return_value=api_response))
2002 result = self.client.ipspace_exists(fake.IPSPACE_NAME)
2004 net_ipspaces_get_iter_args = {
2005 'query': {
2006 'net-ipspaces-info': {
2007 'ipspace': fake.IPSPACE_NAME,
2008 },
2009 },
2010 'desired-attributes': {
2011 'net-ipspaces-info': {
2012 'ipspace': None,
2013 },
2014 },
2015 }
2016 self.client.send_iter_request.assert_has_calls([
2017 mock.call('net-ipspaces-get-iter', net_ipspaces_get_iter_args)])
2018 self.assertEqual(expected, result)
2020 def test_ipspace_exists_not_supported(self):
2022 result = self.client.ipspace_exists(fake.IPSPACE_NAME)
2024 self.assertFalse(result)
2026 def test_create_ipspace(self):
2028 self.mock_object(self.client, 'send_request')
2030 self.client.create_ipspace(fake.IPSPACE_NAME)
2032 net_ipspaces_create_args = {'ipspace': fake.IPSPACE_NAME}
2033 self.client.send_request.assert_has_calls([
2034 mock.call('net-ipspaces-create', net_ipspaces_create_args)])
2036 def test_delete_ipspace(self):
2038 self.client.features.add_feature('IPSPACES')
2039 mock_ipspace_has_data_vservers = self.mock_object(
2040 self.client, 'ipspace_has_data_vservers',
2041 mock.Mock(return_value=False))
2043 mock_delete_broadcast_domains_for_ipspace = self.mock_object(
2044 self.client, '_delete_broadcast_domains_for_ipspace')
2045 self.mock_object(self.client, 'send_request')
2047 self.client.delete_ipspace(fake.IPSPACE_NAME)
2049 net_ipspaces_destroy_args = {'ipspace': fake.IPSPACE_NAME}
2050 mock_ipspace_has_data_vservers.assert_called_once_with(
2051 fake.IPSPACE_NAME)
2052 mock_delete_broadcast_domains_for_ipspace.assert_called_once_with(
2053 fake.IPSPACE_NAME)
2054 self.client.send_request.assert_has_calls([
2055 mock.call('net-ipspaces-destroy', net_ipspaces_destroy_args)])
2057 def test_get_ipspace_name_for_vlan_port(self):
2058 self.client.features.add_feature('IPSPACES')
2059 api_response = netapp_api.NaElement(fake.NET_PORT_GET_RESPONSE)
2060 self.mock_object(self.client,
2061 'send_request',
2062 mock.Mock(return_value=api_response))
2064 ipspace = self.client.get_ipspace_name_for_vlan_port(
2065 fake.NODE_NAME, fake.PORT, fake.VLAN)
2067 port = '%(port)s-%(id)s' % {'port': fake.PORT, 'id': fake.VLAN}
2068 self.client.send_request.assert_called_once_with(
2069 'net-port-get',
2070 {'node': fake.NODE_NAME, 'port': port})
2071 self.assertEqual(fake.IPSPACE_NAME, ipspace)
2073 def test_get_ipspace_name_for_vlan_port_no_ipspace_feature(self):
2074 self.mock_object(self.client, 'send_request')
2076 ipspace = self.client.get_ipspace_name_for_vlan_port(
2077 fake.NODE_NAME, fake.PORT, fake.VLAN)
2079 self.client.send_request.assert_not_called()
2080 self.assertIsNone(ipspace)
2082 def test_get_ipspace_name_for_vlan_port_no_ipspace_found(self):
2083 self.client.features.add_feature('IPSPACES')
2084 self.mock_object(
2085 self.client,
2086 'send_request',
2087 self._mock_api_error(code=netapp_api.EOBJECTNOTFOUND))
2089 ipspace = self.client.get_ipspace_name_for_vlan_port(
2090 fake.NODE_NAME, fake.PORT, fake.VLAN)
2092 self.assertIsNone(ipspace)
2094 def test_get_ipspace_name_for_vlan_port_no_vlan(self):
2095 self.client.features.add_feature('IPSPACES')
2096 api_response = netapp_api.NaElement(fake.NET_PORT_GET_RESPONSE_NO_VLAN)
2097 self.mock_object(self.client,
2098 'send_request',
2099 mock.Mock(return_value=api_response))
2101 ipspace = self.client.get_ipspace_name_for_vlan_port(
2102 fake.NODE_NAME, fake.PORT, None)
2104 self.client.send_request.assert_called_once_with(
2105 'net-port-get',
2106 {'node': fake.NODE_NAME, 'port': fake.PORT})
2107 self.assertEqual(fake.IPSPACE_NAME, ipspace)
2109 def test_get_ipspace_name_for_vlan_port_raises_api_error(self):
2110 self.client.features.add_feature('IPSPACES')
2111 self.mock_object(self.client,
2112 'send_request',
2113 mock.Mock(side_effect=self._mock_api_error()))
2115 self.assertRaises(netapp_api.NaApiError,
2116 self.client.get_ipspace_name_for_vlan_port,
2117 fake.NODE_NAME, fake.VLAN_PORT, None)
2119 def test_add_vserver_to_ipspace(self):
2121 self.mock_object(self.client, 'send_request')
2123 self.client.add_vserver_to_ipspace(fake.IPSPACE_NAME,
2124 fake.VSERVER_NAME)
2126 net_ipspaces_assign_vserver_args = {
2127 'ipspace': fake.IPSPACE_NAME,
2128 'vserver': fake.VSERVER_NAME
2129 }
2130 self.client.send_request.assert_has_calls([
2131 mock.call('net-ipspaces-assign-vserver',
2132 net_ipspaces_assign_vserver_args)])
2134 def test_get_node_for_aggregate(self):
2136 api_response = netapp_api.NaElement(
2137 fake.AGGR_GET_NODE_RESPONSE).get_child_by_name(
2138 'attributes-list').get_children()
2139 self.mock_object(self.client,
2140 '_get_aggregates',
2141 mock.Mock(return_value=api_response))
2143 result = self.client.get_node_for_aggregate(fake.SHARE_AGGREGATE_NAME)
2145 desired_attributes = {
2146 'aggr-attributes': {
2147 'aggregate-name': None,
2148 'aggr-ownership-attributes': {
2149 'home-name': None,
2150 },
2151 },
2152 }
2154 self.client._get_aggregates.assert_has_calls([
2155 mock.call(
2156 aggregate_names=[fake.SHARE_AGGREGATE_NAME],
2157 desired_attributes=desired_attributes)])
2159 self.assertEqual(fake.NODE_NAME, result)
2161 def test_get_node_for_aggregate_none_requested(self):
2163 result = self.client.get_node_for_aggregate(None)
2165 self.assertIsNone(result)
2167 def test_get_node_for_aggregate_api_not_found(self):
2169 self.mock_object(self.client,
2170 'send_iter_request',
2171 mock.Mock(side_effect=self._mock_api_error(
2172 netapp_api.EAPINOTFOUND)))
2174 result = self.client.get_node_for_aggregate(fake.SHARE_AGGREGATE_NAME)
2176 self.assertIsNone(result)
2178 def test_get_node_for_aggregate_api_error(self):
2180 self.mock_object(self.client,
2181 'send_iter_request',
2182 self._mock_api_error())
2184 self.assertRaises(netapp_api.NaApiError,
2185 self.client.get_node_for_aggregate,
2186 fake.SHARE_AGGREGATE_NAME)
2188 def test_get_node_for_aggregate_not_found(self):
2190 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
2191 self.mock_object(self.client,
2192 'send_iter_request',
2193 mock.Mock(return_value=api_response))
2195 result = self.client.get_node_for_aggregate(fake.SHARE_AGGREGATE_NAME)
2197 self.assertIsNone(result)
2199 def test_get_cluster_aggregate_capacities(self):
2201 api_response = netapp_api.NaElement(
2202 fake.AGGR_GET_SPACE_RESPONSE).get_child_by_name(
2203 'attributes-list').get_children()
2204 self.mock_object(self.client,
2205 '_get_aggregates',
2206 mock.Mock(return_value=api_response))
2208 result = self.client.get_cluster_aggregate_capacities(
2209 fake.SHARE_AGGREGATE_NAMES)
2211 desired_attributes = {
2212 'aggr-attributes': {
2213 'aggregate-name': None,
2214 'aggr-space-attributes': {
2215 'size-available': None,
2216 'size-total': None,
2217 'size-used': None,
2218 }
2219 }
2220 }
2222 self.client._get_aggregates.assert_has_calls([
2223 mock.call(
2224 aggregate_names=fake.SHARE_AGGREGATE_NAMES,
2225 desired_attributes=desired_attributes)])
2227 expected = {
2228 fake.SHARE_AGGREGATE_NAMES[0]: {
2229 'available': 45670400,
2230 'total': 943718400,
2231 'used': 898048000,
2232 },
2233 fake.SHARE_AGGREGATE_NAMES[1]: {
2234 'available': 4267659264,
2235 'total': 7549747200,
2236 'used': 3282087936,
2237 },
2238 }
2239 self.assertDictEqual(expected, result)
2241 def test_get_cluster_aggregate_capacities_not_found(self):
2243 api_response = netapp_api.NaElement('none').get_children()
2244 self.mock_object(self.client,
2245 '_get_aggregates',
2246 mock.Mock(return_value=api_response))
2248 result = self.client.get_cluster_aggregate_capacities(
2249 fake.SHARE_AGGREGATE_NAMES)
2251 self.assertEqual({}, result)
2253 def test_get_cluster_aggregate_capacities_none_requested(self):
2255 result = self.client.get_cluster_aggregate_capacities([])
2257 self.assertEqual({}, result)
2259 def test_get_vserver_aggregate_capacities(self):
2261 api_response = netapp_api.NaElement(fake.VSERVER_GET_RESPONSE)
2262 self.mock_object(self.vserver_client,
2263 'send_request',
2264 mock.Mock(return_value=api_response))
2266 result = self.vserver_client.get_vserver_aggregate_capacities()
2268 vserver_args = {
2269 'desired-attributes': {
2270 'vserver-info': {
2271 'vserver-name': None,
2272 'vserver-aggr-info-list': {
2273 'vserver-aggr-info': {
2274 'aggr-name': None,
2275 'aggr-availsize': None
2276 }
2277 }
2278 }
2279 }
2280 }
2282 self.vserver_client.send_request.assert_has_calls([
2283 mock.call('vserver-get', vserver_args)])
2284 self.assertDictEqual(fake.VSERVER_AGGREGATES, result)
2286 def test_get_vserver_aggregate_capacities_partial_request(self):
2288 api_response = netapp_api.NaElement(fake.VSERVER_GET_RESPONSE)
2289 self.mock_object(self.vserver_client,
2290 'send_request',
2291 mock.Mock(return_value=api_response))
2293 result = self.vserver_client.get_vserver_aggregate_capacities(
2294 fake.SHARE_AGGREGATE_NAMES[0])
2296 expected = {fake.SHARE_AGGREGATE_NAMES[0]:
2297 fake.VSERVER_AGGREGATES[fake.SHARE_AGGREGATE_NAMES[0]]}
2298 self.assertDictEqual(expected, result)
2300 def test_get_vserver_aggregate_capacities_aggregate_not_found(self):
2302 api_response = netapp_api.NaElement(
2303 fake.VSERVER_GET_RESPONSE_NO_AGGREGATES)
2304 self.mock_object(self.vserver_client,
2305 'send_request',
2306 mock.Mock(return_value=api_response))
2308 result = self.vserver_client.get_vserver_aggregate_capacities()
2310 self.assertDictEqual({}, result)
2311 self.assertEqual(1, client_cmode.LOG.warning.call_count)
2313 def test_get_vserver_aggregate_capacities_vserver_not_found(self):
2315 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
2316 self.mock_object(self.vserver_client,
2317 'send_request',
2318 mock.Mock(return_value=api_response))
2320 self.assertRaises(exception.NetAppException,
2321 self.vserver_client.get_vserver_aggregate_capacities)
2323 def test_get_vserver_aggregate_capacities_none_requested(self):
2325 result = self.client.get_vserver_aggregate_capacities([])
2327 self.assertEqual({}, result)
2329 def test_get_aggregates(self):
2331 api_response = netapp_api.NaElement(fake.AGGR_GET_ITER_RESPONSE)
2332 self.mock_object(self.client,
2333 'send_iter_request',
2334 mock.Mock(return_value=api_response))
2336 result = self.client._get_aggregates()
2338 self.client.send_iter_request.assert_has_calls([
2339 mock.call('aggr-get-iter', {})])
2340 self.assertListEqual(
2341 [aggr.to_string() for aggr in api_response.get_child_by_name(
2342 'attributes-list').get_children()],
2343 [aggr.to_string() for aggr in result])
2345 def test_get_aggregates_with_filters(self):
2347 api_response = netapp_api.NaElement(fake.AGGR_GET_SPACE_RESPONSE)
2348 self.mock_object(self.client,
2349 'send_iter_request',
2350 mock.Mock(return_value=api_response))
2352 desired_attributes = {
2353 'aggr-attributes': {
2354 'aggregate-name': None,
2355 'aggr-space-attributes': {
2356 'size-total': None,
2357 'size-available': None,
2358 }
2359 }
2360 }
2362 result = self.client._get_aggregates(
2363 aggregate_names=fake.SHARE_AGGREGATE_NAMES,
2364 desired_attributes=desired_attributes)
2366 aggr_get_iter_args = {
2367 'query': {
2368 'aggr-attributes': {
2369 'aggregate-name': '|'.join(fake.SHARE_AGGREGATE_NAMES),
2370 }
2371 },
2372 'desired-attributes': desired_attributes
2373 }
2375 self.client.send_iter_request.assert_has_calls([
2376 mock.call('aggr-get-iter', aggr_get_iter_args)])
2377 self.assertListEqual(
2378 [aggr.to_string() for aggr in api_response.get_child_by_name(
2379 'attributes-list').get_children()],
2380 [aggr.to_string() for aggr in result])
2382 def test_get_aggregates_not_found(self):
2384 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
2385 self.mock_object(self.client,
2386 'send_iter_request',
2387 mock.Mock(return_value=api_response))
2389 result = self.client._get_aggregates()
2391 self.client.send_iter_request.assert_has_calls([
2392 mock.call('aggr-get-iter', {})])
2393 self.assertListEqual([], result)
2395 def test_get_performance_instance_uuids(self):
2397 api_response = netapp_api.NaElement(
2398 fake.PERF_OBJECT_INSTANCE_LIST_INFO_ITER_RESPONSE)
2399 self.mock_object(self.client,
2400 'send_request',
2401 mock.Mock(return_value=api_response))
2403 result = self.client.get_performance_instance_uuids(
2404 'system', fake.NODE_NAME)
2406 expected = [fake.NODE_NAME + ':kernel:system']
2407 self.assertEqual(expected, result)
2409 perf_object_instance_list_info_iter_args = {
2410 'objectname': 'system',
2411 'query': {
2412 'instance-info': {
2413 'uuid': fake.NODE_NAME + ':*',
2414 }
2415 }
2416 }
2417 self.client.send_request.assert_called_once_with(
2418 'perf-object-instance-list-info-iter',
2419 perf_object_instance_list_info_iter_args)
2421 def test_get_performance_counter_info(self):
2423 api_response = netapp_api.NaElement(
2424 fake.PERF_OBJECT_COUNTER_LIST_INFO_WAFL_RESPONSE)
2425 self.mock_object(self.client,
2426 'send_request',
2427 mock.Mock(return_value=api_response))
2429 result = self.client.get_performance_counter_info('wafl',
2430 'cp_phase_times')
2432 expected = {
2433 'name': 'cp_phase_times',
2434 'base-counter': 'total_cp_msecs',
2435 'labels': fake.PERF_OBJECT_COUNTER_TOTAL_CP_MSECS_LABELS,
2436 }
2437 self.assertEqual(expected, result)
2439 perf_object_counter_list_info_args = {'objectname': 'wafl'}
2440 self.client.send_request.assert_called_once_with(
2441 'perf-object-counter-list-info',
2442 perf_object_counter_list_info_args)
2444 def test_get_performance_counter_info_not_found(self):
2446 api_response = netapp_api.NaElement(
2447 fake.PERF_OBJECT_COUNTER_LIST_INFO_WAFL_RESPONSE)
2448 self.mock_object(self.client,
2449 'send_request',
2450 mock.Mock(return_value=api_response))
2452 self.assertRaises(exception.NotFound,
2453 self.client.get_performance_counter_info,
2454 'wafl',
2455 'invalid')
2457 def test_get_performance_counters(self):
2459 api_response = netapp_api.NaElement(
2460 fake.PERF_OBJECT_GET_INSTANCES_SYSTEM_RESPONSE_CMODE)
2461 self.mock_object(self.client,
2462 'send_request',
2463 mock.Mock(return_value=api_response))
2465 instance_uuids = [
2466 fake.NODE_NAMES[0] + ':kernel:system',
2467 fake.NODE_NAMES[1] + ':kernel:system',
2468 ]
2469 counter_names = ['avg_processor_busy']
2470 result = self.client.get_performance_counters('system',
2471 instance_uuids,
2472 counter_names)
2474 expected = [
2475 {
2476 'avg_processor_busy': '5674745133134',
2477 'instance-name': 'system',
2478 'instance-uuid': instance_uuids[0],
2479 'node-name': fake.NODE_NAMES[0],
2480 'timestamp': '1453412013',
2481 }, {
2482 'avg_processor_busy': '4077649009234',
2483 'instance-name': 'system',
2484 'instance-uuid': instance_uuids[1],
2485 'node-name': fake.NODE_NAMES[1],
2486 'timestamp': '1453412013'
2487 },
2488 ]
2489 self.assertEqual(expected, result)
2491 perf_object_get_instances_args = {
2492 'objectname': 'system',
2493 'instance-uuids': [
2494 {'instance-uuid': instance_uuid}
2495 for instance_uuid in instance_uuids
2496 ],
2497 'counters': [
2498 {'counter': counter} for counter in counter_names
2499 ],
2500 }
2501 self.client.send_request.assert_called_once_with(
2502 'perf-object-get-instances', perf_object_get_instances_args)
2504 def test_setup_security_services_ldap(self):
2506 self.mock_object(self.client, 'send_request')
2507 self.mock_object(self.vserver_client, 'configure_ldap')
2509 self.client.setup_security_services([fake.LDAP_LINUX_SECURITY_SERVICE],
2510 self.vserver_client,
2511 fake.VSERVER_NAME,
2512 False)
2514 vserver_modify_args = {
2515 'name-mapping-switch': [
2516 {'nmswitch': 'ldap'},
2517 {'nmswitch': 'file'},
2518 ],
2519 'name-server-switch': [
2520 {'nsswitch': 'ldap'},
2521 {'nsswitch': 'file'},
2522 ],
2523 'vserver-name': fake.VSERVER_NAME
2524 }
2525 self.client.send_request.assert_has_calls([
2526 mock.call('vserver-modify', vserver_modify_args)])
2527 self.vserver_client.configure_ldap.assert_has_calls([
2528 mock.call(fake.LDAP_LINUX_SECURITY_SERVICE, timeout=30)])
2530 def test_setup_security_services_active_directory(self):
2532 self.mock_object(self.client, 'send_request')
2533 self.mock_object(self.vserver_client, 'configure_active_directory')
2534 self.mock_object(self.vserver_client, 'configure_cifs_options')
2536 self.client.setup_security_services([fake.CIFS_SECURITY_SERVICE],
2537 self.vserver_client,
2538 fake.VSERVER_NAME,
2539 False)
2541 vserver_modify_args = {
2542 'name-mapping-switch': [
2543 {'nmswitch': 'ldap'},
2544 {'nmswitch': 'file'},
2545 ],
2546 'name-server-switch': [
2547 {'nsswitch': 'ldap'},
2548 {'nsswitch': 'file'},
2549 ],
2550 'vserver-name': fake.VSERVER_NAME
2551 }
2552 self.client.send_request.assert_has_calls([
2553 mock.call('vserver-modify', vserver_modify_args)])
2554 self.vserver_client.configure_active_directory.assert_has_calls([
2555 mock.call(fake.CIFS_SECURITY_SERVICE, fake.VSERVER_NAME, False)])
2556 self.vserver_client.configure_cifs_options.assert_has_calls([
2557 mock.call(fake.CIFS_SECURITY_SERVICE)])
2559 def test_setup_security_services_kerberos(self):
2561 self.mock_object(self.client, 'send_request')
2562 self.mock_object(self.vserver_client, 'create_kerberos_realm')
2563 self.mock_object(self.vserver_client, 'configure_kerberos')
2565 self.client.setup_security_services([fake.KERBEROS_SECURITY_SERVICE],
2566 self.vserver_client,
2567 fake.VSERVER_NAME,
2568 False)
2570 vserver_modify_args = {
2571 'name-mapping-switch': [
2572 {'nmswitch': 'ldap'},
2573 {'nmswitch': 'file'},
2574 ],
2575 'name-server-switch': [
2576 {'nsswitch': 'ldap'},
2577 {'nsswitch': 'file'},
2578 ],
2579 'vserver-name': fake.VSERVER_NAME
2580 }
2581 self.client.send_request.assert_has_calls([
2582 mock.call('vserver-modify', vserver_modify_args)])
2583 self.vserver_client.create_kerberos_realm.assert_has_calls([
2584 mock.call(fake.KERBEROS_SECURITY_SERVICE)])
2585 self.vserver_client.configure_kerberos.assert_has_calls([
2586 mock.call(fake.KERBEROS_SECURITY_SERVICE, fake.VSERVER_NAME)])
2588 def test_setup_security_services_invalid(self):
2590 self.mock_object(self.client, 'send_request')
2592 self.assertRaises(exception.NetAppException,
2593 self.client.setup_security_services,
2594 [fake.INVALID_SECURITY_SERVICE],
2595 self.vserver_client,
2596 fake.VSERVER_NAME,
2597 False)
2599 vserver_modify_args = {
2600 'name-mapping-switch': [
2601 {'nmswitch': 'ldap'},
2602 {'nmswitch': 'file'},
2603 ],
2604 'name-server-switch': [
2605 {'nsswitch': 'ldap'},
2606 {'nsswitch': 'file'},
2607 ],
2608 'vserver-name': fake.VSERVER_NAME
2609 }
2610 self.client.send_request.assert_has_calls([
2611 mock.call('vserver-modify', vserver_modify_args)])
2613 def test_update_showmount(self):
2615 self.mock_object(self.client, 'send_request')
2617 fake_showmount = 'true'
2618 self.client.update_showmount(fake_showmount)
2620 nfs_service_modify_args = {
2621 'showmount': fake_showmount,
2622 }
2623 self.client.send_request.assert_called_once_with(
2624 'nfs-service-modify', nfs_service_modify_args)
2626 @ddt.data({'tcp-max-xfer-size': 10000}, {}, None)
2627 def test_enable_nfs(self, nfs_config):
2629 self.mock_object(self.client, 'send_request')
2630 self.mock_object(self.client, '_enable_nfs_protocols')
2631 self.mock_object(self.client, '_create_default_nfs_export_rules')
2632 self.mock_object(self.client, '_configure_nfs')
2634 self.client.enable_nfs(fake.NFS_VERSIONS, nfs_config)
2636 self.client.send_request.assert_called_once_with('nfs-enable')
2637 self.client._enable_nfs_protocols.assert_called_once_with(
2638 fake.NFS_VERSIONS)
2639 self.client._create_default_nfs_export_rules.assert_called_once_with()
2640 if nfs_config:
2641 self.client._configure_nfs.assert_called_once_with(nfs_config)
2642 else:
2643 self.client._configure_nfs.assert_not_called()
2645 @ddt.data((True, True, True), (True, False, False), (False, True, True))
2646 @ddt.unpack
2647 def test_enable_nfs_protocols(self, v3, v40, v41):
2649 self.mock_object(self.client, 'send_request')
2651 versions = []
2652 if v3:
2653 versions.append('nfs3')
2654 if v40:
2655 versions.append('nfs4.0')
2656 if v41:
2657 versions.append('nfs4.1')
2659 self.client._enable_nfs_protocols(versions)
2661 nfs_service_modify_args = {
2662 'is-nfsv3-enabled': 'true' if v3 else 'false',
2663 'is-nfsv40-enabled': 'true' if v40 else 'false',
2664 'is-nfsv41-enabled': 'true' if v41 else 'false',
2665 'showmount': 'true',
2666 'is-v3-ms-dos-client-enabled': 'true',
2667 'is-nfsv3-connection-drop-enabled': 'false',
2668 'enable-ejukebox': 'false',
2669 }
2670 self.client.send_request.assert_called_once_with(
2671 'nfs-service-modify', nfs_service_modify_args)
2673 def test_configure_nfs(self):
2674 fake_nfs = {
2675 'tcp-max-xfer-size': 10000,
2676 }
2677 self.mock_object(self.client, 'send_request')
2679 self.client._configure_nfs(fake_nfs)
2681 self.client.send_request.assert_called_once_with(
2682 'nfs-service-modify', fake_nfs)
2684 def test_create_default_nfs_export_rules(self):
2686 class CopyingMock(mock.Mock):
2687 def __call__(self, *args, **kwargs):
2688 args = copy.deepcopy(args)
2689 kwargs = copy.deepcopy(kwargs)
2690 return super(CopyingMock, self).__call__(*args, **kwargs)
2692 self.mock_object(self.client, 'send_request', CopyingMock())
2694 self.client._create_default_nfs_export_rules()
2696 export_rule_create_args = {
2697 'client-match': '0.0.0.0/0',
2698 'policy-name': 'default',
2699 'ro-rule': {
2700 'security-flavor': 'any'
2701 },
2702 'rw-rule': {
2703 'security-flavor': 'never'
2704 }
2705 }
2706 export_rule_create_args2 = export_rule_create_args.copy()
2707 export_rule_create_args2['client-match'] = '::/0'
2708 self.client.send_request.assert_has_calls([
2709 mock.call('export-rule-create', export_rule_create_args),
2710 mock.call('export-rule-create', export_rule_create_args2)])
2712 @ddt.data(fake.LDAP_LINUX_SECURITY_SERVICE, fake.LDAP_AD_SECURITY_SERVICE)
2713 def test_configure_ldap(self, sec_service):
2714 self.client.features.add_feature('LDAP_LDAP_SERVERS')
2716 self.mock_object(self.client, 'send_request')
2717 self.mock_object(self.client, 'configure_dns')
2719 self.client.configure_ldap(sec_service)
2721 config_name = hashlib.md5(
2722 sec_service['id'].encode("latin-1")).hexdigest()
2724 ldap_client_create_args = {
2725 'ldap-client-config': config_name,
2726 'tcp-port': '389',
2727 'bind-password': sec_service['password'],
2728 }
2730 if sec_service.get('domain'):
2731 ldap_client_create_args['schema'] = 'MS-AD-BIS'
2732 ldap_client_create_args['bind-dn'] = (
2733 sec_service['user'] + '@' + sec_service['domain'])
2734 ldap_client_create_args['ad-domain'] = sec_service['domain']
2735 else:
2736 ldap_client_create_args['schema'] = 'RFC-2307'
2737 ldap_client_create_args['bind-dn'] = sec_service['user']
2738 ldap_client_create_args['ldap-servers'] = [{
2739 'string': sec_service['server']
2740 }]
2742 if sec_service.get('ou'): 2742 ↛ 2745line 2742 didn't jump to line 2745 because the condition on line 2742 was always true
2743 ldap_client_create_args['base-dn'] = sec_service['ou']
2745 ldap_config_create_args = {
2746 'client-config': config_name,
2747 'client-enabled': 'true'
2748 }
2750 self.client.send_request.assert_has_calls([
2751 mock.call('ldap-client-create', ldap_client_create_args),
2752 mock.call('ldap-config-create', ldap_config_create_args)])
2754 @ddt.data({'server': None, 'domain': None},
2755 {'server': 'fake_server', 'domain': 'fake_domain'})
2756 @ddt.unpack
2757 def test_configure_ldap_invalid_parameters(self, server, domain):
2758 fake_ldap_sec_service = copy.deepcopy(fake.LDAP_AD_SECURITY_SERVICE)
2759 fake_ldap_sec_service['server'] = server
2760 fake_ldap_sec_service['domain'] = domain
2762 self.assertRaises(exception.NetAppException,
2763 self.client.configure_ldap,
2764 fake_ldap_sec_service)
2766 def test__enable_ldap_client_timeout(self):
2767 mock_warning_log = self.mock_object(client_cmode.LOG, 'warning')
2768 na_api_error = netapp_api.NaApiError(code=netapp_api.EAPIERROR)
2769 mock_send_request = self.mock_object(
2770 self.client, 'send_request', mock.Mock(side_effect=na_api_error))
2772 self.assertRaises(exception.NetAppException,
2773 self.client._enable_ldap_client,
2774 'fake_config_name',
2775 timeout=6)
2777 self.assertEqual(2, mock_send_request.call_count)
2778 self.assertEqual(2, mock_warning_log.call_count)
2780 def test_configure_active_directory(self):
2782 self.mock_object(self.client, 'send_request')
2783 self.mock_object(self.client, 'configure_dns')
2784 self.mock_object(self.client, 'configure_cifs_aes_encryption')
2785 self.mock_object(self.client, 'set_preferred_dc')
2787 self.client.configure_active_directory(fake.CIFS_SECURITY_SERVICE,
2788 fake.VSERVER_NAME,
2789 False)
2791 cifs_server = (fake.VSERVER_NAME[0:8] +
2792 '-' +
2793 fake.VSERVER_NAME[-6:]).replace('_', '-').upper()
2795 cifs_server_create_args = {
2796 'admin-username': fake.CIFS_SECURITY_SERVICE['user'],
2797 'admin-password': fake.CIFS_SECURITY_SERVICE['password'],
2798 'force-account-overwrite': 'true',
2799 'cifs-server': cifs_server,
2800 'organizational-unit': fake.CIFS_SECURITY_SERVICE['ou'],
2801 'domain': fake.CIFS_SECURITY_SERVICE['domain'],
2802 }
2804 self.client.configure_dns.assert_called_with(
2805 fake.CIFS_SECURITY_SERVICE)
2806 self.client.configure_cifs_aes_encryption.assert_called_with(False)
2807 self.client.set_preferred_dc.assert_called_with(
2808 fake.CIFS_SECURITY_SERVICE)
2809 self.client.send_request.assert_has_calls([
2810 mock.call('cifs-server-create', cifs_server_create_args)])
2812 def test_configure_active_directory_with_ad_site(self):
2814 self.mock_object(self.client, 'send_request')
2815 self.mock_object(self.client, 'configure_dns')
2816 self.mock_object(self.client, 'configure_cifs_aes_encryption')
2817 self.mock_object(self.client, 'set_preferred_dc')
2819 self.client.configure_active_directory(fake.CIFS_SECURITY_SERVICE_3,
2820 fake.VSERVER_NAME, False)
2822 cifs_server = (fake.VSERVER_NAME[0:8] +
2823 '-' +
2824 fake.VSERVER_NAME[-6:]).replace('_', '-').upper()
2826 cifs_server_create_args = {
2827 'admin-username': fake.CIFS_SECURITY_SERVICE_3['user'],
2828 'admin-password': fake.CIFS_SECURITY_SERVICE_3['password'],
2829 'force-account-overwrite': 'true',
2830 'cifs-server': cifs_server,
2831 'organizational-unit': fake.CIFS_SECURITY_SERVICE_3['ou'],
2832 'domain': fake.CIFS_SECURITY_SERVICE_3['domain'],
2833 'default-site': fake.CIFS_SECURITY_SERVICE_3['default_ad_site'],
2834 }
2836 self.client.configure_dns.assert_called_with(
2837 fake.CIFS_SECURITY_SERVICE_3)
2838 self.client.configure_cifs_aes_encryption.assert_called_with(False)
2839 self.client.set_preferred_dc.assert_called_with(
2840 fake.CIFS_SECURITY_SERVICE_3)
2841 self.client.send_request.assert_has_calls([
2842 mock.call('cifs-server-create', cifs_server_create_args)])
2844 def test_configure_active_directory_api_error(self):
2846 self.mock_object(self.client, 'send_request', self._mock_api_error())
2847 self.mock_object(self.client, 'configure_dns')
2849 self.assertRaises(exception.NetAppException,
2850 self.client.configure_active_directory,
2851 fake.CIFS_SECURITY_SERVICE,
2852 fake.VSERVER_NAME,
2853 False)
2855 def test_create_kerberos_realm(self):
2856 self.client.features.add_feature('KERBEROS_VSERVER')
2857 self.mock_object(self.client, 'send_request')
2859 self.client.create_kerberos_realm(fake.KERBEROS_SECURITY_SERVICE)
2861 kerberos_realm_create_args = {
2862 'admin-server-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2863 'admin-server-port': '749',
2864 'clock-skew': '5',
2865 'comment': '',
2866 'kdc-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2867 'kdc-port': '88',
2868 'kdc-vendor': 'other',
2869 'password-server-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2870 'password-server-port': '464',
2871 'realm': fake.KERBEROS_SECURITY_SERVICE['domain'].upper()
2872 }
2874 self.client.send_request.assert_has_calls([
2875 mock.call('kerberos-realm-create', kerberos_realm_create_args)])
2877 def test_create_kerberos_realm_already_present(self):
2878 self.client.features.add_feature('KERBEROS_VSERVER')
2879 self.mock_object(self.client,
2880 'send_request',
2881 self._mock_api_error(code=netapp_api.EDUPLICATEENTRY))
2883 self.client.create_kerberos_realm(fake.KERBEROS_SECURITY_SERVICE)
2885 kerberos_realm_create_args = {
2886 'admin-server-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2887 'admin-server-port': '749',
2888 'clock-skew': '5',
2889 'comment': '',
2890 'kdc-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2891 'kdc-port': '88',
2892 'kdc-vendor': 'other',
2893 'password-server-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2894 'password-server-port': '464',
2895 'realm': fake.KERBEROS_SECURITY_SERVICE['domain'].upper()
2896 }
2898 self.client.send_request.assert_has_calls([
2899 mock.call('kerberos-realm-create', kerberos_realm_create_args)])
2900 self.assertEqual(1, client_cmode.LOG.debug.call_count)
2902 def test_create_kerberos_realm_api_error(self):
2903 self.client.features.add_feature('KERBEROS_VSERVER')
2904 self.mock_object(self.client, 'send_request', self._mock_api_error())
2906 self.assertRaises(exception.NetAppException,
2907 self.client.create_kerberos_realm,
2908 fake.KERBEROS_SECURITY_SERVICE)
2910 def test_update_kerberos_realm(self):
2911 self.client.features.add_feature('KERBEROS_VSERVER')
2912 self.mock_object(self.client, 'send_request')
2914 self.client.update_kerberos_realm(fake.KERBEROS_SECURITY_SERVICE)
2916 kerberos_realm_create_args = {
2917 'admin-server-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2918 'kdc-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2919 'password-server-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2920 'realm': fake.KERBEROS_SECURITY_SERVICE['domain'].upper(),
2921 }
2923 self.client.send_request.assert_has_calls([
2924 mock.call('kerberos-realm-modify',
2925 kerberos_realm_create_args)])
2927 def test_update_kerberos_realm_failure(self):
2928 self.client.features.add_feature('KERBEROS_VSERVER')
2929 self.mock_object(self.client, 'send_request', self._mock_api_error())
2931 self.assertRaises(exception.NetAppException,
2932 self.client.update_kerberos_realm,
2933 fake.KERBEROS_SECURITY_SERVICE)
2935 kerberos_realm_create_args = {
2936 'admin-server-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2937 'kdc-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2938 'password-server-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
2939 'realm': fake.KERBEROS_SECURITY_SERVICE['domain'].upper(),
2940 }
2942 self.client.send_request.assert_has_calls([
2943 mock.call('kerberos-realm-modify',
2944 kerberos_realm_create_args)])
2946 def test_configure_kerberos(self):
2947 self.client.features.add_feature('KERBEROS_VSERVER')
2948 self.mock_object(self.client, 'send_request')
2949 self.mock_object(self.client, 'configure_dns')
2950 self.mock_object(self.client,
2951 'list_network_interfaces',
2952 mock.Mock(return_value=['lif1', 'lif2']))
2954 self.client.configure_kerberos(
2955 fake.KERBEROS_SECURITY_SERVICE, fake.VSERVER_NAME)
2957 spn = self.client._get_kerberos_service_principal_name(
2958 fake.KERBEROS_SECURITY_SERVICE, fake.VSERVER_NAME)
2960 kerberos_config_modify_args1 = {
2961 'admin-password': fake.KERBEROS_SECURITY_SERVICE['password'],
2962 'admin-user-name': fake.KERBEROS_SECURITY_SERVICE['user'],
2963 'interface-name': 'lif1',
2964 'is-kerberos-enabled': 'true',
2965 'service-principal-name': spn
2966 }
2967 kerberos_config_modify_args2 = {
2968 'admin-password': fake.KERBEROS_SECURITY_SERVICE['password'],
2969 'admin-user-name': fake.KERBEROS_SECURITY_SERVICE['user'],
2970 'interface-name': 'lif2',
2971 'is-kerberos-enabled': 'true',
2972 'service-principal-name': spn
2973 }
2975 self.client.configure_dns.assert_called_with(
2976 fake.KERBEROS_SECURITY_SERVICE)
2977 self.client.send_request.assert_has_calls([
2978 mock.call('kerberos-config-modify',
2979 kerberos_config_modify_args1),
2980 mock.call('kerberos-config-modify',
2981 kerberos_config_modify_args2)])
2983 def test_configure_kerberos_no_network_interfaces(self):
2984 self.client.features.add_feature('KERBEROS_VSERVER')
2985 self.mock_object(self.client, 'send_request')
2986 self.mock_object(self.client, 'configure_dns')
2987 self.mock_object(self.client,
2988 'list_network_interfaces',
2989 mock.Mock(return_value=[]))
2991 self.assertRaises(exception.NetAppException,
2992 self.client.configure_kerberos,
2993 fake.KERBEROS_SECURITY_SERVICE,
2994 fake.VSERVER_NAME)
2996 self.client.configure_dns.assert_called_with(
2997 fake.KERBEROS_SECURITY_SERVICE)
2999 def test_disable_kerberos(self):
3000 self.mock_object(self.client, 'send_request')
3001 self.mock_object(self.client,
3002 'list_network_interfaces',
3003 mock.Mock(return_value=['lif1', 'lif2']))
3005 self.client.disable_kerberos(fake.KERBEROS_SECURITY_SERVICE)
3007 kerberos_config_modify_args1 = {
3008 'admin-password': fake.KERBEROS_SECURITY_SERVICE['password'],
3009 'admin-user-name': fake.KERBEROS_SECURITY_SERVICE['user'],
3010 'interface-name': 'lif1',
3011 'is-kerberos-enabled': 'false',
3012 }
3013 kerberos_config_modify_args2 = {
3014 'admin-password': fake.KERBEROS_SECURITY_SERVICE['password'],
3015 'admin-user-name': fake.KERBEROS_SECURITY_SERVICE['user'],
3016 'interface-name': 'lif2',
3017 'is-kerberos-enabled': 'false',
3018 }
3020 self.client.send_request.assert_has_calls([
3021 mock.call('kerberos-config-modify',
3022 kerberos_config_modify_args1),
3023 mock.call('kerberos-config-modify',
3024 kerberos_config_modify_args2)])
3025 self.client.list_network_interfaces.assert_called_once()
3027 def test_disable_kerberos_already_disabled(self):
3028 self.mock_object(self.client, 'send_request',
3029 self._mock_api_error(
3030 code=netapp_api.EAPIERROR,
3031 message='Kerberos is already disabled'))
3032 self.mock_object(self.client,
3033 'list_network_interfaces',
3034 mock.Mock(return_value=['lif1']))
3036 self.client.disable_kerberos(fake.KERBEROS_SECURITY_SERVICE)
3038 kerberos_config_modify_args = {
3039 'admin-password': fake.KERBEROS_SECURITY_SERVICE['password'],
3040 'admin-user-name': fake.KERBEROS_SECURITY_SERVICE['user'],
3041 'interface-name': 'lif1',
3042 'is-kerberos-enabled': 'false',
3043 }
3045 self.client.send_request.assert_called_once_with(
3046 'kerberos-config-modify', kerberos_config_modify_args)
3047 self.client.list_network_interfaces.assert_called_once()
3049 def test_is_kerberos_enabled(self):
3050 self.client.features.add_feature('KERBEROS_VSERVER')
3051 api_response = netapp_api.NaElement(
3052 fake.KERBEROS_CONFIG_GET_RESPONSE)
3053 self.mock_object(self.client, 'send_request',
3054 mock.Mock(return_value=api_response))
3055 self.mock_object(self.client,
3056 'get_network_interfaces',
3057 mock.Mock(return_value=[{'interface-name': 'lif1'}]))
3059 result = self.client.is_kerberos_enabled()
3061 kerberos_config_get_args = {
3062 'interface-name': 'lif1',
3063 'desired-attributes': {
3064 'kerberos-config-info': {
3065 'is-kerberos-enabled': None,
3066 }
3067 }
3068 }
3070 self.assertTrue(result)
3071 self.client.send_request.assert_called_once_with(
3072 'kerberos-config-get', kerberos_config_get_args)
3073 self.client.get_network_interfaces.assert_called_once_with(
3074 protocols=['NFS', 'CIFS'])
3076 def test_is_kerberos_enabled_exception_raise(self):
3077 self.client.features.add_feature('KERBEROS_VSERVER')
3078 api_response = netapp_api.NaElement(
3079 fake.KERBEROS_CONFIG_GET_RESPONSE)
3080 self.mock_object(self.client, 'send_request',
3081 mock.Mock(side_effect=[api_response,
3082 netapp_api.NaApiError('foobar')]))
3083 self.mock_object(self.client,
3084 'get_network_interfaces',
3085 mock.Mock(return_value=[{'interface-name': 'lif1'},
3086 {'interface-name': 'lif2'},
3087 {'interface-name': 'lif3'}]))
3089 self.assertRaises(netapp_api.NaApiError,
3090 self.client.is_kerberos_enabled)
3092 kerberos_config_get_args_lif1 = {
3093 'interface-name': 'lif1',
3094 'desired-attributes': {
3095 'kerberos-config-info': {
3096 'is-kerberos-enabled': None,
3097 }
3098 }
3099 }
3101 kerberos_config_get_args_lif2 = {
3102 'interface-name': 'lif2',
3103 'desired-attributes': {
3104 'kerberos-config-info': {
3105 'is-kerberos-enabled': None,
3106 }
3107 }
3108 }
3110 self.client.send_request.assert_has_calls([
3111 mock.call('kerberos-config-get', kerberos_config_get_args_lif1),
3112 mock.call('kerberos-config-get', kerberos_config_get_args_lif2),
3113 ])
3114 self.client.get_network_interfaces.assert_called_once_with(
3115 protocols=['NFS', 'CIFS'])
3117 def test_is_kerberos_enabled_exception_return_false(self):
3118 self.client.features.add_feature('KERBEROS_VSERVER')
3119 api_response = netapp_api.NaElement(
3120 fake.KERBEROS_CONFIG_GET_RESPONSE)
3121 self.mock_object(
3122 self.client, 'send_request',
3123 mock.Mock(side_effect=[api_response, netapp_api.NaApiError(
3124 message="entry doesn't exist")]))
3125 self.mock_object(self.client,
3126 'get_network_interfaces',
3127 mock.Mock(return_value=[{'interface-name': 'lif1'},
3128 {'interface-name': 'lif2'},
3129 {'interface-name': 'lif3'}]))
3131 result = self.client.is_kerberos_enabled()
3133 kerberos_config_get_args_lif1 = {
3134 'interface-name': 'lif1',
3135 'desired-attributes': {
3136 'kerberos-config-info': {
3137 'is-kerberos-enabled': None,
3138 }
3139 }
3140 }
3142 kerberos_config_get_args_lif2 = {
3143 'interface-name': 'lif2',
3144 'desired-attributes': {
3145 'kerberos-config-info': {
3146 'is-kerberos-enabled': None,
3147 }
3148 }
3149 }
3151 self.assertFalse(result)
3152 self.client.send_request.assert_has_calls([
3153 mock.call('kerberos-config-get', kerberos_config_get_args_lif1),
3154 mock.call('kerberos-config-get', kerberos_config_get_args_lif2),
3155 ])
3156 self.client.get_network_interfaces.assert_called_once_with(
3157 protocols=['NFS', 'CIFS'])
3159 def test_get_kerberos_service_principal_name(self):
3161 spn = self.client._get_kerberos_service_principal_name(
3162 fake.KERBEROS_SECURITY_SERVICE, fake.VSERVER_NAME
3163 )
3164 self.assertEqual(fake.KERBEROS_SERVICE_PRINCIPAL_NAME, spn)
3166 def test_configure_dns_for_active_directory(self):
3168 self.mock_object(self.client, 'send_request')
3169 self.mock_object(self.client, 'get_dns_config',
3170 mock.Mock(return_value={}))
3172 self.client.configure_dns(fake.CIFS_SECURITY_SERVICE)
3174 net_dns_create_args = {
3175 'domains': [{'string': fake.CIFS_SECURITY_SERVICE['domain']}],
3176 'name-servers': [{
3177 'ip-address': fake.CIFS_SECURITY_SERVICE['dns_ip']
3178 }],
3179 'dns-state': 'enabled'
3180 }
3182 self.client.send_request.assert_has_calls([
3183 mock.call('net-dns-create', net_dns_create_args)])
3185 def test_configure_dns_multiple_dns_ip(self):
3187 self.mock_object(self.client, 'send_request')
3188 self.mock_object(self.client, 'get_dns_config',
3189 mock.Mock(return_value={}))
3190 mock_dns_ips = ['10.0.0.1', '10.0.0.2', '10.0.0.3']
3191 security_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
3192 security_service['dns_ip'] = ', '.join(mock_dns_ips)
3194 self.client.configure_dns(security_service)
3196 self.client.send_request.assert_called_once()
3198 def test_configure_dns_for_kerberos(self):
3200 self.mock_object(self.client, 'send_request')
3201 self.mock_object(self.client, 'get_dns_config',
3202 mock.Mock(return_value={}))
3204 self.client.configure_dns(fake.KERBEROS_SECURITY_SERVICE)
3206 net_dns_create_args = {
3207 'domains': [{'string': fake.KERBEROS_SECURITY_SERVICE['domain']}],
3208 'name-servers': [{
3209 'ip-address': fake.KERBEROS_SECURITY_SERVICE['dns_ip']
3210 }],
3211 'dns-state': 'enabled'
3212 }
3214 self.client.send_request.assert_has_calls([
3215 mock.call('net-dns-create', net_dns_create_args)])
3217 def test_configure_dns_already_present(self):
3218 dns_config = {
3219 'dns-state': 'enabled',
3220 'domains': [fake.KERBEROS_SECURITY_SERVICE['domain']],
3221 'dns-ips': [fake.KERBEROS_SECURITY_SERVICE['dns_ip']],
3222 }
3223 self.mock_object(self.client, 'get_dns_config',
3224 mock.Mock(return_value=dns_config))
3225 self.mock_object(self.client, 'send_request')
3227 self.client.configure_dns(fake.KERBEROS_SECURITY_SERVICE)
3229 net_dns_create_args = {
3230 'domains': [{'string': fake.KERBEROS_SECURITY_SERVICE['domain']}],
3231 'name-servers': [{
3232 'ip-address': fake.KERBEROS_SECURITY_SERVICE['dns_ip']
3233 }],
3234 'dns-state': 'enabled'
3235 }
3237 self.client.send_request.assert_has_calls([
3238 mock.call('net-dns-modify', net_dns_create_args)])
3240 def test_update_dns_configuration(self):
3241 fake_configured_dns = {
3242 'dns-state': 'enabled',
3243 'domains': ['fake_domain_2'],
3244 'dns-ips': ['fake_dns_ip_2']
3245 }
3246 self.mock_object(self.client, 'get_dns_config',
3247 mock.Mock(return_value=fake_configured_dns))
3248 self.mock_object(self.client, 'send_request')
3250 self.client.configure_dns(fake.KERBEROS_SECURITY_SERVICE)
3251 domains = set()
3252 domains.add(fake_configured_dns['domains'][0])
3253 domains.add(fake.KERBEROS_SECURITY_SERVICE['domain'])
3255 dns_ips = set()
3256 dns_ips.add(fake_configured_dns['dns-ips'][0])
3257 dns_ips.add(fake.KERBEROS_SECURITY_SERVICE['dns_ip'])
3259 net_dns_create_args = {
3260 'domains': [{'string': domain} for domain in domains],
3261 'dns-state': 'enabled',
3262 'name-servers': [{'ip-address': dns_ip} for dns_ip in dns_ips]
3263 }
3265 self.client.send_request.assert_has_calls([
3266 mock.call('net-dns-modify', net_dns_create_args)])
3268 def test_configure_dns_api_error(self):
3270 self.mock_object(self.client, 'send_request', self._mock_api_error())
3271 self.mock_object(self.client, 'get_dns_config',
3272 mock.Mock(return_value={}))
3274 self.assertRaises(exception.NetAppException,
3275 self.client.configure_dns,
3276 fake.KERBEROS_SECURITY_SERVICE)
3278 def test_get_dns_configuration(self):
3279 api_response = netapp_api.NaElement(
3280 fake.DNS_CONFIG_GET_RESPONSE)
3281 self.mock_object(self.client, 'send_request',
3282 mock.Mock(return_value=api_response))
3284 result = self.client.get_dns_config()
3286 expected_result = {
3287 'dns-state': 'enabled',
3288 'domains': ['fake_domain.com'],
3289 'dns-ips': ['fake_dns_1', 'fake_dns_2']
3290 }
3291 self.assertEqual(expected_result, result)
3292 self.client.send_request.assert_called_once_with('net-dns-get', {})
3294 @ddt.data(True, False)
3295 def test_configure_cifs_aes_encryption_enable(self, specify_types):
3296 self.client.features.add_feature(
3297 'AES_ENCRYPTION_TYPES', supported=specify_types)
3298 self.mock_object(self.client, 'send_request')
3300 self.client.configure_cifs_aes_encryption(True)
3302 if specify_types:
3303 configure_cifs_aes_encryption_args = {
3304 'advertised-enc-types': [{'cifskrbenctypes': 'aes_128'},
3305 {'cifskrbenctypes': 'aes_256'}]
3306 }
3307 else:
3308 configure_cifs_aes_encryption_args = {
3309 'is-aes-encryption-enabled': 'true',
3310 }
3311 self.client.send_request.assert_called_with(
3312 'cifs-security-modify', configure_cifs_aes_encryption_args)
3314 @ddt.data(True, False)
3315 def test_configure_cifs_aes_encryption_disable(self, specify_types):
3316 self.client.features.add_feature(
3317 'AES_ENCRYPTION_TYPES', supported=specify_types)
3318 self.mock_object(self.client, 'send_request')
3320 self.client.configure_cifs_aes_encryption(False)
3322 if specify_types:
3323 configure_cifs_aes_encryption_args = {
3324 'advertised-enc-types': [{'cifskrbenctypes': 'des'},
3325 {'cifskrbenctypes': 'rc4'}]
3326 }
3327 else:
3328 configure_cifs_aes_encryption_args = {
3329 'is-aes-encryption-enabled': 'false',
3330 }
3331 self.client.send_request.assert_called_with(
3332 'cifs-security-modify', configure_cifs_aes_encryption_args)
3334 @ddt.data(
3335 {
3336 'server': '',
3337 'check_feature': False
3338 },
3339 {
3340 'server': ['10.0.0.2', '10.0.0.3'],
3341 'check_feature': False
3342 },
3343 {
3344 'server': '10.0.0.1',
3345 'check_feature': False
3346 },
3347 {
3348 'server': '10.0.0.1',
3349 'check_feature': True
3350 }
3351 )
3352 @ddt.unpack
3353 def test_set_preferred_dc(self, server, check_feature):
3354 if check_feature:
3355 self.client.features.add_feature('CIFS_DC_ADD_SKIP_CHECK')
3357 self.mock_object(self.client, 'send_request')
3358 security_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
3359 security_service['server'] = ', '.join(server)
3361 self.client.set_preferred_dc(security_service)
3363 if server == '':
3364 self.client.send_request.assert_not_called()
3365 else:
3366 preferred_dc_add_args = {
3367 'domain': fake.CIFS_SECURITY_SERVICE['domain'],
3368 'preferred-dc': [{'string': dc_ip} for dc_ip in server]
3369 }
3371 if check_feature:
3372 preferred_dc_add_args['skip-config-validation'] = 'false'
3374 self.client.send_request.assert_has_calls([
3375 mock.call('cifs-domain-preferred-dc-add',
3376 preferred_dc_add_args)])
3378 def test_set_preferred_dc_api_error(self):
3380 self.mock_object(self.client, 'send_request', self._mock_api_error())
3381 security_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
3382 security_service['server'] = 'fake_server'
3384 self.assertRaises(exception.NetAppException,
3385 self.client.set_preferred_dc,
3386 security_service)
3388 def test_remove_preferred_dcs(self):
3389 self.mock_object(self.client, 'send_request')
3390 security_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
3392 self.client.remove_preferred_dcs(security_service)
3394 preferred_dc_add_args = {
3395 'domain': security_service['domain'],
3396 }
3397 self.client.send_request.assert_has_calls([
3398 mock.call('cifs-domain-preferred-dc-remove',
3399 preferred_dc_add_args)])
3401 def test_remove_preferred_dcs_error(self):
3402 self.mock_object(self.client, 'send_request', self._mock_api_error())
3403 security_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
3405 self.assertRaises(exception.NetAppException,
3406 self.client.remove_preferred_dcs,
3407 security_service)
3409 preferred_dc_add_args = {
3410 'domain': security_service['domain'],
3411 }
3412 self.client.send_request.assert_has_calls([
3413 mock.call('cifs-domain-preferred-dc-remove',
3414 preferred_dc_add_args)])
3416 @ddt.data(True, False)
3417 def test_create_volume(self, set_max_files):
3418 self.client.features.add_feature('ADAPTIVE_QOS')
3419 self.mock_object(self.client, 'set_volume_max_files')
3420 self.mock_object(self.client, 'send_request')
3421 self.mock_object(self.client, 'update_volume_efficiency_attributes')
3422 self.mock_object(
3423 self.client, '_get_create_volume_api_args',
3424 mock.Mock(return_value={}))
3425 options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}
3427 self.client.create_volume(
3428 fake.SHARE_AGGREGATE_NAME, fake.SHARE_NAME, 100,
3429 max_files=fake.MAX_FILES if set_max_files else None,
3430 **options
3431 )
3433 volume_create_args = {
3434 'containing-aggr-name': fake.SHARE_AGGREGATE_NAME,
3435 'size': '100g',
3436 'volume': fake.SHARE_NAME,
3437 }
3439 self.client._get_create_volume_api_args.assert_called_once_with(
3440 fake.SHARE_NAME, False, None, None, None, 'rw', None, False,
3441 None, None, None)
3442 self.client.send_request.assert_called_with('volume-create',
3443 volume_create_args)
3444 (
3445 self.client.update_volume_efficiency_attributes.
3446 assert_called_once_with
3447 (fake.SHARE_NAME, False, False,
3448 efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME)
3449 )
3450 if set_max_files:
3451 self.client.set_volume_max_files.assert_called_once_with(
3452 fake.SHARE_NAME, fake.MAX_FILES)
3453 else:
3454 self.client.set_volume_max_files.assert_not_called()
3456 @ddt.data(True, False)
3457 def test_create_volume_thin_provisioned(self, thin_provisioned):
3459 self.mock_object(self.client, 'send_request')
3460 self.mock_object(self.client, 'update_volume_efficiency_attributes')
3462 self.client.create_volume(
3463 fake.SHARE_AGGREGATE_NAME, fake.SHARE_NAME, 100,
3464 thin_provisioned=thin_provisioned)
3466 volume_create_args = {
3467 'containing-aggr-name': fake.SHARE_AGGREGATE_NAME,
3468 'size': '100g',
3469 'volume': fake.SHARE_NAME,
3470 'volume-type': 'rw',
3471 'junction-path': '/%s' % fake.SHARE_NAME,
3472 'space-reserve': ('none' if thin_provisioned else 'volume'),
3473 'encrypt': 'false'
3474 }
3476 self.client.send_request.assert_called_once_with('volume-create',
3477 volume_create_args)
3479 @ddt.data("compliance", "enterprise")
3480 def test_create_volume_snaplock_type(self, snaplock_type):
3482 self.mock_object(self.client, 'send_request')
3483 self.mock_object(self.client, 'update_volume_efficiency_attributes')
3484 self.mock_object(self.client, 'set_snaplock_attributes')
3486 self.client.create_volume(
3487 fake.SHARE_AGGREGATE_NAME, fake.SHARE_NAME, 100,
3488 snaplock_type=snaplock_type)
3490 volume_create_args = {
3491 'containing-aggr-name': fake.SHARE_AGGREGATE_NAME,
3492 'size': '100g',
3493 'volume': fake.SHARE_NAME,
3494 'volume-type': 'rw',
3495 'junction-path': '/%s' % fake.SHARE_NAME,
3496 'space-reserve': 'volume',
3497 'encrypt': 'false',
3498 'snaplock-type': snaplock_type,
3499 }
3501 self.client.send_request.assert_called_once_with('volume-create',
3502 volume_create_args)
3504 def test_create_volume_adaptive_not_supported(self):
3506 self.client.features.add_feature('ADAPTIVE_QOS', supported=False)
3507 self.mock_object(self.client, 'send_request')
3508 self.assertRaises(exception.NetAppException,
3509 self.client.create_volume,
3510 fake.SHARE_AGGREGATE_NAME,
3511 fake.SHARE_NAME,
3512 100,
3513 adaptive_qos_policy_group='fake')
3514 self.client.send_request.assert_not_called()
3516 @ddt.data(True, False)
3517 def test_create_volume_async(self, auto_provisioned):
3518 api_response = netapp_api.NaElement(fake.ASYNC_OPERATION_RESPONSE)
3519 self.mock_object(self.client, 'send_request',
3520 mock.Mock(return_value=api_response))
3521 self.mock_object(
3522 self.client, '_get_create_volume_api_args',
3523 mock.Mock(return_value={}))
3525 result = self.client.create_volume_async(
3526 [fake.SHARE_AGGREGATE_NAME], fake.SHARE_NAME, 1,
3527 auto_provisioned=auto_provisioned)
3529 volume_create_args = {
3530 'size': 1073741824,
3531 'volume-name': fake.SHARE_NAME,
3532 }
3533 if auto_provisioned:
3534 volume_create_args['auto-provision-as'] = 'flexgroup'
3535 else:
3536 volume_create_args['aggr-list'] = [
3537 {'aggr-name': fake.SHARE_AGGREGATE_NAME}]
3539 expected_result = {
3540 'jobid': '123',
3541 'error-code': None,
3542 'error-message': None,
3543 }
3545 self.client._get_create_volume_api_args.assert_called_once_with(
3546 fake.SHARE_NAME, False, None, None, None, 'rw', None, False,
3547 None, None, None)
3548 self.client.send_request.assert_called_with('volume-create-async',
3549 volume_create_args)
3550 self.assertEqual(expected_result, result)
3552 def test_create_volume_async_adaptive_not_supported(self):
3554 self.client.features.add_feature('ADAPTIVE_QOS', supported=False)
3555 self.mock_object(self.client, 'send_request')
3556 self.assertRaises(exception.NetAppException,
3557 self.client.create_volume_async,
3558 [fake.SHARE_AGGREGATE_NAME],
3559 fake.SHARE_NAME,
3560 100,
3561 adaptive_qos_policy_group='fake')
3562 self.client.send_request.assert_not_called()
3564 def test_get_create_volume_api_args_with_mount_point_name(self):
3566 self.client.features.add_feature('FLEXVOL_ENCRYPTION')
3567 volume_type = 'rw'
3568 thin_provisioned = False
3569 snapshot_policy = 'default'
3570 language = 'en-US'
3571 reserve = 15
3572 qos_name = 'fake_qos'
3573 encrypt = True
3574 qos_adaptive_name = 'fake_adaptive_qos'
3575 mount_point_name = 'fake_mp'
3577 result_api_args = self.client._get_create_volume_api_args(
3578 fake.SHARE_NAME, thin_provisioned, snapshot_policy, language,
3579 reserve, volume_type, qos_name, encrypt, qos_adaptive_name,
3580 mount_point_name)
3582 expected_api_args = {
3583 'volume-type': volume_type,
3584 'junction-path': '/fake_mp',
3585 'space-reserve': 'volume',
3586 'snapshot-policy': snapshot_policy,
3587 'language-code': language,
3588 'percentage-snapshot-reserve': str(reserve),
3589 'qos-policy-group-name': qos_name,
3590 'qos-adaptive-policy-group-name': qos_adaptive_name,
3591 'encrypt': 'true',
3592 }
3593 self.assertEqual(expected_api_args, result_api_args)
3595 def test_get_create_volume_api_args_with_extra_specs(self):
3597 self.client.features.add_feature('FLEXVOL_ENCRYPTION')
3598 volume_type = 'rw'
3599 thin_provisioned = False
3600 snapshot_policy = 'default'
3601 language = 'en-US'
3602 reserve = 15
3603 qos_name = 'fake_qos'
3604 encrypt = True
3605 qos_adaptive_name = 'fake_adaptive_qos'
3607 result_api_args = self.client._get_create_volume_api_args(
3608 fake.SHARE_NAME, thin_provisioned, snapshot_policy, language,
3609 reserve, volume_type, qos_name, encrypt, qos_adaptive_name)
3611 expected_api_args = {
3612 'volume-type': volume_type,
3613 'junction-path': '/fake_share',
3614 'space-reserve': 'volume',
3615 'snapshot-policy': snapshot_policy,
3616 'language-code': language,
3617 'percentage-snapshot-reserve': str(reserve),
3618 'qos-policy-group-name': qos_name,
3619 'qos-adaptive-policy-group-name': qos_adaptive_name,
3620 'encrypt': 'true',
3621 }
3622 self.assertEqual(expected_api_args, result_api_args)
3624 def test_get_create_volume_api_args_no_extra_specs(self):
3626 self.client.features.add_feature('FLEXVOL_ENCRYPTION')
3627 volume_type = 'dp'
3628 thin_provisioned = False
3629 snapshot_policy = None
3630 language = None
3631 reserve = None
3632 qos_name = None
3633 encrypt = False
3634 qos_adaptive_name = None
3636 result_api_args = self.client._get_create_volume_api_args(
3637 fake.SHARE_NAME, thin_provisioned, snapshot_policy, language,
3638 reserve, volume_type, qos_name, encrypt, qos_adaptive_name)
3640 expected_api_args = {
3641 'volume-type': volume_type,
3642 'space-reserve': 'volume',
3643 'encrypt': 'false'
3644 }
3645 self.assertEqual(expected_api_args, result_api_args)
3647 def test_get_create_volume_api_args_encrypted_not_supported(self):
3649 encrypt = True
3650 self.assertRaises(exception.NetAppException,
3651 self.client._get_create_volume_api_args,
3652 fake.SHARE_NAME, True, 'default', 'en-US',
3653 15, 'rw', 'fake_qos', encrypt, 'fake_qos_adaptive')
3655 def test_is_flexvol_encrypted_unsupported(self):
3657 self.client.features.add_feature('FLEXVOL_ENCRYPTION', supported=False)
3659 result = self.client.is_flexvol_encrypted(fake.SHARE_NAME,
3660 fake.VSERVER_NAME)
3662 self.assertFalse(result)
3664 def test_is_flexvol_encrypted_no_records_found(self):
3666 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
3667 self.mock_object(self.client,
3668 'send_iter_request',
3669 mock.Mock(return_value=api_response))
3671 result = self.client.is_flexvol_encrypted(fake.SHARE_NAME,
3672 fake.VSERVER_NAME)
3674 self.assertFalse(result)
3676 def test_is_flexvol_encrypted(self):
3678 self.client.features.add_feature('FLEXVOL_ENCRYPTION', supported=True)
3679 api_response = netapp_api.NaElement(
3680 fake.GET_VOLUME_FOR_ENCRYPTED_RESPONSE)
3681 self.mock_object(self.client,
3682 'send_iter_request',
3683 mock.Mock(return_value=api_response))
3685 result = self.client.is_flexvol_encrypted(fake.SHARE_NAME,
3686 fake.VSERVER_NAME)
3688 volume_get_iter_args = {
3689 'query': {
3690 'volume-attributes': {
3691 'encrypt': 'true',
3692 'volume-id-attributes': {
3693 'name': fake.SHARE_NAME,
3694 'owning-vserver-name': fake.VSERVER_NAME,
3695 }
3696 }
3697 },
3698 'desired-attributes': {
3699 'volume-attributes': {
3700 'encrypt': None,
3701 }
3702 }
3703 }
3705 self.client.send_iter_request.assert_called_once_with(
3706 'volume-get-iter', volume_get_iter_args)
3708 self.assertTrue(result)
3710 def test_is_flexvol_encrypted_8_x_system_version_response(self):
3712 self.client.features.add_feature('FLEXVOL_ENCRYPTION', supported=True)
3713 api_response = netapp_api.NaElement(
3714 fake.GET_VOLUME_FOR_ENCRYPTED_OLD_SYS_VERSION_RESPONSE)
3715 self.mock_object(self.client,
3716 'send_iter_request',
3717 mock.Mock(return_value=api_response))
3719 result = self.client.is_flexvol_encrypted(fake.SHARE_NAME,
3720 fake.VSERVER_NAME)
3722 volume_get_iter_args = {
3723 'query': {
3724 'volume-attributes': {
3725 'encrypt': 'true',
3726 'volume-id-attributes': {
3727 'name': fake.SHARE_NAME,
3728 'owning-vserver-name': fake.VSERVER_NAME,
3729 }
3730 }
3731 },
3732 'desired-attributes': {
3733 'volume-attributes': {
3734 'encrypt': None,
3735 }
3736 }
3737 }
3739 self.client.send_iter_request.assert_called_once_with(
3740 'volume-get-iter', volume_get_iter_args)
3742 self.assertFalse(result)
3744 def test_update_volume_snapshot_policy(self):
3745 self.mock_object(self.client, 'send_request')
3747 self.client.update_volume_snapshot_policy(fake.SHARE_NAME,
3748 fake.SNAPSHOT_POLICY_NAME)
3750 volume_modify_iter_api_args = {
3751 'query': {
3752 'volume-attributes': {
3753 'volume-id-attributes': {
3754 'name': fake.SHARE_NAME,
3755 },
3756 },
3757 },
3758 'attributes': {
3759 'volume-attributes': {
3760 'volume-snapshot-attributes': {
3761 'snapshot-policy': fake.SNAPSHOT_POLICY_NAME,
3762 },
3763 },
3764 },
3765 }
3767 self.client.send_request.assert_called_once_with(
3768 'volume-modify-iter', volume_modify_iter_api_args)
3770 def test_enable_dedup(self):
3772 self.mock_object(self.client, 'send_request')
3774 self.client.enable_dedup(fake.SHARE_NAME)
3776 sis_enable_args = {'path': '/vol/%s' % fake.SHARE_NAME}
3778 self.client.send_request.assert_called_once_with('sis-enable',
3779 sis_enable_args)
3781 def test_enable_dedup_already_enabled(self):
3782 side_effect = netapp_api.NaApiError(
3783 code=netapp_api.OPERATION_ALREADY_ENABLED,
3784 message='It has already been enabled')
3786 self.mock_object(self.client,
3787 'send_request',
3788 mock.Mock(side_effect=side_effect))
3790 self.client.enable_dedup(fake.SHARE_NAME)
3792 sis_enable_args = {'path': '/vol/%s' % fake.SHARE_NAME}
3794 self.client.send_request.assert_called_once_with('sis-enable',
3795 sis_enable_args)
3797 def test_enable_dedup_currently_active(self):
3798 side_effect = netapp_api.NaApiError(
3799 code=netapp_api.OPERATION_ALREADY_ENABLED,
3800 message='The sis operation is currently active')
3802 self.mock_object(self.client,
3803 'send_request',
3804 mock.Mock(side_effect=side_effect))
3806 self.assertRaises(exception.NetAppException,
3807 self.client.enable_dedup,
3808 fake.SHARE_NAME)
3810 def test_disable_dedup(self):
3812 self.mock_object(self.client, 'send_request')
3814 self.client.disable_dedup(fake.SHARE_NAME)
3816 sis_disable_args = {'path': '/vol/%s' % fake.SHARE_NAME}
3818 self.client.send_request.assert_called_once_with('sis-disable',
3819 sis_disable_args)
3821 def test_disable_dedup_currently_active(self):
3822 side_effect = netapp_api.NaApiError(
3823 code=netapp_api.OPERATION_ALREADY_ENABLED,
3824 message='The sis operation is currently active')
3826 self.mock_object(self.client,
3827 'send_request',
3828 mock.Mock(side_effect=side_effect))
3830 self.assertRaises(exception.NetAppException,
3831 self.client.disable_dedup,
3832 fake.SHARE_NAME)
3834 def test_enable_compression(self):
3836 self.mock_object(self.client, 'send_request')
3838 self.client.enable_compression(fake.SHARE_NAME)
3840 sis_set_config_args = {
3841 'path': '/vol/%s' % fake.SHARE_NAME,
3842 'enable-compression': 'true'
3843 }
3845 self.client.send_request.assert_called_once_with('sis-set-config',
3846 sis_set_config_args)
3848 def test_disable_compression(self):
3850 self.mock_object(self.client, 'send_request')
3852 self.client.disable_compression(fake.SHARE_NAME)
3854 sis_set_config_args = {
3855 'path': '/vol/%s' % fake.SHARE_NAME,
3856 'enable-compression': 'false'
3857 }
3859 self.client.send_request.assert_called_once_with('sis-set-config',
3860 sis_set_config_args)
3862 def test_enable_dedupe_async(self):
3863 self.mock_object(self.client, 'send_request')
3865 self.client.enable_dedupe_async(fake.SHARE_NAME)
3867 sis_enable_args = {'volume-name': fake.SHARE_NAME}
3868 self.client.send_request.assert_called_once_with(
3869 'sis-enable-async', sis_enable_args)
3871 def test_disable_dedupe_async(self):
3872 self.mock_object(self.client, 'send_request')
3874 self.client.disable_dedupe_async(fake.SHARE_NAME)
3876 sis_enable_args = {'volume-name': fake.SHARE_NAME}
3877 self.client.send_request.assert_called_once_with(
3878 'sis-disable-async', sis_enable_args)
3880 def test_enable_compression_async(self):
3881 self.mock_object(self.client, 'send_request')
3883 self.client.enable_compression_async(fake.SHARE_NAME)
3885 sis_set_config_args = {
3886 'volume-name': fake.SHARE_NAME,
3887 'enable-compression': 'true'
3888 }
3889 self.client.send_request.assert_called_once_with(
3890 'sis-set-config-async', sis_set_config_args)
3892 def test_disable_compression_async(self):
3893 self.mock_object(self.client, 'send_request')
3895 self.client.disable_compression_async(fake.SHARE_NAME)
3897 sis_set_config_args = {
3898 'volume-name': fake.SHARE_NAME,
3899 'enable-compression': 'false'
3900 }
3901 self.client.send_request.assert_called_once_with(
3902 'sis-set-config-async', sis_set_config_args)
3904 def test_apply_volume_efficiency_policy_with_policy(self):
3905 self.mock_object(self.client, 'send_request')
3906 self.client.apply_volume_efficiency_policy(
3907 fake.SHARE_NAME, fake.VOLUME_EFFICIENCY_POLICY_NAME
3908 )
3910 volume_efficiency_config_args = {
3911 'path': '/vol/%s' % fake.SHARE_NAME,
3912 'policy-name': fake.VOLUME_EFFICIENCY_POLICY_NAME
3913 }
3915 self.client.send_request.assert_called_once_with(
3916 'sis-set-config', volume_efficiency_config_args)
3918 def test_apply_volume_efficiency_policy_without_policy(self):
3919 self.mock_object(self.client, 'send_request')
3920 self.client.apply_volume_efficiency_policy(
3921 fake.SHARE_NAME, None
3922 )
3924 self.client.send_request.assert_not_called()
3926 def test_apply_volume_efficiency_policy_async_with_policy(self):
3927 self.mock_object(self.client.connection, 'send_request')
3928 self.client.apply_volume_efficiency_policy_async(
3929 fake.SHARE_NAME, fake.VOLUME_EFFICIENCY_POLICY_NAME
3930 )
3932 volume_efficiency_config_args = {
3933 'path': '/vol/%s' % fake.SHARE_NAME,
3934 'policy-name': fake.VOLUME_EFFICIENCY_POLICY_NAME
3935 }
3937 self.client.connection.send_request.assert_called_once_with(
3938 'sis-set-config-async', volume_efficiency_config_args)
3940 def test_apply_volume_efficiency_policy_async_without_policy(self):
3941 self.mock_object(self.client.connection, 'send_request')
3942 self.client.apply_volume_efficiency_policy_async(
3943 fake.SHARE_NAME
3944 )
3946 self.client.connection.send_request.assert_not_called()
3948 def test_get_volume_efficiency_status(self):
3950 api_response = netapp_api.NaElement(fake.SIS_GET_ITER_RESPONSE)
3951 self.mock_object(self.client,
3952 'send_iter_request',
3953 mock.Mock(return_value=api_response))
3955 result = self.client.get_volume_efficiency_status(fake.SHARE_NAME)
3957 sis_get_iter_args = {
3958 'query': {
3959 'sis-status-info': {
3960 'path': '/vol/%s' % fake.SHARE_NAME,
3961 },
3962 },
3963 'desired-attributes': {
3964 'sis-status-info': {
3965 'state': None,
3966 'is-compression-enabled': None,
3967 },
3968 },
3969 }
3970 self.client.send_iter_request.assert_has_calls([
3971 mock.call('sis-get-iter', sis_get_iter_args)])
3973 expected = {'dedupe': True, 'compression': True}
3974 self.assertDictEqual(expected, result)
3976 def test_get_volume_efficiency_status_not_found(self):
3978 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
3979 self.mock_object(self.client,
3980 'send_iter_request',
3981 mock.Mock(return_value=api_response))
3983 result = self.client.get_volume_efficiency_status(fake.SHARE_NAME)
3985 expected = {'dedupe': False, 'compression': False}
3986 self.assertDictEqual(expected, result)
3988 def test_set_volume_max_files(self):
3990 api_response = netapp_api.NaElement(fake.VOLUME_MODIFY_ITER_RESPONSE)
3991 self.mock_object(self.client,
3992 'send_request',
3993 mock.Mock(return_value=api_response))
3995 self.client.set_volume_max_files(fake.SHARE_NAME, fake.MAX_FILES)
3997 volume_modify_iter_api_args = {
3998 'query': {
3999 'volume-attributes': {
4000 'volume-id-attributes': {
4001 'name': fake.SHARE_NAME,
4002 },
4003 },
4004 },
4005 'attributes': {
4006 'volume-attributes': {
4007 'volume-inode-attributes': {
4008 'files-total': fake.MAX_FILES,
4009 },
4010 },
4011 },
4012 }
4014 self.client.send_request.assert_called_once_with(
4015 'volume-modify-iter', volume_modify_iter_api_args)
4017 def test_set_volume_name(self):
4019 self.mock_object(self.client, 'send_request')
4021 self.client.set_volume_name(fake.SHARE_NAME, 'new_name')
4023 volume_rename_api_args = {
4024 'volume': fake.SHARE_NAME,
4025 'new-volume-name': 'new_name',
4026 }
4028 self.client.send_request.assert_called_once_with(
4029 'volume-rename', volume_rename_api_args)
4031 def test_rename_vserver(self):
4033 vserver_api_args = {
4034 'vserver-name': fake.VSERVER_NAME,
4035 'new-name': fake.VSERVER_NAME_2,
4036 }
4037 self.mock_object(self.client, 'send_request')
4039 self.client.rename_vserver(fake.VSERVER_NAME, fake.VSERVER_NAME_2)
4041 self.client.send_request.assert_called_once_with(
4042 'vserver-rename', vserver_api_args
4043 )
4045 @ddt.data(True, False)
4046 def test_modify_volume_no_optional_args(self, is_flexgroup):
4048 self.mock_object(self.client, 'send_request')
4049 mock_update_volume_efficiency_attributes = self.mock_object(
4050 self.client, 'update_volume_efficiency_attributes')
4051 self.mock_object(self.client, '_is_snaplock_enabled_volume',
4052 mock.Mock(return_value=True))
4054 aggr = fake.SHARE_AGGREGATE_NAME
4055 if is_flexgroup:
4056 aggr = list(fake.SHARE_AGGREGATE_NAMES)
4058 self.client.modify_volume(aggr, fake.SHARE_NAME)
4060 volume_modify_iter_api_args = {
4061 'query': {
4062 'volume-attributes': {
4063 'volume-id-attributes': {
4064 'name': fake.SHARE_NAME,
4065 },
4066 },
4067 },
4068 'attributes': {
4069 'volume-attributes': {
4070 'volume-inode-attributes': {},
4071 'volume-language-attributes': {},
4072 'volume-snapshot-attributes': {},
4073 'volume-space-attributes': {
4074 'space-guarantee': 'volume',
4075 },
4076 'volume-autosize-attributes': {},
4077 },
4078 },
4079 }
4081 if is_flexgroup:
4082 volume_modify_iter_api_args['query']['volume-attributes'][
4083 'volume-id-attributes']['aggr-list'] = [
4084 {'aggr-name': aggr[0]}, {'aggr-name': aggr[1]}]
4085 else:
4086 volume_modify_iter_api_args['query']['volume-attributes'][
4087 'volume-id-attributes'][
4088 'containing-aggregate-name'] = aggr
4090 self.client.send_request.assert_called_once_with(
4091 'volume-modify-iter', volume_modify_iter_api_args)
4092 mock_update_volume_efficiency_attributes.assert_called_once_with(
4093 fake.SHARE_NAME, False, False,
4094 is_flexgroup=is_flexgroup, efficiency_policy=None
4095 )
4097 @ddt.data((fake.QOS_POLICY_GROUP_NAME, None),
4098 (None, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME))
4099 @ddt.unpack
4100 def test_modify_volume_all_optional_args(self, qos_group,
4101 adaptive_qos_group):
4102 self.client.features.add_feature('ADAPTIVE_QOS')
4103 self.mock_object(self.client, 'send_request')
4104 mock_update_volume_efficiency_attributes = self.mock_object(
4105 self.client, 'update_volume_efficiency_attributes')
4106 options = {'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME}
4107 self.mock_object(self.client, '_is_snaplock_enabled_volume',
4108 mock.Mock(return_value=True))
4110 self.client.modify_volume(
4111 fake.SHARE_AGGREGATE_NAME,
4112 fake.SHARE_NAME,
4113 thin_provisioned=True,
4114 snapshot_policy=fake.SNAPSHOT_POLICY_NAME,
4115 language=fake.LANGUAGE,
4116 dedup_enabled=True,
4117 compression_enabled=False,
4118 max_files=fake.MAX_FILES,
4119 qos_policy_group=qos_group,
4120 adaptive_qos_policy_group=adaptive_qos_group,
4121 autosize_attributes=fake.VOLUME_AUTOSIZE_ATTRS,
4122 hide_snapdir=True,
4123 **options
4124 )
4126 volume_modify_iter_api_args = {
4127 'query': {
4128 'volume-attributes': {
4129 'volume-id-attributes': {
4130 'containing-aggregate-name': fake.SHARE_AGGREGATE_NAME,
4131 'name': fake.SHARE_NAME,
4132 },
4133 },
4134 },
4135 'attributes': {
4136 'volume-attributes': {
4137 'volume-inode-attributes': {
4138 'files-total': fake.MAX_FILES,
4139 },
4140 'volume-language-attributes': {
4141 'language': fake.LANGUAGE,
4142 },
4143 'volume-snapshot-attributes': {
4144 'snapshot-policy': fake.SNAPSHOT_POLICY_NAME,
4145 'snapdir-access-enabled': 'false'
4146 },
4147 'volume-space-attributes': {
4148 'space-guarantee': 'none',
4149 },
4150 'volume-autosize-attributes': fake.VOLUME_AUTOSIZE_ATTRS,
4151 },
4152 },
4153 }
4154 if qos_group:
4155 qos_update = {
4156 'volume-qos-attributes': {
4157 'policy-group-name': qos_group,
4158 },
4159 }
4160 volume_modify_iter_api_args[
4161 'attributes']['volume-attributes'].update(qos_update)
4162 if adaptive_qos_group:
4163 qos_update = {
4164 'volume-qos-attributes': {
4165 'adaptive-policy-group-name': adaptive_qos_group,
4166 },
4167 }
4168 volume_modify_iter_api_args[
4169 'attributes']['volume-attributes'].update(qos_update)
4171 self.client.send_request.assert_called_once_with(
4172 'volume-modify-iter', volume_modify_iter_api_args)
4173 mock_update_volume_efficiency_attributes.assert_called_once_with(
4174 fake.SHARE_NAME, True, False,
4175 is_flexgroup=False,
4176 efficiency_policy=fake.VOLUME_EFFICIENCY_POLICY_NAME
4177 )
4179 @ddt.data(
4180 {'existing': (True, True), 'desired': (True, True), 'fg': False,
4181 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4182 {'existing': (True, True), 'desired': (False, False), 'fg': False,
4183 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4184 {'existing': (True, True), 'desired': (True, False), 'fg': False,
4185 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4186 {'existing': (True, False), 'desired': (True, False), 'fg': False,
4187 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4188 {'existing': (True, False), 'desired': (False, False), 'fg': False,
4189 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4190 {'existing': (True, False), 'desired': (True, True), 'fg': False,
4191 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4192 {'existing': (False, False), 'desired': (False, False), 'fg': False,
4193 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4194 {'existing': (False, False), 'desired': (True, False), 'fg': False,
4195 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4196 {'existing': (False, False), 'desired': (True, True), 'fg': False,
4197 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4198 {'existing': (True, True), 'desired': (True, True), 'fg': True,
4199 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4200 {'existing': (True, True), 'desired': (False, False), 'fg': True,
4201 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4202 {'existing': (True, True), 'desired': (True, False), 'fg': True,
4203 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4204 {'existing': (True, False), 'desired': (True, False), 'fg': True,
4205 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4206 {'existing': (True, False), 'desired': (False, False), 'fg': True,
4207 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4208 {'existing': (True, False), 'desired': (True, True), 'fg': True,
4209 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4210 {'existing': (False, False), 'desired': (False, False), 'fg': True,
4211 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4212 {'existing': (False, False), 'desired': (True, False), 'fg': True,
4213 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4214 {'existing': (False, False), 'desired': (True, True), 'fg': True,
4215 'efficiency_policy': fake.VOLUME_EFFICIENCY_POLICY_NAME},
4216 )
4217 @ddt.unpack
4218 def test_update_volume_efficiency_attributes(self, existing, desired, fg,
4219 efficiency_policy):
4221 existing_dedupe = existing[0]
4222 existing_compression = existing[1]
4223 desired_dedupe = desired[0]
4224 desired_compression = desired[1]
4226 self.mock_object(
4227 self.client,
4228 'get_volume_efficiency_status',
4229 mock.Mock(return_value={'dedupe': existing_dedupe,
4230 'compression': existing_compression}))
4231 mock_enable_compression = self.mock_object(self.client,
4232 'enable_compression')
4233 mock_enable_compression_async = self.mock_object(
4234 self.client, 'enable_compression_async')
4235 mock_disable_compression = self.mock_object(self.client,
4236 'disable_compression')
4237 mock_disable_compression_async = self.mock_object(
4238 self.client, 'disable_compression_async')
4239 mock_enable_dedup = self.mock_object(self.client, 'enable_dedup')
4240 mock_enable_dedup_async = self.mock_object(self.client,
4241 'enable_dedupe_async')
4242 mock_disable_dedup = self.mock_object(self.client, 'disable_dedup')
4243 mock_disable_dedup_async = self.mock_object(self.client,
4244 'disable_dedupe_async')
4245 mock_apply_volume_efficiency_policy = (
4246 self.mock_object(self.client, 'apply_volume_efficiency_policy'))
4247 mock_apply_volume_efficiency_policy_async = (
4248 self.mock_object(self.client,
4249 'apply_volume_efficiency_policy_async'
4250 )
4251 )
4253 self.client.update_volume_efficiency_attributes(
4254 fake.SHARE_NAME, desired_dedupe, desired_compression,
4255 is_flexgroup=fg, efficiency_policy=efficiency_policy)
4257 if existing_dedupe == desired_dedupe:
4258 if fg:
4259 self.assertFalse(mock_enable_dedup_async.called)
4260 self.assertFalse(mock_disable_dedup_async.called)
4261 else:
4262 self.assertFalse(mock_enable_dedup.called)
4263 self.assertFalse(mock_disable_dedup.called)
4264 elif existing_dedupe and not desired_dedupe:
4265 if fg:
4266 self.assertFalse(mock_enable_dedup_async.called)
4267 self.assertTrue(mock_disable_dedup_async.called)
4268 else:
4269 self.assertFalse(mock_enable_dedup.called)
4270 self.assertTrue(mock_disable_dedup.called)
4271 elif not existing_dedupe and desired_dedupe: 4271 ↛ 4279line 4271 didn't jump to line 4279 because the condition on line 4271 was always true
4272 if fg:
4273 self.assertTrue(mock_enable_dedup_async.called)
4274 self.assertFalse(mock_disable_dedup_async.called)
4275 else:
4276 self.assertTrue(mock_enable_dedup.called)
4277 self.assertFalse(mock_disable_dedup.called)
4279 if existing_compression == desired_compression:
4280 if fg:
4281 self.assertFalse(mock_enable_compression_async.called)
4282 self.assertFalse(mock_disable_compression_async.called)
4283 else:
4284 self.assertFalse(mock_enable_compression.called)
4285 self.assertFalse(mock_disable_compression.called)
4286 elif existing_compression and not desired_compression:
4287 if fg:
4288 self.assertFalse(mock_enable_compression_async.called)
4289 self.assertTrue(mock_disable_compression_async.called)
4290 else:
4291 self.assertFalse(mock_enable_compression.called)
4292 self.assertTrue(mock_disable_compression.called)
4293 elif not existing_compression and desired_compression: 4293 ↛ 4301line 4293 didn't jump to line 4301 because the condition on line 4293 was always true
4294 if fg:
4295 self.assertTrue(mock_enable_compression_async.called)
4296 self.assertFalse(mock_disable_compression_async.called)
4297 else:
4298 self.assertTrue(mock_enable_compression.called)
4299 self.assertFalse(mock_disable_compression.called)
4301 if fg:
4302 self.assertTrue(mock_apply_volume_efficiency_policy_async.called)
4303 else:
4304 self.assertTrue(mock_apply_volume_efficiency_policy.called)
4306 def test_set_volume_size(self):
4308 api_response = netapp_api.NaElement(fake.VOLUME_MODIFY_ITER_RESPONSE)
4309 self.mock_object(self.client,
4310 'send_request',
4311 mock.Mock(return_value=api_response))
4313 self.client.set_volume_size(fake.SHARE_NAME, 10)
4315 volume_modify_iter_args = {
4316 'query': {
4317 'volume-attributes': {
4318 'volume-id-attributes': {
4319 'name': fake.SHARE_NAME
4320 }
4321 }
4322 },
4323 'attributes': {
4324 'volume-attributes': {
4325 'volume-space-attributes': {
4326 'size': 10737418240,
4327 },
4328 },
4329 },
4330 }
4331 self.client.send_request.assert_has_calls([
4332 mock.call('volume-modify-iter', volume_modify_iter_args)])
4334 @ddt.data(True, False)
4335 def test_set_volume_snapdir_access(self, hide_snapdir):
4336 api_response = netapp_api.NaElement(
4337 fake.VOLUME_MODIFY_ITER_RESPONSE)
4338 self.mock_object(self.client,
4339 'send_request',
4340 mock.Mock(return_value=api_response))
4342 self.client.set_volume_snapdir_access(fake.SHARE_NAME, hide_snapdir)
4344 api_args = {
4345 'query': {
4346 'volume-attributes': {
4347 'volume-id-attributes': {
4348 'name': fake.SHARE_NAME
4349 }
4350 }
4351 },
4352 'attributes': {
4353 'volume-attributes': {
4354 'volume-snapshot-attributes': {
4355 'snapdir-access-enabled': str(
4356 not hide_snapdir).lower(),
4357 },
4358 },
4359 },
4360 }
4361 self.client.send_request.assert_called_once_with(
4362 'volume-modify-iter', api_args)
4364 def test_set_volume_snapdir_access_api_error(self):
4366 api_response = netapp_api.NaElement(
4367 fake.VOLUME_MODIFY_ITER_ERROR_RESPONSE)
4368 self.mock_object(self.client,
4369 'send_request',
4370 mock.Mock(return_value=api_response))
4372 self.assertRaises(netapp_api.NaApiError,
4373 self.client.set_volume_size,
4374 fake.SHARE_NAME,
4375 10)
4377 @ddt.data(True, False)
4378 def test_set_volume_filesys_size_fixed(self, filesys_size_fixed):
4379 api_response = netapp_api.NaElement(
4380 fake.VOLUME_MODIFY_ITER_RESPONSE)
4381 self.mock_object(self.client,
4382 'send_request',
4383 mock.Mock(return_value=api_response))
4385 self.client.set_volume_filesys_size_fixed(fake.SHARE_NAME,
4386 filesys_size_fixed)
4388 api_args = {
4389 'query': {
4390 'volume-attributes': {
4391 'volume-id-attributes': {
4392 'name': fake.SHARE_NAME
4393 }
4394 }
4395 },
4396 'attributes': {
4397 'volume-attributes': {
4398 'volume-space-attributes': {
4399 'is-filesys-size-fixed': str(
4400 filesys_size_fixed).lower(),
4401 },
4402 },
4403 },
4404 }
4405 self.client.send_request.assert_called_once_with(
4406 'volume-modify-iter', api_args)
4408 def test_set_volume_size_api_error(self):
4410 api_response = netapp_api.NaElement(
4411 fake.VOLUME_MODIFY_ITER_ERROR_RESPONSE)
4412 self.mock_object(self.client,
4413 'send_request',
4414 mock.Mock(return_value=api_response))
4416 self.assertRaises(netapp_api.NaApiError,
4417 self.client.set_volume_size,
4418 fake.SHARE_NAME,
4419 10)
4421 @ddt.data(None, 'ntfs')
4422 def test_set_volume_security_style(self, security_style):
4424 api_response = netapp_api.NaElement(fake.VOLUME_MODIFY_ITER_RESPONSE)
4425 self.mock_object(self.client,
4426 'send_request',
4427 mock.Mock(return_value=api_response))
4428 kwargs = {'security_style': security_style} if security_style else {}
4430 self.client.set_volume_security_style(fake.SHARE_NAME, **kwargs)
4432 volume_modify_iter_args = {
4433 'query': {
4434 'volume-attributes': {
4435 'volume-id-attributes': {
4436 'name': fake.SHARE_NAME
4437 }
4438 }
4439 },
4440 'attributes': {
4441 'volume-attributes': {
4442 'volume-security-attributes': {
4443 'style': security_style or 'unix',
4444 },
4445 },
4446 },
4447 }
4448 self.client.send_request.assert_called_once_with(
4449 'volume-modify-iter', volume_modify_iter_args)
4451 def test_set_volume_security_style_api_error(self):
4453 api_response = netapp_api.NaElement(
4454 fake.VOLUME_MODIFY_ITER_ERROR_RESPONSE)
4455 self.mock_object(self.client,
4456 'send_request',
4457 mock.Mock(return_value=api_response))
4459 self.assertRaises(netapp_api.NaApiError,
4460 self.client.set_volume_security_style,
4461 fake.SHARE_NAME,
4462 'ntfs')
4464 def test_volume_exists(self):
4466 api_response = netapp_api.NaElement(fake.VOLUME_GET_NAME_RESPONSE)
4467 self.mock_object(self.client,
4468 'send_iter_request',
4469 mock.Mock(return_value=api_response))
4471 result = self.client.volume_exists(fake.SHARE_NAME)
4473 volume_get_iter_args = {
4474 'query': {
4475 'volume-attributes': {
4476 'volume-id-attributes': {
4477 'name': fake.SHARE_NAME
4478 }
4479 }
4480 },
4481 'desired-attributes': {
4482 'volume-attributes': {
4483 'volume-id-attributes': {
4484 'name': None
4485 }
4486 }
4487 }
4488 }
4490 self.client.send_iter_request.assert_has_calls([
4491 mock.call('volume-get-iter', volume_get_iter_args)])
4492 self.assertTrue(result)
4494 def test_volume_exists_not_found(self):
4496 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
4497 self.mock_object(self.client,
4498 'send_request',
4499 mock.Mock(return_value=api_response))
4501 self.assertFalse(self.client.volume_exists(fake.SHARE_NAME))
4503 def test_snapshot_exists(self):
4505 api_response = netapp_api.NaElement(fake.VOLUME_GET_NAME_RESPONSE)
4506 self.mock_object(self.client,
4507 'send_request',
4508 mock.Mock(return_value=api_response))
4510 result = self.client.snapshot_exists(fake.SNAPSHOT_NAME,
4511 fake.SHARE_NAME)
4513 snapshot_get_iter_args = {
4514 'query': {
4515 'snapshot-info': {
4516 'name': fake.SNAPSHOT_NAME,
4517 'volume': fake.SHARE_NAME,
4518 }
4519 },
4520 'desired-attributes': {
4521 'snapshot-info': {
4522 'name': None,
4523 'volume': None,
4524 'busy': None,
4525 'snapshot-owners-list': {
4526 'snapshot-owner': None,
4527 }
4528 }
4529 }
4530 }
4532 self.client.send_request.assert_has_calls([
4533 mock.call('snapshot-get-iter', snapshot_get_iter_args)])
4534 self.assertTrue(result)
4536 def test_snapshot_exists_not_found(self):
4537 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
4538 self.mock_object(self.client,
4539 'send_request',
4540 mock.Mock(return_value=api_response))
4542 self.assertFalse(self.client.snapshot_exists(fake.SNAPSHOT_NAME,
4543 fake.SHARE_NAME))
4545 @ddt.data({
4546 'api_response_xml': fake.SNAPSHOT_GET_ITER_UNAVAILABLE_RESPONSE,
4547 'raised_exception': exception.SnapshotUnavailable,
4548 }, {
4549 'api_response_xml': fake.SNAPSHOT_GET_ITER_OTHER_ERROR_RESPONSE,
4550 'raised_exception': exception.NetAppException,
4551 })
4552 @ddt.unpack
4553 def test_snapshot_exists_error(self, api_response_xml, raised_exception):
4555 api_response = netapp_api.NaElement(api_response_xml)
4556 self.mock_object(self.client,
4557 'send_request',
4558 mock.Mock(return_value=api_response))
4560 self.assertRaises(raised_exception,
4561 self.client.snapshot_exists,
4562 fake.SNAPSHOT_NAME,
4563 fake.SHARE_NAME)
4565 @ddt.data(True, False)
4566 def test_get_aggregate_for_volume(self, is_flexgroup):
4568 api_response = netapp_api.NaElement(
4569 fake.GET_AGGREGATE_FOR_FLEXGROUP_VOL_RESPONSE if is_flexgroup
4570 else fake.GET_AGGREGATE_FOR_VOLUME_RESPONSE)
4571 self.mock_object(self.client,
4572 'send_iter_request',
4573 mock.Mock(return_value=api_response))
4575 result = self.client.get_aggregate_for_volume(fake.SHARE_NAME)
4577 volume_get_iter_args = {
4578 'query': {
4579 'volume-attributes': {
4580 'volume-id-attributes': {
4581 'name': fake.SHARE_NAME
4582 }
4583 }
4584 },
4585 'desired-attributes': {
4586 'volume-attributes': {
4587 'volume-id-attributes': {
4588 'aggr-list': {
4589 'aggr-name': None,
4590 },
4591 'containing-aggregate-name': None,
4592 'name': None
4593 }
4594 }
4595 }
4596 }
4598 self.client.send_iter_request.assert_has_calls([
4599 mock.call('volume-get-iter', volume_get_iter_args)])
4600 if is_flexgroup:
4601 self.assertEqual([fake.SHARE_AGGREGATE_NAME], result)
4602 else:
4603 self.assertEqual(fake.SHARE_AGGREGATE_NAME, result)
4605 def test_get_aggregate_for_volume_not_found(self):
4607 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
4608 self.mock_object(self.client,
4609 'send_iter_request',
4610 mock.Mock(return_value=api_response))
4612 self.assertRaises(exception.NetAppException,
4613 self.client.get_aggregate_for_volume,
4614 fake.SHARE_NAME)
4616 def test_volume_has_luns(self):
4618 api_response = netapp_api.NaElement(fake.LUN_GET_ITER_RESPONSE)
4619 self.mock_object(self.client,
4620 'send_iter_request',
4621 mock.Mock(return_value=api_response))
4623 result = self.client.volume_has_luns(fake.SHARE_NAME)
4625 lun_get_iter_args = {
4626 'query': {
4627 'lun-info': {
4628 'volume': fake.SHARE_NAME,
4629 },
4630 },
4631 'desired-attributes': {
4632 'lun-info': {
4633 'path': None,
4634 },
4635 },
4636 }
4638 self.client.send_iter_request.assert_has_calls([
4639 mock.call('lun-get-iter', lun_get_iter_args)])
4640 self.assertTrue(result)
4642 def test_volume_has_luns_not_found(self):
4644 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
4645 self.mock_object(self.client,
4646 'send_request',
4647 mock.Mock(return_value=api_response))
4649 result = self.client.volume_has_luns(fake.SHARE_NAME)
4651 self.assertFalse(result)
4653 def test_volume_has_junctioned_volumes(self):
4655 api_response = netapp_api.NaElement(
4656 fake.VOLUME_GET_ITER_JUNCTIONED_VOLUMES_RESPONSE)
4657 self.mock_object(self.client,
4658 'send_iter_request',
4659 mock.Mock(return_value=api_response))
4661 fake_junction_path = '/%s' % fake.SHARE_NAME
4662 result = self.client.volume_has_junctioned_volumes(fake_junction_path)
4664 volume_get_iter_args = {
4665 'query': {
4666 'volume-attributes': {
4667 'volume-id-attributes': {
4668 'junction-path': fake_junction_path + '/*',
4669 },
4670 },
4671 },
4672 'desired-attributes': {
4673 'volume-attributes': {
4674 'volume-id-attributes': {
4675 'name': None,
4676 },
4677 },
4678 },
4679 }
4680 self.client.send_iter_request.assert_has_calls([
4681 mock.call('volume-get-iter', volume_get_iter_args)])
4682 self.assertTrue(result)
4684 def test_volume_has_junctioned_volumes_no_junction_path(self):
4686 result = self.client.volume_has_junctioned_volumes(None)
4688 self.assertFalse(result)
4690 def test_volume_has_junctioned_volumes_not_found(self):
4692 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
4693 self.mock_object(self.client,
4694 'send_request',
4695 mock.Mock(return_value=api_response))
4697 fake_junction_path = '/%s' % fake.SHARE_NAME
4698 result = self.client.volume_has_junctioned_volumes(fake_junction_path)
4700 self.assertFalse(result)
4702 def test_get_volume_snapshot_attributes(self):
4704 api_response = netapp_api.NaElement(
4705 fake.VOLUME_GET_ITER_SNAPSHOT_ATTRIBUTES_RESPONSE)
4706 self.mock_object(self.client,
4707 'send_request',
4708 mock.Mock(return_value=api_response))
4710 result = self.client.get_volume_snapshot_attributes(fake.SHARE_NAME)
4712 desired_snapshot_attributes = {
4713 'snapshot-policy': None,
4714 'snapdir-access-enabled': None,
4715 }
4716 snap_get_iter_args = {
4717 'query': {
4718 'volume-attributes': {
4719 'volume-id-attributes': {
4720 'name': fake.SHARE_NAME,
4721 },
4722 },
4723 },
4724 'desired-attributes': {
4725 'volume-attributes': {
4726 'volume-snapshot-attributes': desired_snapshot_attributes,
4727 },
4728 },
4729 }
4731 self.client.send_request.assert_has_calls([
4732 mock.call('volume-get-iter', snap_get_iter_args)])
4734 expected = {
4735 'snapshot-policy': 'daily', 'snapdir-access-enabled': 'false'}
4736 self.assertDictEqual(expected, result)
4738 @ddt.data(True, False)
4739 def test_get_volume(self, is_flexgroup):
4741 api_response = netapp_api.NaElement(
4742 fake.VOLUME_GET_ITER_FLEXGROUP_VOLUME_TO_MANAGE_RESPONSE
4743 if is_flexgroup
4744 else fake.VOLUME_GET_ITER_VOLUME_TO_MANAGE_RESPONSE)
4745 self.mock_object(self.client,
4746 'send_request',
4747 mock.Mock(return_value=api_response))
4749 result = self.client.get_volume(fake.SHARE_NAME)
4751 volume_get_iter_args = {
4752 'query': {
4753 'volume-attributes': {
4754 'volume-id-attributes': {
4755 'name': fake.SHARE_NAME,
4756 },
4757 },
4758 },
4759 'desired-attributes': {
4760 'volume-attributes': {
4761 'volume-id-attributes': {
4762 'aggr-list': {
4763 'aggr-name': None,
4764 },
4765 'containing-aggregate-name': None,
4766 'junction-path': None,
4767 'name': None,
4768 'owning-vserver-name': None,
4769 'type': None,
4770 'style': None,
4771 'style-extended': None,
4772 },
4773 'volume-space-attributes': {
4774 'size': None,
4775 'size-used': None,
4776 },
4777 'volume-qos-attributes': {
4778 'policy-group-name': None,
4779 },
4780 'volume-snaplock-attributes': {
4781 'snaplock-type': None,
4782 },
4783 },
4784 },
4785 }
4787 expected = {
4788 'aggregate': '' if is_flexgroup else fake.SHARE_AGGREGATE_NAME,
4789 'aggr-list': [fake.SHARE_AGGREGATE_NAME] if is_flexgroup else [],
4790 'junction-path': '/%s' % fake.SHARE_NAME,
4791 'name': fake.SHARE_NAME,
4792 'type': 'rw',
4793 'style': 'flex',
4794 'size': fake.SHARE_SIZE,
4795 'size-used': fake.SHARE_USED_SIZE,
4796 'owning-vserver-name': fake.VSERVER_NAME,
4797 'qos-policy-group-name': fake.QOS_POLICY_GROUP_NAME,
4798 'style-extended': (fake.FLEXGROUP_STYLE_EXTENDED
4799 if is_flexgroup
4800 else fake.FLEXVOL_STYLE_EXTENDED),
4801 'snaplock-type': 'compliance',
4802 }
4803 self.client.send_request.assert_has_calls([
4804 mock.call('volume-get-iter', volume_get_iter_args)])
4805 self.assertDictEqual(expected, result)
4807 def test_get_volume_no_qos(self):
4808 api_response = netapp_api.NaElement(
4809 fake.VOLUME_GET_ITER_NO_QOS_RESPONSE)
4810 self.mock_object(self.client,
4811 'send_request',
4812 mock.Mock(return_value=api_response))
4814 result = self.client.get_volume(fake.SHARE_NAME)
4816 volume_get_iter_args = {
4817 'query': {
4818 'volume-attributes': {
4819 'volume-id-attributes': {
4820 'name': fake.SHARE_NAME,
4821 },
4822 },
4823 },
4824 'desired-attributes': {
4825 'volume-attributes': {
4826 'volume-id-attributes': {
4827 'aggr-list': {
4828 'aggr-name': None,
4829 },
4830 'containing-aggregate-name': None,
4831 'junction-path': None,
4832 'name': None,
4833 'owning-vserver-name': None,
4834 'type': None,
4835 'style': None,
4836 'style-extended': None,
4837 },
4838 'volume-space-attributes': {
4839 'size': None,
4840 'size-used': None,
4841 },
4842 'volume-qos-attributes': {
4843 'policy-group-name': None,
4844 },
4845 'volume-snaplock-attributes': {
4846 'snaplock-type': None,
4847 },
4848 },
4849 },
4850 }
4852 expected = {
4853 'aggregate': fake.SHARE_AGGREGATE_NAME,
4854 'aggr-list': [],
4855 'junction-path': '/%s' % fake.SHARE_NAME,
4856 'name': fake.SHARE_NAME,
4857 'type': 'rw',
4858 'style': 'flex',
4859 'size': fake.SHARE_SIZE,
4860 'size-used': fake.SHARE_USED_SIZE,
4861 'owning-vserver-name': fake.VSERVER_NAME,
4862 'qos-policy-group-name': None,
4863 'style-extended': fake.FLEXVOL_STYLE_EXTENDED,
4864 'snaplock-type': "compliance",
4865 }
4866 self.client.send_request.assert_has_calls([
4867 mock.call('volume-get-iter', volume_get_iter_args)])
4868 self.assertDictEqual(expected, result)
4870 def test_get_volume_not_found(self):
4872 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
4873 self.mock_object(self.client,
4874 'send_request',
4875 mock.Mock(return_value=api_response))
4877 self.assertRaises(exception.StorageResourceNotFound,
4878 self.client.get_volume,
4879 fake.SHARE_NAME)
4881 def test_get_volume_not_unique(self):
4883 api_response = netapp_api.NaElement(
4884 fake.VOLUME_GET_ITER_NOT_UNIQUE_RESPONSE)
4885 self.mock_object(self.client,
4886 'send_request',
4887 mock.Mock(return_value=api_response))
4889 self.assertRaises(exception.NetAppException,
4890 self.client.get_volume,
4891 fake.SHARE_NAME)
4893 def test_get_volume_at_junction_path(self):
4895 api_response = netapp_api.NaElement(
4896 fake.VOLUME_GET_ITER_VOLUME_TO_MANAGE_RESPONSE)
4897 self.mock_object(self.client,
4898 'send_iter_request',
4899 mock.Mock(return_value=api_response))
4900 fake_junction_path = '/%s' % fake.SHARE_NAME
4902 result = self.client.get_volume_at_junction_path(fake_junction_path)
4904 volume_get_iter_args = {
4905 'query': {
4906 'volume-attributes': {
4907 'volume-id-attributes': {
4908 'junction-path': fake_junction_path,
4909 'style-extended': 'flexgroup|flexvol',
4910 },
4911 },
4912 },
4913 'desired-attributes': {
4914 'volume-attributes': {
4915 'volume-id-attributes': {
4916 'name': None,
4917 },
4918 },
4919 },
4920 }
4921 expected = {
4922 'name': fake.SHARE_NAME,
4923 }
4924 self.client.send_iter_request.assert_has_calls([
4925 mock.call('volume-get-iter', volume_get_iter_args)])
4926 self.assertDictEqual(expected, result)
4928 def test_get_volume_at_junction_path_not_specified(self):
4930 result = self.client.get_volume_at_junction_path(None)
4932 self.assertIsNone(result)
4934 def test_get_volume_at_junction_path_not_found(self):
4936 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
4937 self.mock_object(self.client,
4938 'send_iter_request',
4939 mock.Mock(return_value=api_response))
4940 fake_junction_path = '/%s' % fake.SHARE_NAME
4942 result = self.client.get_volume_at_junction_path(fake_junction_path)
4944 self.assertIsNone(result)
4946 @ddt.data(True, False)
4947 def test_get_volume_to_manage(self, is_flexgroup):
4949 api_response = netapp_api.NaElement(
4950 fake.VOLUME_GET_ITER_FLEXGROUP_VOLUME_TO_MANAGE_RESPONSE
4951 if is_flexgroup
4952 else fake.VOLUME_GET_ITER_VOLUME_TO_MANAGE_RESPONSE)
4953 self.mock_object(self.client,
4954 'send_iter_request',
4955 mock.Mock(return_value=api_response))
4957 aggr = fake.SHARE_AGGREGATE_NAME
4958 result = self.client.get_volume_to_manage(
4959 [aggr] if is_flexgroup else aggr,
4960 fake.SHARE_NAME)
4962 volume_get_iter_args = {
4963 'query': {
4964 'volume-attributes': {
4965 'volume-id-attributes': {
4966 'name': fake.SHARE_NAME,
4967 },
4968 },
4969 },
4970 'desired-attributes': {
4971 'volume-attributes': {
4972 'volume-id-attributes': {
4973 'aggr-list': {
4974 'aggr-name': None,
4975 },
4976 'containing-aggregate-name': None,
4977 'junction-path': None,
4978 'name': None,
4979 'type': None,
4980 'style': None,
4981 'owning-vserver-name': None,
4982 },
4983 'volume-space-attributes': {
4984 'size': None,
4985 },
4986 'volume-qos-attributes': {
4987 'policy-group-name': None,
4988 },
4989 },
4990 },
4991 }
4992 if is_flexgroup:
4993 volume_get_iter_args['query']['volume-attributes'][
4994 'volume-id-attributes']['aggr-list'] = [{'aggr-name': aggr}]
4995 else:
4996 volume_get_iter_args['query']['volume-attributes'][
4997 'volume-id-attributes']['containing-aggregate-name'] = aggr
4999 expected = {
5000 'aggregate': '' if is_flexgroup else aggr,
5001 'aggr-list': [aggr] if is_flexgroup else [],
5002 'junction-path': '/%s' % fake.SHARE_NAME,
5003 'name': fake.SHARE_NAME,
5004 'type': 'rw',
5005 'style': 'flex',
5006 'size': fake.SHARE_SIZE,
5007 'owning-vserver-name': fake.VSERVER_NAME,
5008 'qos-policy-group-name': fake.QOS_POLICY_GROUP_NAME,
5009 }
5010 self.client.send_iter_request.assert_has_calls([
5011 mock.call('volume-get-iter', volume_get_iter_args)])
5012 self.assertDictEqual(expected, result)
5014 def test_get_volume_to_manage_not_found(self):
5016 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
5017 self.mock_object(self.client,
5018 'send_iter_request',
5019 mock.Mock(return_value=api_response))
5021 result = self.client.get_volume_to_manage(fake.SHARE_AGGREGATE_NAME,
5022 fake.SHARE_NAME)
5024 self.assertIsNone(result)
5026 @ddt.data({'qos_policy_group_name': None,
5027 'adaptive_qos_policy_group_name': None},
5028 {'qos_policy_group_name': fake.QOS_POLICY_GROUP_NAME,
5029 'adaptive_qos_policy_group_name': None},
5030 {'qos_policy_group_name': None,
5031 'adaptive_qos_policy_group_name':
5032 fake.ADAPTIVE_QOS_POLICY_GROUP_NAME},
5033 {'mount_point_name': None},
5034 )
5035 @ddt.unpack
5036 def test_create_volume_clone(self, qos_policy_group_name=None,
5037 adaptive_qos_policy_group_name=None,
5038 mount_point_name=None):
5039 self.client.features.add_feature('ADAPTIVE_QOS')
5040 self.mock_object(self.client, 'send_request')
5041 set_qos_adapt_mock = self.mock_object(
5042 self.client,
5043 'set_qos_adaptive_policy_group_for_volume')
5045 self.client.create_volume_clone(
5046 fake.SHARE_NAME,
5047 fake.PARENT_SHARE_NAME,
5048 fake.PARENT_SNAPSHOT_NAME,
5049 mount_point_name=mount_point_name,
5050 qos_policy_group=qos_policy_group_name,
5051 adaptive_qos_policy_group=adaptive_qos_policy_group_name,)
5053 volume_clone_create_args = {
5054 'volume': fake.SHARE_NAME,
5055 'parent-volume': fake.PARENT_SHARE_NAME,
5056 'parent-snapshot': fake.PARENT_SNAPSHOT_NAME,
5057 'junction-path': '/%s' % (mount_point_name or fake.SHARE_NAME)
5058 }
5060 if qos_policy_group_name:
5061 volume_clone_create_args.update(
5062 {'qos-policy-group-name': fake.QOS_POLICY_GROUP_NAME})
5063 if adaptive_qos_policy_group_name:
5064 set_qos_adapt_mock.assert_called_once_with(
5065 fake.SHARE_NAME, fake.ADAPTIVE_QOS_POLICY_GROUP_NAME
5066 )
5068 @ddt.data(None,
5069 mock.Mock(side_effect=netapp_api.NaApiError(
5070 code=netapp_api.EVOL_CLONE_BEING_SPLIT)))
5071 def test_volume_clone_split_start(self, side_effect):
5073 self.mock_object(
5074 self.client, 'send_request',
5075 mock.Mock(side_effect=side_effect))
5077 self.client.volume_clone_split_start(fake.SHARE_NAME)
5079 volume_clone_split_args = {'volume': fake.SHARE_NAME}
5081 self.client.send_request.assert_has_calls([
5082 mock.call('volume-clone-split-start', volume_clone_split_args)])
5084 @ddt.data(None,
5085 mock.Mock(side_effect=netapp_api.NaApiError(
5086 code=netapp_api.EVOLOPNOTUNDERWAY)))
5087 def test_volume_clone_split_stop(self, side_effect):
5089 self.mock_object(
5090 self.client, 'send_request',
5091 mock.Mock(side_effect=side_effect))
5093 self.client.volume_clone_split_stop(fake.SHARE_NAME)
5095 volume_clone_split_args = {'volume': fake.SHARE_NAME}
5097 self.client.send_request.assert_has_calls([
5098 mock.call('volume-clone-split-stop', volume_clone_split_args)])
5100 def test_volume_clone_split_start_api_error(self):
5102 self.mock_object(self.client,
5103 'send_request',
5104 mock.Mock(side_effect=self._mock_api_error()))
5106 self.assertRaises(netapp_api.NaApiError,
5107 self.client.volume_clone_split_start,
5108 fake.SHARE_NAME)
5110 def test_get_clone_children_for_snapshot(self):
5112 api_response = netapp_api.NaElement(
5113 fake.VOLUME_GET_ITER_CLONE_CHILDREN_RESPONSE)
5114 self.mock_object(self.client,
5115 'send_iter_request',
5116 mock.Mock(return_value=api_response))
5118 result = self.client.get_clone_children_for_snapshot(
5119 fake.SHARE_NAME, fake.SNAPSHOT_NAME)
5121 volume_get_iter_args = {
5122 'query': {
5123 'volume-attributes': {
5124 'volume-clone-attributes': {
5125 'volume-clone-parent-attributes': {
5126 'name': fake.SHARE_NAME,
5127 'snapshot-name': fake.SNAPSHOT_NAME,
5128 },
5129 },
5130 },
5131 },
5132 'desired-attributes': {
5133 'volume-attributes': {
5134 'volume-id-attributes': {
5135 'name': None,
5136 },
5137 },
5138 },
5139 }
5140 self.client.send_iter_request.assert_has_calls([
5141 mock.call('volume-get-iter', volume_get_iter_args)])
5143 expected = [
5144 {'name': fake.CLONE_CHILD_1},
5145 {'name': fake.CLONE_CHILD_2},
5146 ]
5147 self.assertEqual(expected, result)
5149 def test_get_clone_children_for_snapshot_not_found(self):
5151 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
5152 self.mock_object(self.client,
5153 'send_iter_request',
5154 mock.Mock(return_value=api_response))
5156 result = self.client.get_clone_children_for_snapshot(
5157 fake.SHARE_NAME, fake.SNAPSHOT_NAME)
5159 self.assertEqual([], result)
5161 def test_get_volume_junction_path(self):
5163 api_response = netapp_api.NaElement(
5164 fake.VOLUME_GET_VOLUME_PATH_RESPONSE)
5165 self.mock_object(self.client,
5166 'send_request',
5167 mock.Mock(return_value=api_response))
5169 result = self.client.get_volume_junction_path(fake.SHARE_NAME)
5171 volume_get_volume_path_args = {
5172 'volume': fake.SHARE_NAME,
5173 'is-style-cifs': 'false'
5174 }
5176 self.client.send_request.assert_has_calls([
5177 mock.call('volume-get-volume-path', volume_get_volume_path_args)])
5178 self.assertEqual(fake.VOLUME_JUNCTION_PATH, result)
5180 def test_get_volume_junction_path_cifs(self):
5182 api_response = netapp_api.NaElement(
5183 fake.VOLUME_GET_VOLUME_PATH_CIFS_RESPONSE)
5184 self.mock_object(self.client,
5185 'send_request',
5186 mock.Mock(return_value=api_response))
5188 result = self.client.get_volume_junction_path(fake.SHARE_NAME,
5189 is_style_cifs=True)
5191 volume_get_volume_path_args = {
5192 'volume': fake.SHARE_NAME,
5193 'is-style-cifs': 'true'
5194 }
5196 self.client.send_request.assert_has_calls([
5197 mock.call('volume-get-volume-path', volume_get_volume_path_args)])
5198 self.assertEqual(fake.VOLUME_JUNCTION_PATH_CIFS, result)
5200 def test_mount_volume_default_junction_path(self):
5202 self.mock_object(self.client, 'send_request')
5204 self.client.mount_volume(fake.SHARE_NAME)
5206 volume_mount_args = {
5207 'volume-name': fake.SHARE_NAME,
5208 'junction-path': '/%s' % fake.SHARE_NAME,
5209 }
5211 self.client.send_request.assert_has_calls([
5212 mock.call('volume-mount', volume_mount_args)])
5214 def test_mount_volume(self):
5216 self.mock_object(self.client, 'send_request')
5217 fake_path = '/fake_path'
5219 self.client.mount_volume(fake.SHARE_NAME, junction_path=fake_path)
5221 volume_mount_args = {
5222 'volume-name': fake.SHARE_NAME,
5223 'junction-path': fake_path,
5224 }
5226 self.client.send_request.assert_has_calls([
5227 mock.call('volume-mount', volume_mount_args)])
5229 def test_online_volume(self):
5231 self.mock_object(self.client, 'send_request')
5233 self.client.online_volume(fake.SHARE_NAME)
5235 volume_online_args = {'name': fake.SHARE_NAME}
5237 self.client.send_request.assert_has_calls([
5238 mock.call('volume-online', volume_online_args)])
5240 def test_online_volume_api_error(self):
5242 self.mock_object(self.client,
5243 'send_request',
5244 mock.Mock(side_effect=self._mock_api_error()))
5246 self.assertRaises(exception.NetAppException,
5247 self.client.online_volume,
5248 fake.SHARE_NAME)
5250 def test_offline_volume(self):
5252 self.mock_object(self.client, 'send_request')
5254 self.client.offline_volume(fake.SHARE_NAME)
5256 volume_offline_args = {'name': fake.SHARE_NAME}
5258 self.client.send_request.assert_has_calls([
5259 mock.call('volume-offline', volume_offline_args)])
5261 def test_offline_volume_already_offline(self):
5263 self.mock_object(self.client,
5264 'send_request',
5265 mock.Mock(side_effect=self._mock_api_error(
5266 netapp_api.EVOLUMEOFFLINE)))
5268 self.client.offline_volume(fake.SHARE_NAME)
5270 volume_offline_args = {'name': fake.SHARE_NAME}
5272 self.client.send_request.assert_has_calls([
5273 mock.call('volume-offline', volume_offline_args)])
5275 def test_offline_volume_api_error(self):
5277 self.mock_object(self.client,
5278 'send_request',
5279 mock.Mock(side_effect=self._mock_api_error()))
5281 self.assertRaises(exception.NetAppException,
5282 self.client.offline_volume,
5283 fake.SHARE_NAME)
5285 def test__unmount_volume(self):
5287 self.mock_object(self.client, 'send_request')
5289 self.client._unmount_volume(fake.SHARE_NAME)
5291 volume_unmount_args = {
5292 'volume-name': fake.SHARE_NAME,
5293 'force': 'false'
5294 }
5296 self.client.send_request.assert_has_calls([
5297 mock.call('volume-unmount', volume_unmount_args)])
5299 def test__unmount_volume_force(self):
5301 self.mock_object(self.client, 'send_request')
5303 self.client._unmount_volume(fake.SHARE_NAME, force=True)
5305 volume_unmount_args = {'volume-name': fake.SHARE_NAME, 'force': 'true'}
5307 self.client.send_request.assert_has_calls([
5308 mock.call('volume-unmount', volume_unmount_args)])
5310 def test__unmount_volume_already_unmounted(self):
5312 self.mock_object(self.client,
5313 'send_request',
5314 mock.Mock(side_effect=self._mock_api_error(
5315 netapp_api.EVOL_NOT_MOUNTED)))
5317 self.client._unmount_volume(fake.SHARE_NAME, force=True)
5319 volume_unmount_args = {'volume-name': fake.SHARE_NAME, 'force': 'true'}
5321 self.client.send_request.assert_has_calls([
5322 mock.call('volume-unmount', volume_unmount_args)])
5324 def test__unmount_volume_api_error(self):
5326 self.mock_object(self.client,
5327 'send_request',
5328 mock.Mock(side_effect=self._mock_api_error()))
5330 self.assertRaises(netapp_api.NaApiError,
5331 self.client._unmount_volume,
5332 fake.SHARE_NAME,
5333 force=True)
5335 def test_unmount_volume(self):
5337 self.mock_object(self.client, '_unmount_volume')
5339 self.client.unmount_volume(fake.SHARE_NAME)
5341 self.client._unmount_volume.assert_called_once_with(fake.SHARE_NAME,
5342 force=False)
5343 self.assertEqual(1, client_cmode.LOG.debug.call_count)
5344 self.assertEqual(0, client_cmode.LOG.warning.call_count)
5346 def test_unmount_volume_api_error(self):
5348 self.mock_object(self.client,
5349 '_unmount_volume',
5350 self._mock_api_error())
5352 self.assertRaises(netapp_api.NaApiError,
5353 self.client.unmount_volume,
5354 fake.SHARE_NAME)
5356 self.assertEqual(1, self.client._unmount_volume.call_count)
5357 self.assertEqual(0, client_cmode.LOG.debug.call_count)
5358 self.assertEqual(0, client_cmode.LOG.warning.call_count)
5360 def test_unmount_volume_with_retries(self):
5362 side_effect = [netapp_api.NaApiError(code=netapp_api.EAPIERROR,
5363 message='...job ID...')] * 5
5364 side_effect.append(None)
5365 self.mock_object(self.client,
5366 '_unmount_volume',
5367 mock.Mock(side_effect=side_effect))
5368 self.mock_object(time, 'sleep')
5370 self.client.unmount_volume(fake.SHARE_NAME)
5372 self.assertEqual(6, self.client._unmount_volume.call_count)
5373 self.assertEqual(1, client_cmode.LOG.debug.call_count)
5374 self.assertEqual(5, client_cmode.LOG.warning.call_count)
5376 def test_unmount_volume_with_max_retries(self):
5378 side_effect = [netapp_api.NaApiError(code=netapp_api.EAPIERROR,
5379 message='...job ID...')] * 30
5380 self.mock_object(self.client,
5381 '_unmount_volume',
5382 mock.Mock(side_effect=side_effect))
5383 self.mock_object(time, 'sleep')
5385 self.assertRaises(exception.NetAppException,
5386 self.client.unmount_volume,
5387 fake.SHARE_NAME)
5389 self.assertEqual(10, self.client._unmount_volume.call_count)
5390 self.assertEqual(0, client_cmode.LOG.debug.call_count)
5391 self.assertEqual(10, client_cmode.LOG.warning.call_count)
5393 def test_delete_volume(self):
5395 self.mock_object(self.client, 'send_request')
5397 self.client.delete_volume(fake.SHARE_NAME)
5399 volume_destroy_args = {'name': fake.SHARE_NAME}
5400 self.client.send_request.assert_has_calls([
5401 mock.call('volume-destroy', volume_destroy_args)])
5403 def test_rename_volume(self):
5405 self.mock_object(self.client, 'send_request')
5407 self.client.rename_volume(
5408 fake.SHARE_NAME,
5409 client_cmode.DELETED_PREFIX + fake.SHARE_NAME)
5410 volume_rename_args = {
5411 'volume': fake.SHARE_NAME,
5412 'new-volume-name': client_cmode.DELETED_PREFIX + fake.SHARE_NAME,
5413 }
5414 self.client.send_request.assert_has_calls([
5415 mock.call('volume-rename', volume_rename_args)])
5417 def test_soft_delete_volume(self):
5419 self.mock_object(self.client, 'send_request')
5421 self.client.soft_delete_volume(fake.SHARE_NAME)
5423 volume_destroy_args = {'name': fake.SHARE_NAME}
5424 self.client.send_request.assert_has_calls([
5425 mock.call('volume-destroy', volume_destroy_args)])
5427 def test_soft_delete_volume_error(self):
5429 self.mock_object(
5430 self.client, 'send_request',
5431 self._mock_api_error(code=netapp_api.EVOLDEL_NOT_ALLOW_BY_CLONE))
5432 mock_rename = self.mock_object(self.client, 'rename_volume')
5434 self.client.soft_delete_volume(fake.SHARE_NAME)
5436 volume_destroy_args = {'name': fake.SHARE_NAME}
5437 self.client.send_request.assert_has_calls([
5438 mock.call('volume-destroy', volume_destroy_args)])
5439 mock_rename.assert_called_once_with(
5440 fake.SHARE_NAME, client_cmode.DELETED_PREFIX + fake.SHARE_NAME)
5442 def test_create_snapshot(self):
5444 self.mock_object(self.client, 'send_request')
5446 self.client.create_snapshot(fake.SHARE_NAME, fake.SNAPSHOT_NAME)
5448 snapshot_create_args = {
5449 'volume': fake.SHARE_NAME,
5450 'snapshot': fake.SNAPSHOT_NAME
5451 }
5453 self.client.send_request.assert_has_calls([
5454 mock.call('snapshot-create', snapshot_create_args)])
5456 @ddt.data({
5457 'mock_return': fake.SNAPSHOT_GET_ITER_NOT_BUSY_RESPONSE,
5458 'expected': {
5459 'access-time': fake.SNAPSHOT_ACCESS_TIME,
5460 'name': fake.SNAPSHOT_NAME,
5461 'volume': fake.SHARE_NAME,
5462 'busy': False,
5463 'owners': set(),
5464 'locked_by_clone': False,
5465 }
5466 }, {
5467 'mock_return': fake.SNAPSHOT_GET_ITER_BUSY_RESPONSE,
5468 'expected': {
5469 'access-time': fake.SNAPSHOT_ACCESS_TIME,
5470 'name': fake.SNAPSHOT_NAME,
5471 'volume': fake.SHARE_NAME,
5472 'busy': True,
5473 'owners': {'volume clone'},
5474 'locked_by_clone': True,
5475 }
5476 })
5477 @ddt.unpack
5478 def test_get_snapshot(self, mock_return, expected):
5480 api_response = netapp_api.NaElement(mock_return)
5481 self.mock_object(self.client,
5482 'send_request',
5483 mock.Mock(return_value=api_response))
5485 result = self.client.get_snapshot(fake.SHARE_NAME, fake.SNAPSHOT_NAME)
5487 snapshot_get_iter_args = {
5488 'query': {
5489 'snapshot-info': {
5490 'name': fake.SNAPSHOT_NAME,
5491 'volume': fake.SHARE_NAME,
5492 },
5493 },
5494 'desired-attributes': {
5495 'snapshot-info': {
5496 'access-time': None,
5497 'name': None,
5498 'volume': None,
5499 'busy': None,
5500 'snapshot-owners-list': {
5501 'snapshot-owner': None,
5502 }
5503 },
5504 },
5505 }
5506 self.client.send_request.assert_has_calls([
5507 mock.call('snapshot-get-iter', snapshot_get_iter_args)])
5508 self.assertDictEqual(expected, result)
5510 @ddt.data({
5511 'api_response_xml': fake.NO_RECORDS_RESPONSE,
5512 'raised_exception': exception.SnapshotResourceNotFound,
5513 }, {
5514 'api_response_xml': fake.SNAPSHOT_GET_ITER_NOT_UNIQUE_RESPONSE,
5515 'raised_exception': exception.NetAppException,
5516 }, {
5517 'api_response_xml': fake.SNAPSHOT_GET_ITER_UNAVAILABLE_RESPONSE,
5518 'raised_exception': exception.SnapshotUnavailable,
5519 }, {
5520 'api_response_xml': fake.SNAPSHOT_GET_ITER_OTHER_ERROR_RESPONSE,
5521 'raised_exception': exception.NetAppException,
5522 })
5523 @ddt.unpack
5524 def test_get_snapshot_error(self, api_response_xml, raised_exception):
5526 api_response = netapp_api.NaElement(api_response_xml)
5527 self.mock_object(self.client,
5528 'send_request',
5529 mock.Mock(return_value=api_response))
5531 self.assertRaises(raised_exception,
5532 self.client.get_snapshot,
5533 fake.SHARE_NAME,
5534 fake.SNAPSHOT_NAME)
5536 def test_rename_snapshot(self):
5538 self.mock_object(self.client, 'send_request')
5540 self.client.rename_snapshot(fake.SHARE_NAME,
5541 fake.SNAPSHOT_NAME,
5542 'new_snapshot_name')
5544 snapshot_rename_args = {
5545 'volume': fake.SHARE_NAME,
5546 'current-name': fake.SNAPSHOT_NAME,
5547 'new-name': 'new_snapshot_name'
5548 }
5549 self.client.send_request.assert_has_calls([
5550 mock.call('snapshot-rename', snapshot_rename_args)])
5552 def test_restore_snapshot(self):
5554 self.mock_object(self.client, 'send_request')
5556 self.client.restore_snapshot(fake.SHARE_NAME,
5557 fake.SNAPSHOT_NAME)
5559 snapshot_restore_args = {
5560 'volume': fake.SHARE_NAME,
5561 'snapshot': fake.SNAPSHOT_NAME,
5562 }
5563 self.client.send_request.assert_has_calls([
5564 mock.call('snapshot-restore-volume', snapshot_restore_args)])
5566 @ddt.data(True, False)
5567 def test_delete_snapshot(self, ignore_owners):
5569 self.mock_object(self.client, 'send_request')
5571 self.client.delete_snapshot(
5572 fake.SHARE_NAME, fake.SNAPSHOT_NAME, ignore_owners=ignore_owners)
5574 snapshot_delete_args = {
5575 'volume': fake.SHARE_NAME,
5576 'snapshot': fake.SNAPSHOT_NAME,
5577 'ignore-owners': 'true' if ignore_owners else 'false',
5578 }
5580 self.client.send_request.assert_has_calls([
5581 mock.call('snapshot-delete', snapshot_delete_args)])
5583 def test_soft_delete_snapshot(self):
5585 mock_delete_snapshot = self.mock_object(self.client, 'delete_snapshot')
5586 mock_rename_snapshot = self.mock_object(self.client, 'rename_snapshot')
5588 self.client.soft_delete_snapshot(fake.SHARE_NAME, fake.SNAPSHOT_NAME)
5590 mock_delete_snapshot.assert_called_once_with(
5591 fake.SHARE_NAME, fake.SNAPSHOT_NAME)
5592 self.assertFalse(mock_rename_snapshot.called)
5594 def test_soft_delete_snapshot_api_error(self):
5596 mock_delete_snapshot = self.mock_object(
5597 self.client, 'delete_snapshot', self._mock_api_error())
5598 mock_rename_snapshot = self.mock_object(self.client, 'rename_snapshot')
5599 mock_get_clone_children_for_snapshot = self.mock_object(
5600 self.client, 'get_clone_children_for_snapshot',
5601 mock.Mock(return_value=fake.CDOT_CLONE_CHILDREN))
5602 mock_volume_clone_split_start = self.mock_object(
5603 self.client, 'volume_clone_split_start')
5605 self.client.soft_delete_snapshot(fake.SHARE_NAME, fake.SNAPSHOT_NAME)
5607 mock_delete_snapshot.assert_called_once_with(
5608 fake.SHARE_NAME, fake.SNAPSHOT_NAME)
5609 mock_rename_snapshot.assert_called_once_with(
5610 fake.SHARE_NAME, fake.SNAPSHOT_NAME,
5611 'deleted_manila_' + fake.SNAPSHOT_NAME)
5612 mock_get_clone_children_for_snapshot.assert_called_once_with(
5613 fake.SHARE_NAME, 'deleted_manila_' + fake.SNAPSHOT_NAME)
5614 mock_volume_clone_split_start.assert_has_calls([
5615 mock.call(fake.CDOT_CLONE_CHILD_1),
5616 mock.call(fake.CDOT_CLONE_CHILD_2),
5617 ])
5619 def test_prune_deleted_snapshots(self):
5621 deleted_snapshots_map = {
5622 'vserver1': [{
5623 'name': 'deleted_snap_1',
5624 'volume': 'fake_volume_1',
5625 'vserver': 'vserver1',
5626 }],
5627 'vserver2': [{
5628 'name': 'deleted_snap_2',
5629 'volume': 'fake_volume_2',
5630 'vserver': 'vserver2',
5631 }],
5632 }
5633 mock_get_deleted_snapshots = self.mock_object(
5634 self.client, '_get_deleted_snapshots',
5635 mock.Mock(return_value=deleted_snapshots_map))
5636 mock_delete_snapshot = self.mock_object(
5637 self.client, 'delete_snapshot',
5638 mock.Mock(side_effect=[None, netapp_api.NaApiError]))
5639 self.mock_object(
5640 copy, 'deepcopy', mock.Mock(return_value=self.client))
5642 self.client.prune_deleted_snapshots()
5644 mock_get_deleted_snapshots.assert_called_once_with()
5645 mock_delete_snapshot.assert_has_calls([
5646 mock.call('fake_volume_1', 'deleted_snap_1'),
5647 mock.call('fake_volume_2', 'deleted_snap_2'),
5648 ], any_order=True)
5650 def test_get_deleted_snapshots(self):
5652 api_response = netapp_api.NaElement(
5653 fake.SNAPSHOT_GET_ITER_DELETED_RESPONSE)
5654 self.mock_object(self.client,
5655 'send_iter_request',
5656 mock.Mock(return_value=api_response))
5658 result = self.client._get_deleted_snapshots()
5660 snapshot_get_iter_args = {
5661 'query': {
5662 'snapshot-info': {
5663 'name': 'deleted_manila_*',
5664 'busy': 'false',
5665 },
5666 },
5667 'desired-attributes': {
5668 'snapshot-info': {
5669 'name': None,
5670 'vserver': None,
5671 'volume': None,
5672 },
5673 },
5674 }
5675 self.client.send_iter_request.assert_has_calls([
5676 mock.call('snapshot-get-iter', snapshot_get_iter_args)])
5678 expected = {
5679 fake.VSERVER_NAME: [{
5680 'name': 'deleted_manila_' + fake.SNAPSHOT_NAME,
5681 'volume': fake.SHARE_NAME,
5682 'vserver': fake.VSERVER_NAME,
5683 }],
5684 }
5685 self.assertDictEqual(expected, result)
5687 def test_create_cg_snapshot(self):
5689 mock_start_cg_snapshot = self.mock_object(
5690 self.client, '_start_cg_snapshot',
5691 mock.Mock(return_value=fake.CG_SNAPSHOT_ID))
5692 mock_commit_cg_snapshot = self.mock_object(
5693 self.client, '_commit_cg_snapshot')
5695 self.client.create_cg_snapshot([fake.SHARE_NAME, fake.SHARE_NAME_2],
5696 fake.SNAPSHOT_NAME)
5698 mock_start_cg_snapshot.assert_called_once_with(
5699 [fake.SHARE_NAME, fake.SHARE_NAME_2], fake.SNAPSHOT_NAME)
5700 mock_commit_cg_snapshot.assert_called_once_with(fake.CG_SNAPSHOT_ID)
5702 def test_create_cg_snapshot_no_id(self):
5704 mock_start_cg_snapshot = self.mock_object(
5705 self.client, '_start_cg_snapshot', mock.Mock(return_value=None))
5706 mock_commit_cg_snapshot = self.mock_object(
5707 self.client, '_commit_cg_snapshot')
5709 self.assertRaises(exception.NetAppException,
5710 self.client.create_cg_snapshot,
5711 [fake.SHARE_NAME, fake.SHARE_NAME_2],
5712 fake.SNAPSHOT_NAME)
5714 mock_start_cg_snapshot.assert_called_once_with(
5715 [fake.SHARE_NAME, fake.SHARE_NAME_2], fake.SNAPSHOT_NAME)
5716 self.assertFalse(mock_commit_cg_snapshot.called)
5718 def test_start_cg_snapshot(self):
5720 self.mock_object(self.client, 'send_request')
5722 self.client._start_cg_snapshot([fake.SHARE_NAME, fake.SHARE_NAME_2],
5723 fake.SNAPSHOT_NAME)
5725 cg_start_args = {
5726 'snapshot': fake.SNAPSHOT_NAME,
5727 'timeout': 'relaxed',
5728 'volumes': [
5729 {'volume-name': fake.SHARE_NAME},
5730 {'volume-name': fake.SHARE_NAME_2},
5731 ],
5732 }
5734 self.client.send_request.assert_has_calls([
5735 mock.call('cg-start', cg_start_args)])
5737 def test_commit_cg_snapshot(self):
5739 self.mock_object(self.client, 'send_request')
5741 self.client._commit_cg_snapshot(fake.CG_SNAPSHOT_ID)
5743 cg_commit_args = {'cg-id': fake.CG_SNAPSHOT_ID}
5745 self.client.send_request.assert_has_calls([
5746 mock.call('cg-commit', cg_commit_args)])
5748 def test_create_cifs_share(self):
5750 self.mock_object(self.client, 'send_request')
5752 self.client.create_cifs_share(
5753 fake.SHARE_NAME, fake.VOLUME_JUNCTION_PATH)
5755 cifs_share_create_args = {
5756 'path': fake.VOLUME_JUNCTION_PATH,
5757 'share-name': fake.SHARE_NAME
5758 }
5760 self.client.send_request.assert_has_calls([
5761 mock.call('cifs-share-create', cifs_share_create_args)])
5763 def test_get_cifs_share_access(self):
5765 api_response = netapp_api.NaElement(
5766 fake.CIFS_SHARE_ACCESS_CONTROL_GET_ITER)
5767 self.mock_object(self.client,
5768 'send_iter_request',
5769 mock.Mock(return_value=api_response))
5771 result = self.client.get_cifs_share_access(fake.SHARE_NAME)
5773 cifs_share_access_control_get_iter_args = {
5774 'query': {
5775 'cifs-share-access-control': {
5776 'share': fake.SHARE_NAME,
5777 },
5778 },
5779 'desired-attributes': {
5780 'cifs-share-access-control': {
5781 'user-or-group': None,
5782 'permission': None,
5783 },
5784 },
5785 }
5786 self.client.send_iter_request.assert_has_calls([
5787 mock.call('cifs-share-access-control-get-iter',
5788 cifs_share_access_control_get_iter_args)])
5790 expected = {
5791 'Administrator': 'full_control',
5792 'Administrators': 'change',
5793 'Power Users': 'read',
5794 'Users': 'no_access',
5795 }
5796 self.assertDictEqual(expected, result)
5798 def test_get_cifs_share_access_not_found(self):
5800 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
5801 self.mock_object(self.client,
5802 'send_iter_request',
5803 mock.Mock(return_value=api_response))
5805 result = self.client.get_cifs_share_access(fake.SHARE_NAME)
5807 self.assertEqual({}, result)
5809 @ddt.data({'readonly': False, 'exception': True},
5810 {'readonly': True, 'exception': False},
5811 {'readonly': False, 'exception': False},
5812 {'readonly': True, 'exception': True})
5813 @ddt.unpack
5814 def test_add_cifs_share_access(self, readonly, exception):
5816 mock_exception = mock.Mock(side_effect=netapp_api.NaApiError(
5817 code=netapp_api.EDUPLICATEENTRY))
5819 self.mock_object(
5820 self.client, 'send_request',
5821 mock_exception if exception else mock.Mock(return_value=None))
5823 self.client.add_cifs_share_access(fake.SHARE_NAME,
5824 fake.USER_NAME,
5825 readonly)
5827 cifs_share_access_control_create_args = {
5828 'permission': 'read' if readonly else 'full_control',
5829 'share': fake.SHARE_NAME,
5830 'user-or-group': fake.USER_NAME
5831 }
5833 self.client.send_request.assert_has_calls([
5834 mock.call(
5835 'cifs-share-access-control-create',
5836 cifs_share_access_control_create_args)])
5838 @ddt.data(True, False)
5839 def test_modify_cifs_share_access(self, readonly):
5841 self.mock_object(self.client, 'send_request')
5843 self.client.modify_cifs_share_access(fake.SHARE_NAME,
5844 fake.USER_NAME,
5845 readonly)
5847 cifs_share_access_control_modify_args = {
5848 'permission': 'read' if readonly else 'full_control',
5849 'share': fake.SHARE_NAME,
5850 'user-or-group': fake.USER_NAME
5851 }
5853 self.client.send_request.assert_has_calls([
5854 mock.call(
5855 'cifs-share-access-control-modify',
5856 cifs_share_access_control_modify_args)])
5858 def test_remove_cifs_share_access(self):
5860 self.mock_object(self.client, 'send_request')
5862 self.client.remove_cifs_share_access(fake.SHARE_NAME, fake.USER_NAME)
5864 cifs_share_access_control_delete_args = {
5865 'user-or-group': fake.USER_NAME,
5866 'share': fake.SHARE_NAME
5867 }
5869 self.client.send_request.assert_has_calls([
5870 mock.call(
5871 'cifs-share-access-control-delete',
5872 cifs_share_access_control_delete_args)])
5874 def test_remove_cifs_share(self):
5876 self.mock_object(self.client, 'send_request')
5878 self.client.remove_cifs_share(fake.SHARE_NAME)
5880 cifs_share_delete_args = {'share-name': fake.SHARE_NAME}
5882 self.client.send_request.assert_has_calls([
5883 mock.call('cifs-share-delete', cifs_share_delete_args)])
5885 def test_remove_cifs_share_not_found(self):
5887 self.mock_object(self.client,
5888 'send_request',
5889 self._mock_api_error(code=netapp_api.EOBJECTNOTFOUND))
5891 self.client.remove_cifs_share(fake.SHARE_NAME)
5893 cifs_share_args = {'share-name': fake.SHARE_NAME}
5894 self.client.send_request.assert_has_calls([
5895 mock.call('cifs-share-delete', cifs_share_args)])
5897 def test_add_nfs_export_rule(self):
5899 mock_get_nfs_export_rule_indices = self.mock_object(
5900 self.client, '_get_nfs_export_rule_indices',
5901 mock.Mock(return_value=[]))
5902 mock_add_nfs_export_rule = self.mock_object(
5903 self.client, '_add_nfs_export_rule')
5904 mock_update_nfs_export_rule = self.mock_object(
5905 self.client, '_update_nfs_export_rule')
5906 auth_methods = ['sys']
5908 self.client.add_nfs_export_rule(fake.EXPORT_POLICY_NAME,
5909 fake.IP_ADDRESS,
5910 False,
5911 auth_methods)
5913 mock_get_nfs_export_rule_indices.assert_called_once_with(
5914 fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS)
5915 mock_add_nfs_export_rule.assert_called_once_with(
5916 fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False, auth_methods)
5917 self.assertFalse(mock_update_nfs_export_rule.called)
5919 def test_add_nfs_export_rule_single_existing(self):
5921 mock_get_nfs_export_rule_indices = self.mock_object(
5922 self.client, '_get_nfs_export_rule_indices',
5923 mock.Mock(return_value=['1']))
5924 mock_add_nfs_export_rule = self.mock_object(
5925 self.client, '_add_nfs_export_rule')
5926 mock_update_nfs_export_rule = self.mock_object(
5927 self.client, '_update_nfs_export_rule')
5928 mock_remove_nfs_export_rules = self.mock_object(
5929 self.client, '_remove_nfs_export_rules')
5930 auth_methods = ['sys']
5932 self.client.add_nfs_export_rule(fake.EXPORT_POLICY_NAME,
5933 fake.IP_ADDRESS,
5934 False,
5935 auth_methods)
5937 mock_get_nfs_export_rule_indices.assert_called_once_with(
5938 fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS)
5939 self.assertFalse(mock_add_nfs_export_rule.called)
5940 mock_update_nfs_export_rule.assert_called_once_with(
5941 fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False, '1',
5942 auth_methods)
5943 mock_remove_nfs_export_rules.assert_called_once_with(
5944 fake.EXPORT_POLICY_NAME, [])
5946 def test_add_nfs_export_rule_multiple_existing(self):
5948 mock_get_nfs_export_rule_indices = self.mock_object(
5949 self.client, '_get_nfs_export_rule_indices',
5950 mock.Mock(return_value=['2', '4', '6']))
5951 mock_add_nfs_export_rule = self.mock_object(
5952 self.client, '_add_nfs_export_rule')
5953 mock_update_nfs_export_rule = self.mock_object(
5954 self.client, '_update_nfs_export_rule')
5955 mock_remove_nfs_export_rules = self.mock_object(
5956 self.client, '_remove_nfs_export_rules')
5957 auth_methods = ['sys']
5958 self.client.add_nfs_export_rule(fake.EXPORT_POLICY_NAME,
5959 fake.IP_ADDRESS,
5960 False,
5961 auth_methods)
5963 mock_get_nfs_export_rule_indices.assert_called_once_with(
5964 fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS)
5965 self.assertFalse(mock_add_nfs_export_rule.called)
5966 mock_update_nfs_export_rule.assert_called_once_with(
5967 fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False, '2', auth_methods)
5968 mock_remove_nfs_export_rules.assert_called_once_with(
5969 fake.EXPORT_POLICY_NAME, ['4', '6'])
5971 @ddt.data({'readonly': False, 'auth_method': 'sys'},
5972 {'readonly': True, 'auth_method': 'sys'})
5973 @ddt.unpack
5974 def test__add_nfs_export_rule(self, readonly, auth_method):
5976 self.mock_object(self.client, 'send_request')
5978 self.client._add_nfs_export_rule(fake.EXPORT_POLICY_NAME,
5979 fake.IP_ADDRESS,
5980 readonly,
5981 [auth_method])
5982 export_rule_create_args = {
5983 'policy-name': fake.EXPORT_POLICY_NAME,
5984 'client-match': fake.IP_ADDRESS,
5985 'ro-rule': [
5986 {'security-flavor': auth_method},
5987 ],
5988 'rw-rule': [
5989 {'security-flavor': auth_method},
5990 ],
5991 'super-user-security': [
5992 {'security-flavor': auth_method},
5993 ],
5994 }
5995 if readonly:
5996 export_rule_create_args['rw-rule'] = [
5997 {'security-flavor': 'never'}
5998 ]
6000 self.client.send_request.assert_has_calls(
6001 [mock.call('export-rule-create', export_rule_create_args)])
6003 @ddt.data({'readonly': False, 'auth_method': 'sys', 'index': '2'},
6004 {'readonly': True, 'auth_method': 'krb5', 'index': '4'})
6005 @ddt.unpack
6006 def test_update_nfs_export_rule(self, readonly, auth_method, index):
6008 self.mock_object(self.client, 'send_request')
6009 self.client._update_nfs_export_rule(fake.EXPORT_POLICY_NAME,
6010 fake.IP_ADDRESS,
6011 readonly,
6012 index,
6013 [auth_method])
6015 export_rule_modify_args = {
6016 'policy-name': fake.EXPORT_POLICY_NAME,
6017 'rule-index': index,
6018 'client-match': fake.IP_ADDRESS,
6019 'ro-rule': [
6020 {'security-flavor': auth_method},
6021 ],
6022 'rw-rule': [
6023 {'security-flavor': auth_method},
6024 ],
6025 'super-user-security': [
6026 {'security-flavor': auth_method},
6027 ],
6028 }
6029 if readonly:
6030 export_rule_modify_args['rw-rule'] = [
6031 {'security-flavor': 'never'}
6032 ]
6034 self.client.send_request.assert_has_calls(
6035 [mock.call('export-rule-modify', export_rule_modify_args)])
6037 def test_get_nfs_export_rule_indices(self):
6039 api_response = netapp_api.NaElement(fake.EXPORT_RULE_GET_ITER_RESPONSE)
6040 self.mock_object(self.client,
6041 'send_iter_request',
6042 mock.Mock(return_value=api_response))
6044 result = self.client._get_nfs_export_rule_indices(
6045 fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS)
6047 export_rule_get_iter_args = {
6048 'query': {
6049 'export-rule-info': {
6050 'policy-name': fake.EXPORT_POLICY_NAME,
6051 'client-match': fake.IP_ADDRESS,
6052 },
6053 },
6054 'desired-attributes': {
6055 'export-rule-info': {
6056 'vserver-name': None,
6057 'policy-name': None,
6058 'client-match': None,
6059 'rule-index': None,
6060 },
6061 },
6062 }
6063 self.assertListEqual(['1', '3'], result)
6064 self.client.send_iter_request.assert_has_calls([
6065 mock.call('export-rule-get-iter', export_rule_get_iter_args)])
6067 def test_remove_nfs_export_rule(self):
6069 fake_indices = ['1', '3', '4']
6070 mock_get_nfs_export_rule_indices = self.mock_object(
6071 self.client, '_get_nfs_export_rule_indices',
6072 mock.Mock(return_value=fake_indices))
6073 mock_remove_nfs_export_rules = self.mock_object(
6074 self.client, '_remove_nfs_export_rules')
6076 self.client.remove_nfs_export_rule(fake.EXPORT_POLICY_NAME,
6077 fake.IP_ADDRESS)
6079 mock_get_nfs_export_rule_indices.assert_called_once_with(
6080 fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS)
6081 mock_remove_nfs_export_rules.assert_called_once_with(
6082 fake.EXPORT_POLICY_NAME, fake_indices)
6084 def test_remove_nfs_export_rules(self):
6086 fake_indices = ['1', '3']
6087 self.mock_object(self.client, 'send_request')
6089 self.client._remove_nfs_export_rules(fake.EXPORT_POLICY_NAME,
6090 fake_indices)
6092 self.client.send_request.assert_has_calls([
6093 mock.call(
6094 'export-rule-destroy',
6095 {'policy-name': fake.EXPORT_POLICY_NAME, 'rule-index': '1'}),
6096 mock.call(
6097 'export-rule-destroy',
6098 {'policy-name': fake.EXPORT_POLICY_NAME, 'rule-index': '3'})])
6100 def test_remove_nfs_export_rules_not_found(self):
6102 self.mock_object(self.client,
6103 'send_request',
6104 self._mock_api_error(code=netapp_api.EOBJECTNOTFOUND))
6106 self.client._remove_nfs_export_rules(fake.EXPORT_POLICY_NAME, ['1'])
6108 self.client.send_request.assert_has_calls([
6109 mock.call(
6110 'export-rule-destroy',
6111 {'policy-name': fake.EXPORT_POLICY_NAME, 'rule-index': '1'})])
6113 def test_remove_nfs_export_rules_api_error(self):
6115 self.mock_object(self.client, 'send_request', self._mock_api_error())
6117 self.assertRaises(netapp_api.NaApiError,
6118 self.client._remove_nfs_export_rules,
6119 fake.EXPORT_POLICY_NAME,
6120 ['1'])
6122 def test_clear_nfs_export_policy_for_volume(self):
6124 mock_set_nfs_export_policy_for_volume = self.mock_object(
6125 self.client, 'set_nfs_export_policy_for_volume')
6127 self.client.clear_nfs_export_policy_for_volume(fake.SHARE_NAME)
6129 mock_set_nfs_export_policy_for_volume.assert_called_once_with(
6130 fake.SHARE_NAME, 'default')
6132 def test_set_nfs_export_policy_for_volume(self):
6134 self.mock_object(self.client, 'send_request')
6136 self.client.set_nfs_export_policy_for_volume(fake.SHARE_NAME,
6137 fake.EXPORT_POLICY_NAME)
6139 volume_modify_iter_args = {
6140 'query': {
6141 'volume-attributes': {
6142 'volume-id-attributes': {
6143 'name': fake.SHARE_NAME,
6144 },
6145 },
6146 },
6147 'attributes': {
6148 'volume-attributes': {
6149 'volume-export-attributes': {
6150 'policy': fake.EXPORT_POLICY_NAME,
6151 },
6152 },
6153 },
6154 }
6155 self.client.send_request.assert_has_calls([
6156 mock.call('volume-modify-iter', volume_modify_iter_args)])
6158 def test_set_qos_policy_group_for_volume(self):
6160 self.mock_object(self.client, 'send_request')
6162 self.client.set_qos_policy_group_for_volume(fake.SHARE_NAME,
6163 fake.QOS_POLICY_GROUP_NAME)
6165 volume_modify_iter_args = {
6166 'query': {
6167 'volume-attributes': {
6168 'volume-id-attributes': {
6169 'name': fake.SHARE_NAME,
6170 },
6171 },
6172 },
6173 'attributes': {
6174 'volume-attributes': {
6175 'volume-qos-attributes': {
6176 'policy-group-name': fake.QOS_POLICY_GROUP_NAME,
6177 },
6178 },
6179 },
6180 }
6181 self.client.send_request.assert_called_once_with(
6182 'volume-modify-iter', volume_modify_iter_args)
6184 def test_get_nfs_export_policy_for_volume(self):
6186 api_response = netapp_api.NaElement(
6187 fake.VOLUME_GET_EXPORT_POLICY_RESPONSE)
6188 self.mock_object(self.client,
6189 'send_iter_request',
6190 mock.Mock(return_value=api_response))
6192 result = self.client.get_nfs_export_policy_for_volume(fake.SHARE_NAME)
6194 volume_get_iter_args = {
6195 'query': {
6196 'volume-attributes': {
6197 'volume-id-attributes': {
6198 'name': fake.SHARE_NAME,
6199 },
6200 },
6201 },
6202 'desired-attributes': {
6203 'volume-attributes': {
6204 'volume-export-attributes': {
6205 'policy': None,
6206 },
6207 },
6208 },
6209 }
6210 self.assertEqual(fake.EXPORT_POLICY_NAME, result)
6211 self.client.send_iter_request.assert_has_calls([
6212 mock.call('volume-get-iter', volume_get_iter_args)])
6214 def test_get_nfs_export_policy_for_volume_not_found(self):
6216 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
6217 self.mock_object(self.client,
6218 'send_iter_request',
6219 mock.Mock(return_value=api_response))
6221 self.assertRaises(exception.NetAppException,
6222 self.client.get_nfs_export_policy_for_volume,
6223 fake.SHARE_NAME)
6225 def test_create_nfs_export_policy(self):
6227 self.mock_object(self.client, 'send_request')
6229 self.client.create_nfs_export_policy(fake.EXPORT_POLICY_NAME)
6231 export_policy_create_args = {'policy-name': fake.EXPORT_POLICY_NAME}
6232 self.client.send_request.assert_has_calls([
6233 mock.call('export-policy-create', export_policy_create_args)])
6235 def test_create_nfs_export_policy_already_present(self):
6237 self.mock_object(self.client,
6238 'send_request',
6239 self._mock_api_error(code=netapp_api.EDUPLICATEENTRY))
6241 self.client.create_nfs_export_policy(fake.EXPORT_POLICY_NAME)
6243 export_policy_create_args = {'policy-name': fake.EXPORT_POLICY_NAME}
6244 self.client.send_request.assert_has_calls([
6245 mock.call('export-policy-create', export_policy_create_args)])
6247 def test_create_nfs_export_policy_api_error(self):
6249 self.mock_object(self.client, 'send_request', self._mock_api_error())
6251 self.assertRaises(netapp_api.NaApiError,
6252 self.client.create_nfs_export_policy,
6253 fake.EXPORT_POLICY_NAME)
6255 def test_soft_delete_nfs_export_policy(self):
6257 self.mock_object(self.client, 'delete_nfs_export_policy')
6258 self.mock_object(self.client, 'rename_nfs_export_policy')
6260 self.client.soft_delete_nfs_export_policy(fake.EXPORT_POLICY_NAME)
6262 self.client.delete_nfs_export_policy.assert_has_calls([
6263 mock.call(fake.EXPORT_POLICY_NAME)])
6264 self.assertFalse(self.client.rename_nfs_export_policy.called)
6266 def test_soft_delete_nfs_export_policy_api_error(self):
6268 self.mock_object(self.client,
6269 'delete_nfs_export_policy',
6270 self._mock_api_error())
6271 self.mock_object(self.client, 'rename_nfs_export_policy')
6273 self.client.soft_delete_nfs_export_policy(fake.EXPORT_POLICY_NAME)
6275 self.client.delete_nfs_export_policy.assert_has_calls([
6276 mock.call(fake.EXPORT_POLICY_NAME)])
6277 self.assertTrue(self.client.rename_nfs_export_policy.called)
6279 def test_delete_nfs_export_policy(self):
6281 self.mock_object(self.client, 'send_request')
6283 self.client.delete_nfs_export_policy(fake.EXPORT_POLICY_NAME)
6285 export_policy_destroy_args = {'policy-name': fake.EXPORT_POLICY_NAME}
6286 self.client.send_request.assert_has_calls([
6287 mock.call('export-policy-destroy', export_policy_destroy_args)])
6289 def test_delete_nfs_export_policy_not_found(self):
6291 self.mock_object(self.client,
6292 'send_request',
6293 self._mock_api_error(code=netapp_api.EOBJECTNOTFOUND))
6295 self.client.delete_nfs_export_policy(fake.EXPORT_POLICY_NAME)
6297 export_policy_destroy_args = {'policy-name': fake.EXPORT_POLICY_NAME}
6298 self.client.send_request.assert_has_calls([
6299 mock.call('export-policy-destroy', export_policy_destroy_args)])
6301 def test_delete_nfs_export_policy_api_error(self):
6303 self.mock_object(self.client, 'send_request', self._mock_api_error())
6305 self.assertRaises(netapp_api.NaApiError,
6306 self.client.delete_nfs_export_policy,
6307 fake.EXPORT_POLICY_NAME)
6309 def test_rename_nfs_export_policy(self):
6311 self.mock_object(self.client, 'send_request')
6313 self.client.rename_nfs_export_policy(fake.EXPORT_POLICY_NAME,
6314 'new_policy_name')
6316 export_policy_rename_args = {
6317 'policy-name': fake.EXPORT_POLICY_NAME,
6318 'new-policy-name': 'new_policy_name'
6319 }
6320 self.client.send_request.assert_has_calls([
6321 mock.call('export-policy-rename', export_policy_rename_args)])
6323 def test_prune_deleted_nfs_export_policies(self):
6324 # Mock client lest we not be able to see calls on its copy.
6325 self.mock_object(copy,
6326 'deepcopy',
6327 mock.Mock(return_value=self.client))
6328 self.mock_object(self.client,
6329 '_get_deleted_nfs_export_policies',
6330 mock.Mock(return_value=fake.DELETED_EXPORT_POLICIES))
6331 self.mock_object(self.client, 'delete_nfs_export_policy')
6333 self.client.prune_deleted_nfs_export_policies()
6335 self.assertTrue(self.client.delete_nfs_export_policy.called)
6336 self.client.delete_nfs_export_policy.assert_has_calls(
6337 [mock.call(policy) for policy in
6338 fake.DELETED_EXPORT_POLICIES[fake.VSERVER_NAME]])
6340 def test_prune_deleted_nfs_export_policies_api_error(self):
6341 self.mock_object(copy,
6342 'deepcopy',
6343 mock.Mock(return_value=self.client))
6344 self.mock_object(self.client,
6345 '_get_deleted_nfs_export_policies',
6346 mock.Mock(return_value=fake.DELETED_EXPORT_POLICIES))
6347 self.mock_object(self.client,
6348 'delete_nfs_export_policy',
6349 self._mock_api_error())
6351 self.client.prune_deleted_nfs_export_policies()
6353 self.assertTrue(self.client.delete_nfs_export_policy.called)
6354 self.client.delete_nfs_export_policy.assert_has_calls(
6355 [mock.call(policy) for policy in
6356 fake.DELETED_EXPORT_POLICIES[fake.VSERVER_NAME]])
6358 def test_get_deleted_nfs_export_policies(self):
6360 api_response = netapp_api.NaElement(
6361 fake.DELETED_EXPORT_POLICY_GET_ITER_RESPONSE)
6362 self.mock_object(self.client,
6363 'send_iter_request',
6364 mock.Mock(return_value=api_response))
6366 result = self.client._get_deleted_nfs_export_policies()
6368 export_policy_get_iter_args = {
6369 'query': {
6370 'export-policy-info': {
6371 'policy-name': 'deleted_manila_*',
6372 },
6373 },
6374 'desired-attributes': {
6375 'export-policy-info': {
6376 'policy-name': None,
6377 'vserver': None,
6378 },
6379 },
6380 }
6381 self.assertSequenceEqual(fake.DELETED_EXPORT_POLICIES, result)
6382 self.client.send_iter_request.assert_has_calls([
6383 mock.call('export-policy-get-iter', export_policy_get_iter_args)])
6385 def test_get_ems_log_destination_vserver(self):
6387 self.mock_object(self.client,
6388 'get_ontapi_version',
6389 mock.Mock(return_value=(1, 21)))
6390 mock_list_vservers = self.mock_object(
6391 self.client,
6392 'list_vservers',
6393 mock.Mock(return_value=[fake.ADMIN_VSERVER_NAME]))
6395 result = self.client._get_ems_log_destination_vserver()
6397 mock_list_vservers.assert_called_once_with(vserver_type='admin')
6398 self.assertEqual(fake.ADMIN_VSERVER_NAME, result)
6400 def test_get_ems_log_destination_vserver_future(self):
6402 self.mock_object(self.client,
6403 'get_ontapi_version',
6404 mock.Mock(return_value=(2, 0)))
6405 mock_list_vservers = self.mock_object(
6406 self.client,
6407 'list_vservers',
6408 mock.Mock(return_value=[fake.ADMIN_VSERVER_NAME]))
6410 result = self.client._get_ems_log_destination_vserver()
6412 mock_list_vservers.assert_called_once_with(vserver_type='admin')
6413 self.assertEqual(fake.ADMIN_VSERVER_NAME, result)
6415 def test_get_ems_log_destination_vserver_legacy(self):
6417 self.mock_object(self.client,
6418 'get_ontapi_version',
6419 mock.Mock(return_value=(1, 15)))
6420 mock_list_vservers = self.mock_object(
6421 self.client,
6422 'list_vservers',
6423 mock.Mock(return_value=[fake.NODE_VSERVER_NAME]))
6425 result = self.client._get_ems_log_destination_vserver()
6427 mock_list_vservers.assert_called_once_with(vserver_type='node')
6428 self.assertEqual(fake.NODE_VSERVER_NAME, result)
6430 def test_get_ems_log_destination_no_cluster_creds(self):
6432 self.mock_object(self.client,
6433 'get_ontapi_version',
6434 mock.Mock(return_value=(1, 21)))
6435 mock_list_vservers = self.mock_object(
6436 self.client,
6437 'list_vservers',
6438 mock.Mock(side_effect=[[], [fake.VSERVER_NAME]]))
6440 result = self.client._get_ems_log_destination_vserver()
6442 mock_list_vservers.assert_has_calls([
6443 mock.call(vserver_type='admin'),
6444 mock.call(vserver_type='data')])
6445 self.assertEqual(fake.VSERVER_NAME, result)
6447 def test_get_ems_log_destination_vserver_not_found(self):
6449 self.mock_object(self.client,
6450 'get_ontapi_version',
6451 mock.Mock(return_value=(1, 21)))
6452 mock_list_vservers = self.mock_object(
6453 self.client,
6454 'list_vservers',
6455 mock.Mock(return_value=[]))
6457 self.assertRaises(exception.NotFound,
6458 self.client._get_ems_log_destination_vserver)
6460 mock_list_vservers.assert_has_calls([
6461 mock.call(vserver_type='admin'),
6462 mock.call(vserver_type='data'),
6463 mock.call(vserver_type='node')])
6465 def test_send_ems_log_message(self):
6467 # Mock client lest we not be able to see calls on its copy.
6468 self.mock_object(
6469 copy, 'copy',
6470 mock.Mock(side_effect=[self.client, self.client.connection]))
6471 self.mock_object(self.client,
6472 '_get_ems_log_destination_vserver',
6473 mock.Mock(return_value=fake.ADMIN_VSERVER_NAME))
6474 self.mock_object(self.client, 'send_request')
6476 self.client.send_ems_log_message(fake.EMS_MESSAGE)
6478 self.client.send_request.assert_has_calls([
6479 mock.call('ems-autosupport-log', fake.EMS_MESSAGE)])
6480 self.assertEqual(1, client_cmode.LOG.debug.call_count)
6482 def test_send_ems_log_message_api_error(self):
6484 # Mock client lest we not be able to see calls on its copy.
6485 self.mock_object(
6486 copy, 'copy',
6487 mock.Mock(side_effect=[self.client, self.client.connection]))
6488 self.mock_object(self.client,
6489 '_get_ems_log_destination_vserver',
6490 mock.Mock(return_value=fake.ADMIN_VSERVER_NAME))
6491 self.mock_object(self.client, 'send_request', self._mock_api_error())
6493 self.client.send_ems_log_message(fake.EMS_MESSAGE)
6495 self.client.send_request.assert_has_calls([
6496 mock.call('ems-autosupport-log', fake.EMS_MESSAGE)])
6497 self.assertEqual(1, client_cmode.LOG.warning.call_count)
6499 def test_get_aggregate_none_specified(self):
6501 result = self.client.get_aggregate('')
6503 self.assertEqual({}, result)
6505 def test_get_aggregate(self):
6506 self.client.features.SNAPLOCK = True
6507 api_response = netapp_api.NaElement(
6508 fake.AGGR_GET_ITER_SSC_RESPONSE).get_child_by_name(
6509 'attributes-list').get_children()
6510 self.mock_object(self.client,
6511 '_get_aggregates',
6512 mock.Mock(return_value=api_response))
6514 result = self.client.get_aggregate(fake.SHARE_AGGREGATE_NAME)
6515 desired_attributes = {
6516 'aggr-attributes': {
6517 'aggregate-name': None,
6518 'aggr-raid-attributes': {
6519 'raid-type': None,
6520 'is-hybrid': None,
6521 },
6522 'aggr-ownership-attributes': {
6523 'home-id': None,
6524 'owner-id': None,
6525 },
6526 },
6527 }
6529 if self.client.features.SNAPLOCK: 6529 ↛ 6533line 6529 didn't jump to line 6533 because the condition on line 6529 was always true
6530 desired_attributes['aggr-attributes']['aggr-snaplock-attributes']\
6531 = {'is-snaplock': None, 'snaplock-type': None}
6533 self.client._get_aggregates.assert_has_calls([
6534 mock.call(
6535 aggregate_names=[fake.SHARE_AGGREGATE_NAME],
6536 desired_attributes=desired_attributes)])
6538 expected = {
6539 'name': fake.SHARE_AGGREGATE_NAME,
6540 'raid-type': 'raid_dp',
6541 'is-hybrid': False,
6542 'is-home': True,
6543 'snaplock-type': 'compliance',
6544 'is-snaplock': 'true'
6545 }
6546 self.assertEqual(expected, result)
6548 def test_get_aggregate_not_found(self):
6550 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
6551 self.mock_object(self.client,
6552 'send_request',
6553 mock.Mock(return_value=api_response))
6555 result = self.client.get_aggregate(fake.SHARE_AGGREGATE_NAME)
6557 self.assertEqual({}, result)
6559 def test_get_aggregate_api_error(self):
6561 self.mock_object(self.client,
6562 'send_request',
6563 mock.Mock(side_effect=self._mock_api_error()))
6565 result = self.client.get_aggregate(fake.SHARE_AGGREGATE_NAME)
6567 self.assertEqual({}, result)
6569 @ddt.data({'types': {'FCAL'}, 'expected': ['FCAL']},
6570 {'types': {'SATA', 'SSD'}, 'expected': ['SATA', 'SSD']},)
6571 @ddt.unpack
6572 def test_get_aggregate_disk_types(self, types, expected):
6574 mock_get_aggregate_disk_types = self.mock_object(
6575 self.client, '_get_aggregate_disk_types',
6576 mock.Mock(return_value=types))
6578 result = self.client.get_aggregate_disk_types(
6579 fake.SHARE_AGGREGATE_NAME)
6581 self.assertEqual(sorted(expected), sorted(result))
6582 mock_get_aggregate_disk_types.assert_called_once_with(
6583 fake.SHARE_AGGREGATE_NAME)
6585 def test_get_aggregate_disk_types_not_found(self):
6587 mock_get_aggregate_disk_types = self.mock_object(
6588 self.client, '_get_aggregate_disk_types',
6589 mock.Mock(return_value=set()))
6591 result = self.client.get_aggregate_disk_types(
6592 fake.SHARE_AGGREGATE_NAME)
6594 self.assertIsNone(result)
6595 mock_get_aggregate_disk_types.assert_called_once_with(
6596 fake.SHARE_AGGREGATE_NAME)
6598 def test_get_aggregate_disk_types_shared(self):
6600 self.client.features.add_feature('ADVANCED_DISK_PARTITIONING')
6601 mock_get_aggregate_disk_types = self.mock_object(
6602 self.client, '_get_aggregate_disk_types',
6603 mock.Mock(side_effect=[set(['SSD']), set(['SATA'])]))
6605 result = self.client.get_aggregate_disk_types(
6606 fake.SHARE_AGGREGATE_NAME)
6608 self.assertIsInstance(result, list)
6609 self.assertEqual(sorted(['SATA', 'SSD']), sorted(result))
6610 mock_get_aggregate_disk_types.assert_has_calls([
6611 mock.call(fake.SHARE_AGGREGATE_NAME),
6612 mock.call(fake.SHARE_AGGREGATE_NAME, shared=True),
6613 ])
6615 @ddt.data({
6616 'shared': False,
6617 'query_disk_raid_info': {
6618 'disk-aggregate-info': {
6619 'aggregate-name': fake.SHARE_AGGREGATE_NAME,
6620 },
6621 },
6622 }, {
6623 'shared': True,
6624 'query_disk_raid_info': {
6625 'disk-shared-info': {
6626 'aggregate-list': {
6627 'shared-aggregate-info': {
6628 'aggregate-name':
6629 fake.SHARE_AGGREGATE_NAME,
6630 },
6631 },
6632 },
6633 },
6634 })
6635 @ddt.unpack
6636 def test__get_aggregate_disk_types_ddt(self, shared, query_disk_raid_info):
6638 api_response = netapp_api.NaElement(
6639 fake.STORAGE_DISK_GET_ITER_RESPONSE)
6640 self.mock_object(self.client,
6641 'send_iter_request',
6642 mock.Mock(return_value=api_response))
6644 result = self.client._get_aggregate_disk_types(
6645 fake.SHARE_AGGREGATE_NAME, shared=shared)
6647 storage_disk_get_iter_args = {
6648 'query': {
6649 'storage-disk-info': {
6650 'disk-raid-info': query_disk_raid_info,
6651 },
6652 },
6653 'desired-attributes': {
6654 'storage-disk-info': {
6655 'disk-raid-info': {
6656 'effective-disk-type': None,
6657 },
6658 },
6659 },
6660 }
6661 self.client.send_iter_request.assert_called_once_with(
6662 'storage-disk-get-iter', storage_disk_get_iter_args)
6664 expected = set(fake.SHARE_AGGREGATE_DISK_TYPES)
6665 self.assertEqual(expected, result)
6667 def test__get_aggregate_disk_types_not_found(self):
6669 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
6670 self.mock_object(self.client,
6671 'send_iter_request',
6672 mock.Mock(return_value=api_response))
6674 result = self.client._get_aggregate_disk_types(
6675 fake.SHARE_AGGREGATE_NAME)
6677 self.assertEqual(set(), result)
6679 def test__get_aggregate_disk_types_api_error(self):
6681 self.mock_object(self.client,
6682 'send_iter_request',
6683 mock.Mock(side_effect=self._mock_api_error()))
6685 result = self.client._get_aggregate_disk_types(
6686 fake.SHARE_AGGREGATE_NAME)
6688 self.assertEqual(set([]), result)
6690 def test_check_for_cluster_credentials(self):
6692 api_response = netapp_api.NaElement(fake.SYSTEM_NODE_GET_ITER_RESPONSE)
6693 self.mock_object(self.client,
6694 'send_iter_request',
6695 mock.Mock(return_value=api_response))
6697 result = self.client.check_for_cluster_credentials()
6699 self.assertTrue(result)
6701 def test_check_for_cluster_credentials_not_cluster(self):
6703 self.mock_object(self.client,
6704 'send_iter_request',
6705 mock.Mock(side_effect=self._mock_api_error(
6706 netapp_api.EAPINOTFOUND)))
6708 result = self.client.check_for_cluster_credentials()
6710 self.assertFalse(result)
6712 def test_check_for_cluster_credentials_api_error(self):
6714 self.mock_object(self.client,
6715 'send_iter_request',
6716 self._mock_api_error())
6718 self.assertRaises(netapp_api.NaApiError,
6719 self.client.check_for_cluster_credentials)
6721 def test_create_cluster_peer(self):
6723 self.mock_object(self.client, 'send_request')
6725 self.client.create_cluster_peer(['fake_address_1', 'fake_address_2'],
6726 'fake_user', 'fake_password',
6727 'fake_passphrase')
6729 cluster_peer_create_args = {
6730 'peer-addresses': [
6731 {'remote-inet-address': 'fake_address_1'},
6732 {'remote-inet-address': 'fake_address_2'},
6733 ],
6734 'user-name': 'fake_user',
6735 'password': 'fake_password',
6736 'passphrase': 'fake_passphrase',
6737 }
6738 self.client.send_request.assert_has_calls([
6739 mock.call('cluster-peer-create', cluster_peer_create_args,
6740 enable_tunneling=False)])
6742 def test_get_cluster_peers(self):
6744 api_response = netapp_api.NaElement(
6745 fake.CLUSTER_PEER_GET_ITER_RESPONSE)
6746 self.mock_object(self.client,
6747 'send_iter_request',
6748 mock.Mock(return_value=api_response))
6750 result = self.client.get_cluster_peers()
6752 cluster_peer_get_iter_args = {}
6753 self.client.send_iter_request.assert_has_calls([
6754 mock.call('cluster-peer-get-iter', cluster_peer_get_iter_args)])
6756 expected = [{
6757 'active-addresses': [
6758 fake.CLUSTER_ADDRESS_1,
6759 fake.CLUSTER_ADDRESS_2
6760 ],
6761 'availability': 'available',
6762 'cluster-name': fake.CLUSTER_NAME,
6763 'cluster-uuid': 'fake_uuid',
6764 'peer-addresses': [fake.CLUSTER_ADDRESS_1],
6765 'remote-cluster-name': fake.REMOTE_CLUSTER_NAME,
6766 'serial-number': 'fake_serial_number',
6767 'timeout': '60',
6768 }]
6770 self.assertEqual(expected, result)
6772 def test_get_cluster_peers_single(self):
6774 api_response = netapp_api.NaElement(
6775 fake.CLUSTER_PEER_GET_ITER_RESPONSE)
6776 self.mock_object(self.client,
6777 'send_iter_request',
6778 mock.Mock(return_value=api_response))
6780 self.client.get_cluster_peers(remote_cluster_name=fake.CLUSTER_NAME)
6782 cluster_peer_get_iter_args = {
6783 'query': {
6784 'cluster-peer-info': {
6785 'remote-cluster-name': fake.CLUSTER_NAME,
6786 }
6787 },
6788 }
6789 self.client.send_iter_request.assert_has_calls([
6790 mock.call('cluster-peer-get-iter', cluster_peer_get_iter_args)])
6792 def test_get_cluster_peers_not_found(self):
6794 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
6795 self.mock_object(self.client,
6796 'send_iter_request',
6797 mock.Mock(return_value=api_response))
6799 result = self.client.get_cluster_peers(
6800 remote_cluster_name=fake.CLUSTER_NAME)
6802 self.assertEqual([], result)
6803 self.assertTrue(self.client.send_iter_request.called)
6805 def test_delete_cluster_peer(self):
6807 self.mock_object(self.client, 'send_request')
6809 self.client.delete_cluster_peer(fake.CLUSTER_NAME)
6811 cluster_peer_delete_args = {'cluster-name': fake.CLUSTER_NAME}
6812 self.client.send_request.assert_has_calls([
6813 mock.call('cluster-peer-delete', cluster_peer_delete_args,
6814 enable_tunneling=False)])
6816 def test_get_cluster_peer_policy(self):
6818 self.client.features.add_feature('CLUSTER_PEER_POLICY')
6820 api_response = netapp_api.NaElement(
6821 fake.CLUSTER_PEER_POLICY_GET_RESPONSE)
6822 self.mock_object(self.client,
6823 'send_request',
6824 mock.Mock(return_value=api_response))
6826 result = self.client.get_cluster_peer_policy()
6828 expected = {
6829 'is-unauthenticated-access-permitted': False,
6830 'passphrase-minimum-length': 8
6831 }
6832 self.assertEqual(expected, result)
6833 self.assertTrue(self.client.send_request.called)
6835 def test_get_cluster_peer_policy_not_supported(self):
6837 result = self.client.get_cluster_peer_policy()
6839 self.assertEqual({}, result)
6841 def test_set_cluster_peer_policy_not_supported(self):
6843 self.mock_object(self.client, 'send_request')
6845 self.client.set_cluster_peer_policy()
6847 self.assertFalse(self.client.send_request.called)
6849 def test_set_cluster_peer_policy_no_arguments(self):
6851 self.client.features.add_feature('CLUSTER_PEER_POLICY')
6852 self.mock_object(self.client, 'send_request')
6854 self.client.set_cluster_peer_policy()
6856 self.assertFalse(self.client.send_request.called)
6858 def test_set_cluster_peer_policy(self):
6860 self.client.features.add_feature('CLUSTER_PEER_POLICY')
6861 self.mock_object(self.client, 'send_request')
6863 self.client.set_cluster_peer_policy(
6864 is_unauthenticated_access_permitted=True,
6865 passphrase_minimum_length=12)
6867 cluster_peer_policy_modify_args = {
6868 'is-unauthenticated-access-permitted': 'true',
6869 'passphrase-minlength': '12',
6870 }
6871 self.client.send_request.assert_has_calls([
6872 mock.call('cluster-peer-policy-modify',
6873 cluster_peer_policy_modify_args)])
6875 @ddt.data(None, 'cluster_name')
6876 def test_create_vserver_peer(self, cluster_name):
6878 self.mock_object(self.client, 'send_request')
6880 self.client.create_vserver_peer(fake.VSERVER_NAME,
6881 fake.VSERVER_PEER_NAME,
6882 peer_cluster_name=cluster_name)
6884 vserver_peer_create_args = {
6885 'vserver': fake.VSERVER_NAME,
6886 'peer-vserver': fake.VSERVER_PEER_NAME,
6887 'applications': [
6888 {'vserver-peer-application': 'snapmirror'},
6889 ],
6890 }
6891 if cluster_name:
6892 vserver_peer_create_args['peer-cluster'] = cluster_name
6894 self.client.send_request.assert_has_calls([
6895 mock.call('vserver-peer-create', vserver_peer_create_args,
6896 enable_tunneling=False)])
6898 def test_delete_vserver_peer(self):
6900 self.mock_object(self.client, 'send_request')
6902 self.client.delete_vserver_peer('fake_vserver', 'fake_vserver_peer')
6904 vserver_peer_delete_args = {
6905 'vserver': 'fake_vserver',
6906 'peer-vserver': 'fake_vserver_peer',
6907 }
6908 self.client.send_request.assert_has_calls([
6909 mock.call('vserver-peer-delete', vserver_peer_delete_args,
6910 enable_tunneling=False)])
6912 def test_accept_vserver_peer(self):
6914 self.mock_object(self.client, 'send_request')
6916 self.client.accept_vserver_peer('fake_vserver', 'fake_vserver_peer')
6918 vserver_peer_accept_args = {
6919 'vserver': 'fake_vserver',
6920 'peer-vserver': 'fake_vserver_peer',
6921 }
6922 self.client.send_request.assert_has_calls([
6923 mock.call('vserver-peer-accept', vserver_peer_accept_args,
6924 enable_tunneling=False)])
6926 def test_get_vserver_peers(self):
6928 api_response = netapp_api.NaElement(
6929 fake.VSERVER_PEER_GET_ITER_RESPONSE)
6930 self.mock_object(self.client,
6931 'send_iter_request',
6932 mock.Mock(return_value=api_response))
6934 result = self.client.get_vserver_peers(
6935 vserver_name=fake.VSERVER_NAME,
6936 peer_vserver_name=fake.VSERVER_NAME_2)
6938 vserver_peer_get_iter_args = {
6939 'query': {
6940 'vserver-peer-info': {
6941 'vserver': fake.VSERVER_NAME,
6942 'peer-vserver': fake.VSERVER_NAME_2,
6943 }
6944 },
6945 }
6946 self.client.send_iter_request.assert_has_calls([
6947 mock.call('vserver-peer-get-iter', vserver_peer_get_iter_args)])
6949 expected = [{
6950 'vserver': 'fake_vserver',
6951 'peer-vserver': 'fake_vserver_2',
6952 'peer-state': 'peered',
6953 'peer-cluster': 'fake_cluster'
6954 }]
6955 self.assertEqual(expected, result)
6957 def test_get_vserver_peers_not_found(self):
6959 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
6960 self.mock_object(self.client,
6961 'send_iter_request',
6962 mock.Mock(return_value=api_response))
6964 result = self.client.get_vserver_peers(
6965 vserver_name=fake.VSERVER_NAME,
6966 peer_vserver_name=fake.VSERVER_NAME_2)
6968 self.assertEqual([], result)
6969 self.assertTrue(self.client.send_iter_request.called)
6971 def test_ensure_snapmirror_v2(self):
6973 self.assertIsNone(self.client._ensure_snapmirror_v2())
6975 def test_ensure_snapmirror_v2_not_supported(self):
6977 self.client.features.add_feature('SNAPMIRROR_V2', supported=False)
6979 self.assertRaises(exception.NetAppException,
6980 self.client._ensure_snapmirror_v2)
6982 @ddt.data({'schedule': 'fake_schedule', 'policy': 'fake_policy'},
6983 {'schedule': None, 'policy': None})
6984 @ddt.unpack
6985 def test_create_snapmirror(self, schedule, policy):
6986 self.mock_object(self.client, 'send_request')
6988 self.client.create_snapmirror_vol(
6989 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
6990 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
6991 na_utils.DATA_PROTECTION_TYPE, schedule=schedule, policy=policy)
6993 snapmirror_create_args = {
6994 'source-vserver': fake.SM_SOURCE_VSERVER,
6995 'source-volume': fake.SM_SOURCE_VOLUME,
6996 'destination-vserver': fake.SM_DEST_VSERVER,
6997 'destination-volume': fake.SM_DEST_VOLUME,
6998 'relationship-type': na_utils.DATA_PROTECTION_TYPE,
6999 }
7000 if schedule:
7001 snapmirror_create_args['schedule'] = schedule
7002 if policy:
7003 snapmirror_create_args['policy'] = policy
7004 self.client.send_request.assert_has_calls([
7005 mock.call('snapmirror-create', snapmirror_create_args)])
7007 def test_create_snapmirror_already_exists(self):
7008 mock_send_req = mock.Mock(side_effect=netapp_api.NaApiError(
7009 code=netapp_api.ERELATION_EXISTS))
7010 self.mock_object(self.client, 'send_request', mock_send_req)
7012 self.client.create_snapmirror_vol(
7013 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7014 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
7015 na_utils.DATA_PROTECTION_TYPE)
7017 snapmirror_create_args = {
7018 'source-vserver': fake.SM_SOURCE_VSERVER,
7019 'source-volume': fake.SM_SOURCE_VOLUME,
7020 'destination-vserver': fake.SM_DEST_VSERVER,
7021 'destination-volume': fake.SM_DEST_VOLUME,
7022 'relationship-type': na_utils.DATA_PROTECTION_TYPE,
7023 'policy': na_utils.MIRROR_ALL_SNAP_POLICY,
7024 }
7025 self.client.send_request.assert_has_calls([
7026 mock.call('snapmirror-create', snapmirror_create_args)])
7028 def test_create_snapmirror_error(self):
7029 mock_send_req = mock.Mock(side_effect=netapp_api.NaApiError(
7030 code=0))
7031 self.mock_object(self.client, 'send_request', mock_send_req)
7033 self.assertRaises(netapp_api.NaApiError,
7034 self.client.create_snapmirror_vol,
7035 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7036 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
7037 na_utils.DATA_PROTECTION_TYPE)
7038 self.assertTrue(self.client.send_request.called)
7040 def test_create_snapmirror_svm(self):
7041 self.mock_object(self.client, 'send_request')
7043 self.client.create_snapmirror_svm(fake.SM_SOURCE_VSERVER,
7044 fake.SM_DEST_VSERVER,
7045 max_transfer_rate='fake_xfer_rate')
7047 snapmirror_create_args = {
7048 'source-vserver': fake.SM_SOURCE_VSERVER,
7049 'destination-vserver': fake.SM_DEST_VSERVER,
7050 'relationship-type': na_utils.DATA_PROTECTION_TYPE,
7051 'identity-preserve': 'true',
7052 'max-transfer-rate': 'fake_xfer_rate'
7053 }
7054 self.client.send_request.assert_has_calls([
7055 mock.call('snapmirror-create', snapmirror_create_args)])
7057 @ddt.data(
7058 {
7059 'source_snapshot': 'fake_snapshot',
7060 'transfer_priority': 'fake_priority'
7061 },
7062 {
7063 'source_snapshot': None,
7064 'transfer_priority': None
7065 }
7066 )
7067 @ddt.unpack
7068 def test_initialize_snapmirror(self, source_snapshot, transfer_priority):
7070 api_response = netapp_api.NaElement(fake.SNAPMIRROR_INITIALIZE_RESULT)
7071 self.mock_object(self.client,
7072 'send_request',
7073 mock.Mock(return_value=api_response))
7075 result = self.client.initialize_snapmirror_vol(
7076 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7077 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
7078 source_snapshot=source_snapshot,
7079 transfer_priority=transfer_priority)
7081 snapmirror_initialize_args = {
7082 'source-vserver': fake.SM_SOURCE_VSERVER,
7083 'source-volume': fake.SM_SOURCE_VOLUME,
7084 'destination-vserver': fake.SM_DEST_VSERVER,
7085 'destination-volume': fake.SM_DEST_VOLUME,
7086 }
7087 if source_snapshot:
7088 snapmirror_initialize_args['source-snapshot'] = source_snapshot
7089 if transfer_priority:
7090 snapmirror_initialize_args['transfer-priority'] = transfer_priority
7091 self.client.send_request.assert_has_calls([
7092 mock.call('snapmirror-initialize', snapmirror_initialize_args)])
7094 expected = {
7095 'operation-id': None,
7096 'status': 'succeeded',
7097 'jobid': None,
7098 'error-code': None,
7099 'error-message': None
7100 }
7101 self.assertEqual(expected, result)
7103 def test_initialize_snapmirror_svm(self):
7105 api_response = netapp_api.NaElement(fake.SNAPMIRROR_INITIALIZE_RESULT)
7106 self.mock_object(self.client,
7107 'send_request',
7108 mock.Mock(return_value=api_response))
7110 result = self.client.initialize_snapmirror_svm(fake.SM_SOURCE_VSERVER,
7111 fake.SM_DEST_VSERVER)
7113 snapmirror_initialize_args = {
7114 'source-location': fake.SM_SOURCE_VSERVER + ':',
7115 'destination-location': fake.SM_DEST_VSERVER + ':',
7116 }
7117 self.client.send_request.assert_has_calls([
7118 mock.call('snapmirror-initialize', snapmirror_initialize_args)])
7120 expected = {
7121 'operation-id': None,
7122 'status': 'succeeded',
7123 'jobid': None,
7124 'error-code': None,
7125 'error-message': None
7126 }
7127 self.assertEqual(expected, result)
7129 @ddt.data({'snapmirror_destinations_list': [],
7130 'relationship_info_only': True},
7131 {'snapmirror_destinations_list': [],
7132 'relationship_info_only': False},
7133 {'snapmirror_destinations_list':
7134 [{'relationship-id': 'fake_relationship_id'}],
7135 'relationship_info_only': True},
7136 {'snapmirror_destinations_list':
7137 [{'relationship-id': 'fake_relationship_id'}],
7138 'relationship_info_only': False})
7139 @ddt.unpack
7140 def test_release_snapmirror_vol(self, relationship_info_only,
7141 snapmirror_destinations_list):
7142 self.mock_object(self.client, 'send_request')
7143 self.mock_object(self.client, 'get_snapmirror_destinations',
7144 mock.Mock(return_value=snapmirror_destinations_list))
7145 self.mock_object(self.client, '_ensure_snapmirror_v2')
7147 self.client.release_snapmirror_vol(
7148 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7149 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
7150 relationship_info_only=relationship_info_only)
7152 snapmirror_release_args = {
7153 'source-vserver': fake.SM_SOURCE_VSERVER,
7154 'source-volume': fake.SM_SOURCE_VOLUME,
7155 'destination-vserver': fake.SM_DEST_VSERVER,
7156 'destination-volume': fake.SM_DEST_VOLUME,
7157 'relationship-info-only': ('true' if relationship_info_only
7158 else 'false'),
7159 }
7161 if len(snapmirror_destinations_list) == 1:
7162 snapmirror_release_args['relationship-id'] = 'fake_relationship_id'
7164 self.client.send_request.assert_called_once_with(
7165 'snapmirror-release', snapmirror_release_args,
7166 enable_tunneling=True)
7168 def test_release_snapmirror_vol_error_not_unique_relationship(self):
7169 self.mock_object(self.client, 'send_request')
7170 self.mock_object(self.client, 'get_snapmirror_destinations',
7171 mock.Mock(return_value=[{'relationship-id': 'fake'},
7172 {'relationship-id': 'fake'}]))
7174 self.assertRaises(exception.NetAppException,
7175 self.client.release_snapmirror_vol,
7176 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7177 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7179 def test_release_snapmirror_svm(self):
7181 self.mock_object(self.client, 'send_request')
7182 self.mock_object(self.client, '_ensure_snapmirror_v2')
7184 self.client.release_snapmirror_svm(
7185 fake.SM_SOURCE_VSERVER, fake.SM_DEST_VSERVER)
7187 snapmirror_release_args = {
7188 'query': {
7189 'snapmirror-destination-info': {
7190 'source-location': fake.SM_SOURCE_VSERVER + ':',
7191 'destination-location': fake.SM_DEST_VSERVER + ':',
7192 },
7193 },
7194 'relationship-info-only': 'false',
7195 }
7196 self.client.send_request.assert_has_calls([
7197 mock.call('snapmirror-release-iter', snapmirror_release_args,
7198 enable_tunneling=False)])
7200 def test_quiesce_snapmirror(self):
7202 self.mock_object(self.client, 'send_request')
7204 self.client.quiesce_snapmirror_vol(
7205 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7206 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7208 snapmirror_quiesce_args = {
7209 'source-vserver': fake.SM_SOURCE_VSERVER,
7210 'source-volume': fake.SM_SOURCE_VOLUME,
7211 'destination-vserver': fake.SM_DEST_VSERVER,
7212 'destination-volume': fake.SM_DEST_VOLUME,
7213 }
7214 self.client.send_request.assert_has_calls([
7215 mock.call('snapmirror-quiesce', snapmirror_quiesce_args)])
7217 def test_quiesce_snapmirror_svm(self):
7219 self.mock_object(self.client, 'send_request')
7221 self.client.quiesce_snapmirror_svm(
7222 fake.SM_SOURCE_VSERVER, fake.SM_DEST_VSERVER)
7224 snapmirror_quiesce_args = {
7225 'source-location': fake.SM_SOURCE_VSERVER + ':',
7226 'destination-location': fake.SM_DEST_VSERVER + ':',
7227 }
7228 self.client.send_request.assert_has_calls([
7229 mock.call('snapmirror-quiesce', snapmirror_quiesce_args)])
7231 @ddt.data(True, False)
7232 def test_abort_snapmirror(self, clear_checkpoint):
7234 self.mock_object(self.client, 'send_request')
7236 self.client.abort_snapmirror_vol(
7237 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7238 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
7239 clear_checkpoint=clear_checkpoint)
7241 snapmirror_abort_args = {
7242 'source-vserver': fake.SM_SOURCE_VSERVER,
7243 'source-volume': fake.SM_SOURCE_VOLUME,
7244 'destination-vserver': fake.SM_DEST_VSERVER,
7245 'destination-volume': fake.SM_DEST_VOLUME,
7246 'clear-checkpoint': 'true' if clear_checkpoint else 'false',
7247 }
7248 self.client.send_request.assert_has_calls([
7249 mock.call('snapmirror-abort', snapmirror_abort_args)])
7251 def test_abort_snapmirror_svm(self):
7253 self.mock_object(self.client, 'send_request')
7255 self.client.abort_snapmirror_svm(
7256 fake.SM_SOURCE_VSERVER, fake.SM_DEST_VSERVER)
7258 snapmirror_abort_args = {
7259 'source-location': fake.SM_SOURCE_VSERVER + ':',
7260 'destination-location': fake.SM_DEST_VSERVER + ':',
7261 'clear-checkpoint': 'false'
7262 }
7263 self.client.send_request.assert_has_calls([
7264 mock.call('snapmirror-abort', snapmirror_abort_args)])
7266 def test_abort_snapmirror_no_transfer_in_progress(self):
7267 mock_send_req = mock.Mock(side_effect=netapp_api.NaApiError(
7268 code=netapp_api.ENOTRANSFER_IN_PROGRESS))
7269 self.mock_object(self.client, 'send_request', mock_send_req)
7271 self.client.abort_snapmirror_vol(
7272 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7273 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7275 snapmirror_abort_args = {
7276 'source-vserver': fake.SM_SOURCE_VSERVER,
7277 'source-volume': fake.SM_SOURCE_VOLUME,
7278 'destination-vserver': fake.SM_DEST_VSERVER,
7279 'destination-volume': fake.SM_DEST_VOLUME,
7280 'clear-checkpoint': 'false',
7281 }
7282 self.client.send_request.assert_has_calls([
7283 mock.call('snapmirror-abort', snapmirror_abort_args)])
7285 def test_abort_snapmirror_error(self):
7286 mock_send_req = mock.Mock(side_effect=netapp_api.NaApiError(code=0))
7287 self.mock_object(self.client, 'send_request', mock_send_req)
7289 self.assertRaises(netapp_api.NaApiError,
7290 self.client.abort_snapmirror_vol,
7291 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7292 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7294 def test_break_snapmirror(self):
7296 self.mock_object(self.client, 'send_request')
7298 self.client.break_snapmirror_vol(
7299 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7300 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7302 snapmirror_break_args = {
7303 'source-vserver': fake.SM_SOURCE_VSERVER,
7304 'source-volume': fake.SM_SOURCE_VOLUME,
7305 'destination-vserver': fake.SM_DEST_VSERVER,
7306 'destination-volume': fake.SM_DEST_VOLUME,
7307 }
7308 self.client.send_request.assert_has_calls([
7309 mock.call('snapmirror-break', snapmirror_break_args)])
7311 def test_break_snapmirror_svm(self):
7313 self.mock_object(self.client, 'send_request')
7315 self.client.break_snapmirror_svm(
7316 fake.SM_SOURCE_VSERVER, fake.SM_DEST_VSERVER)
7318 snapmirror_break_args = {
7319 'source-location': fake.SM_SOURCE_VSERVER + ':',
7320 'destination-location': fake.SM_DEST_VSERVER + ':',
7321 }
7322 self.client.send_request.assert_has_calls([
7323 mock.call('snapmirror-break', snapmirror_break_args)])
7325 @ddt.data(
7326 {
7327 'schedule': 'fake_schedule',
7328 'policy': 'fake_policy',
7329 'tries': 5,
7330 'max_transfer_rate': 1024,
7331 },
7332 {
7333 'schedule': None,
7334 'policy': None,
7335 'tries': None,
7336 'max_transfer_rate': None,
7337 }
7338 )
7339 @ddt.unpack
7340 def test_modify_snapmirror(self, schedule, policy, tries,
7341 max_transfer_rate):
7343 self.mock_object(self.client, 'send_request')
7345 self.client.modify_snapmirror_vol(
7346 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7347 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME,
7348 schedule=schedule, policy=policy, tries=tries,
7349 max_transfer_rate=max_transfer_rate)
7351 snapmirror_modify_args = {
7352 'source-vserver': fake.SM_SOURCE_VSERVER,
7353 'source-volume': fake.SM_SOURCE_VOLUME,
7354 'destination-vserver': fake.SM_DEST_VSERVER,
7355 'destination-volume': fake.SM_DEST_VOLUME,
7356 }
7357 if schedule:
7358 snapmirror_modify_args['schedule'] = schedule
7359 if policy:
7360 snapmirror_modify_args['policy'] = policy
7361 if tries:
7362 snapmirror_modify_args['tries'] = tries
7363 if max_transfer_rate:
7364 snapmirror_modify_args['max-transfer-rate'] = max_transfer_rate
7365 self.client.send_request.assert_has_calls([
7366 mock.call('snapmirror-modify', snapmirror_modify_args)])
7368 def test_update_snapmirror(self):
7370 self.mock_object(self.client, 'send_request')
7372 self.client.update_snapmirror_vol(
7373 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7374 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7376 snapmirror_update_args = {
7377 'source-vserver': fake.SM_SOURCE_VSERVER,
7378 'source-volume': fake.SM_SOURCE_VOLUME,
7379 'destination-vserver': fake.SM_DEST_VSERVER,
7380 'destination-volume': fake.SM_DEST_VOLUME,
7381 }
7382 self.client.send_request.assert_has_calls([
7383 mock.call('snapmirror-update', snapmirror_update_args)])
7385 def test_update_snapmirror_svm(self):
7387 self.mock_object(self.client, 'send_request')
7389 self.client.update_snapmirror_svm(
7390 fake.SM_SOURCE_VSERVER, fake.SM_DEST_VSERVER)
7392 snapmirror_update_args = {
7393 'source-location': fake.SM_SOURCE_VSERVER + ':',
7394 'destination-location': fake.SM_DEST_VSERVER + ':',
7395 }
7396 self.client.send_request.assert_has_calls([
7397 mock.call('snapmirror-update', snapmirror_update_args)])
7399 def test_update_snapmirror_already_transferring(self):
7400 mock_send_req = mock.Mock(side_effect=netapp_api.NaApiError(
7401 code=netapp_api.ETRANSFER_IN_PROGRESS))
7402 self.mock_object(self.client, 'send_request', mock_send_req)
7404 self.client.update_snapmirror_vol(
7405 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7406 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7408 snapmirror_update_args = {
7409 'source-vserver': fake.SM_SOURCE_VSERVER,
7410 'source-volume': fake.SM_SOURCE_VOLUME,
7411 'destination-vserver': fake.SM_DEST_VSERVER,
7412 'destination-volume': fake.SM_DEST_VOLUME,
7413 }
7414 self.client.send_request.assert_has_calls([
7415 mock.call('snapmirror-update', snapmirror_update_args)])
7417 def test_update_snapmirror_already_transferring_two(self):
7418 mock_send_req = mock.Mock(side_effect=netapp_api.NaApiError(
7419 code=netapp_api.EANOTHER_OP_ACTIVE))
7420 self.mock_object(self.client, 'send_request', mock_send_req)
7422 self.client.update_snapmirror_vol(
7423 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7424 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7426 snapmirror_update_args = {
7427 'source-vserver': fake.SM_SOURCE_VSERVER,
7428 'source-volume': fake.SM_SOURCE_VOLUME,
7429 'destination-vserver': fake.SM_DEST_VSERVER,
7430 'destination-volume': fake.SM_DEST_VOLUME,
7431 }
7432 self.client.send_request.assert_has_calls([
7433 mock.call('snapmirror-update', snapmirror_update_args)])
7435 def test_update_snapmirror_error(self):
7436 mock_send_req = mock.Mock(side_effect=netapp_api.NaApiError(code=0))
7437 self.mock_object(self.client, 'send_request', mock_send_req)
7439 self.assertRaises(netapp_api.NaApiError,
7440 self.client.update_snapmirror_vol,
7441 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7442 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7444 def test_delete_snapmirror(self):
7446 self.mock_object(self.client, 'send_request')
7448 self.client.delete_snapmirror_vol(
7449 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7450 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7452 snapmirror_delete_args = {
7453 'query': {
7454 'snapmirror-info': {
7455 'source-vserver': fake.SM_SOURCE_VSERVER,
7456 'source-volume': fake.SM_SOURCE_VOLUME,
7457 'destination-vserver': fake.SM_DEST_VSERVER,
7458 'destination-volume': fake.SM_DEST_VOLUME,
7459 }
7460 }
7461 }
7462 self.client.send_request.assert_has_calls([
7463 mock.call('snapmirror-destroy-iter', snapmirror_delete_args)])
7465 def test_delete_snapmirror_svm(self):
7467 self.mock_object(self.client, 'send_request')
7469 self.client.delete_snapmirror_svm(
7470 fake.SM_SOURCE_VSERVER, fake.SM_DEST_VSERVER)
7472 snapmirror_delete_args = {
7473 'query': {
7474 'snapmirror-info': {
7475 'source-location': fake.SM_SOURCE_VSERVER + ':',
7476 'destination-location': fake.SM_DEST_VSERVER + ':',
7477 }
7478 }
7479 }
7480 self.client.send_request.assert_has_calls([
7481 mock.call('snapmirror-destroy-iter', snapmirror_delete_args)])
7483 def test__get_snapmirrors(self):
7485 api_response = netapp_api.NaElement(fake.SNAPMIRROR_GET_ITER_RESPONSE)
7486 self.mock_object(self.client,
7487 'send_iter_request',
7488 mock.Mock(return_value=api_response))
7490 desired_attributes = {
7491 'snapmirror-info': {
7492 'source-vserver': None,
7493 'source-volume': None,
7494 'destination-vserver': None,
7495 'destination-volume': None,
7496 'is-healthy': None,
7497 }
7498 }
7500 result = self.client._get_snapmirrors(
7501 source_vserver=fake.SM_SOURCE_VSERVER,
7502 source_volume=fake.SM_SOURCE_VOLUME,
7503 dest_vserver=fake.SM_DEST_VSERVER,
7504 dest_volume=fake.SM_DEST_VOLUME,
7505 desired_attributes=desired_attributes)
7507 snapmirror_get_iter_args = {
7508 'query': {
7509 'snapmirror-info': {
7510 'source-vserver': fake.SM_SOURCE_VSERVER,
7511 'source-volume': fake.SM_SOURCE_VOLUME,
7512 'destination-vserver': fake.SM_DEST_VSERVER,
7513 'destination-volume': fake.SM_DEST_VOLUME,
7514 },
7515 },
7516 'desired-attributes': {
7517 'snapmirror-info': {
7518 'source-vserver': None,
7519 'source-volume': None,
7520 'destination-vserver': None,
7521 'destination-volume': None,
7522 'is-healthy': None,
7523 },
7524 },
7525 }
7526 self.client.send_iter_request.assert_has_calls([
7527 mock.call('snapmirror-get-iter', snapmirror_get_iter_args)])
7528 self.assertEqual(1, len(result))
7530 def test__get_snapmirrors_not_found(self):
7532 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
7533 self.mock_object(self.client,
7534 'send_iter_request',
7535 mock.Mock(return_value=api_response))
7537 result = self.client._get_snapmirrors()
7539 self.client.send_iter_request.assert_has_calls([
7540 mock.call('snapmirror-get-iter', {})])
7542 self.assertEqual([], result)
7544 def test_get_snapmirrors(self):
7546 api_response = netapp_api.NaElement(
7547 fake.SNAPMIRROR_GET_ITER_FILTERED_RESPONSE)
7548 self.mock_object(self.client,
7549 'send_iter_request',
7550 mock.Mock(return_value=api_response))
7552 desired_attributes = ['source-vserver', 'source-volume',
7553 'destination-vserver', 'destination-volume',
7554 'is-healthy', 'mirror-state', 'schedule',
7555 'relationship-status']
7557 result = self.client.get_snapmirrors(
7558 source_vserver=fake.SM_SOURCE_VSERVER,
7559 dest_vserver=fake.SM_DEST_VSERVER,
7560 source_volume=fake.SM_SOURCE_VOLUME,
7561 dest_volume=fake.SM_DEST_VOLUME,
7562 desired_attributes=desired_attributes)
7564 snapmirror_get_iter_args = {
7565 'query': {
7566 'snapmirror-info': {
7567 'source-vserver': fake.SM_SOURCE_VSERVER,
7568 'source-volume': fake.SM_SOURCE_VOLUME,
7569 'destination-vserver': fake.SM_DEST_VSERVER,
7570 'destination-volume': fake.SM_DEST_VOLUME,
7571 },
7572 },
7573 'desired-attributes': {
7574 'snapmirror-info': {
7575 'source-vserver': None,
7576 'source-volume': None,
7577 'destination-vserver': None,
7578 'destination-volume': None,
7579 'is-healthy': None,
7580 'mirror-state': None,
7581 'schedule': None,
7582 'relationship-status': None,
7583 },
7584 },
7585 }
7587 expected = [{
7588 'source-vserver': fake.SM_SOURCE_VSERVER,
7589 'source-volume': fake.SM_SOURCE_VOLUME,
7590 'destination-vserver': fake.SM_DEST_VSERVER,
7591 'destination-volume': fake.SM_DEST_VOLUME,
7592 'is-healthy': 'true',
7593 'mirror-state': 'snapmirrored',
7594 'schedule': 'daily',
7595 'relationship-status': 'idle'
7596 }]
7598 self.client.send_iter_request.assert_has_calls([
7599 mock.call('snapmirror-get-iter', snapmirror_get_iter_args)])
7600 self.assertEqual(expected, result)
7602 def test_get_snapmirrors_svm(self):
7604 api_response = netapp_api.NaElement(
7605 fake.SNAPMIRROR_GET_ITER_FILTERED_RESPONSE_2)
7606 self.mock_object(self.client,
7607 'send_iter_request',
7608 mock.Mock(return_value=api_response))
7610 desired_attributes = ['source-vserver', 'destination-vserver',
7611 'relationship-status', 'mirror-state']
7613 result = self.client.get_snapmirrors_svm(
7614 source_vserver=fake.SM_SOURCE_VSERVER,
7615 dest_vserver=fake.SM_DEST_VSERVER,
7616 desired_attributes=desired_attributes)
7618 snapmirror_get_iter_args = {
7619 'query': {
7620 'snapmirror-info': {
7621 'source-location': fake.SM_SOURCE_VSERVER + ':',
7622 'destination-location': fake.SM_DEST_VSERVER + ':',
7623 },
7624 },
7625 'desired-attributes': {
7626 'snapmirror-info': {
7627 'source-vserver': None,
7628 'destination-vserver': None,
7629 'relationship-status': None,
7630 'mirror-state': None,
7631 },
7632 },
7633 }
7635 expected = [{
7636 'source-vserver': fake.SM_SOURCE_VSERVER,
7637 'destination-vserver': fake.SM_DEST_VSERVER,
7638 'relationship-status': 'idle',
7639 'mirror-state': 'snapmirrored',
7640 }]
7642 self.client.send_iter_request.assert_has_calls([
7643 mock.call('snapmirror-get-iter', snapmirror_get_iter_args)])
7644 self.assertEqual(expected, result)
7646 @ddt.data(fake.SNAPMIRROR_GET_DESTINATIONS_ITER_FILTERED_RESPONSE,
7647 fake.NO_RECORDS_RESPONSE)
7648 def test_get_snapmirror_destinations_svm(self, api_response):
7649 self.mock_object(
7650 self.client, 'send_iter_request',
7651 mock.Mock(return_value=netapp_api.NaElement(api_response)))
7653 result = self.client.get_snapmirror_destinations_svm(
7654 source_vserver=fake.SM_SOURCE_VSERVER,
7655 dest_vserver=fake.SM_DEST_VSERVER)
7657 snapmirror_get_iter_args = {
7658 'query': {
7659 'snapmirror-destination-info': {
7660 'source-location': fake.SM_SOURCE_VSERVER + ':',
7661 'destination-location': fake.SM_DEST_VSERVER + ':',
7662 },
7663 },
7664 }
7666 if api_response == fake.NO_RECORDS_RESPONSE:
7667 expected = []
7668 else:
7669 expected = [{
7670 'source-vserver': fake.SM_SOURCE_VSERVER,
7671 'destination-vserver': fake.SM_DEST_VSERVER,
7672 'source-location': fake.SM_SOURCE_VSERVER + ':',
7673 'destination-location': fake.SM_DEST_VSERVER + ':',
7674 'relationship-id': 'fake_relationship_id',
7675 }]
7677 self.client.send_iter_request.assert_has_calls([
7678 mock.call('snapmirror-get-destination-iter',
7679 snapmirror_get_iter_args)])
7680 self.assertEqual(expected, result)
7682 def test_resume_snapmirror(self):
7683 self.mock_object(self.client, 'send_request')
7685 self.client.resume_snapmirror_vol(
7686 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7687 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7689 snapmirror_resume_args = {
7690 'source-vserver': fake.SM_SOURCE_VSERVER,
7691 'source-volume': fake.SM_SOURCE_VOLUME,
7692 'destination-vserver': fake.SM_DEST_VSERVER,
7693 'destination-volume': fake.SM_DEST_VOLUME,
7694 }
7695 self.client.send_request.assert_has_calls([
7696 mock.call('snapmirror-resume', snapmirror_resume_args)])
7698 def test_resume_snapmirror_svm(self):
7699 self.mock_object(self.client, 'send_request')
7701 self.client.resume_snapmirror_svm(
7702 fake.SM_SOURCE_VSERVER, fake.SM_DEST_VSERVER)
7704 snapmirror_resume_args = {
7705 'source-location': fake.SM_SOURCE_VSERVER + ':',
7706 'destination-location': fake.SM_DEST_VSERVER + ':',
7707 }
7708 self.client.send_request.assert_has_calls([
7709 mock.call('snapmirror-resume', snapmirror_resume_args)])
7711 def test_resume_snapmirror_not_quiesed(self):
7712 mock_send_req = mock.Mock(side_effect=netapp_api.NaApiError(
7713 code=netapp_api.ERELATION_NOT_QUIESCED))
7714 self.mock_object(self.client, 'send_request', mock_send_req)
7716 self.client.resume_snapmirror_vol(
7717 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7718 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7720 snapmirror_resume_args = {
7721 'source-vserver': fake.SM_SOURCE_VSERVER,
7722 'source-volume': fake.SM_SOURCE_VOLUME,
7723 'destination-vserver': fake.SM_DEST_VSERVER,
7724 'destination-volume': fake.SM_DEST_VOLUME,
7725 }
7726 self.client.send_request.assert_has_calls([
7727 mock.call('snapmirror-resume', snapmirror_resume_args)])
7729 def test_resume_snapmirror_error(self):
7730 mock_send_req = mock.Mock(side_effect=netapp_api.NaApiError(code=0))
7731 self.mock_object(self.client, 'send_request', mock_send_req)
7733 self.assertRaises(netapp_api.NaApiError,
7734 self.client.resume_snapmirror_vol,
7735 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7736 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7738 def test_resync_snapmirror(self):
7739 self.mock_object(self.client, 'send_request')
7741 self.client.resync_snapmirror_vol(
7742 fake.SM_SOURCE_VSERVER, fake.SM_SOURCE_VOLUME,
7743 fake.SM_DEST_VSERVER, fake.SM_DEST_VOLUME)
7745 snapmirror_resync_args = {
7746 'source-vserver': fake.SM_SOURCE_VSERVER,
7747 'source-volume': fake.SM_SOURCE_VOLUME,
7748 'destination-vserver': fake.SM_DEST_VSERVER,
7749 'destination-volume': fake.SM_DEST_VOLUME,
7750 }
7751 self.client.send_request.assert_has_calls([
7752 mock.call('snapmirror-resync', snapmirror_resync_args)])
7754 def test_resync_snapmirror_svm(self):
7755 self.mock_object(self.client, 'send_request')
7757 self.client.resync_snapmirror_svm(
7758 fake.SM_SOURCE_VSERVER, fake.SM_DEST_VSERVER)
7760 snapmirror_resync_args = {
7761 'source-location': fake.SM_SOURCE_VSERVER + ':',
7762 'destination-location': fake.SM_DEST_VSERVER + ':',
7763 }
7764 self.client.send_request.assert_has_calls([
7765 mock.call('snapmirror-resync', snapmirror_resync_args)])
7767 @ddt.data('source', 'destination', None)
7768 def test_volume_has_snapmirror_relationships(self, snapmirror_rel_type):
7769 """Snapmirror relationships can be both ways."""
7771 vol = fake.FAKE_MANAGE_VOLUME
7772 snapmirror = {
7773 'source-vserver': fake.SM_SOURCE_VSERVER,
7774 'source-volume': fake.SM_SOURCE_VOLUME,
7775 'destination-vserver': fake.SM_DEST_VSERVER,
7776 'destination-volume': fake.SM_DEST_VOLUME,
7777 'is-healthy': 'true',
7778 'mirror-state': 'snapmirrored',
7779 'schedule': 'daily',
7780 }
7781 expected_get_snapmirrors_call_count = 2
7782 expected_get_snapmirrors_calls = [
7783 mock.call(source_vserver=vol['owning-vserver-name'],
7784 source_volume=vol['name']),
7785 mock.call(dest_vserver=vol['owning-vserver-name'],
7786 dest_volume=vol['name']),
7787 ]
7788 if snapmirror_rel_type is None:
7789 side_effect = ([], [])
7790 elif snapmirror_rel_type == 'source':
7791 snapmirror['source-vserver'] = vol['owning-vserver-name']
7792 snapmirror['source-volume'] = vol['name']
7793 side_effect = ([snapmirror], None)
7794 expected_get_snapmirrors_call_count = 1
7795 expected_get_snapmirrors_calls.pop()
7796 else:
7797 snapmirror['destination-vserver'] = vol['owning-vserver-name']
7798 snapmirror['destination-volume'] = vol['name']
7799 side_effect = (None, [snapmirror])
7800 mock_get_snapmirrors_call = self.mock_object(
7801 self.client, 'get_snapmirrors', mock.Mock(side_effect=side_effect))
7802 mock_exc_log = self.mock_object(client_cmode.LOG, 'exception')
7803 expected_retval = True if snapmirror_rel_type else False
7805 retval = self.client.volume_has_snapmirror_relationships(vol)
7807 self.assertEqual(expected_retval, retval)
7808 self.assertEqual(expected_get_snapmirrors_call_count,
7809 mock_get_snapmirrors_call.call_count)
7810 mock_get_snapmirrors_call.assert_has_calls(
7811 expected_get_snapmirrors_calls)
7812 self.assertFalse(mock_exc_log.called)
7814 def test_volume_has_snapmirror_relationships_api_error(self):
7816 vol = fake.FAKE_MANAGE_VOLUME
7817 expected_get_snapmirrors_calls = [
7818 mock.call(source_vserver=vol['owning-vserver-name'],
7819 source_volume=vol['name']),
7820 ]
7821 mock_get_snapmirrors_call = self.mock_object(
7822 self.client, 'get_snapmirrors', mock.Mock(
7823 side_effect=self._mock_api_error(netapp_api.EINTERNALERROR)))
7824 mock_exc_log = self.mock_object(client_cmode.LOG, 'exception')
7826 retval = self.client.volume_has_snapmirror_relationships(vol)
7828 self.assertFalse(retval)
7829 self.assertEqual(1, mock_get_snapmirrors_call.call_count)
7830 mock_get_snapmirrors_call.assert_has_calls(
7831 expected_get_snapmirrors_calls)
7832 self.assertTrue(mock_exc_log.called)
7834 @ddt.data(None, '12345')
7835 def test_list_snapmirror_snapshots(self, newer_than):
7837 api_response = netapp_api.NaElement(
7838 fake.SNAPSHOT_GET_ITER_SNAPMIRROR_RESPONSE)
7839 self.mock_object(self.client,
7840 'send_iter_request',
7841 mock.Mock(return_value=api_response))
7843 result = self.client.list_snapmirror_snapshots(fake.SHARE_NAME,
7844 newer_than=newer_than)
7846 snapshot_get_iter_args = {
7847 'query': {
7848 'snapshot-info': {
7849 'dependency': 'snapmirror',
7850 'volume': fake.SHARE_NAME,
7851 },
7852 },
7853 }
7854 if newer_than:
7855 snapshot_get_iter_args['query']['snapshot-info']['access-time'] = (
7856 '>' + newer_than)
7857 self.client.send_iter_request.assert_has_calls([
7858 mock.call('snapshot-get-iter', snapshot_get_iter_args)])
7860 expected = [fake.SNAPSHOT_NAME]
7861 self.assertEqual(expected, result)
7863 @ddt.data(
7864 {'method_name': 'start_volume_move', 'ontapi_version': (1, 20)},
7865 {'method_name': 'start_volume_move', 'ontapi_version': (1, 110)},
7866 {'method_name': 'check_volume_move', 'ontapi_version': (1, 20)},
7867 {'method_name': 'check_volume_move', 'ontapi_version': (1, 110)}
7868 )
7869 @ddt.unpack
7870 def test_volume_move_method(self, method_name, ontapi_version):
7871 self.mock_object(client_base.NetAppBaseClient,
7872 'get_ontapi_version',
7873 mock.Mock(return_value=ontapi_version))
7875 self.client._init_features()
7877 method = getattr(self.client, method_name)
7878 self.mock_object(self.client, 'send_request')
7880 retval = method(fake.SHARE_NAME, fake.VSERVER_NAME,
7881 fake.SHARE_AGGREGATE_NAME)
7883 expected_api_args = {
7884 'source-volume': fake.SHARE_NAME,
7885 'vserver': fake.VSERVER_NAME,
7886 'dest-aggr': fake.SHARE_AGGREGATE_NAME,
7887 'cutover-action': 'wait',
7888 }
7890 if ontapi_version >= (1, 110):
7891 expected_api_args['encrypt-destination'] = 'false'
7892 self.assertTrue(self.client.features.FLEXVOL_ENCRYPTION)
7893 else:
7894 self.assertFalse(self.client.features.FLEXVOL_ENCRYPTION)
7896 if method_name.startswith('check'):
7897 expected_api_args['perform-validation-only'] = 'true'
7899 self.assertIsNone(retval)
7900 self.client.send_request.assert_called_once_with(
7901 'volume-move-start', expected_api_args)
7903 def test_abort_volume_move(self):
7904 self.mock_object(self.client, 'send_request')
7906 retval = self.client.abort_volume_move(
7907 fake.SHARE_NAME, fake.VSERVER_NAME)
7909 expected_api_args = {
7910 'source-volume': fake.SHARE_NAME,
7911 'vserver': fake.VSERVER_NAME,
7912 }
7913 self.assertIsNone(retval)
7914 self.client.send_request.assert_called_once_with(
7915 'volume-move-trigger-abort', expected_api_args)
7917 @ddt.data(True, False)
7918 def test_trigger_volume_move_cutover_force(self, forced):
7919 self.mock_object(self.client, 'send_request')
7921 retval = self.client.trigger_volume_move_cutover(
7922 fake.SHARE_NAME, fake.VSERVER_NAME, force=forced)
7924 expected_api_args = {
7925 'source-volume': fake.SHARE_NAME,
7926 'vserver': fake.VSERVER_NAME,
7927 'force': 'true' if forced else 'false',
7928 }
7929 self.assertIsNone(retval)
7930 self.client.send_request.assert_called_once_with(
7931 'volume-move-trigger-cutover', expected_api_args)
7933 def test_get_volume_move_status_no_records(self):
7934 self.mock_object(self.client, 'send_iter_request')
7935 self.mock_object(self.client, '_has_records',
7936 mock.Mock(return_value=False))
7938 self.assertRaises(exception.NetAppException,
7939 self.client.get_volume_move_status,
7940 fake.SHARE_NAME, fake.VSERVER_NAME)
7942 expected_api_args = {
7943 'query': {
7944 'volume-move-info': {
7945 'volume': fake.SHARE_NAME,
7946 'vserver': fake.VSERVER_NAME,
7947 },
7948 },
7949 'desired-attributes': {
7950 'volume-move-info': {
7951 'percent-complete': None,
7952 'estimated-completion-time': None,
7953 'state': None,
7954 'details': None,
7955 'cutover-action': None,
7956 'phase': None,
7957 },
7958 },
7959 }
7960 self.client.send_iter_request.assert_called_once_with(
7961 'volume-move-get-iter', expected_api_args)
7963 def test_get_volume_move_status(self):
7964 move_status = netapp_api.NaElement(fake.VOLUME_MOVE_GET_ITER_RESULT)
7965 self.mock_object(self.client, 'send_iter_request',
7966 mock.Mock(return_value=move_status))
7968 actual_status_info = self.client.get_volume_move_status(
7969 fake.SHARE_NAME, fake.VSERVER_NAME)
7971 expected_api_args = {
7972 'query': {
7973 'volume-move-info': {
7974 'volume': fake.SHARE_NAME,
7975 'vserver': fake.VSERVER_NAME,
7976 },
7977 },
7978 'desired-attributes': {
7979 'volume-move-info': {
7980 'percent-complete': None,
7981 'estimated-completion-time': None,
7982 'state': None,
7983 'details': None,
7984 'cutover-action': None,
7985 'phase': None,
7986 },
7987 },
7988 }
7989 expected_status_info = {
7990 'percent-complete': '82',
7991 'estimated-completion-time': '1481919246',
7992 'state': 'healthy',
7993 'details': 'Cutover Completed::Volume move job finishing move',
7994 'cutover-action': 'retry_on_failure',
7995 'phase': 'finishing',
7996 }
7998 self.assertDictEqual(expected_status_info, actual_status_info)
7999 self.client.send_iter_request.assert_called_once_with(
8000 'volume-move-get-iter', expected_api_args)
8002 def test_qos_policy_group_exists_no_records(self):
8003 self.mock_object(self.client, 'qos_policy_group_get', mock.Mock(
8004 side_effect=exception.NetAppException))
8006 policy_exists = self.client.qos_policy_group_exists(
8007 'i-dont-exist-but-i-am')
8009 self.assertIs(False, policy_exists)
8011 def test_qos_policy_group_exists(self):
8012 self.mock_object(self.client, 'qos_policy_group_get',
8013 mock.Mock(return_value=fake.QOS_POLICY_GROUP))
8015 policy_exists = self.client.qos_policy_group_exists(
8016 fake.QOS_POLICY_GROUP_NAME)
8018 self.assertIs(True, policy_exists)
8020 def test_qos_policy_group_get_no_permissions_to_execute_zapi(self):
8021 naapi_error = self._mock_api_error(code=netapp_api.EAPINOTFOUND,
8022 message='13005:Unable to find API')
8023 self.mock_object(self.client, 'send_request', naapi_error)
8025 self.assertRaises(exception.NetAppException,
8026 self.client.qos_policy_group_get,
8027 'possibly-valid-qos-policy')
8029 def test_qos_policy_group_get_other_zapi_errors(self):
8030 naapi_error = self._mock_api_error(code=netapp_api.EINTERNALERROR,
8031 message='13114:Internal error')
8032 self.mock_object(self.client, 'send_request', naapi_error)
8034 self.assertRaises(netapp_api.NaApiError,
8035 self.client.qos_policy_group_get,
8036 'possibly-valid-qos-policy')
8038 def test_qos_policy_group_get_none_found(self):
8039 no_records_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
8040 self.mock_object(self.client, 'send_request',
8041 mock.Mock(return_value=no_records_response))
8043 self.assertRaises(exception.NetAppException,
8044 self.client.qos_policy_group_get,
8045 'non-existent-qos-policy')
8047 qos_policy_group_get_iter_args = {
8048 'query': {
8049 'qos-policy-group-info': {
8050 'policy-group': 'non-existent-qos-policy',
8051 },
8052 },
8053 'desired-attributes': {
8054 'qos-policy-group-info': {
8055 'policy-group': None,
8056 'vserver': None,
8057 'max-throughput': None,
8058 'min-throughput': None,
8059 'num-workloads': None
8060 },
8061 },
8062 }
8064 self.client.send_request.assert_called_once_with(
8065 'qos-policy-group-get-iter', qos_policy_group_get_iter_args, False)
8067 def test_qos_policy_group_get(self):
8068 api_response = netapp_api.NaElement(
8069 fake.QOS_POLICY_GROUP_GET_ITER_RESPONSE)
8070 self.mock_object(self.client, 'send_request',
8071 mock.Mock(return_value=api_response))
8073 qos_info = self.client.qos_policy_group_get(fake.QOS_POLICY_GROUP_NAME)
8075 qos_policy_group_get_iter_args = {
8076 'query': {
8077 'qos-policy-group-info': {
8078 'policy-group': fake.QOS_POLICY_GROUP_NAME,
8079 },
8080 },
8081 'desired-attributes': {
8082 'qos-policy-group-info': {
8083 'policy-group': None,
8084 'vserver': None,
8085 'max-throughput': None,
8086 'min-throughput': None,
8087 'num-workloads': None
8088 },
8089 },
8090 }
8091 self.client.send_request.assert_called_once_with(
8092 'qos-policy-group-get-iter', qos_policy_group_get_iter_args, False)
8093 self.assertDictEqual(fake.QOS_POLICY_GROUP, qos_info)
8095 @ddt.data(
8096 {'max_throughput': None, 'min_throughput': None},
8097 {'max_throughput': fake.QOS_MAX_THROUGHPUT, 'min_throughput': None},
8098 {'max_throughput': None, 'min_throughput': fake.QOS_MIN_THROUGHPUT},
8099 {'max_throughput': fake.QOS_MAX_THROUGHPUT,
8100 'min_throughput': fake.QOS_MIN_THROUGHPUT})
8101 @ddt.unpack
8102 def test_qos_policy_group_create(self, max_throughput, min_throughput):
8103 self.mock_object(self.client, 'send_request',
8104 mock.Mock(return_value=fake.PASSED_RESPONSE))
8106 self.client.qos_policy_group_create(
8107 fake.QOS_POLICY_GROUP_NAME, fake.VSERVER_NAME,
8108 max_throughput=max_throughput,
8109 min_throughput=min_throughput)
8111 qos_policy_group_create_args = {
8112 'policy-group': fake.QOS_POLICY_GROUP_NAME,
8113 'vserver': fake.VSERVER_NAME,
8114 }
8115 if max_throughput:
8116 qos_policy_group_create_args.update(
8117 {'max-throughput': max_throughput})
8118 if min_throughput:
8119 qos_policy_group_create_args.update(
8120 {'min-throughput': min_throughput})
8122 self.client.send_request.assert_called_once_with(
8123 'qos-policy-group-create', qos_policy_group_create_args, False)
8125 def test_qos_policy_group_modify(self):
8126 self.mock_object(self.client, 'send_request',
8127 mock.Mock(return_value=fake.PASSED_RESPONSE))
8129 self.client.qos_policy_group_modify(fake.QOS_POLICY_GROUP_NAME,
8130 '3000iops', '20iops')
8132 qos_policy_group_modify_args = {
8133 'policy-group': fake.QOS_POLICY_GROUP_NAME,
8134 'max-throughput': '3000iops',
8135 'min-throughput': '20iops',
8136 }
8138 self.client.send_request.assert_called_once_with(
8139 'qos-policy-group-modify', qos_policy_group_modify_args, False)
8141 def test_qos_policy_group_delete(self):
8142 self.mock_object(self.client, 'send_request',
8143 mock.Mock(return_value=fake.PASSED_RESPONSE))
8145 self.client.qos_policy_group_delete(fake.QOS_POLICY_GROUP_NAME)
8147 qos_policy_group_delete_args = {
8148 'policy-group': fake.QOS_POLICY_GROUP_NAME,
8149 }
8151 self.client.send_request.assert_called_once_with(
8152 'qos-policy-group-delete', qos_policy_group_delete_args, False)
8154 def test_qos_policy_group_rename(self):
8155 self.mock_object(self.client, 'send_request',
8156 mock.Mock(return_value=fake.PASSED_RESPONSE))
8158 self.client.qos_policy_group_rename(
8159 fake.QOS_POLICY_GROUP_NAME, 'new_' + fake.QOS_POLICY_GROUP_NAME)
8161 qos_policy_group_rename_args = {
8162 'policy-group-name': fake.QOS_POLICY_GROUP_NAME,
8163 'new-name': 'new_' + fake.QOS_POLICY_GROUP_NAME,
8164 }
8166 self.client.send_request.assert_called_once_with(
8167 'qos-policy-group-rename', qos_policy_group_rename_args, False)
8169 def test_qos_policy_group_rename_noop(self):
8170 self.mock_object(self.client, 'send_request')
8172 # rename to same name = no-op
8173 self.client.qos_policy_group_rename(
8174 fake.QOS_POLICY_GROUP_NAME, fake.QOS_POLICY_GROUP_NAME)
8176 self.assertFalse(self.client.send_request.called)
8178 def test_mark_qos_policy_group_for_deletion_rename_failure(self):
8179 self.mock_object(self.client, 'qos_policy_group_exists',
8180 mock.Mock(return_value=True))
8181 self.mock_object(self.client, 'qos_policy_group_rename',
8182 mock.Mock(side_effect=netapp_api.NaApiError))
8183 self.mock_object(client_cmode.LOG, 'warning')
8184 self.mock_object(self.client, 'remove_unused_qos_policy_groups')
8186 retval = self.client.mark_qos_policy_group_for_deletion(
8187 fake.QOS_POLICY_GROUP_NAME)
8189 self.assertIsNone(retval)
8190 client_cmode.LOG.warning.assert_called_once()
8191 self.client.qos_policy_group_exists.assert_called_once_with(
8192 fake.QOS_POLICY_GROUP_NAME)
8193 self.client.qos_policy_group_rename.assert_called_once_with(
8194 fake.QOS_POLICY_GROUP_NAME,
8195 client_cmode.DELETED_PREFIX + fake.QOS_POLICY_GROUP_NAME)
8196 self.client.remove_unused_qos_policy_groups.assert_called_once_with()
8198 @ddt.data(True, False)
8199 def test_mark_qos_policy_group_for_deletion_policy_exists(self, exists):
8200 self.mock_object(self.client, 'qos_policy_group_exists',
8201 mock.Mock(return_value=exists))
8202 self.mock_object(self.client, 'qos_policy_group_rename')
8203 mock_remove_unused_policies = self.mock_object(
8204 self.client, 'remove_unused_qos_policy_groups')
8205 self.mock_object(client_cmode.LOG, 'warning')
8207 retval = self.client.mark_qos_policy_group_for_deletion(
8208 fake.QOS_POLICY_GROUP_NAME)
8210 self.assertIsNone(retval)
8212 if exists:
8213 self.client.qos_policy_group_rename.assert_called_once_with(
8214 fake.QOS_POLICY_GROUP_NAME,
8215 client_cmode.DELETED_PREFIX + fake.QOS_POLICY_GROUP_NAME)
8216 mock_remove_unused_policies.assert_called_once_with()
8217 else:
8218 self.assertFalse(self.client.qos_policy_group_rename.called)
8219 self.assertFalse(
8220 self.client.remove_unused_qos_policy_groups.called)
8221 self.assertFalse(client_cmode.LOG.warning.called)
8223 @ddt.data(True, False)
8224 def test_remove_unused_qos_policy_groups_with_failure(self, failed):
8226 if failed:
8227 args = mock.Mock(side_effect=netapp_api.NaApiError)
8228 else:
8229 args = mock.Mock(return_value=fake.PASSED_FAILED_ITER_RESPONSE)
8231 self.mock_object(self.client, 'send_request', args)
8232 self.mock_object(client_cmode.LOG, 'debug')
8234 retval = self.client.remove_unused_qos_policy_groups()
8236 qos_policy_group_delete_iter_args = {
8237 'query': {
8238 'qos-policy-group-info': {
8239 'policy-group': '%s*' % client_cmode.DELETED_PREFIX,
8240 }
8241 },
8242 'max-records': 3500,
8243 'continue-on-failure': 'true',
8244 'return-success-list': 'false',
8245 'return-failure-list': 'false',
8246 }
8248 self.assertIsNone(retval)
8249 self.client.send_request.assert_called_once_with(
8250 'qos-policy-group-delete-iter',
8251 qos_policy_group_delete_iter_args, False)
8252 self.assertIs(failed, client_cmode.LOG.debug.called)
8254 def test_get_cluster_name(self):
8255 api_response = netapp_api.NaElement(
8256 fake.CLUSTER_GET_CLUSTER_NAME)
8257 self.mock_object(self.client,
8258 'send_request',
8259 mock.Mock(return_value=api_response))
8260 api_args = {
8261 'desired-attributes': {
8262 'cluster-identity-info': {
8263 'cluster-name': None,
8264 }
8265 }
8266 }
8267 result = self.client.get_cluster_name()
8269 self.assertEqual(fake.CLUSTER_NAME, result)
8270 self.client.send_request.assert_called_once_with(
8271 'cluster-identity-get', api_args, enable_tunneling=False)
8273 @ddt.data('fake_snapshot_name', None)
8274 def test_check_volume_clone_split_completed(self, get_clone_parent):
8275 volume_name = fake.SHARE_NAME
8276 mock_get_vol_clone_parent = self.mock_object(
8277 self.client, 'get_volume_clone_parent_snaphot',
8278 mock.Mock(return_value=get_clone_parent))
8280 result = self.client.check_volume_clone_split_completed(volume_name)
8282 mock_get_vol_clone_parent.assert_called_once_with(volume_name)
8283 expected_result = get_clone_parent is None
8284 self.assertEqual(expected_result, result)
8286 def test_rehost_volume(self):
8287 volume_name = fake.SHARE_NAME
8288 vserver = fake.VSERVER_NAME
8289 dest_vserver = fake.VSERVER_NAME_2
8290 api_args = {
8291 'volume': volume_name,
8292 'vserver': vserver,
8293 'destination-vserver': dest_vserver,
8294 }
8295 self.mock_object(self.client, 'send_request')
8297 self.client.rehost_volume(volume_name, vserver, dest_vserver)
8299 self.client.send_request.assert_called_once_with('volume-rehost',
8300 api_args)
8302 @ddt.data(
8303 {'fake_api_response': fake.VOLUME_GET_ITER_PARENT_SNAP_EMPTY_RESPONSE,
8304 'expected_snapshot_name': None},
8305 {'fake_api_response': fake.VOLUME_GET_ITER_PARENT_SNAP_RESPONSE,
8306 'expected_snapshot_name': fake.SNAPSHOT_NAME},
8307 {'fake_api_response': fake.NO_RECORDS_RESPONSE,
8308 'expected_snapshot_name': None})
8309 @ddt.unpack
8310 def test_get_volume_clone_parent_snaphot(self, fake_api_response,
8311 expected_snapshot_name):
8313 api_response = netapp_api.NaElement(fake_api_response)
8314 self.mock_object(self.client,
8315 'send_iter_request',
8316 mock.Mock(return_value=api_response))
8318 result = self.client.get_volume_clone_parent_snaphot(fake.SHARE_NAME)
8320 expected_api_args = {
8321 'query': {
8322 'volume-attributes': {
8323 'volume-id-attributes': {
8324 'name': fake.SHARE_NAME
8325 }
8326 }
8327 },
8328 'desired-attributes': {
8329 'volume-attributes': {
8330 'volume-clone-attributes': {
8331 'volume-clone-parent-attributes': {
8332 'snapshot-name': ''
8333 }
8334 }
8335 }
8336 }
8337 }
8338 self.client.send_iter_request.assert_called_once_with(
8339 'volume-get-iter', expected_api_args)
8340 self.assertEqual(expected_snapshot_name, result)
8342 def test_set_qos_adaptive_policy_group_for_volume(self):
8344 self.client.features.add_feature('ADAPTIVE_QOS')
8346 self.mock_object(self.client, 'send_request')
8348 self.client.set_qos_adaptive_policy_group_for_volume(
8349 fake.SHARE_NAME,
8350 fake.QOS_POLICY_GROUP_NAME)
8352 volume_modify_iter_args = {
8353 'query': {
8354 'volume-attributes': {
8355 'volume-id-attributes': {
8356 'name': fake.SHARE_NAME,
8357 },
8358 },
8359 },
8360 'attributes': {
8361 'volume-attributes': {
8362 'volume-qos-attributes': {
8363 'adaptive-policy-group-name':
8364 fake.QOS_POLICY_GROUP_NAME,
8365 },
8366 },
8367 },
8368 }
8369 self.client.send_request.assert_called_once_with(
8370 'volume-modify-iter', volume_modify_iter_args)
8372 def test_get_nfs_config(self):
8373 api_args = {
8374 'query': {
8375 'nfs-info': {
8376 'vserver': 'vserver',
8377 },
8378 },
8379 'desired-attributes': {
8380 'nfs-info': {
8381 'field': None,
8382 },
8383 },
8384 }
8385 api_response = netapp_api.NaElement(
8386 fake.NFS_CONFIG_SERVER_RESULT)
8387 self.mock_object(self.client,
8388 'send_request',
8389 mock.Mock(return_value=api_response))
8390 self.mock_object(self.client,
8391 'parse_nfs_config',
8392 mock.Mock(return_value=None))
8394 self.client.get_nfs_config(['field'], 'vserver')
8396 self.client.send_request.assert_called_once_with(
8397 'nfs-service-get-iter', api_args)
8399 def test_get_nfs_config_default(self):
8400 api_response = netapp_api.NaElement(
8401 fake.NFS_CONFIG_DEFAULT_RESULT)
8402 self.mock_object(self.client,
8403 'send_request',
8404 mock.Mock(return_value=api_response))
8405 self.mock_object(self.client,
8406 'parse_nfs_config',
8407 mock.Mock(return_value=None))
8409 self.client.get_nfs_config_default(['field'])
8411 self.client.send_request.assert_called_once_with(
8412 'nfs-service-get-create-defaults', None)
8414 @ddt.data(
8415 {'nfs_info': fake.NFS_CONFIG_SERVER_RESULT,
8416 'desired_args': ['tcp-max-xfer-size'],
8417 'expected_nfs': {
8418 'tcp-max-xfer-size': '65536',
8419 }},
8420 {'nfs_info': fake.NFS_CONFIG_SERVER_RESULT,
8421 'desired_args': ['udp-max-xfer-size'],
8422 'expected_nfs': {
8423 'udp-max-xfer-size': '32768',
8424 }},
8425 {'nfs_info': fake.NFS_CONFIG_SERVER_RESULT,
8426 'desired_args': ['tcp-max-xfer-size', 'udp-max-xfer-size'],
8427 'expected_nfs': {
8428 'tcp-max-xfer-size': '65536',
8429 'udp-max-xfer-size': '32768',
8430 }},
8431 {'nfs_info': fake.NFS_CONFIG_SERVER_RESULT,
8432 'desired_args': [],
8433 'expected_nfs': {}})
8434 @ddt.unpack
8435 def test_parse_nfs_config(self, nfs_info, desired_args, expected_nfs):
8436 parent_elem = netapp_api.NaElement(nfs_info).get_child_by_name(
8437 'attributes-list')
8439 nfs_config = self.client.parse_nfs_config(parent_elem, desired_args)
8441 self.assertDictEqual(nfs_config, expected_nfs)
8443 @ddt.data(fake.NO_RECORDS_RESPONSE,
8444 fake.VSERVER_GET_ITER_RESPONSE_INFO)
8445 def test_get_vserver_info(self, api_response):
8446 self.mock_object(self.client, 'send_iter_request',
8447 mock.Mock(
8448 return_value=netapp_api.NaElement(
8449 api_response)))
8451 result = self.client.get_vserver_info(fake.VSERVER_NAME)
8453 expected_api_args = {
8454 'query': {
8455 'vserver-info': {
8456 'vserver-name': fake.VSERVER_NAME,
8457 },
8458 },
8459 'desired-attributes': {
8460 'vserver-info': {
8461 'vserver-name': None,
8462 'vserver-subtype': None,
8463 'state': None,
8464 'operational-state': None,
8465 },
8466 },
8467 }
8468 self.client.send_iter_request.assert_called_once_with(
8469 'vserver-get-iter', expected_api_args)
8470 if api_response == fake.NO_RECORDS_RESPONSE:
8471 self.assertIsNone(result)
8472 else:
8473 self.assertDictEqual(fake.VSERVER_INFO, result)
8475 @ddt.data({'discard_network': True, 'preserve_snapshots': False},
8476 {'discard_network': False, 'preserve_snapshots': True})
8477 @ddt.unpack
8478 def test_create_snapmirror_policy(self, discard_network,
8479 preserve_snapshots):
8480 api_response = netapp_api.NaElement(fake.PASSED_RESPONSE)
8481 self.mock_object(self.client, 'send_request',
8482 mock.Mock(return_value=api_response))
8484 self.client.create_snapmirror_policy(
8485 fake.SNAPMIRROR_POLICY_NAME, discard_network_info=discard_network,
8486 snapmirror_label="backup", preserve_snapshots=preserve_snapshots)
8487 expected_create_api_args = {
8488 'policy-name': fake.SNAPMIRROR_POLICY_NAME,
8489 'type': 'async_mirror',
8490 }
8491 if discard_network:
8492 expected_create_api_args['discard-configs'] = {
8493 'svmdr-config-obj': 'network'
8494 }
8495 expected_calls = [
8496 mock.call('snapmirror-policy-create', expected_create_api_args)
8497 ]
8499 if preserve_snapshots:
8500 expected_add_rules = {
8501 'policy-name': fake.SNAPMIRROR_POLICY_NAME,
8502 'snapmirror-label': 'backup',
8503 'keep': 1,
8504 'preserve': 'false'
8505 }
8506 expected_calls.append(mock.call('snapmirror-policy-add-rule',
8507 expected_add_rules))
8509 self.client.send_request.assert_has_calls(expected_calls)
8511 def test_delete_snapmirror_policy(self):
8512 api_response = netapp_api.NaElement(fake.PASSED_RESPONSE)
8513 self.mock_object(self.client, 'send_request',
8514 mock.Mock(return_value=api_response))
8516 self.client.delete_snapmirror_policy(fake.SNAPMIRROR_POLICY_NAME)
8518 expected_api_args = {
8519 'policy-name': fake.SNAPMIRROR_POLICY_NAME,
8520 }
8522 self.client.send_request.assert_called_once_with(
8523 'snapmirror-policy-delete', expected_api_args)
8525 def test_delete_snapmirror_policy_not_found(self):
8526 self.mock_object(self.client, 'send_request',
8527 self._mock_api_error(code=netapp_api.EOBJECTNOTFOUND))
8529 self.client.delete_snapmirror_policy(fake.SNAPMIRROR_POLICY_NAME)
8531 expected_api_args = {
8532 'policy-name': fake.SNAPMIRROR_POLICY_NAME,
8533 }
8535 self.client.send_request.assert_called_once_with(
8536 'snapmirror-policy-delete', expected_api_args)
8538 def test_get_snapmirror_policies(self):
8539 api_response = netapp_api.NaElement(
8540 fake.SNAPMIRROR_POLICY_GET_ITER_RESPONSE)
8541 self.mock_object(self.client, 'send_iter_request',
8542 mock.Mock(return_value=api_response))
8543 result_elem = [fake.SNAPMIRROR_POLICY_NAME]
8545 result = self.client.get_snapmirror_policies(
8546 fake.VSERVER_NAME)
8548 expected_api_args = {
8549 'query': {
8550 'snapmirror-policy-info': {
8551 'vserver-name': fake.VSERVER_NAME,
8552 },
8553 },
8554 'desired-attributes': {
8555 'snapmirror-policy-info': {
8556 'policy-name': None,
8557 },
8558 },
8559 }
8561 self.client.send_iter_request.assert_called_once_with(
8562 'snapmirror-policy-get-iter', expected_api_args)
8563 self.assertEqual(result_elem, result)
8565 @ddt.data(True, False, None)
8566 def test_start_vserver(self, force):
8567 api_response = netapp_api.NaElement(fake.PASSED_RESPONSE)
8568 self.mock_object(self.client, 'send_request',
8569 mock.Mock(return_value=api_response))
8571 self.client.start_vserver(fake.VSERVER_NAME, force=force)
8573 expected_api_args = {
8574 'vserver-name': fake.VSERVER_NAME,
8575 }
8576 if force is not None:
8577 expected_api_args['force'] = 'true' if force is True else 'false'
8579 self.client.send_request.assert_called_once_with(
8580 'vserver-start', expected_api_args, enable_tunneling=False)
8582 def test_start_vserver_already_started(self):
8583 self.mock_object(self.client, 'send_request',
8584 self._mock_api_error(
8585 code=netapp_api.EVSERVERALREADYSTARTED))
8587 self.client.start_vserver(fake.VSERVER_NAME)
8589 expected_api_args = {
8590 'vserver-name': fake.VSERVER_NAME,
8591 }
8593 self.client.send_request.assert_called_once_with(
8594 'vserver-start', expected_api_args, enable_tunneling=False)
8596 def test_stop_vserver(self):
8597 api_response = netapp_api.NaElement(fake.PASSED_RESPONSE)
8598 self.mock_object(self.client, 'send_request',
8599 mock.Mock(return_value=api_response))
8601 self.client.stop_vserver(fake.VSERVER_NAME)
8603 expected_api_args = {
8604 'vserver-name': fake.VSERVER_NAME,
8605 }
8607 self.client.send_request.assert_called_once_with(
8608 'vserver-stop', expected_api_args, enable_tunneling=False)
8610 def test_is_svm_dr_supported(self):
8611 self.client.features.add_feature('SVM_DR')
8613 result = self.client.is_svm_dr_supported()
8615 self.assertTrue(result)
8617 @ddt.data({'get_iter_response': fake.CIFS_SHARE_GET_ITER_RESPONSE,
8618 'expected_result': True},
8619 {'get_iter_response': fake.NO_RECORDS_RESPONSE,
8620 'expected_result': False})
8621 @ddt.unpack
8622 def test_cifs_share_exists(self, get_iter_response, expected_result):
8623 api_response = netapp_api.NaElement(get_iter_response)
8624 self.mock_object(self.client,
8625 'send_iter_request',
8626 mock.Mock(return_value=api_response))
8627 fake_share_path = '/%s' % fake.SHARE_NAME
8629 result = self.client.cifs_share_exists(fake.SHARE_NAME)
8631 cifs_share_get_iter_args = {
8632 'query': {
8633 'cifs-share': {
8634 'share-name': fake.SHARE_NAME,
8635 'path': fake_share_path,
8636 },
8637 },
8638 'desired-attributes': {
8639 'cifs-share': {
8640 'share-name': None
8641 }
8642 },
8643 }
8644 self.assertEqual(expected_result, result)
8645 self.client.send_iter_request.assert_called_once_with(
8646 'cifs-share-get-iter', cifs_share_get_iter_args)
8648 def test_get_volume_autosize_attributes(self):
8649 api_response = netapp_api.NaElement(fake.VOLUME_AUTOSIZE_GET_RESPONSE)
8650 self.mock_object(self.client,
8651 'send_request',
8652 mock.Mock(return_value=api_response))
8654 result = self.client.get_volume_autosize_attributes(fake.SHARE_NAME)
8656 expected_result = {}
8657 expected_keys = ['mode', 'grow-threshold-percent', 'minimum-size',
8658 'shrink-threshold-percent', 'maximum-size']
8659 for key in expected_keys:
8660 expected_result[key] = fake.VOLUME_AUTOSIZE_ATTRS[key]
8662 self.assertEqual(expected_result, result)
8663 self.client.send_request.assert_called_once_with(
8664 'volume-autosize-get', {'volume': fake.SHARE_NAME})
8666 @ddt.data('server_to_server',
8667 'server_to_default_ad_site',
8668 'default_ad_site_to_default_ad_site',
8669 'default_ad_site_to_server')
8670 def test_modify_active_directory_security_service(self,
8671 modify_ad_direction):
8672 if modify_ad_direction == 'server_to_server':
8673 curr_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
8674 new_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE_2)
8675 if modify_ad_direction == 'server_to_default_ad_site':
8676 curr_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
8677 new_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE_3)
8678 if modify_ad_direction == 'default_ad_site_to_default_ad_site':
8679 curr_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE_3)
8680 new_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE_4)
8681 if modify_ad_direction == 'default_ad_site_to_server':
8682 curr_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE_4)
8683 new_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE_2)
8685 # we don't support domain change, but this validation isn't made in
8686 # within this method
8687 new_sec_service['domain'] = curr_sec_service['domain']
8688 api_responses = [fake.PASSED_RESPONSE, fake.PASSED_RESPONSE,
8689 fake.PASSED_RESPONSE]
8691 self.mock_object(self.client, 'send_request',
8692 mock.Mock(side_effect=api_responses))
8693 self.mock_object(self.client, 'remove_preferred_dcs')
8694 self.mock_object(self.client, 'set_preferred_dc')
8695 self.mock_object(self.client, 'configure_cifs_options')
8696 differing_keys = {'password', 'user', 'server', 'default_ad_site'}
8698 self.client.modify_active_directory_security_service(
8699 fake.VSERVER_NAME, differing_keys, new_sec_service,
8700 curr_sec_service)
8702 cifs_server = self.client._get_cifs_server_name(fake.VSERVER_NAME)
8703 current_cifs_username = cifs_server + '\\' + curr_sec_service['user']
8704 set_pass_api_args = {
8705 'user-name': current_cifs_username,
8706 'user-password': new_sec_service['password']
8707 }
8708 user_rename_api_args = {
8709 'user-name': current_cifs_username,
8710 'new-user-name': new_sec_service['user']
8711 }
8713 self.client.send_request.assert_has_calls([
8714 mock.call('cifs-local-user-set-password', set_pass_api_args),
8715 mock.call('cifs-local-user-rename', user_rename_api_args)])
8717 if modify_ad_direction in ('default_ad_site_to_default_ad_site',
8718 'server_to_default_ad_site'):
8719 cifs_server_modify_args = {
8720 'admin-username': new_sec_service['user'],
8721 'admin-password': new_sec_service['password'],
8722 'force-account-overwrite': 'true',
8723 'cifs-server': cifs_server,
8724 'default-site': new_sec_service['default_ad_site'],
8725 }
8726 self.client.send_request.assert_has_calls([
8727 mock.call('cifs-server-modify', cifs_server_modify_args)])
8728 self.client.configure_cifs_options.assert_has_calls([
8729 mock.call(new_sec_service)])
8730 if modify_ad_direction in ('server_to_server',
8731 'server_to_default_ad_site'):
8732 self.client.remove_preferred_dcs.assert_called_once_with(
8733 curr_sec_service)
8734 if modify_ad_direction in ('server_to_server',
8735 'default_ad_site_to_server'):
8736 self.client.set_preferred_dc.assert_called_once_with(
8737 new_sec_service)
8738 self.client.configure_cifs_options.assert_has_calls([
8739 mock.call(new_sec_service)])
8741 @ddt.data(True, False)
8742 def test_modify_active_directory_security_service_error(
8743 self, cifs_set_password_failure):
8744 curr_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE)
8745 new_sec_service = copy.deepcopy(fake.CIFS_SECURITY_SERVICE_2)
8746 # we don't support domain change, but this validation isn't made in
8747 # within this method
8748 new_sec_service['domain'] = curr_sec_service['domain']
8749 if cifs_set_password_failure:
8750 api_responses = [netapp_api.NaApiError(code='fake'),
8751 fake.PASSED_RESPONSE]
8752 else:
8753 api_responses = [fake.PASSED_RESPONSE,
8754 netapp_api.NaApiError(code='fake')]
8756 self.mock_object(self.client, 'send_request',
8757 mock.Mock(side_effect=api_responses))
8758 differing_keys = {'password', 'user', 'server'}
8760 self.assertRaises(
8761 exception.NetAppException,
8762 self.client.modify_active_directory_security_service,
8763 fake.VSERVER_NAME, differing_keys, new_sec_service,
8764 curr_sec_service)
8766 cifs_server = self.client._get_cifs_server_name(fake.VSERVER_NAME)
8767 current_cifs_username = cifs_server + '\\' + curr_sec_service['user']
8768 set_pass_api_args = {
8769 'user-name': current_cifs_username,
8770 'user-password': new_sec_service['password']
8771 }
8772 user_rename_api_args = {
8773 'user-name': current_cifs_username,
8774 'new-user-name': new_sec_service['user']
8775 }
8777 if cifs_set_password_failure:
8778 send_request_calls = [
8779 mock.call('cifs-local-user-set-password', set_pass_api_args)]
8780 else:
8781 send_request_calls = [
8782 mock.call('cifs-local-user-set-password', set_pass_api_args),
8783 mock.call('cifs-local-user-rename', user_rename_api_args)
8784 ]
8786 self.client.send_request.assert_has_calls(send_request_calls)
8788 @ddt.data(False, True)
8789 def test_modify_ldap(self, api_not_found):
8790 current_ldap_service = fake.LDAP_AD_SECURITY_SERVICE
8791 new_ldap_service = fake.LDAP_LINUX_SECURITY_SERVICE
8792 config_name = hashlib.md5(
8793 new_ldap_service['id'].encode("latin-1")).hexdigest()
8794 api_result = (self._mock_api_error(code=netapp_api.EOBJECTNOTFOUND)
8795 if api_not_found else mock.Mock())
8796 mock_create_client = self.mock_object(
8797 self.client, '_create_ldap_client')
8798 mock_send_request = self.mock_object(
8799 self.client, 'send_request',
8800 mock.Mock(return_value=api_result))
8801 mock_delete_client = self.mock_object(
8802 self.client, '_delete_ldap_client',
8803 mock.Mock(return_value=api_result))
8805 self.client.modify_ldap(new_ldap_service, current_ldap_service)
8807 api_args = {'client-config': config_name, 'client-enabled': 'true'}
8808 mock_create_client.assert_called_once_with(new_ldap_service)
8809 mock_send_request.assert_has_calls([
8810 mock.call('ldap-config-delete'),
8811 mock.call('ldap-config-create', api_args)])
8812 mock_delete_client.assert_called_once_with(current_ldap_service)
8814 def test_modify_ldap_config_delete_failure(self):
8815 current_ldap_service = fake.LDAP_AD_SECURITY_SERVICE
8816 new_ldap_service = fake.LDAP_LINUX_SECURITY_SERVICE
8817 mock_create_client = self.mock_object(
8818 self.client, '_create_ldap_client')
8819 mock_send_request = self.mock_object(
8820 self.client, 'send_request', mock.Mock(
8821 side_effect=netapp_api.NaApiError(code=netapp_api.EAPIERROR)))
8822 mock_delete_client = self.mock_object(
8823 self.client, '_delete_ldap_client')
8825 self.assertRaises(exception.NetAppException,
8826 self.client.modify_ldap,
8827 new_ldap_service,
8828 current_ldap_service)
8830 mock_create_client.assert_called_once_with(new_ldap_service)
8831 mock_send_request.assert_called_once_with('ldap-config-delete')
8832 mock_delete_client.assert_called_once_with(new_ldap_service)
8834 def test_modify_ldap_current_config_delete_error(self):
8835 current_ldap_service = fake.LDAP_AD_SECURITY_SERVICE
8836 new_ldap_service = fake.LDAP_LINUX_SECURITY_SERVICE
8837 config_name = hashlib.md5(
8838 new_ldap_service['id'].encode("latin-1")).hexdigest()
8839 mock_create_client = self.mock_object(
8840 self.client, '_create_ldap_client')
8841 mock_send_request = self.mock_object(
8842 self.client, 'send_request')
8843 mock_delete_client = self.mock_object(
8844 self.client, '_delete_ldap_client', mock.Mock(
8845 side_effect=netapp_api.NaApiError(code=netapp_api.EAPIERROR)))
8847 self.client.modify_ldap(new_ldap_service, current_ldap_service)
8849 api_args = {'client-config': config_name, 'client-enabled': 'true'}
8850 mock_create_client.assert_called_once_with(new_ldap_service)
8851 mock_send_request.assert_has_calls([
8852 mock.call('ldap-config-delete'),
8853 mock.call('ldap-config-create', api_args)])
8854 mock_delete_client.assert_called_once_with(current_ldap_service)
8856 def test_create_fpolicy_event(self):
8857 self.mock_object(self.client, 'send_request')
8859 self.client.create_fpolicy_event(fake.SHARE_NAME,
8860 fake.FPOLICY_EVENT_NAME,
8861 fake.FPOLICY_PROTOCOL,
8862 fake.FPOLICY_FILE_OPERATIONS_LIST)
8864 expected_args = {
8865 'event-name': fake.FPOLICY_EVENT_NAME,
8866 'protocol': fake.FPOLICY_PROTOCOL,
8867 'file-operations': [],
8868 }
8869 for file_op in fake.FPOLICY_FILE_OPERATIONS_LIST:
8870 expected_args['file-operations'].append(
8871 {'fpolicy-operation': file_op})
8873 self.client.send_request.assert_called_once_with(
8874 'fpolicy-policy-event-create', expected_args)
8876 @ddt.data(None, netapp_api.EEVENTNOTFOUND)
8877 def test_delete_fpolicy_event(self, send_request_error):
8878 if send_request_error:
8879 send_request_mock = mock.Mock(
8880 side_effect=self._mock_api_error(code=send_request_error))
8881 else:
8882 send_request_mock = mock.Mock()
8883 self.mock_object(self.client, 'send_request', send_request_mock)
8885 self.client.delete_fpolicy_event(fake.SHARE_NAME,
8886 fake.FPOLICY_EVENT_NAME)
8888 self.client.send_request.assert_called_once_with(
8889 'fpolicy-policy-event-delete',
8890 {'event-name': fake.FPOLICY_EVENT_NAME})
8892 def test_delete_fpolicy_event_error(self):
8893 eapi_error = self._mock_api_error(code=netapp_api.EAPIERROR)
8894 self.mock_object(
8895 self.client, 'send_request', mock.Mock(side_effect=eapi_error))
8897 self.assertRaises(exception.NetAppException,
8898 self.client.delete_fpolicy_event,
8899 fake.SHARE_NAME,
8900 fake.FPOLICY_EVENT_NAME)
8902 self.client.send_request.assert_called_once_with(
8903 'fpolicy-policy-event-delete',
8904 {'event-name': fake.FPOLICY_EVENT_NAME})
8906 def test_get_fpolicy_events(self):
8907 api_response = netapp_api.NaElement(
8908 fake.FPOLICY_EVENT_GET_ITER_RESPONSE)
8909 self.mock_object(self.client, 'send_iter_request',
8910 mock.Mock(return_value=api_response))
8912 result = self.client.get_fpolicy_events(
8913 event_name=fake.FPOLICY_EVENT_NAME,
8914 protocol=fake.FPOLICY_PROTOCOL,
8915 file_operations=fake.FPOLICY_FILE_OPERATIONS_LIST)
8917 expected_options = {
8918 'event-name': fake.FPOLICY_EVENT_NAME,
8919 'protocol': fake.FPOLICY_PROTOCOL,
8920 'file-operations': []
8921 }
8922 for file_op in fake.FPOLICY_FILE_OPERATIONS_LIST:
8923 expected_options['file-operations'].append(
8924 {'fpolicy-operation': file_op})
8926 expected_args = {
8927 'query': {
8928 'fpolicy-event-options-config': expected_options,
8929 },
8930 }
8931 expected = [{
8932 'event-name': fake.FPOLICY_EVENT_NAME,
8933 'protocol': fake.FPOLICY_PROTOCOL,
8934 'file-operations': fake.FPOLICY_FILE_OPERATIONS_LIST
8935 }]
8937 self.assertEqual(expected, result)
8938 self.client.send_iter_request.assert_called_once_with(
8939 'fpolicy-policy-event-get-iter', expected_args)
8941 def test_create_fpolicy_policy(self):
8942 self.mock_object(self.client, 'send_request')
8944 self.client.create_fpolicy_policy(fake.FPOLICY_POLICY_NAME,
8945 fake.SHARE_NAME,
8946 [fake.FPOLICY_EVENT_NAME],
8947 engine=fake.FPOLICY_ENGINE)
8949 expected_args = {
8950 'policy-name': fake.FPOLICY_POLICY_NAME,
8951 'events': [],
8952 'engine-name': fake.FPOLICY_ENGINE
8953 }
8954 for event in [fake.FPOLICY_EVENT_NAME]:
8955 expected_args['events'].append(
8956 {'event-name': event})
8958 self.client.send_request.assert_called_once_with(
8959 'fpolicy-policy-create', expected_args)
8961 @ddt.data(None, netapp_api.EPOLICYNOTFOUND)
8962 def test_delete_fpolicy_policy(self, send_request_error):
8963 if send_request_error:
8964 send_request_mock = mock.Mock(
8965 side_effect=self._mock_api_error(code=send_request_error))
8966 else:
8967 send_request_mock = mock.Mock()
8968 self.mock_object(self.client, 'send_request', send_request_mock)
8970 self.client.delete_fpolicy_policy(
8971 fake.SHARE_NAME, fake.FPOLICY_POLICY_NAME)
8973 self.client.send_request.assert_called_once_with(
8974 'fpolicy-policy-delete',
8975 {'policy-name': fake.FPOLICY_POLICY_NAME})
8977 def test_delete_fpolicy_policy_error(self):
8978 eapi_error = self._mock_api_error(code=netapp_api.EAPIERROR)
8979 self.mock_object(
8980 self.client, 'send_request', mock.Mock(side_effect=eapi_error))
8982 self.assertRaises(exception.NetAppException,
8983 self.client.delete_fpolicy_policy,
8984 fake.SHARE_NAME,
8985 fake.FPOLICY_POLICY_NAME)
8987 self.client.send_request.assert_called_once_with(
8988 'fpolicy-policy-delete',
8989 {'policy-name': fake.FPOLICY_POLICY_NAME})
8991 def test_get_fpolicy_policies(self):
8992 api_response = netapp_api.NaElement(
8993 fake.FPOLICY_POLICY_GET_ITER_RESPONSE)
8994 self.mock_object(self.client, 'send_iter_request',
8995 mock.Mock(return_value=api_response))
8997 result = self.client.get_fpolicy_policies(
8998 share_name=fake.SHARE_NAME,
8999 policy_name=fake.FPOLICY_POLICY_NAME,
9000 engine_name=fake.FPOLICY_ENGINE,
9001 event_names=[fake.FPOLICY_EVENT_NAME])
9003 expected_options = {
9004 'policy-name': fake.FPOLICY_POLICY_NAME,
9005 'engine-name': fake.FPOLICY_ENGINE,
9006 'events': []
9007 }
9008 for policy in [fake.FPOLICY_EVENT_NAME]:
9009 expected_options['events'].append(
9010 {'event-name': policy})
9012 expected_args = {
9013 'query': {
9014 'fpolicy-policy-info': expected_options,
9015 },
9016 }
9017 expected = [{
9018 'policy-name': fake.FPOLICY_POLICY_NAME,
9019 'engine-name': fake.FPOLICY_ENGINE,
9020 'events': [fake.FPOLICY_EVENT_NAME]
9021 }]
9023 self.assertEqual(expected, result)
9024 self.client.send_iter_request.assert_called_once_with(
9025 'fpolicy-policy-get-iter', expected_args)
9027 def test_create_fpolicy_scope(self):
9028 self.mock_object(self.client, 'send_request')
9030 self.client.create_fpolicy_scope(
9031 fake.FPOLICY_POLICY_NAME,
9032 fake.SHARE_NAME,
9033 extensions_to_include=fake.FPOLICY_EXT_TO_INCLUDE,
9034 extensions_to_exclude=fake.FPOLICY_EXT_TO_EXCLUDE)
9036 expected_args = {
9037 'policy-name': fake.FPOLICY_POLICY_NAME,
9038 'shares-to-include': {
9039 'string': fake.SHARE_NAME,
9040 },
9041 'file-extensions-to-include': [],
9042 'file-extensions-to-exclude': [],
9043 }
9044 for file_ext in fake.FPOLICY_EXT_TO_INCLUDE_LIST:
9045 expected_args['file-extensions-to-include'].append(
9046 {'string': file_ext})
9047 for file_ext in fake.FPOLICY_EXT_TO_EXCLUDE_LIST:
9048 expected_args['file-extensions-to-exclude'].append(
9049 {'string': file_ext})
9051 self.client.send_request.assert_called_once_with(
9052 'fpolicy-policy-scope-create', expected_args)
9054 def test_modify_fpolicy_scope(self):
9055 self.mock_object(self.client, 'send_request')
9057 self.client.modify_fpolicy_scope(
9058 fake.SHARE_NAME,
9059 fake.FPOLICY_POLICY_NAME,
9060 shares_to_include=[fake.SHARE_NAME],
9061 extensions_to_include=fake.FPOLICY_EXT_TO_INCLUDE,
9062 extensions_to_exclude=fake.FPOLICY_EXT_TO_EXCLUDE)
9064 expected_args = {
9065 'policy-name': fake.FPOLICY_POLICY_NAME,
9066 'file-extensions-to-include': [],
9067 'file-extensions-to-exclude': [],
9068 'shares-to-include': [{
9069 'string': fake.SHARE_NAME,
9070 }],
9071 }
9072 for file_ext in fake.FPOLICY_EXT_TO_INCLUDE_LIST:
9073 expected_args['file-extensions-to-include'].append(
9074 {'string': file_ext})
9075 for file_ext in fake.FPOLICY_EXT_TO_EXCLUDE_LIST:
9076 expected_args['file-extensions-to-exclude'].append(
9077 {'string': file_ext})
9079 self.client.send_request.assert_called_once_with(
9080 'fpolicy-policy-scope-modify', expected_args)
9082 @ddt.data(None, netapp_api.ESCOPENOTFOUND)
9083 def test_delete_fpolicy_scope(self, send_request_error):
9084 if send_request_error:
9085 send_request_mock = mock.Mock(
9086 side_effect=self._mock_api_error(code=send_request_error))
9087 else:
9088 send_request_mock = mock.Mock()
9089 self.mock_object(self.client, 'send_request', send_request_mock)
9091 self.client.delete_fpolicy_scope(fake.FPOLICY_POLICY_NAME)
9093 self.client.send_request.assert_called_once_with(
9094 'fpolicy-policy-scope-delete',
9095 {'policy-name': fake.FPOLICY_POLICY_NAME})
9097 def test_delete_fpolicy_scope_error(self):
9098 eapi_error = self._mock_api_error(code=netapp_api.EAPIERROR)
9099 self.mock_object(
9100 self.client, 'send_request', mock.Mock(side_effect=eapi_error))
9102 self.assertRaises(exception.NetAppException,
9103 self.client.delete_fpolicy_scope,
9104 fake.FPOLICY_POLICY_NAME)
9106 self.client.send_request.assert_called_once_with(
9107 'fpolicy-policy-scope-delete',
9108 {'policy-name': fake.FPOLICY_POLICY_NAME})
9110 def test_get_fpolicy_scopes(self):
9111 api_response = netapp_api.NaElement(
9112 fake.FPOLICY_SCOPE_GET_ITER_RESPONSE)
9113 self.mock_object(self.client, 'send_iter_request',
9114 mock.Mock(return_value=api_response))
9116 result = self.client.get_fpolicy_scopes(
9117 share_name=fake.SHARE_NAME,
9118 policy_name=fake.FPOLICY_POLICY_NAME,
9119 extensions_to_include=fake.FPOLICY_EXT_TO_INCLUDE,
9120 extensions_to_exclude=fake.FPOLICY_EXT_TO_EXCLUDE,
9121 shares_to_include=[fake.SHARE_NAME])
9123 expected_options = {
9124 'policy-name': fake.FPOLICY_POLICY_NAME,
9125 'shares-to-include': [{
9126 'string': fake.SHARE_NAME,
9127 }],
9128 'file-extensions-to-include': [],
9129 'file-extensions-to-exclude': [],
9130 }
9131 for file_ext in fake.FPOLICY_EXT_TO_INCLUDE_LIST:
9132 expected_options['file-extensions-to-include'].append(
9133 {'string': file_ext})
9134 for file_ext in fake.FPOLICY_EXT_TO_EXCLUDE_LIST:
9135 expected_options['file-extensions-to-exclude'].append(
9136 {'string': file_ext})
9138 expected_args = {
9139 'query': {
9140 'fpolicy-scope-config': expected_options,
9141 },
9142 }
9143 expected = [{
9144 'policy-name': fake.FPOLICY_POLICY_NAME,
9145 'file-extensions-to-include': fake.FPOLICY_EXT_TO_INCLUDE_LIST,
9146 'file-extensions-to-exclude': fake.FPOLICY_EXT_TO_EXCLUDE_LIST,
9147 'shares-to-include': [fake.SHARE_NAME],
9148 }]
9150 self.assertEqual(expected, result)
9151 self.client.send_iter_request.assert_called_once_with(
9152 'fpolicy-policy-scope-get-iter', expected_args)
9154 def test_enable_fpolicy_policy(self):
9155 self.mock_object(self.client, 'send_request')
9157 self.client.enable_fpolicy_policy(
9158 fake.SHARE_NAME, fake.FPOLICY_POLICY_NAME, 10)
9160 expected_args = {
9161 'policy-name': fake.FPOLICY_POLICY_NAME,
9162 'sequence-number': 10,
9163 }
9164 self.client.send_request.assert_called_once_with(
9165 'fpolicy-enable-policy', expected_args)
9167 @ddt.data(None, netapp_api.EPOLICYNOTFOUND)
9168 def test_disable_fpolicy_policy(self, send_request_error):
9169 if send_request_error:
9170 send_request_mock = mock.Mock(
9171 side_effect=self._mock_api_error(code=send_request_error))
9172 else:
9173 send_request_mock = mock.Mock()
9174 self.mock_object(self.client, 'send_request', send_request_mock)
9176 self.client.disable_fpolicy_policy(fake.FPOLICY_POLICY_NAME)
9178 expected_args = {
9179 'policy-name': fake.FPOLICY_POLICY_NAME,
9180 }
9181 self.client.send_request.assert_called_once_with(
9182 'fpolicy-disable-policy', expected_args)
9184 def test_disable_fpolicy_policy_error(self):
9185 eapi_error = self._mock_api_error(code=netapp_api.EAPIERROR)
9186 self.mock_object(
9187 self.client, 'send_request', mock.Mock(side_effect=eapi_error))
9189 self.assertRaises(exception.NetAppException,
9190 self.client.disable_fpolicy_policy,
9191 fake.FPOLICY_POLICY_NAME)
9193 self.client.send_request.assert_called_once_with(
9194 'fpolicy-disable-policy',
9195 {'policy-name': fake.FPOLICY_POLICY_NAME})
9197 def test_get_fpolicy_status(self):
9198 api_response = netapp_api.NaElement(
9199 fake.FPOLICY_POLICY_STATUS_GET_ITER_RESPONSE)
9200 self.mock_object(self.client, 'send_iter_request',
9201 mock.Mock(return_value=api_response))
9203 result = self.client.get_fpolicy_policies_status(
9204 share_name=fake.SHARE_NAME,
9205 policy_name=fake.FPOLICY_POLICY_NAME)
9207 expected_args = {
9208 'query': {
9209 'fpolicy-policy-status-info': {
9210 'policy-name': fake.FPOLICY_POLICY_NAME,
9211 'status': 'true'
9212 },
9213 },
9214 }
9215 expected = [{
9216 'policy-name': fake.FPOLICY_POLICY_NAME,
9217 'status': True,
9218 'sequence-number': '1'
9219 }]
9221 self.assertEqual(expected, result)
9222 self.client.send_iter_request.assert_called_once_with(
9223 'fpolicy-policy-status-get-iter', expected_args)
9225 def test_is_svm_migrate_supported(self):
9226 self.client.features.add_feature('SVM_MIGRATE')
9228 result = self.client.is_svm_migrate_supported()
9230 self.assertTrue(result)
9232 @ddt.data(
9233 {"body": fake.FAKE_HTTP_BODY,
9234 "headers": fake.FAKE_HTTP_HEADER,
9235 "query": {},
9236 "url_params": fake.FAKE_URL_PARAMS
9237 },
9238 {"body": {},
9239 "headers": fake.FAKE_HTTP_HEADER,
9240 "query": fake.FAKE_HTTP_QUERY,
9241 "url_params": fake.FAKE_URL_PARAMS
9242 },
9243 )
9244 @ddt.unpack
9245 def test__format_request(self, body, headers, query, url_params):
9246 expected_result = {
9247 "body": body,
9248 "headers": headers,
9249 "query": query,
9250 "url_params": url_params
9251 }
9253 result = self.client._format_request(
9254 body, headers=headers, query=query, url_params=url_params)
9256 for k, v in expected_result.items():
9257 self.assertIn(k, result)
9258 self.assertEqual(result.get(k), v)
9260 @ddt.data(
9261 {"dest_ipspace": None, "check_only": True},
9262 {"dest_ipspace": "fake_dest_ipspace", "check_only": False},
9263 )
9264 @ddt.unpack
9265 def test_svm_migration_start(self, dest_ipspace, check_only):
9266 api_args = {
9267 "auto_cutover": False,
9268 "auto_source_cleanup": True,
9269 "check_only": check_only,
9270 "source": {
9271 "cluster": {"name": fake.CLUSTER_NAME},
9272 "svm": {"name": fake.VSERVER_NAME},
9273 },
9274 "destination": {
9275 "volume_placement": {
9276 "aggregates": [fake.SHARE_AGGREGATE_NAME],
9277 },
9278 },
9279 }
9280 if dest_ipspace:
9281 ipspace_data = {
9282 "ipspace": {"name": dest_ipspace}
9283 }
9284 api_args['destination'].update(ipspace_data)
9286 self.mock_object(self.client, '_format_request',
9287 mock.Mock(return_value=api_args))
9288 self.mock_object(
9289 self.client, 'send_request',
9290 mock.Mock(return_value=fake.FAKE_MIGRATION_RESPONSE_WITH_JOB))
9292 result = self.client.svm_migration_start(
9293 fake.CLUSTER_NAME, fake.VSERVER_NAME, [fake.SHARE_AGGREGATE_NAME],
9294 dest_ipspace=dest_ipspace, check_only=check_only)
9296 self.client._format_request.assert_called_once_with(api_args)
9297 self.client.send_request.assert_called_once_with(
9298 'svm-migration-start', api_args=api_args, use_zapi=False)
9300 self.assertEqual(result, fake.FAKE_MIGRATION_RESPONSE_WITH_JOB)
9302 @ddt.data({"check_only": False}, {"check_only": True})
9303 def test_share_server_migration_start_failed(self, check_only):
9304 api_args = {}
9306 self.mock_object(self.client, '_format_request',
9307 mock.Mock(return_value=api_args))
9308 self.mock_object(
9309 self.client, 'send_request',
9310 mock.Mock(side_effect=netapp_api.NaApiError(message='fake')))
9312 self.assertRaises(
9313 netapp_api.NaApiError,
9314 self.client.svm_migration_start,
9315 fake.CLUSTER_NAME, fake.VSERVER_NAME,
9316 [fake.SHARE_AGGREGATE_NAME],
9317 check_only=check_only
9318 )
9320 def test_svm_migrate_complete(self):
9321 migration_id = 'ongoing_migration_id'
9322 request = {
9323 'action': 'cutover'
9324 }
9325 expected_url_params = {
9326 'svm_migration_id': migration_id
9327 }
9329 self.mock_object(self.client, '_format_request',
9330 mock.Mock(return_value=request))
9331 self.mock_object(
9332 self.client, 'send_request',
9333 mock.Mock(return_value=fake.FAKE_MIGRATION_RESPONSE_WITH_JOB))
9335 self.client.svm_migrate_complete(migration_id)
9337 self.client._format_request.assert_called_once_with(
9338 request, url_params=expected_url_params)
9339 self.client.send_request.assert_called_once_with(
9340 'svm-migration-complete', api_args=request, use_zapi=False)
9342 def test_get_job(self):
9343 request = {}
9344 job_uuid = 'fake_job_uuid'
9345 url_params = {
9346 'job_uuid': job_uuid
9347 }
9349 self.mock_object(self.client, '_format_request',
9350 mock.Mock(return_value=request))
9351 self.mock_object(self.client, 'send_request',
9352 mock.Mock(return_value=fake.FAKE_JOB_SUCCESS_STATE))
9354 result = self.client.get_job(job_uuid)
9356 self.assertEqual(fake.FAKE_JOB_SUCCESS_STATE, result)
9357 self.client._format_request.assert_called_once_with(
9358 request, url_params=url_params)
9359 self.client.send_request.assert_called_once_with(
9360 'get-job', api_args=request, use_zapi=False)
9362 def test_svm_migrate_cancel(self):
9363 request = {}
9364 migration_id = 'fake_migration_uuid'
9365 url_params = {
9366 "svm_migration_id": migration_id
9367 }
9369 self.mock_object(self.client, '_format_request',
9370 mock.Mock(return_value=request))
9371 self.mock_object(
9372 self.client, 'send_request',
9373 mock.Mock(return_value=fake.FAKE_MIGRATION_RESPONSE_WITH_JOB))
9375 result = self.client.svm_migrate_cancel(migration_id)
9377 self.assertEqual(fake.FAKE_MIGRATION_RESPONSE_WITH_JOB, result)
9378 self.client._format_request.assert_called_once_with(
9379 request, url_params=url_params)
9380 self.client.send_request.assert_called_once_with(
9381 'svm-migration-cancel', api_args=request, use_zapi=False)
9383 def test_svm_migration_get(self):
9384 request = {}
9385 migration_id = 'fake_migration_uuid'
9386 url_params = {
9387 "svm_migration_id": migration_id
9388 }
9390 self.mock_object(self.client, '_format_request',
9391 mock.Mock(return_value=request))
9392 self.mock_object(
9393 self.client, 'send_request',
9394 mock.Mock(return_value=fake.FAKE_MIGRATION_JOB_SUCCESS))
9396 result = self.client.svm_migration_get(migration_id)
9398 self.assertEqual(fake.FAKE_MIGRATION_JOB_SUCCESS, result)
9399 self.client._format_request.assert_called_once_with(
9400 request, url_params=url_params)
9401 self.client.send_request.assert_called_once_with(
9402 'svm-migration-get', api_args=request, use_zapi=False)
9404 def test_svm_migrate_pause(self):
9405 request = {
9406 "action": "pause"
9407 }
9408 migration_id = 'fake_migration_uuid'
9409 url_params = {
9410 "svm_migration_id": migration_id
9411 }
9413 self.mock_object(self.client, '_format_request',
9414 mock.Mock(return_value=request))
9415 self.mock_object(
9416 self.client, 'send_request',
9417 mock.Mock(return_value=fake.FAKE_MIGRATION_RESPONSE_WITH_JOB))
9419 result = self.client.svm_migrate_pause(migration_id)
9421 self.assertEqual(fake.FAKE_MIGRATION_RESPONSE_WITH_JOB, result)
9422 self.client._format_request.assert_called_once_with(
9423 request, url_params=url_params)
9424 self.client.send_request.assert_called_once_with(
9425 'svm-migration-pause', api_args=request, use_zapi=False)
9427 def test_migration_check_job_state(self):
9428 self.mock_object(self.client, 'get_job',
9429 mock.Mock(return_value=fake.FAKE_JOB_SUCCESS_STATE))
9431 result = self.client.get_migration_check_job_state(
9432 fake.FAKE_JOB_ID
9433 )
9435 self.assertEqual(result, fake.FAKE_JOB_SUCCESS_STATE)
9436 self.client.get_job.assert_called_once_with(fake.FAKE_JOB_ID)
9438 @ddt.data(netapp_api.ENFS_V4_0_ENABLED_MIGRATION_FAILURE,
9439 netapp_api.EVSERVER_MIGRATION_TO_NON_AFF_CLUSTER)
9440 def test_migration_check_job_state_failed(self, error_code):
9442 self.mock_object(
9443 self.client, 'get_job',
9444 mock.Mock(side_effect=netapp_api.NaApiError(code=error_code)))
9446 self.assertRaises(
9447 exception.NetAppException,
9448 self.client.get_migration_check_job_state,
9449 fake.FAKE_JOB_ID
9450 )
9451 self.client.get_job.assert_called_once_with(fake.FAKE_JOB_ID)
9453 @ddt.data(True, False)
9454 def test_get_volume_state(self, has_record):
9456 api_response = netapp_api.NaElement(
9457 fake.VOLUME_GET_ITER_STATE_RESPONSE)
9458 mock_send_iter_request = self.mock_object(
9459 self.client, 'send_iter_request',
9460 mock.Mock(return_value=api_response))
9461 mock_has_record = self.mock_object(self.client,
9462 '_has_records',
9463 mock.Mock(return_value=has_record))
9465 state = self.client.get_volume_state(fake.SHARE_NAME)
9467 volume_get_iter_args = {
9468 'query': {
9469 'volume-attributes': {
9470 'volume-id-attributes': {
9471 'name': fake.SHARE_NAME,
9472 },
9473 },
9474 },
9475 'desired-attributes': {
9476 'volume-attributes': {
9477 'volume-state-attributes': {
9478 'state': None
9479 }
9480 }
9481 },
9482 }
9483 mock_send_iter_request.assert_called_once_with(
9484 'volume-get-iter', volume_get_iter_args)
9485 mock_has_record.assert_called_once_with(api_response)
9486 if has_record:
9487 self.assertEqual('online', state)
9488 else:
9489 self.assertEqual('', state)
9491 @ddt.data(True, False)
9492 def test_is_flexgroup_volume(self, is_flexgroup):
9494 self.client.features.add_feature('FLEXGROUP', supported=True)
9495 api_response = netapp_api.NaElement(
9496 fake.VOLUME_GET_ITER_STYLE_FLEXGROUP_RESPONSE
9497 if is_flexgroup else fake.VOLUME_GET_ITER_STYLE_FLEXVOL_RESPONSE)
9498 mock_send_iter_request = self.mock_object(
9499 self.client, 'send_request',
9500 mock.Mock(return_value=api_response))
9501 mock_has_record = self.mock_object(self.client,
9502 '_has_records',
9503 mock.Mock(return_value=True))
9504 mock_is_style_extended_flexgroup = self.mock_object(
9505 na_utils, 'is_style_extended_flexgroup',
9506 mock.Mock(return_value=is_flexgroup))
9508 is_flexgroup_res = self.client.is_flexgroup_volume(fake.SHARE_NAME)
9510 volume_get_iter_args = {
9511 'query': {
9512 'volume-attributes': {
9513 'volume-id-attributes': {
9514 'name': fake.SHARE_NAME,
9515 },
9516 },
9517 },
9518 'desired-attributes': {
9519 'volume-attributes': {
9520 'volume-id-attributes': {
9521 'style-extended': None,
9522 },
9523 },
9524 },
9525 }
9526 mock_send_iter_request.assert_called_once_with(
9527 'volume-get-iter', volume_get_iter_args)
9528 mock_has_record.assert_called_once_with(api_response)
9529 mock_is_style_extended_flexgroup.assert_called_once_with(
9530 fake.FLEXGROUP_STYLE_EXTENDED
9531 if is_flexgroup else fake.FLEXVOL_STYLE_EXTENDED)
9532 self.assertEqual(is_flexgroup, is_flexgroup_res)
9534 def test_is_flexgroup_volume_not_found(self):
9536 self.client.features.add_feature('FLEXGROUP', supported=True)
9537 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
9538 self.mock_object(self.client,
9539 'send_request',
9540 mock.Mock(return_value=api_response))
9542 self.assertRaises(exception.StorageResourceNotFound,
9543 self.client.is_flexgroup_volume,
9544 fake.SHARE_NAME)
9546 def test_is_flexgroup_volume_not_unique(self):
9548 self.client.features.add_feature('FLEXGROUP', supported=True)
9549 api_response = netapp_api.NaElement(
9550 fake.VOLUME_GET_ITER_NOT_UNIQUE_RESPONSE)
9551 self.mock_object(self.client,
9552 'send_request',
9553 mock.Mock(return_value=api_response))
9555 self.assertRaises(exception.NetAppException,
9556 self.client.is_flexgroup_volume,
9557 fake.SHARE_NAME)
9559 def test_is_flexgroup_volume_unsupported(self):
9561 self.client.features.add_feature('FLEXGROUP', supported=False)
9563 result = self.client.is_flexgroup_volume(fake.SHARE_NAME)
9565 self.assertFalse(result)
9567 def test_is_flexgroup_supported(self):
9568 self.client.features.add_feature('FLEXGROUP')
9570 result = self.client.is_flexgroup_supported()
9572 self.assertTrue(result)
9574 def test_is_flexgroup_fan_out_supported(self):
9575 self.client.features.add_feature('FLEXGROUP_FAN_OUT')
9577 result = self.client.is_flexgroup_fan_out_supported()
9579 self.assertTrue(result)
9581 def test_get_job_state(self):
9583 api_response = netapp_api.NaElement(fake.JOB_GET_STATE_RESPONSE)
9584 mock_send_iter_request = self.mock_object(
9585 self.client, 'send_iter_request',
9586 mock.Mock(return_value=api_response))
9587 mock_has_record = self.mock_object(self.client,
9588 '_has_records',
9589 mock.Mock(return_value=True))
9591 job_state_res = self.client.get_job_state(fake.JOB_ID)
9593 job_get_iter_args = {
9594 'query': {
9595 'job-info': {
9596 'job-id': fake.JOB_ID,
9597 },
9598 },
9599 'desired-attributes': {
9600 'job-info': {
9601 'job-state': None,
9602 },
9603 },
9604 }
9605 mock_send_iter_request.assert_called_once_with(
9606 'job-get-iter', job_get_iter_args, enable_tunneling=False)
9607 mock_has_record.assert_called_once_with(api_response)
9608 self.assertEqual(fake.JOB_STATE, job_state_res)
9610 def test_get_job_state_not_found(self):
9612 api_response = netapp_api.NaElement(fake.NO_RECORDS_RESPONSE)
9613 self.mock_object(self.client,
9614 '_has_records',
9615 mock.Mock(return_value=False))
9616 self.mock_object(self.client,
9617 'send_iter_request',
9618 mock.Mock(return_value=api_response))
9620 self.assertRaises(exception.NetAppException,
9621 self.client.get_job_state,
9622 fake.JOB_ID)
9624 def test_get_job_state_not_unique(self):
9626 api_response = netapp_api.NaElement(
9627 fake.JOB_GET_STATE_NOT_UNIQUE_RESPONSE)
9628 self.mock_object(self.client,
9629 '_has_records',
9630 mock.Mock(return_value=True))
9631 self.mock_object(self.client,
9632 'send_iter_request',
9633 mock.Mock(return_value=api_response))
9635 self.assertRaises(exception.NetAppException,
9636 self.client.get_job_state,
9637 fake.JOB_ID)
9639 def test_check_snaprestore_license_svm_scoped_notfound(self):
9640 self.mock_object(self.client,
9641 'restore_snapshot',
9642 mock.Mock(side_effect=netapp_api.NaApiError(
9643 code=netapp_api.EAPIERROR,
9644 message=fake.NO_SNAPRESTORE_LICENSE)))
9645 result = self.client.check_snaprestore_license()
9646 self.assertIs(False, result)
9648 def test_check_snaprestore_license_svm_scoped_found(self):
9649 self.mock_object(self.client,
9650 'restore_snapshot',
9651 mock.Mock(side_effect=netapp_api.NaApiError(
9652 code=netapp_api.EAPIERROR,
9653 message='Other error')))
9654 result = self.client.check_snaprestore_license()
9655 self.assertIs(True, result)
9657 def test_check_snaprestore_license_svm_scoped_found_exception(self):
9658 self.mock_object(client_cmode.LOG, 'exception')
9659 self.mock_object(self.client,
9660 'restore_snapshot',
9661 mock.Mock(return_value=None))
9663 self.assertRaises(
9664 exception.NetAppException,
9665 self.client.check_snaprestore_license)
9666 client_cmode.LOG.exception.assert_called_once()
9668 def test_get_svm_volumes_total_size(self):
9669 expected = 1
9671 request = {}
9673 api_args = {
9674 'svm.name': fake.VSERVER_NAME,
9675 'fields': 'size'
9676 }
9678 self.mock_object(self.client, '_format_request',
9679 mock.Mock(return_value=api_args))
9681 self.mock_object(self.client, 'send_request',
9682 mock.Mock(return_value=fake.FAKE_GET_VOLUME))
9684 result = self.client.get_svm_volumes_total_size(fake.VSERVER_NAME)
9686 self.client._format_request.assert_called_once_with(request,
9687 query=api_args)
9688 self.client.send_request.assert_called_once_with(
9689 'svm-migration-get-progress', api_args=api_args, use_zapi=False)
9691 self.assertEqual(expected, result)
9693 def test_configure_active_directory_credential_error(self):
9694 msg = "could not authenticate"
9695 self.mock_object(self.client, 'send_request',
9696 self._mock_api_error(code=netapp_api.EAPIERROR,
9697 message=msg))
9698 self.mock_object(self.client, 'configure_dns')
9699 self.mock_object(self.client, 'configure_cifs_aes_encryption')
9700 self.mock_object(self.client, 'set_preferred_dc')
9701 self.mock_object(self.client, '_get_cifs_server_name')
9702 self.assertRaises(exception.SecurityServiceFailedAuth,
9703 self.client.configure_active_directory,
9704 fake.CIFS_SECURITY_SERVICE,
9705 fake.VSERVER_NAME,
9706 False)
9708 def test_configure_active_directory_user_privilege_error(self):
9709 msg = "insufficient access"
9710 self.mock_object(self.client, 'send_request',
9711 self._mock_api_error(code=netapp_api.EAPIERROR,
9712 message=msg))
9713 self.mock_object(self.client, 'configure_dns')
9714 self.mock_object(self.client, 'configure_cifs_aes_encryption')
9715 self.mock_object(self.client, 'set_preferred_dc')
9716 self.mock_object(self.client, '_get_cifs_server_name')
9717 self.assertRaises(exception.SecurityServiceFailedAuth,
9718 self.client.configure_active_directory,
9719 fake.CIFS_SECURITY_SERVICE,
9720 fake.VSERVER_NAME,
9721 False)
9723 def test_snapmirror_restore_vol(self):
9724 self.mock_object(self.client, 'send_request')
9725 self.client.snapmirror_restore_vol(source_path=fake.SM_SOURCE_PATH,
9726 dest_path=fake.SM_DEST_PATH,
9727 source_snapshot=fake.SNAPSHOT_NAME,
9728 )
9729 snapmirror_restore_args = {
9730 'source-location': fake.SM_SOURCE_PATH,
9731 'destination-location': fake.SM_DEST_PATH,
9732 'source-snapshot': fake.SNAPSHOT_NAME,
9734 }
9735 self.client.send_request.assert_has_calls([
9736 mock.call('snapmirror-restore', snapmirror_restore_args)])
9738 @ddt.data({'snapmirror_label': None, 'newer_than': '2345'},
9739 {'snapmirror_label': "fake_backup", 'newer_than': None})
9740 @ddt.unpack
9741 def test_list_volume_snapshots(self, snapmirror_label, newer_than):
9742 api_response = netapp_api.NaElement(
9743 fake.SNAPSHOT_GET_ITER_SNAPMIRROR_RESPONSE)
9744 self.mock_object(self.client,
9745 'send_iter_request',
9746 mock.Mock(return_value=api_response))
9748 result = self.client.list_volume_snapshots(
9749 fake.SHARE_NAME,
9750 snapmirror_label=snapmirror_label,
9751 newer_than=newer_than)
9752 snapshot_get_iter_args = {
9753 'query': {
9754 'snapshot-info': {
9755 'volume': fake.SHARE_NAME,
9756 },
9757 },
9758 }
9759 if newer_than:
9760 snapshot_get_iter_args['query']['snapshot-info'][
9761 'access-time'] = '>' + newer_than
9762 if snapmirror_label:
9763 snapshot_get_iter_args['query']['snapshot-info'][
9764 'snapmirror-label'] = snapmirror_label
9765 self.client.send_iter_request.assert_has_calls([
9766 mock.call('snapshot-get-iter', snapshot_get_iter_args)])
9768 expected = [fake.SNAPSHOT_NAME]
9769 self.assertEqual(expected, result)
9771 def test_is_snaplock_compliance_clock_configured(self):
9772 api_response = netapp_api.NaElement(fake.SNAPLOCK_CLOCK_CONFIG_1)
9773 self.mock_object(self.client,
9774 'send_request',
9775 mock.Mock(return_value=api_response))
9776 result = self.client.is_snaplock_compliance_clock_configured(
9777 "fake_node",
9778 )
9779 self.assertIs(True, result)
9781 def test_is_snaplock_compliance_clock_configured_negative(self):
9782 api_response = netapp_api.NaElement(fake.SNAPLOCK_CLOCK_CONFIG_2)
9783 self.mock_object(self.client,
9784 'send_request',
9785 mock.Mock(return_value=api_response))
9786 result = self.client.is_snaplock_compliance_clock_configured(
9787 "fake_node"
9788 )
9789 self.assertIs(False, result)
9791 def test_is_snaplock_compliance_clock_configured_none(self):
9792 api_response = netapp_api.NaElement(fake.SNAPLOCK_CLOCK_CONFIG_1)
9793 self.mock_object(self.client,
9794 'send_request',
9795 mock.Mock(return_value=api_response))
9796 self.mock_object(api_response,
9797 'get_child_by_name',
9798 mock.Mock(return_value=None))
9799 self.assertRaises(
9800 exception.NetAppException,
9801 self.client.is_snaplock_compliance_clock_configured,
9802 "node1"
9803 )
9805 @ddt.data({'options': {'snaplock_autocommit_period': "4hours",
9806 'snaplock_min_retention_period': "6days",
9807 'snaplock_max_retention_period': "8months",
9808 'snaplock_default_retention_period': "8days"},
9809 },
9810 {'options': {'snaplock_autocommit_period': "4hours",
9811 'snaplock_min_retention_period': "6days",
9812 'snaplock_max_retention_period': "8months",
9813 'snaplock_default_retention_period': "min"},
9814 },
9815 {'options': {'snaplock_autocommit_period': "4hours",
9816 'snaplock_min_retention_period': "6days",
9817 'snaplock_max_retention_period': "8months",
9818 'snaplock_default_retention_period': "max"},
9819 },
9820 )
9821 @ddt.unpack
9822 def test_set_snaplock_attributes(self, options):
9823 api_args = {
9824 'volume': fake.SHARE_NAME,
9825 'autocommit-period': options.get('snaplock_autocommit_period'),
9826 'minimum-retention-period': options.get(
9827 'snaplock_min_retention_period'),
9828 'maximum-retention-period': options.get(
9829 'snaplock_max_retention_period'),
9830 'default-retention-period': options.get(
9831 'snaplock_default_retention_period'),
9832 }
9833 if options.get('snaplock_default_retention_period') == "min":
9834 api_args['default-retention-period'] = options.get(
9835 'snaplock_min_retention_period')
9836 elif options.get('snaplock_default_retention_period') == 'max':
9837 api_args['default-retention-period'] = options.get(
9838 'snaplock_max_retention_period')
9839 self.mock_object(self.client, 'send_request')
9840 self.client.set_snaplock_attributes(fake.SHARE_NAME, **options)
9841 self.client.send_request.assert_has_calls([
9842 mock.call('volume-set-snaplock-attrs', api_args)])
9844 def test_set_snaplock_attributes_all_none(self):
9845 self.mock_object(self.client, 'send_request')
9846 options = {'snaplock_autocommit_period': None,
9847 'snaplock_min_retention_period': None,
9848 'snaplock_max_retention_period': None,
9849 'snaplock_default_retention_period': None,
9850 }
9851 self.client.set_snaplock_attributes(fake.SHARE_NAME, **options)
9852 self.client.send_request.assert_not_called()
9854 def test_get_vserver_aggr_snaplock_type(self):
9855 self.client.features.SNAPLOCK = True
9856 api_response = netapp_api.NaElement(
9857 fake.VSERVER_SHOW_AGGR_GET_RESPONSE,
9858 )
9859 self.mock_object(self.client,
9860 'send_iter_request',
9861 mock.Mock(return_value=api_response))
9862 result = self.client.get_vserver_aggr_snaplock_type(
9863 fake.SHARE_AGGREGATE_NAMES
9864 )
9865 self.assertEqual("compliance", result)
9867 def test_get_vserver_aggr_snaplock_type_negative(self):
9868 self.client.features.SNAPLOCK = False
9869 api_response = netapp_api.NaElement(
9870 fake.VSERVER_SHOW_AGGR_GET_RESPONSE,
9871 )
9872 self.mock_object(self.client,
9873 'send_iter_request',
9874 mock.Mock(return_value=api_response))
9875 result = self.client.get_vserver_aggr_snaplock_type(
9876 fake.SHARE_AGGREGATE_NAMES
9877 )
9878 self.assertIsNone(result)
9880 @ddt.data("compliance", "enterprise")
9881 def test__is_snaplock_enabled_volume_true(self, snaplock_type):
9882 vol_attr = {'snaplock-type': snaplock_type}
9883 self.mock_object(self.client,
9884 'get_volume',
9885 mock.Mock(return_value=vol_attr))
9886 result = self.client._is_snaplock_enabled_volume(
9887 fake.SHARE_AGGREGATE_NAMES
9888 )
9889 self.assertIs(True, result)
9891 def test__is_snaplock_enabled_volume_false(self):
9892 vol_attr = {'snaplock-type': 'non-snaplock'}
9893 self.mock_object(self.client,
9894 'get_volume',
9895 mock.Mock(return_value=vol_attr))
9896 result = self.client._is_snaplock_enabled_volume(
9897 fake.SHARE_AGGREGATE_NAMES
9898 )
9899 self.assertIs(False, result)
9901 def test_get_storage_failover_partner(self):
9902 api_response = netapp_api.NaElement(fake.STORAGE_FAIL_OVER_PARTNER)
9903 self.mock_object(self.client,
9904 'send_request',
9905 mock.Mock(return_value=api_response))
9907 result = self.client.get_storage_failover_partner("fake_node")
9908 self.assertEqual("fake_partner_node", result)
9910 def test_get_migratable_data_lif_for_node(self):
9911 api_response = netapp_api.NaElement(
9912 fake.NET_INTERFACE_GET_ITER_RESPONSE)
9913 self.mock_object(self.client,
9914 'send_iter_request',
9915 mock.Mock(return_value=api_response))
9916 failover_policy = ['system-defined', 'sfo-partner-only']
9917 protocols = ['nfs', 'cifs']
9918 api_args = {
9919 'query': {
9920 'net-interface-info': {
9921 'failover-policy': '|'.join(failover_policy),
9922 'home-node': "fake_node",
9923 'data-protocols': {
9924 'data-protocol': '|'.join(protocols),
9925 }
9926 }
9927 }
9928 }
9929 result = self.client.get_migratable_data_lif_for_node("fake_node")
9930 self.client.send_iter_request.assert_has_calls([
9931 mock.call('net-interface-get-iter', api_args)])
9932 self.assertEqual(list(fake.LIF_NAMES), result)
9934 def test_get_data_lif_details_for_nodes(self):
9935 api_response = netapp_api.NaElement(
9936 fake.DATA_LIF_CAPACITY_DETAILS)
9937 self.mock_object(self.client,
9938 'send_iter_request',
9939 mock.Mock(return_value=api_response))
9940 api_args = {
9941 'desired-attributes': {
9942 'data-lif-capacity-details-info': {
9943 'limit-for-node': None,
9944 'count-for-node': None,
9945 'node': None
9946 },
9947 },
9948 }
9949 expected_result = [{'limit-for-node': '512',
9950 'count-for-node': '44',
9951 'node': 'fake_node',
9952 }]
9953 result = self.client.get_data_lif_details_for_nodes()
9954 self.client.send_iter_request.assert_has_calls([
9955 mock.call('data-lif-capacity-details', api_args)])
9956 self.assertEqual(expected_result, result)