Coverage for manila/tests/share/drivers/inspur/as13000/test_as13000_nas.py: 99%
632 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 2018 Inspur Corp.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
16"""
17Share driver test for Inspur AS13000
18"""
20import json
21import time
22from unittest import mock
24import ddt
25from oslo_config import cfg
26import requests
28from manila import context
29from manila import exception
30from manila.share import driver
31from manila.share.drivers.inspur.as13000 import as13000_nas
32from manila import test
33from manila.tests import fake_share
35CONF = cfg.CONF
38class FakeConfig(object):
39 def __init__(self, *args, **kwargs):
40 self.driver_handles_share_servers = False
41 self.share_driver = 'fake_share_driver_name'
42 self.share_backend_name = 'fake_as13000'
43 self.as13000_nas_ip = kwargs.get(
44 'as13000_nas_ip', 'some_ip')
45 self.as13000_nas_port = kwargs.get(
46 'as13000_nas_port', 'some_port')
47 self.as13000_nas_login = kwargs.get(
48 'as13000_nas_login', 'username')
49 self.as13000_nas_password = kwargs.get(
50 'as13000_nas_password', 'password')
51 self.as13000_share_pools = kwargs.get(
52 'as13000_share_pools', ['fakepool'])
53 self.as13000_token_available_time = kwargs.get(
54 'as13000_token_available_time', 3600)
55 self.network_config_group = kwargs.get(
56 "network_config_group", "fake_network_config_group")
57 self.admin_network_config_group = kwargs.get(
58 "admin_network_config_group", "fake_admin_network_config_group")
59 self.config_group = kwargs.get("config_group", "fake_config_group")
60 self.reserved_share_percentage = kwargs.get(
61 "reserved_share_percentage", 0)
62 self.reserved_share_from_snapshot_percentage = kwargs.get(
63 "reserved_share_from_snapshot_percentage", 0)
64 self.reserved_share_extend_percentage = kwargs.get(
65 "reserved_share_extend_percentage", 0)
66 self.max_over_subscription_ratio = kwargs.get(
67 "max_over_subscription_ratio", 20.0)
68 self.filter_function = kwargs.get("filter_function", None)
69 self.goodness_function = kwargs.get("goodness_function", None)
71 def safe_get(self, key):
72 return getattr(self, key)
74 def append_config_values(self, *args, **kwargs):
75 pass
78test_config = FakeConfig()
81class FakeResponse(object):
82 def __init__(self, status, output):
83 self.status_code = status
84 self.text = 'return message'
85 self._json = output
87 def json(self):
88 return self._json
90 def close(self):
91 pass
94@ddt.ddt
95class RestAPIExecutorTestCase(test.TestCase):
96 def setUp(self):
97 self.rest_api = as13000_nas.RestAPIExecutor(
98 test_config.as13000_nas_ip,
99 test_config.as13000_nas_port,
100 test_config.as13000_nas_login,
101 test_config.as13000_nas_password)
102 super(RestAPIExecutorTestCase, self).setUp()
104 def test_logins(self):
105 mock_login = self.mock_object(self.rest_api, 'login',
106 mock.Mock(return_value='fake_token'))
107 self.rest_api.logins()
108 mock_login.assert_called_once()
110 def test_login(self):
111 fake_response = {
112 'token': 'fake_token',
113 'expireTime': '7200',
114 'type': 0}
115 mock_sra = self.mock_object(self.rest_api, 'send_rest_api',
116 mock.Mock(return_value=fake_response))
117 result = self.rest_api.login()
119 self.assertEqual('fake_token', result)
121 login_params = {'name': test_config.as13000_nas_login,
122 'password': test_config.as13000_nas_password}
123 mock_sra.assert_called_once_with(method='security/token',
124 params=login_params,
125 request_type='post')
127 def test_logout(self):
128 mock_sra = self.mock_object(self.rest_api, 'send_rest_api',
129 mock.Mock(return_value=None))
130 self.rest_api.logout()
131 mock_sra.assert_called_once_with(
132 method='security/token', request_type='delete')
134 @ddt.data(True, False)
135 def test_refresh_token(self, force):
136 mock_login = self.mock_object(self.rest_api, 'login',
137 mock.Mock(return_value='fake_token'))
138 mock_logout = self.mock_object(self.rest_api, 'logout',
139 mock.Mock())
140 self.rest_api.refresh_token(force)
141 if force is not True:
142 mock_logout.assert_called_once_with()
143 mock_login.assert_called_once_with()
145 def test_send_rest_api(self):
146 expected = {'value': 'abc'}
147 mock_sa = self.mock_object(self.rest_api, 'send_api',
148 mock.Mock(return_value=expected))
149 result = self.rest_api.send_rest_api(
150 method='fake_method',
151 params='fake_params',
152 request_type='fake_type')
153 self.assertEqual(expected, result)
154 mock_sa.assert_called_once_with(
155 'fake_method',
156 'fake_params',
157 'fake_type')
159 @mock.patch('time.sleep')
160 def test_send_rest_api_retry(self, mock_sleep):
161 expected = {'value': 'abc'}
162 mock_sa = self.mock_object(
163 self.rest_api,
164 'send_api',
165 mock.Mock(
166 side_effect=(
167 exception.NetworkException,
168 expected)))
169 # mock.Mock(side_effect=exception.NetworkException))
170 mock_rt = self.mock_object(self.rest_api, 'refresh_token', mock.Mock())
171 result = self.rest_api.send_rest_api(
172 method='fake_method',
173 params='fake_params',
174 request_type='fake_type'
175 )
176 self.assertEqual(expected, result)
178 mock_sa.assert_called_with(
179 'fake_method',
180 'fake_params',
181 'fake_type')
182 mock_rt.assert_called_with(force=True)
183 mock_sleep.assert_called_once_with(1)
185 @mock.patch('time.sleep')
186 def test_send_rest_api_3times_fail(self, mock_sleep):
187 mock_sa = self.mock_object(
188 self.rest_api, 'send_api', mock.Mock(
189 side_effect=(exception.NetworkException)))
190 mock_rt = self.mock_object(self.rest_api, 'refresh_token', mock.Mock())
191 self.assertRaises(
192 exception.ShareBackendException,
193 self.rest_api.send_rest_api,
194 method='fake_method',
195 params='fake_params',
196 request_type='fake_type')
197 mock_sa.assert_called_with('fake_method',
198 'fake_params',
199 'fake_type')
200 mock_rt.assert_called_with(force=True)
201 # Should sleep 3 times (once for each retry)
202 self.assertEqual(3, mock_sleep.call_count)
203 mock_sleep.assert_has_calls([mock.call(1), mock.call(1), mock.call(1)])
205 def test_send_rest_api_backend_error_fail(self):
206 mock_sa = self.mock_object(self.rest_api, 'send_api', mock.Mock(
207 side_effect=(exception.ShareBackendException(
208 'fake_error_message'))))
209 mock_rt = self.mock_object(self.rest_api, 'refresh_token')
210 self.assertRaises(
211 exception.ShareBackendException,
212 self.rest_api.send_rest_api,
213 method='fake_method',
214 params='fake_params',
215 request_type='fake_type')
216 mock_sa.assert_called_with('fake_method',
217 'fake_params',
218 'fake_type')
219 mock_rt.assert_not_called()
221 @ddt.data(
222 {'method': 'fake_method', 'request_type': 'post', 'params':
223 {'fake_param': 'fake_value'}},
224 {'method': 'fake_method', 'request_type': 'get', 'params':
225 {'fake_param': 'fake_value'}},
226 {'method': 'fake_method', 'request_type': 'delete', 'params':
227 {'fake_param': 'fake_value'}},
228 {'method': 'fake_method', 'request_type': 'put', 'params':
229 {'fake_param': 'fake_value'}}, )
230 @ddt.unpack
231 def test_send_api(self, method, params, request_type):
232 self.rest_api._token_pool = ['fake_token']
233 if request_type in ('post', 'delete', 'put'):
234 fake_output = {'code': 0, 'message': 'success'}
235 elif request_type == 'get': 235 ↛ 238line 235 didn't jump to line 238 because the condition on line 235 was always true
236 fake_output = {'code': 0, 'data': 'fake_date'}
238 fake_response = FakeResponse(200, fake_output)
239 mock_request = self.mock_object(requests,
240 request_type,
241 mock.Mock(return_value=fake_response))
242 self.rest_api.send_api(method,
243 params=params,
244 request_type=request_type)
246 url = 'http://%s:%s/rest/%s' % (test_config.as13000_nas_ip,
247 test_config.as13000_nas_port,
248 method)
249 headers = {'X-Auth-Token': 'fake_token'}
250 mock_request.assert_called_once_with(url,
251 data=json.dumps(params),
252 headers=headers)
254 @ddt.data({'method': r'security/token',
255 'params': {'name': test_config.as13000_nas_login,
256 'password': test_config.as13000_nas_password},
257 'request_type': 'post'},
258 {'method': r'security/token',
259 'params': None,
260 'request_type': 'delete'})
261 @ddt.unpack
262 def test_send_api_access_success(self, method, params, request_type):
263 if request_type == 'post':
264 fake_value = {'code': 0, 'data': {
265 'token': 'fake_token',
266 'expireTime': '7200',
267 'type': 0}}
268 mock_requests = self.mock_object(
269 requests, 'post', mock.Mock(
270 return_value=FakeResponse(
271 200, fake_value)))
272 result = self.rest_api.send_api(method, params, request_type)
273 self.assertEqual(fake_value['data'], result)
274 mock_requests.assert_called_once_with(
275 'http://%s:%s/rest/%s' %
276 (test_config.as13000_nas_ip,
277 test_config.as13000_nas_port,
278 method),
279 data=json.dumps(params),
280 headers=None)
281 if request_type == 'delete':
282 fake_value = {'code': 0, 'message': 'Success!'}
283 self.rest_api._token_pool = ['fake_token']
284 mock_requests = self.mock_object(
285 requests, 'delete', mock.Mock(
286 return_value=FakeResponse(
287 200, fake_value)))
288 self.rest_api.send_api(method, params, request_type)
289 mock_requests.assert_called_once_with(
290 'http://%s:%s/rest/%s' %
291 (test_config.as13000_nas_ip,
292 test_config.as13000_nas_port,
293 method),
294 data=None,
295 headers={'X-Auth-Token': 'fake_token'})
297 def test_send_api_wrong_access_fail(self):
298 req_params = {'method': r'security/token',
299 'params': {'name': test_config.as13000_nas_login,
300 'password': 'fake_password'},
301 'request_type': 'post'}
302 fake_value = {'message': ' User name or password error.', 'code': 400}
303 mock_request = self.mock_object(
304 requests, 'post', mock.Mock(
305 return_value=FakeResponse(
306 200, fake_value)))
307 self.assertRaises(
308 exception.ShareBackendException,
309 self.rest_api.send_api,
310 method=req_params['method'],
311 params=req_params['params'],
312 request_type=req_params['request_type'])
313 mock_request.assert_called_once_with(
314 'http://%s:%s/rest/%s' %
315 (test_config.as13000_nas_ip,
316 test_config.as13000_nas_port,
317 req_params['method']),
318 data=json.dumps(
319 req_params['params']),
320 headers=None)
322 def test_send_api_token_overtime_fail(self):
323 self.rest_api._token_pool = ['fake_token']
324 fake_value = {'method': 'fake_url',
325 'params': 'fake_params',
326 'reuest_type': 'post'}
327 fake_out_put = {'message': 'Unauthorized access!', 'code': 301}
328 mock_requests = self.mock_object(
329 requests, 'post', mock.Mock(
330 return_value=FakeResponse(
331 200, fake_out_put)))
332 self.assertRaises(exception.NetworkException,
333 self.rest_api.send_api,
334 method='fake_url',
335 params='fake_params',
336 request_type='post')
337 mock_requests.assert_called_once_with(
338 'http://%s:%s/rest/%s' %
339 (test_config.as13000_nas_ip,
340 test_config.as13000_nas_port,
341 fake_value['method']),
342 data=json.dumps('fake_params'),
343 headers={
344 'X-Auth-Token': 'fake_token'})
346 def test_send_api_fail(self):
347 self.rest_api._token_pool = ['fake_token']
348 fake_output = {'code': 100, 'message': 'fake_message'}
349 mock_request = self.mock_object(
350 requests, 'post', mock.Mock(
351 return_value=FakeResponse(
352 200, fake_output)))
353 self.assertRaises(
354 exception.ShareBackendException,
355 self.rest_api.send_api,
356 method='fake_method',
357 params='fake_params',
358 request_type='post')
359 mock_request.assert_called_once_with(
360 'http://%s:%s/rest/%s' %
361 (test_config.as13000_nas_ip,
362 test_config.as13000_nas_port,
363 'fake_method'),
364 data=json.dumps('fake_params'),
365 headers={'X-Auth-Token': 'fake_token'}
366 )
369@ddt.ddt
370class AS13000ShareDriverTestCase(test.TestCase):
371 def __init__(self, *args, **kwds):
372 super(AS13000ShareDriverTestCase, self).__init__(*args, **kwds)
373 self._ctxt = context.get_admin_context()
374 self.configuration = FakeConfig()
376 def setUp(self):
377 self.mock_object(as13000_nas.CONF, '_check_required_opts')
378 self.driver = as13000_nas.AS13000ShareDriver(
379 configuration=self.configuration)
380 super(AS13000ShareDriverTestCase, self).setUp()
382 def test_do_setup(self):
383 mock_login = self.mock_object(
384 as13000_nas.RestAPIExecutor, 'logins', mock.Mock())
385 mock_vpe = self.mock_object(
386 self.driver,
387 '_validate_pools_exist',
388 mock.Mock())
389 mock_gdd = self.mock_object(
390 self.driver, '_get_directory_detail', mock.Mock(
391 return_value='{}'))
392 mock_gni = self.mock_object(
393 self.driver, '_get_nodes_ips', mock.Mock(
394 return_value=['fake_ips']))
395 self.driver.do_setup(self._ctxt)
396 mock_login.assert_called_once()
397 mock_vpe.assert_called_once()
398 mock_gdd.assert_called_once_with(
399 test_config.as13000_share_pools[0])
400 mock_gni.assert_called_once()
402 def test_do_setup_login_fail(self):
403 mock_login = self.mock_object(
404 as13000_nas.RestAPIExecutor, 'logins', mock.Mock(
405 side_effect=exception.ShareBackendException('fake_exception')))
406 self.assertRaises(
407 exception.ShareBackendException,
408 self.driver.do_setup,
409 self._ctxt)
410 mock_login.assert_called_once()
412 def test_do_setup_vpe_failed(self):
413 mock_login = self.mock_object(as13000_nas.RestAPIExecutor,
414 'logins', mock.Mock())
415 side_effect = exception.InvalidInput(reason='fake_exception')
416 mock_vpe = self.mock_object(self.driver,
417 '_validate_pools_exist',
418 mock.Mock(side_effect=side_effect))
419 self.assertRaises(exception.InvalidInput,
420 self.driver.do_setup,
421 self._ctxt)
422 mock_login.assert_called_once()
423 mock_vpe.assert_called_once()
425 def test_check_for_setup_error_base_dir_detail_failed(self):
426 self.driver.base_dir_detail = None
427 self.driver.ips = ['fake_ip']
428 self.assertRaises(
429 exception.ShareBackendException,
430 self.driver.check_for_setup_error)
432 def test_check_for_setup_error_node_status_fail(self):
433 self.driver.base_dir_detail = 'fakepool'
434 self.driver.ips = []
435 self.assertRaises(exception.ShareBackendException,
436 self.driver.check_for_setup_error)
438 @ddt.data('nfs', 'cifs')
439 def test_create_share(self, share_proto):
440 share = fake_share.fake_share(share_proto=share_proto)
441 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
442 mock_cd = self.mock_object(self.driver, '_create_directory',
443 mock.Mock(return_value='/fake/path'))
444 mock_cns = self.mock_object(self.driver, '_create_nfs_share')
445 mock_ccs = self.mock_object(self.driver, '_create_cifs_share')
446 mock_sdq = self.mock_object(self.driver, '_set_directory_quota')
448 self.driver.ips = ['127.0.0.1']
449 locations = self.driver.create_share(self._ctxt, share_instance)
450 if share_proto == 'nfs':
451 expect_locations = [{'path': r'127.0.0.1:/fake/path'}]
452 self.assertEqual(locations, expect_locations)
453 else:
454 expect_locations = [{'path': r'\\127.0.0.1\share_fakeinstanceid'}]
455 self.assertEqual(locations, expect_locations)
457 mock_cd.assert_called_once_with(share_name='share_fakeinstanceid',
458 pool_name='P')
460 if share_proto == 'nfs':
461 mock_cns.assert_called_once_with(share_path='/fake/path')
462 elif share['share_proto'] == 'cifs': 462 ↛ 466line 462 didn't jump to line 466 because the condition on line 462 was always true
463 mock_ccs.assert_called_once_with(share_path='/fake/path',
464 share_name='share_fakeinstanceid')
466 mock_sdq.assert_called_once_with('/fake/path', share['size'])
468 @ddt.data('nfs', 'cifs')
469 def test_create_share_from_snapshot(self, share_proto):
470 share = fake_share.fake_share(share_proto=share_proto)
471 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
472 mock_cd = self.mock_object(self.driver, '_create_directory',
473 mock.Mock(return_value='/fake/path'))
474 mock_cns = self.mock_object(self.driver, '_create_nfs_share')
475 mock_ccs = self.mock_object(self.driver, '_create_cifs_share')
476 mock_sdq = self.mock_object(self.driver, '_set_directory_quota')
477 mock_cdtd = self.mock_object(self.driver, '_clone_directory_to_dest')
479 self.driver.ips = ['127.0.0.1']
480 locations = self.driver.create_share_from_snapshot(
481 self._ctxt, share_instance, None)
482 if share_proto == 'nfs':
483 expect_locations = [{'path': r'127.0.0.1:/fake/path'}]
484 self.assertEqual(locations, expect_locations)
485 else:
486 expect_locations = [{'path': r'\\127.0.0.1\share_fakeinstanceid'}]
487 self.assertEqual(locations, expect_locations)
489 mock_cd.assert_called_once_with(share_name='share_fakeinstanceid',
490 pool_name='P')
492 if share_proto == 'nfs':
493 mock_cns.assert_called_once_with(share_path='/fake/path')
494 elif share['share_proto'] == 'cifs': 494 ↛ 498line 494 didn't jump to line 498 because the condition on line 494 was always true
495 mock_ccs.assert_called_once_with(share_path='/fake/path',
496 share_name='share_fakeinstanceid')
498 mock_sdq.assert_called_once_with('/fake/path', share['size'])
499 mock_cdtd.assert_called_once_with(snapshot=None,
500 dest_path='/fake/path')
502 @ddt.data('nfs', 'cifs')
503 def test_delete_share(self, share_proto):
504 share = fake_share.fake_share(share_proto=share_proto)
505 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
506 expect_share_path = r'/P/share_fakeinstanceid'
508 mock_gns = self.mock_object(self.driver, '_get_nfs_share',
509 mock.Mock(return_value=['fake_share']))
510 mock_dns = self.mock_object(self.driver, '_delete_nfs_share')
511 mock_gcs = self.mock_object(self.driver, '_get_cifs_share',
512 mock.Mock(return_value=['fake_share']))
513 mock_dcs = self.mock_object(self.driver, '_delete_cifs_share')
514 mock_dd = self.mock_object(self.driver, '_delete_directory')
516 self.driver.delete_share(self._ctxt, share_instance)
517 if share_proto == 'nfs':
518 mock_gns.assert_called_once_with(expect_share_path)
519 mock_dns.assert_called_once_with(expect_share_path)
520 else:
521 mock_gcs.assert_called_once_with('share_fakeinstanceid')
522 mock_dcs.assert_called_once_with('share_fakeinstanceid')
524 mock_dd.assert_called_once_with(expect_share_path)
526 @ddt.data('nfs', 'cifs')
527 def test_delete_share_not_exist(self, share_proto):
528 share = fake_share.fake_share(share_proto=share_proto)
529 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
530 expect_share_path = r'/P/share_fakeinstanceid'
532 mock_gns = self.mock_object(self.driver, '_get_nfs_share',
533 mock.Mock(return_value=[]))
534 mock_gcs = self.mock_object(self.driver, '_get_cifs_share',
535 mock.Mock(return_value=[]))
536 self.driver.delete_share(self._ctxt, share_instance)
537 if share_proto == 'nfs':
538 mock_gns.assert_called_once_with(expect_share_path)
539 elif share_proto == 'cifs': 539 ↛ exitline 539 didn't return from function 'test_delete_share_not_exist' because the condition on line 539 was always true
540 mock_gcs.assert_called_once_with('share_fakeinstanceid')
542 def test_extend_share(self):
543 share = fake_share.fake_share()
544 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
545 expect_share_path = r'/P/share_fakeinstanceid'
547 mock_sdq = self.mock_object(self.driver, '_set_directory_quota')
549 self.driver.extend_share(share_instance, 2)
551 mock_sdq.assert_called_once_with(expect_share_path, 2)
553 @ddt.data('nfs', 'cifs')
554 def test_ensure_share(self, share_proto):
555 share = fake_share.fake_share(share_proto=share_proto)
556 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
558 mock_gns = self.mock_object(self.driver, '_get_nfs_share',
559 mock.Mock(return_value=['fake_share']))
560 mock_gcs = self.mock_object(self.driver, '_get_cifs_share',
561 mock.Mock(return_value=['fake_share']))
563 self.driver.ips = ['127.0.0.1']
564 locations = self.driver.ensure_share(self._ctxt, share_instance)
565 if share_proto == 'nfs':
566 expect_locations = [{'path': r'127.0.0.1:/P/share_fakeinstanceid'}]
567 self.assertEqual(locations, expect_locations)
568 mock_gns.assert_called_once_with(r'/P/share_fakeinstanceid')
569 else:
570 expect_locations = [{'path': r'\\127.0.0.1\share_fakeinstanceid'}]
571 self.assertEqual(locations, expect_locations)
572 mock_gcs.assert_called_once_with(r'share_fakeinstanceid')
574 def test_ensure_share_fail_1(self):
575 share = fake_share.fake_share()
576 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
578 self.assertRaises(exception.InvalidInput, self.driver.ensure_share,
579 self._ctxt, share_instance)
581 @ddt.data('nfs', 'cifs')
582 def test_ensure_share_None_share_fail(self, share_proto):
583 share = fake_share.fake_share(share_proto=share_proto)
584 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
586 mock_gns = self.mock_object(self.driver, '_get_nfs_share',
587 mock.Mock(return_value=[]))
588 mock_gcs = self.mock_object(self.driver, '_get_cifs_share',
589 mock.Mock(return_value=[]))
590 self.assertRaises(exception.ShareResourceNotFound,
591 self.driver.ensure_share,
592 self._ctxt, share_instance)
594 if share_proto == 'nfs':
595 mock_gns.assert_called_once_with(r'/P/share_fakeinstanceid')
596 elif share['share_proto'] == 'cifs': 596 ↛ exitline 596 didn't return from function 'test_ensure_share_None_share_fail' because the condition on line 596 was always true
597 mock_gcs.assert_called_once_with(r'share_fakeinstanceid')
599 def test_create_snapshot(self):
600 share = fake_share.fake_share()
601 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
602 snapshot_instance_pseudo = {
603 'share': share_instance,
604 'id': 'fakesnapid'
605 }
607 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
608 'send_rest_api')
610 self.driver.create_snapshot(self._ctxt, snapshot_instance_pseudo)
612 method = 'snapshot/directory'
613 request_type = 'post'
614 params = {'path': r'/P/share_fakeinstanceid',
615 'snapName': 'snap_fakesnapid'}
616 mock_rest.assert_called_once_with(method=method,
617 request_type=request_type,
618 params=params)
620 def test_delete_snapshot_normal(self):
621 share = fake_share.fake_share()
622 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
623 snapshot_instance_pseudo = {
624 'share': share_instance,
625 'id': 'fakesnapid'
626 }
628 mock_gsfs = self.mock_object(self.driver, '_get_snapshots_from_share',
629 mock.Mock(return_value=['fakesnapshot']))
630 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
631 'send_rest_api')
633 self.driver.delete_snapshot(self._ctxt, snapshot_instance_pseudo)
635 mock_gsfs.assert_called_once_with('/P/share_fakeinstanceid')
636 method = ('snapshot/directory?'
637 'path=/P/share_fakeinstanceid&snapName=snap_fakesnapid')
638 request_type = 'delete'
639 mock_rest.assert_called_once_with(method=method,
640 request_type=request_type)
642 def test_delete_snapshot_not_exist(self):
643 share = fake_share.fake_share()
644 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
645 snapshot_instance_pseudo = {
646 'share': share_instance,
647 'snapshot_id': 'fakesnapid'
648 }
650 mock_gsfs = self.mock_object(self.driver, '_get_snapshots_from_share',
651 mock.Mock(return_value=[]))
652 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
653 'send_rest_api')
655 self.driver.delete_snapshot(self._ctxt, snapshot_instance_pseudo)
657 mock_gsfs.assert_called_once_with('/P/share_fakeinstanceid')
658 mock_rest.assert_not_called()
660 @ddt.data('nfs', 'icfs', 'cifs')
661 def test_transfer_rule_to_client(self, proto):
662 rule = {'access_to': '1.1.1.1', 'access_level': 'rw'}
664 result = self.driver.transfer_rule_to_client(proto, rule)
666 client = {'name': '1.1.1.1',
667 'authority': 'rwx' if proto == 'cifs' else 'rw'}
669 if proto == 'nfs':
670 client.update({'type': 0})
671 else:
672 client.update({'type': 1})
674 self.assertEqual(client, result)
676 @ddt.data({'share_proto': 'nfs', 'use_access': True},
677 {'share_proto': 'nfs', 'use_access': False},
678 {'share_proto': 'cifs', 'use_access': True},
679 {'share_proto': 'cifs', 'use_access': False})
680 @ddt.unpack
681 def test_update_access(self, share_proto, use_access):
682 share = fake_share.fake_share(share_proto=share_proto)
683 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
685 access_rules = [{'access_to': 'fakename1',
686 'access_level': 'fakelevel1'},
687 {'access_to': 'fakename2',
688 'access_level': 'fakelevel2'}]
689 add_rules = [{'access_to': 'fakename1', 'access_level': 'fakelevel1'}]
690 del_rules = [{'access_to': 'fakename2', 'access_level': 'fakelevel2'}]
692 mock_ca = self.mock_object(self.driver, '_clear_access')
694 fake_share_backend = {'pathAuthority': 'fakepathAuthority'}
695 mock_gns = self.mock_object(self.driver, '_get_nfs_share',
696 mock.Mock(return_value=fake_share_backend))
697 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
698 'send_rest_api')
699 if use_access:
700 self.driver.update_access(self._ctxt, share_instance,
701 access_rules, [], [], [])
702 else:
703 self.driver.update_access(self._ctxt, share_instance,
704 [], add_rules, del_rules, [])
706 access_clients = [{'name': rule['access_to'],
707 'type': 0 if share_proto == 'nfs' else 1,
708 'authority': rule['access_level']
709 } for rule in access_rules]
710 add_clients = [{'name': rule['access_to'],
711 'type': 0 if share_proto == 'nfs' else 1,
712 'authority': rule['access_level']
713 } for rule in add_rules]
714 del_clients = [{'name': rule['access_to'],
715 'type': 0 if share_proto == 'nfs' else 1,
716 'authority': rule['access_level']
717 } for rule in del_rules]
719 params = {
720 'path': r'/P/share_fakeinstanceid',
721 'addedClientList': [],
722 'deletedClientList': [],
723 'editedClientList': []
724 }
726 if share_proto == 'nfs':
727 mock_gns.assert_called_once_with(r'/P/share_fakeinstanceid')
728 params['pathAuthority'] = fake_share_backend['pathAuthority']
729 else:
730 params['name'] = 'share_fakeinstanceid'
732 if use_access:
733 mock_ca.assert_called_once_with(share_instance)
734 params['addedClientList'] = access_clients
735 else:
736 params['addedClientList'] = add_clients
737 params['deletedClientList'] = del_clients
739 mock_rest.assert_called_once_with(
740 method=('file/share/%s' % share_proto),
741 params=params,
742 request_type='put')
744 def test__update_share_stats(self):
745 mock_sg = self.mock_object(FakeConfig, 'safe_get',
746 mock.Mock(return_value='fake_as13000'))
747 self.driver.pools = ['fake_pool']
748 mock_gps = self.mock_object(self.driver, '_get_pool_stats',
749 mock.Mock(return_value='fake_pool'))
750 self.driver._token_time = time.time()
751 mock_rt = self.mock_object(as13000_nas.RestAPIExecutor,
752 'refresh_token')
753 mock_uss = self.mock_object(driver.ShareDriver, '_update_share_stats')
755 self.driver._update_share_stats()
757 data = {}
758 data['vendor_name'] = self.driver.VENDOR
759 data['driver_version'] = self.driver.VERSION
760 data['storage_protocol'] = self.driver.PROTOCOL
761 data['share_backend_name'] = 'fake_as13000'
762 data['snapshot_support'] = True
763 data['create_share_from_snapshot_support'] = True
764 data['pools'] = ['fake_pool']
765 mock_sg.assert_called_once_with('share_backend_name')
766 mock_gps.assert_called_once_with('fake_pool')
767 mock_rt.assert_not_called()
768 mock_uss.assert_called_once_with(data)
770 def test__update_share_stats_refresh_token(self):
771 mock_sg = self.mock_object(FakeConfig, 'safe_get',
772 mock.Mock(return_value='fake_as13000'))
773 self.driver.pools = ['fake_pool']
774 mock_gps = self.mock_object(self.driver, '_get_pool_stats',
775 mock.Mock(return_value='fake_pool'))
776 self.driver._token_time = (
777 time.time() - self.driver.token_available_time - 1)
778 mock_rt = self.mock_object(as13000_nas.RestAPIExecutor,
779 'refresh_token')
780 mock_uss = self.mock_object(driver.ShareDriver, '_update_share_stats')
782 self.driver._update_share_stats()
784 data = {}
785 data['vendor_name'] = self.driver.VENDOR
786 data['driver_version'] = self.driver.VERSION
787 data['storage_protocol'] = self.driver.PROTOCOL
788 data['share_backend_name'] = 'fake_as13000'
789 data['snapshot_support'] = True
790 data['create_share_from_snapshot_support'] = True
791 data['pools'] = ['fake_pool']
792 mock_sg.assert_called_once_with('share_backend_name')
793 mock_gps.assert_called_once_with('fake_pool')
794 mock_rt.assert_called_once()
795 mock_uss.assert_called_once_with(data)
797 @ddt.data('nfs', 'cifs')
798 def test__clear_access(self, share_proto):
799 share = fake_share.fake_share(share_proto=share_proto)
800 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
802 fake_share_backend = {'pathAuthority': 'fakepathAuthority',
803 'clientList': ['fakeclient'],
804 'userList': ['fakeuser']}
805 mock_gns = self.mock_object(self.driver, '_get_nfs_share',
806 mock.Mock(return_value=fake_share_backend))
807 mock_gcs = self.mock_object(self.driver, '_get_cifs_share',
808 mock.Mock(return_value=fake_share_backend))
809 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
810 'send_rest_api')
812 self.driver._clear_access(share_instance)
814 method = 'file/share/%s' % share_proto
815 request_type = 'put'
816 params = {
817 'path': r'/P/share_fakeinstanceid',
818 'addedClientList': [],
819 'deletedClientList': [],
820 'editedClientList': []
821 }
823 if share_proto == 'nfs':
824 mock_gns.assert_called_once_with(r'/P/share_fakeinstanceid')
826 params['deletedClientList'] = fake_share_backend['clientList']
827 params['pathAuthority'] = fake_share_backend['pathAuthority']
828 else:
829 mock_gcs.assert_called_once_with('share_fakeinstanceid')
831 params['deletedClientList'] = fake_share_backend['userList']
832 params['name'] = 'share_fakeinstanceid'
834 mock_rest.assert_called_once_with(method=method,
835 request_type=request_type,
836 params=params)
838 def test__validate_pools_exist(self):
839 self.driver.pools = ['fakepool']
840 mock_gdl = self.mock_object(self.driver, '_get_directory_list',
841 mock.Mock(return_value=['fakepool']))
842 self.driver._validate_pools_exist()
843 mock_gdl.assert_called_once_with('/')
845 def test__validate_pools_exist_fail(self):
846 self.driver.pools = ['fakepool_fail']
847 mock_gdl = self.mock_object(self.driver, '_get_directory_list',
848 mock.Mock(return_value=['fakepool']))
849 self.assertRaises(exception.InvalidInput,
850 self.driver._validate_pools_exist)
851 mock_gdl.assert_called_once_with('/')
853 @ddt.data(0, 1)
854 def test__get_directory_quota(self, hardunit):
855 fake_data = {'hardthreshold': 200,
856 'hardunit': hardunit,
857 'capacity': '50GB'}
858 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
859 'send_rest_api',
860 mock.Mock(return_value=fake_data))
862 total, used = (self.driver._get_directory_quota('fakepath'))
864 if hardunit == 0:
865 self.assertEqual((200, 50), (total, used))
866 else:
867 self.assertEqual((200 * 1024, 50), (total, used))
868 method = 'file/quota/directory?path=/fakepath'
869 request_type = 'get'
870 mock_rest.assert_called_once_with(method=method,
871 request_type=request_type)
873 def test__get_directory_quota_fail(self):
874 fake_data = {'hardthreshold': None,
875 'hardunit': 0,
876 'capacity': '50GB'}
877 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
878 'send_rest_api',
879 mock.Mock(return_value=fake_data))
881 self.assertRaises(exception.ShareBackendException,
882 self.driver._get_directory_quota, 'fakepath')
883 method = 'file/quota/directory?path=/fakepath'
884 request_type = 'get'
885 mock_rest.assert_called_once_with(method=method,
886 request_type=request_type)
888 def test__get_pool_stats(self):
889 mock_gdq = self.mock_object(self.driver, '_get_directory_quota',
890 mock.Mock(return_value=(200, 50)))
891 pool = dict()
892 pool['pool_name'] = 'fakepath'
893 pool['reserved_percentage'] = 0
894 pool['reserved_snapshot_percentage'] = 0
895 pool['reserved_share_extend_percentage'] = 0
896 pool['max_over_subscription_ratio'] = 20.0
897 pool['dedupe'] = False
898 pool['compression'] = False
899 pool['qos'] = False
900 pool['thin_provisioning'] = True
901 pool['total_capacity_gb'] = 200
902 pool['free_capacity_gb'] = 150
903 pool['allocated_capacity_gb'] = 50
904 pool['snapshot_support'] = True
905 pool['create_share_from_snapshot_support'] = True
907 result = self.driver._get_pool_stats('fakepath')
908 self.assertEqual(pool, result)
909 mock_gdq.assert_called_once_with('fakepath')
911 def test__get_directory_list(self):
912 fake_dir_list = [{'name': 'fakedirectory1', 'size': 20},
913 {'name': 'fakedirectory2', 'size': 30}]
914 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
915 'send_rest_api',
916 mock.Mock(return_value=fake_dir_list))
918 expected = ['fakedirectory1', 'fakedirectory2']
919 result = self.driver._get_directory_list('/fakepath')
920 self.assertEqual(expected, result)
921 method = 'file/directory?path=/fakepath'
922 mock_rest.assert_called_once_with(method=method,
923 request_type='get')
925 def test__create_directory(self):
926 base_dir_detail = {
927 'path': '/fakepath',
928 'authorityInfo': {'user': 'root',
929 'group': 'root',
930 'authority': 'rwxrwxrwx'
931 },
932 'dataProtection': {'type': 0,
933 'dc': 2,
934 'cc': 1,
935 'rn': 0,
936 'st': 4},
937 'poolName': 'storage_pool'
938 }
939 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
940 'send_rest_api')
942 self.driver.base_dir_detail = base_dir_detail
943 result = self.driver._create_directory('fakename', 'fakepool')
945 self.assertEqual('/fakepool/fakename', result)
947 method = 'file/directory'
948 request_type = 'post'
949 params = {'name': 'fakename',
950 'parentPath': base_dir_detail['path'],
951 'authorityInfo': base_dir_detail['authorityInfo'],
952 'dataProtection': base_dir_detail['dataProtection'],
953 'poolName': base_dir_detail['poolName']}
954 mock_rest.assert_called_once_with(method=method,
955 request_type=request_type,
956 params=params)
958 def test__delete_directory(self):
959 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
960 'send_rest_api')
962 self.driver._delete_directory('/fakepath')
964 method = 'file/directory?path=/fakepath'
965 request_type = 'delete'
966 mock_rest.assert_called_once_with(method=method,
967 request_type=request_type)
969 def test__set_directory_quota(self):
970 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
971 'send_rest_api')
973 self.driver._set_directory_quota('fakepath', 200)
975 method = 'file/quota/directory'
976 request_type = 'put'
977 params = {'path': 'fakepath',
978 'hardthreshold': 200,
979 'hardunit': 2}
980 mock_rest.assert_called_once_with(method=method,
981 request_type=request_type,
982 params=params)
984 def test__create_nfs_share(self):
985 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
986 'send_rest_api')
988 self.driver._create_nfs_share('fakepath')
990 method = 'file/share/nfs'
991 request_type = 'post'
992 params = {'path': 'fakepath', 'pathAuthority': 'rw', 'client': []}
993 mock_rest.assert_called_once_with(method=method,
994 request_type=request_type,
995 params=params)
997 def test__delete_nfs_share(self):
998 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
999 'send_rest_api')
1001 self.driver._delete_nfs_share('/fakepath')
1003 method = 'file/share/nfs?path=/fakepath'
1004 request_type = 'delete'
1005 mock_rest.assert_called_once_with(method=method,
1006 request_type=request_type)
1008 def test__get_nfs_share(self):
1009 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
1010 'send_rest_api',
1011 mock.Mock(return_value='fakebackend'))
1013 result = self.driver._get_nfs_share('/fakepath')
1014 self.assertEqual('fakebackend', result)
1016 method = 'file/share/nfs?path=/fakepath'
1017 request_type = 'get'
1018 mock_rest.assert_called_once_with(method=method,
1019 request_type=request_type)
1021 def test__create_cifs_share(self):
1022 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
1023 'send_rest_api')
1025 self.driver._create_cifs_share('fakename', 'fakepath')
1027 method = 'file/share/cifs'
1028 request_type = 'post'
1029 params = {'path': 'fakepath', 'name': 'fakename', 'userlist': []}
1030 mock_rest.assert_called_once_with(method=method,
1031 request_type=request_type,
1032 params=params)
1034 def test__delete_cifs_share(self):
1035 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
1036 'send_rest_api')
1038 self.driver._delete_cifs_share('fakename')
1040 method = 'file/share/cifs?name=fakename'
1041 request_type = 'delete'
1042 mock_rest.assert_called_once_with(method=method,
1043 request_type=request_type)
1045 def test__get_cifs_share(self):
1046 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
1047 'send_rest_api',
1048 mock.Mock(return_value='fakebackend'))
1050 result = self.driver._get_cifs_share('fakename')
1051 self.assertEqual('fakebackend', result)
1053 method = 'file/share/cifs?name=fakename'
1054 request_type = 'get'
1055 mock_rest.assert_called_once_with(method=method,
1056 request_type=request_type)
1058 def test__clone_directory_to_dest(self):
1059 share = fake_share.fake_share()
1060 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
1061 snapshot_instance_pseudo = {
1062 'id': 'fakesnapid',
1063 'share_instance': share_instance
1064 }
1066 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
1067 'send_rest_api')
1069 self.driver._clone_directory_to_dest(snapshot_instance_pseudo,
1070 'fakepath')
1072 method = 'snapshot/directory/clone'
1073 request_type = 'post'
1074 params = {'path': '/P/share_fakeinstanceid',
1075 'snapName': 'snap_fakesnapid',
1076 'destPath': 'fakepath'}
1077 mock_rest.assert_called_once_with(method=method,
1078 request_type=request_type,
1079 params=params)
1081 def test__get_snapshots_from_share(self):
1082 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
1083 'send_rest_api',
1084 mock.Mock(return_value=['fakesnap']))
1086 result = self.driver._get_snapshots_from_share('/fakepath')
1088 self.assertEqual(['fakesnap'], result)
1089 method = 'snapshot/directory?path=/fakepath'
1090 request_type = 'get'
1091 mock_rest.assert_called_once_with(method=method,
1092 request_type=request_type)
1094 @ddt.data('nfs', 'cifs')
1095 def test__get_location_path(self, proto):
1096 self.driver.ips = ['ip1', 'ip2']
1098 result = self.driver._get_location_path('fake_name',
1099 '/fake/path',
1100 proto)
1101 if proto == 'nfs':
1102 expect = [{'path': 'ip1:/fake/path'},
1103 {'path': 'ip2:/fake/path'}]
1104 else:
1105 expect = [{'path': r'\\ip1\fake_name'},
1106 {'path': r'\\ip2\fake_name'}]
1107 self.assertEqual(expect, result)
1109 def test__get_nodes_virtual_ips(self):
1110 ctdb_set = {
1111 'virtualIpList': [{'ip': 'fakeip1/24'},
1112 {'ip': 'fakeip2/24'}]
1113 }
1115 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
1116 'send_rest_api',
1117 mock.Mock(return_value=ctdb_set))
1119 result = self.driver._get_nodes_virtual_ips()
1120 self.assertEqual(result, ['fakeip1', 'fakeip2'])
1121 mock_rest.assert_called_once_with(method='ctdb/set',
1122 request_type='get')
1124 def test__get_nodes_physical_ips(self):
1125 nodes = [{'nodeIp': 'fakeip1', 'runningStatus': 1, 'healthStatus': 1},
1126 {'nodeIp': 'fakeip2', 'runningStatus': 1, 'healthStatus': 0},
1127 {'nodeIp': 'fakeip3', 'runningStatus': 0, 'healthStatus': 1},
1128 {'nodeIp': 'fakeip4', 'runningStatus': 0, 'healthStatus': 0}]
1129 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
1130 'send_rest_api',
1131 mock.Mock(return_value=nodes))
1133 result = self.driver._get_nodes_physical_ips()
1135 expect = ['fakeip1']
1136 self.assertEqual(expect, result)
1137 mock_rest.assert_called_once_with(method='cluster/node/cache',
1138 request_type='get')
1140 def test__get_nodes_ips(self):
1141 mock_virtual = self.mock_object(self.driver, '_get_nodes_virtual_ips',
1142 mock.Mock(return_value=['ip1']))
1143 mock_physical = self.mock_object(self.driver,
1144 '_get_nodes_physical_ips',
1145 mock.Mock(return_value=['ip2']))
1147 result = self.driver._get_nodes_ips()
1148 self.assertEqual(['ip1', 'ip2'], result)
1149 mock_virtual.assert_called_once()
1150 mock_physical.assert_called_once()
1152 @ddt.data('nfs', 'cifs')
1153 def test__get_share_instance_pnsp(self, share_proto):
1154 share = fake_share.fake_share(share_proto=share_proto)
1155 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
1157 result = self.driver._get_share_instance_pnsp(share_instance)
1159 self.assertEqual(('P', 'share_fakeinstanceid', 1, share_proto), result)
1161 @ddt.data('5000000000', '5000000k', '5000mb', '50G', '5TB')
1162 def test__unit_convert(self, capacity):
1163 trans = {'5000000000': '%.0f' % (float(5000000000) / 1024 ** 3),
1164 '5000000k': '%.0f' % (float(5000000) / 1024 ** 2),
1165 '5000mb': '%.0f' % (float(5000) / 1024),
1166 '50G': '%.0f' % float(50),
1167 '5TB': '%.0f' % (float(5) * 1024)}
1168 expect = float(trans[capacity])
1169 result = self.driver._unit_convert(capacity)
1170 self.assertEqual(expect, result)
1172 def test__format_name(self):
1173 a = 'atest-1234567890-1234567890-1234567890'
1174 expect = 'atest_1234567890_1234567890_1234'
1175 result = self.driver._format_name(a)
1176 self.assertEqual(expect, result)
1178 def test__generate_share_name(self):
1179 share = fake_share.fake_share()
1180 share_instance = fake_share.fake_share_instance(share, host="H@B#P")
1182 result = self.driver._generate_share_name(share_instance)
1184 self.assertEqual('share_fakeinstanceid', result)
1186 def test__generate_snapshot_name(self):
1187 snapshot_instance_pesudo = {'id': 'fakesnapinstanceid'}
1189 result = self.driver._generate_snapshot_name(snapshot_instance_pesudo)
1191 self.assertEqual('snap_fakesnapinstanceid', result)
1193 def test__generate_share_path(self):
1194 result = self.driver._generate_share_path('fakepool', 'fakename')
1196 self.assertEqual('/fakepool/fakename', result)
1198 def test__get_directory_detail(self):
1199 details = [{'poolName': 'fakepool1'},
1200 {'poolName': 'fakepool2'}]
1201 mock_rest = self.mock_object(as13000_nas.RestAPIExecutor,
1202 'send_rest_api',
1203 mock.Mock(return_value=details))
1205 result = self.driver._get_directory_detail('fakepath')
1207 self.assertEqual(details[0], result)
1208 method = 'file/directory/detail?path=/fakepath'
1209 request_type = 'get'
1210 mock_rest.assert_called_once_with(method=method,
1211 request_type=request_type)