Coverage for manila/tests/share/test_api.py: 99%
3236 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 2012 NetApp. All rights reserved.
2# Copyright (c) 2015 Tom Barron. All rights reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15"""Unit tests for the Share API module."""
17import copy
18import datetime
19import json
20from unittest import mock
23import ddt
24from oslo_config import cfg
25from oslo_utils import timeutils
26from oslo_utils import uuidutils
27from webob import exc as webob_exc
29from manila.common import constants
30from manila import context
31from manila.data import rpcapi as data_rpc
32from manila import db as db_api
33from manila.db.sqlalchemy import models
34from manila import exception
35from manila.keymgr import barbican as barbican_api
36from manila import policy
37from manila import quota
38from manila import share
39from manila.share import api as share_api
40from manila.share import share_types
41from manila import test
42from manila.tests import db_utils
43from manila.tests import fake_share as fakes
44from manila.tests import utils as test_utils
45from manila import utils
47CONF = cfg.CONF
50_FAKE_LIST_OF_ALL_SHARES = [
51 {
52 'name': 'foo',
53 'description': 'ds',
54 'status': constants.STATUS_AVAILABLE,
55 'project_id': 'fake_pid_1',
56 'share_server_id': 'fake_server_1',
57 },
58 {
59 'name': 'bar',
60 'status': constants.STATUS_ERROR,
61 'project_id': 'fake_pid_2',
62 'share_server_id': 'fake_server_2',
63 },
64 {
65 'name': 'foo1',
66 'description': 'ds1',
67 'status': constants.STATUS_AVAILABLE,
68 'project_id': 'fake_pid_2',
69 'share_server_id': 'fake_server_3',
70 },
71 {
72 'name': 'bar',
73 'status': constants.STATUS_ERROR,
74 'project_id': 'fake_pid_2',
75 'share_server_id': 'fake_server_3',
76 },
77]
80_FAKE_LIST_OF_ALL_SNAPSHOTS = [
81 {
82 'name': 'foo',
83 'status': constants.STATUS_AVAILABLE,
84 'project_id': 'fake_pid_1',
85 'share_id': 'fake_server_1',
86 },
87 {
88 'name': 'bar',
89 'status': constants.STATUS_ERROR,
90 'project_id': 'fake_pid_2',
91 'share_id': 'fake_server_2',
92 },
93 {
94 'name': 'foo',
95 'status': constants.STATUS_AVAILABLE,
96 'project_id': 'fake_pid_2',
97 'share_id': 'fake_share_id_3',
98 },
99 {
100 'name': 'bar',
101 'status': constants.STATUS_ERROR,
102 'project_id': 'fake_pid_2',
103 'share_id': 'fake_share_id_3',
104 },
105]
108@ddt.ddt
109class ShareAPITestCase(test.TestCase):
111 def setUp(self):
112 super(ShareAPITestCase, self).setUp()
113 self.context = context.get_admin_context()
114 self.scheduler_rpcapi = mock.Mock()
115 self.share_rpcapi = mock.Mock()
116 self.api = share.API()
117 self.mock_object(self.api.db, 'resource_lock_get_all',
118 mock.Mock(return_value=([], None)))
119 self.mock_object(self.api, 'scheduler_rpcapi', self.scheduler_rpcapi)
120 self.mock_object(self.api, 'share_rpcapi', self.share_rpcapi)
121 self.mock_object(quota.QUOTAS, 'reserve',
122 lambda *args, **kwargs: None)
124 self.dt_utc = timeutils.utcnow()
125 self.mock_object(timeutils, 'utcnow',
126 mock.Mock(return_value=self.dt_utc))
127 self.mock_object(share_api.policy, 'check_policy')
128 self._setup_sized_share_types()
130 def _setup_sized_share_types(self):
131 """create a share type with size limit"""
132 spec_dict = {share_types.MIN_SIZE_KEY: 2,
133 share_types.MAX_SIZE_KEY: 4,
134 share_types.MAX_EXTEND_SIZE_KEY: 6}
135 db_utils.create_share_type(name='limit', extra_specs=spec_dict)
136 self.sized_sha_type = db_api.share_type_get_by_name(self.context,
137 'limit')
139 def _setup_create_mocks(self, protocol='nfs', **kwargs):
140 share = db_utils.create_share(
141 user_id=self.context.user_id,
142 project_id=self.context.project_id,
143 share_type_id=kwargs.pop('share_type_id', 'fake'),
144 **kwargs
145 )
146 share_data = {
147 'share_proto': protocol,
148 'size': 1,
149 'display_name': 'fakename',
150 'display_description': 'fakedesc',
151 'availability_zone': 'fakeaz'
152 }
154 self.mock_object(db_api, 'share_create', mock.Mock(return_value=share))
155 self.mock_object(self.api, 'create_instance')
157 return share, share_data
159 def _setup_create_instance_mocks(self):
160 host = 'fake'
161 share_type_id = "fake_share_type"
162 share = db_utils.create_share(
163 user_id=self.context.user_id,
164 project_id=self.context.project_id,
165 create_share_instance=False,
166 )
167 share_instance = db_utils.create_share_instance(
168 share_id=share['id'],
169 share_type_id=share_type_id)
170 share_type = {
171 'fake': 'fake',
172 'mount_point_name_support': False
173 }
174 self.mock_object(db_api, 'share_instance_create',
175 mock.Mock(return_value=share_instance))
176 self.mock_object(db_api, 'share_type_get',
177 mock.Mock(return_value=share_type))
178 az_mock = mock.Mock()
179 type(az_mock.return_value).id = mock.PropertyMock(
180 return_value='fake_id')
181 self.mock_object(db_api, 'availability_zone_get', az_mock)
182 self.mock_object(self.api.share_rpcapi, 'create_share_instance')
183 self.mock_object(self.api.scheduler_rpcapi, 'create_share_instance')
185 return host, share, share_instance
187 def _setup_create_from_snapshot_mocks(self, use_scheduler=True, host=None):
188 CONF.set_default("use_scheduler_creating_share_from_snapshot",
189 use_scheduler)
191 share_type = fakes.fake_share_type()
193 original_share = db_utils.create_share(
194 user_id=self.context.user_id,
195 project_id=self.context.project_id,
196 status=constants.STATUS_AVAILABLE,
197 host=host if host else 'fake',
198 size=1,
199 share_type_id=share_type['id'],
200 )
201 snapshot = db_utils.create_snapshot(
202 share_id=original_share['id'],
203 status=constants.STATUS_AVAILABLE,
204 size=1
205 )
207 share, share_data = self._setup_create_mocks(
208 snapshot_id=snapshot['id'], share_type_id=share_type['id'])
209 request_spec = {
210 'share_properties': share.to_dict(),
211 'share_proto': share['share_proto'],
212 'share_id': share['id'],
213 'share_type': None,
214 'snapshot_id': share['snapshot_id'],
215 }
217 self.mock_object(quota.QUOTAS, 'reserve',
218 mock.Mock(return_value='reservation'))
219 self.mock_object(quota.QUOTAS, 'commit')
220 self.mock_object(
221 share_types, 'get_share_type', mock.Mock(return_value=share_type))
223 return snapshot, share, share_data, request_spec
225 def _setup_delete_mocks(self, status, snapshots=None, **kwargs):
226 if snapshots is None:
227 snapshots = []
228 share = db_utils.create_share(status=status, **kwargs)
229 self.mock_object(db_api, 'share_delete')
230 self.mock_object(db_api, 'share_server_update')
231 self.mock_object(db_api, 'share_snapshot_get_all_for_share',
232 mock.Mock(return_value=snapshots))
233 self.mock_object(db_api, 'share_backups_get_all',
234 mock.Mock(return_value=[]))
235 self.mock_object(self.api, 'delete_instance')
236 return share
238 def _setup_delete_share_instance_mocks(self, **kwargs):
239 share = db_utils.create_share(**kwargs)
241 self.mock_object(db_api, 'share_instance_update',
242 mock.Mock(return_value=share.instance))
243 self.mock_object(self.api.share_rpcapi, 'delete_share_instance')
244 self.mock_object(db_api, 'share_server_update')
245 self.mock_object(db_api, 'share_instance_delete')
247 return share.instance
249 def test_get_all_admin_default_filters(self):
250 self.mock_object(db_api, 'share_get_all_by_project',
251 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[0]))
252 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=True)
254 shares = self.api.get_all(ctx)
256 db_api.share_get_all_by_project.assert_called_once_with(
257 ctx, sort_dir='desc', sort_key='created_at',
258 project_id='fake_pid_1',
259 filters={'list_deferred_delete': True},
260 is_public=False
261 )
262 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[0], shares)
264 def test_get_all_admin_filter_by_all_tenants(self):
265 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=True)
266 self.mock_object(db_api, 'share_get_all',
267 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES))
268 self.mock_object(share_api.policy, 'check_policy',
269 mock.Mock(return_value=True))
271 shares = self.api.get_all(ctx, {'all_tenants': 1})
273 db_api.share_get_all.assert_called_once_with(
274 ctx, sort_dir='desc', sort_key='created_at',
275 filters={'list_deferred_delete': True})
276 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES, shares)
278 def test_get_all_admin_filter_by_all_tenants_with_blank(self):
279 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=True)
280 self.mock_object(db_api, 'share_get_all',
281 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES))
282 self.mock_object(share_api.policy, 'check_policy',
283 mock.Mock(return_value=True))
285 shares = self.api.get_all(ctx, {'all_tenants': ''})
287 db_api.share_get_all.assert_called_once_with(
288 ctx, sort_dir='desc', sort_key='created_at',
289 filters={'list_deferred_delete': True})
290 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES, shares)
292 def test_get_all_admin_filter_by_all_tenants_with_false(self):
293 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=True)
294 self.mock_object(db_api, 'share_get_all_by_project',
295 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[0]))
297 shares = self.api.get_all(ctx, {'all_tenants': 'false'})
299 db_api.share_get_all_by_project.assert_called_once_with(
300 ctx, sort_dir='desc', sort_key='created_at',
301 project_id='fake_pid_1', filters={'list_deferred_delete': True},
302 is_public=False
303 )
304 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[0], shares)
306 def test_get_all_admin_filter_by_all_tenants_with_invaild_value(self):
307 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=True)
308 self.mock_object(db_api, 'share_get_all')
309 self.assertRaises(
310 exception.InvalidInput,
311 self.api.get_all, ctx, {'all_tenants': 'wonk'})
313 @ddt.data(
314 ({'share_server_id': 'fake_share_server'}, 'list_by_share_server_id'),
315 ({'host': 'fake_host'}, 'list_by_host'),
316 )
317 @ddt.unpack
318 def test_get_all_by_non_admin_using_admin_filter(self, filters, policy):
320 def fake_policy_checker(*args, **kwargs):
321 if policy == args[2] and not args[0].is_admin:
322 raise exception.NotAuthorized
324 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
325 mock_policy = self.mock_object(
326 share_api.policy, 'check_policy',
327 mock.Mock(side_effect=fake_policy_checker))
329 self.assertRaises(
330 exception.NotAuthorized,
331 self.api.get_all, ctx, filters)
333 mock_policy.assert_has_calls([
334 mock.call(
335 ctx, 'share',
336 'list_shares_in_deferred_deletion_states',
337 do_raise=False),
338 mock.call(ctx, 'share', policy)])
340 def test_get_all_admin_filter_by_share_server_and_all_tenants(self):
341 # NOTE(vponomaryov): if share_server_id provided, 'all_tenants' opt
342 # should not make any influence.
343 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=True)
344 self.mock_object(db_api, 'share_get_all_by_share_server',
345 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[2:]))
346 self.mock_object(db_api, 'share_get_all')
347 self.mock_object(db_api, 'share_get_all_by_project')
348 mock_policy = self.mock_object(share_api.policy, 'check_policy')
349 shares = self.api.get_all(
350 ctx, {'share_server_id': 'fake_server_3', 'all_tenants': 1})
351 mock_policy.assert_has_calls([
352 mock.call(
353 ctx, 'share',
354 'list_shares_in_deferred_deletion_states',
355 do_raise=False),
356 mock.call(ctx, 'share', 'list_all_projects', do_raise=False),
357 mock.call(ctx, 'share', 'list_by_share_server_id')])
359 db_api.share_get_all_by_share_server.assert_called_once_with(
360 ctx, 'fake_server_3', sort_dir='desc', sort_key='created_at',
361 filters={'list_deferred_delete': True},
362 )
363 db_api.share_get_all_by_project.assert_has_calls([])
364 db_api.share_get_all.assert_has_calls([])
365 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[2:], shares)
367 def test_get_all_admin_filter_by_name(self):
368 ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True)
369 self.mock_object(
370 db_api, 'share_get_all_by_project',
371 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[1::2]))
372 expected_filters = {'display_name': 'bar',
373 'list_deferred_delete': True}
375 shares = self.api.get_all(ctx, {'display_name': 'bar'})
377 db_api.share_get_all_by_project.assert_called_once_with(
378 ctx, sort_dir='desc', sort_key='created_at',
379 project_id='fake_pid_2', filters=expected_filters, is_public=False
380 )
381 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1::2], shares)
383 @ddt.data(({'display_name': 'fo'}, 0), ({'display_description': 'd'}, 0),
384 ({'display_name': 'foo', 'display_description': 'd'}, 0),
385 ({'display_name': 'foo'}, 1), ({'display_description': 'ds'}, 1),
386 ({'display_name~': 'foo', 'display_description~': 'ds'}, 2),
387 ({'display_name': 'foo', 'display_description~': 'ds'}, 1),
388 ({'display_name~': 'foo', 'display_description': 'ds'}, 1))
389 @ddt.unpack
390 def test_get_all_admin_filter_by_name_and_description(
391 self, search_opts, get_share_number):
392 ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True)
394 expected_result = []
396 if get_share_number == 2:
397 expected_result = _FAKE_LIST_OF_ALL_SHARES[0::2]
398 elif get_share_number == 1:
399 expected_result = _FAKE_LIST_OF_ALL_SHARES[:1]
401 self.mock_object(db_api, 'share_get_all_by_project',
402 mock.Mock(return_value=expected_result))
403 expected_filters = copy.copy(search_opts)
404 expected_filters.update({'list_deferred_delete': True})
406 shares = self.api.get_all(ctx, search_opts)
408 db_api.share_get_all_by_project.assert_called_once_with(
409 ctx, sort_dir='desc', sort_key='created_at',
410 project_id='fake_pid_2',
411 filters=expected_filters, is_public=False
412 )
413 self.assertEqual(get_share_number, len(shares))
414 self.assertEqual(expected_result, shares)
416 @ddt.data('id', 'path')
417 def test_get_all_admin_filter_by_export_location(self, type):
418 ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True)
419 self.mock_object(db_api, 'share_get_all_by_project',
420 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[1:]))
422 shares = self.api.get_all(ctx, {'export_location_' + type: 'test'})
424 db_api.share_get_all_by_project.assert_called_once_with(
425 ctx, sort_dir='desc', sort_key='created_at',
426 project_id='fake_pid_2',
427 filters={'export_location_' + type: 'test',
428 'list_deferred_delete': True},
429 is_public=False
430 )
431 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1:], shares)
433 def test_get_all_admin_filter_by_name_and_all_tenants(self):
434 ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True)
435 self.mock_object(db_api, 'share_get_all',
436 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[:1]))
438 shares = self.api.get_all(ctx, {'name': 'foo', 'all_tenants': 1})
440 db_api.share_get_all.assert_called_once_with(
441 ctx, sort_dir='desc', sort_key='created_at',
442 filters={'list_deferred_delete': True})
443 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[:1], shares)
445 def test_get_all_admin_filter_by_status(self):
446 ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True)
447 expected_filter = {'status': constants.STATUS_AVAILABLE,
448 'list_deferred_delete': True}
449 self.mock_object(
450 db_api, 'share_get_all_by_project',
451 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[0::2]))
453 shares = self.api.get_all(ctx, {'status': constants.STATUS_AVAILABLE})
455 db_api.share_get_all_by_project.assert_called_once_with(
456 ctx, sort_dir='desc', sort_key='created_at',
457 project_id='fake_pid_2', filters=expected_filter, is_public=False
458 )
459 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[0::2], shares)
461 def test_get_all_admin_filter_by_status_and_all_tenants(self):
462 ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True)
463 self.mock_object(
464 db_api, 'share_get_all',
465 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[1::2]))
466 expected_filter = {'status': constants.STATUS_ERROR,
467 'list_deferred_delete': True}
468 shares = self.api.get_all(
469 ctx, {'status': constants.STATUS_ERROR, 'all_tenants': 1})
470 db_api.share_get_all.assert_called_once_with(
471 ctx, sort_dir='desc', sort_key='created_at',
472 filters=expected_filter)
473 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1::2], shares)
475 def test_get_all_non_admin_filter_by_all_tenants(self):
476 # Expected share list only by project of non-admin user
477 ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=False)
478 self.mock_object(db_api, 'share_get_all_by_project',
479 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[1:]))
480 self.mock_policy_check = self.mock_object(
481 policy, 'check_policy', mock.Mock(return_value=False))
483 shares = self.api.get_all(ctx, {'all_tenants': 1})
485 db_api.share_get_all_by_project.assert_called_once_with(
486 ctx, sort_dir='desc', sort_key='created_at',
487 project_id='fake_pid_2', filters={}, is_public=False
488 )
489 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1:], shares)
491 def test_get_all_non_admin_with_name_and_status_filters(self):
492 ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=False)
493 self.mock_object(
494 db_api, 'share_get_all_by_project',
495 mock.Mock(side_effect=[
496 _FAKE_LIST_OF_ALL_SHARES[1::2],
497 _FAKE_LIST_OF_ALL_SHARES[2::4]]))
498 self.mock_policy_check = self.mock_object(
499 policy, 'check_policy', mock.Mock(return_value=False))
501 shares = self.api.get_all(
502 ctx, {'name': 'bar', 'status': constants.STATUS_ERROR})
504 expected_filter_1 = {'status': constants.STATUS_ERROR}
505 expected_filter_2 = {'status': constants.STATUS_AVAILABLE}
507 db_api.share_get_all_by_project.assert_called_once_with(
508 ctx, sort_dir='desc', sort_key='created_at',
509 project_id='fake_pid_2', filters=expected_filter_1, is_public=False
510 )
512 # two items expected, one filtered
513 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1::2], shares)
515 # one item expected, two filtered
516 shares = self.api.get_all(
517 ctx, {'name': 'foo1', 'status': constants.STATUS_AVAILABLE})
519 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[2::4], shares)
520 db_api.share_get_all_by_project.assert_has_calls([
521 mock.call(
522 ctx, sort_dir='desc', sort_key='created_at',
523 project_id='fake_pid_2', filters=expected_filter_1,
524 is_public=False),
525 mock.call(
526 ctx, sort_dir='desc', sort_key='created_at',
527 project_id='fake_pid_2', filters=expected_filter_2,
528 is_public=False),
529 ])
531 @ddt.data('True', 'true', '1', 'yes', 'y', 'on', 't', True)
532 def test_get_all_non_admin_public(self, is_public):
533 ctx = context.RequestContext('fake_uid', 'fake_pid_2',
534 is_admin=False)
535 self.mock_object(db_api, 'share_get_all_by_project', mock.Mock(
536 return_value=_FAKE_LIST_OF_ALL_SHARES[1:]))
537 self.mock_policy_check = self.mock_object(
538 policy, 'check_policy', mock.Mock(return_value=False))
539 shares = self.api.get_all(ctx, {'is_public': is_public})
540 db_api.share_get_all_by_project.assert_called_once_with(
541 ctx, sort_dir='desc', sort_key='created_at',
542 project_id='fake_pid_2', filters={}, is_public=True
543 )
544 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1:], shares)
546 @ddt.data('False', 'false', '0', 'no', 'n', 'off', 'f', False)
547 def test_get_all_non_admin_not_public(self, is_public):
548 ctx = context.RequestContext('fake_uid', 'fake_pid_2',
549 is_admin=False)
550 self.mock_object(db_api, 'share_get_all_by_project', mock.Mock(
551 return_value=_FAKE_LIST_OF_ALL_SHARES[1:]))
552 self.mock_policy_check = self.mock_object(
553 policy, 'check_policy', mock.Mock(return_value=False))
555 shares = self.api.get_all(ctx, {'is_public': is_public})
556 db_api.share_get_all_by_project.assert_called_once_with(
557 ctx, sort_dir='desc', sort_key='created_at',
558 project_id='fake_pid_2', filters={}, is_public=False
559 )
560 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1:], shares)
562 @ddt.data('truefoo', 'bartrue')
563 def test_get_all_invalid_public_value(self, is_public):
564 ctx = context.RequestContext('fake_uid', 'fake_pid_2',
565 is_admin=False)
566 self.assertRaises(ValueError, self.api.get_all,
567 ctx, {'is_public': is_public})
569 def test_get_all_with_sorting_valid(self):
570 self.mock_object(db_api, 'share_get_all_by_project',
571 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[0]))
572 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
573 self.mock_policy_check = self.mock_object(
574 policy, 'check_policy', mock.Mock(return_value=False))
576 shares = self.api.get_all(ctx, sort_key='status', sort_dir='asc')
578 db_api.share_get_all_by_project.assert_called_once_with(
579 ctx, sort_dir='asc', sort_key='status',
580 project_id='fake_pid_1', filters={}, is_public=False
581 )
582 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[0], shares)
584 def test_get_all_sort_key_invalid(self):
585 self.mock_object(db_api, 'share_get_all_by_project',
586 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[0]))
587 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
588 self.assertRaises(
589 exception.InvalidInput,
590 self.api.get_all,
591 ctx,
592 sort_key=1,
593 )
595 def test_get_all_sort_dir_invalid(self):
596 self.mock_object(db_api, 'share_get_all_by_project',
597 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[0]))
598 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
599 self.assertRaises(
600 exception.InvalidInput,
601 self.api.get_all,
602 ctx,
603 sort_dir=1,
604 )
606 def _get_all_filter_metadata_or_extra_specs_valid(self, key):
607 self.mock_object(db_api, 'share_get_all_by_project',
608 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[0]))
609 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
610 mock_policy_check = self.mock_object(
611 policy, 'check_policy', mock.Mock(return_value=False))
613 search_opts = {key: {'foo1': 'bar1', 'foo2': 'bar2'}}
615 shares = self.api.get_all(ctx, search_opts=search_opts.copy())
617 if key == 'extra_specs':
618 mock_policy_check.assert_has_calls([
619 mock.call(ctx, 'share_types_extra_spec', 'index'),
620 mock.call(
621 ctx, 'share',
622 'list_shares_in_deferred_deletion_states',
623 do_raise=False)])
624 else:
625 mock_policy_check.assert_called_once_with(
626 ctx, 'share',
627 'list_shares_in_deferred_deletion_states',
628 do_raise=False),
630 db_api.share_get_all_by_project.assert_called_once_with(
631 ctx, sort_dir='desc', sort_key='created_at',
632 project_id='fake_pid_1', filters=search_opts, is_public=False)
633 self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[0], shares)
635 def test_get_all_filter_by_metadata(self):
636 self._get_all_filter_metadata_or_extra_specs_valid(key='metadata')
638 def test_get_all_filter_by_extra_specs(self):
639 self._get_all_filter_metadata_or_extra_specs_valid(key='extra_specs')
641 def _get_all_filter_metadata_or_extra_specs_invalid(self, key):
642 self.mock_object(db_api, 'share_get_all_by_project',
643 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[0]))
644 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
645 search_opts = {key: "{'foo': 'bar'}"}
646 self.assertRaises(exception.InvalidInput, self.api.get_all, ctx,
647 search_opts=search_opts)
648 if key == 'extra_specs':
649 share_api.policy.check_policy.assert_called_once_with(
650 ctx, 'share_types_extra_spec', 'index')
652 def test_get_all_filter_by_invalid_metadata(self):
653 self._get_all_filter_metadata_or_extra_specs_invalid(key='metadata')
655 def test_get_all_filter_by_invalid_extra_specs(self):
656 self._get_all_filter_metadata_or_extra_specs_invalid(key='extra_specs')
658 @ddt.data(True, False)
659 def test_update_metadata_from_share_type_extra_specs(self, with_metadata):
660 share_type = fakes.fake_share_type(
661 extra_specs={
662 'driver_handles_share_servers': 'False',
663 'fake_driver:dedupe': 'True',
664 'fake_driver:encrypt': 'True',
665 'fake_driver:snapshot_policy': 'daily',
666 'provisioning:max_share_size': '10',
667 }
668 )
670 user_metadata = {}
671 if with_metadata:
672 user_metadata = {
673 'snapshot_policy': 'monthly',
674 'tag': 't1',
675 'max_share_size': '5',
676 }
678 CONF.set_default(
679 "driver_updatable_metadata",
680 ['dedupe', 'snapshot_policy', 'thin_provisioning'],
681 )
683 result = self.api.update_metadata_from_share_type_extra_specs(
684 self.context,
685 share_type,
686 user_metadata
687 )
689 if with_metadata:
690 self.assertEqual(
691 result,
692 {'dedupe': 'True', 'snapshot_policy': 'monthly', 'tag': 't1',
693 'max_share_size': '5'})
694 else:
695 self.assertEqual(
696 result,
697 {'dedupe': 'True', 'snapshot_policy': 'daily'})
699 def test_update_share_network_subnet_from_metadata(self):
700 CONF.set_default(
701 "driver_updatable_subnet_metadata",
702 ['dedupe', 'snapshot_policy', 'thin_provisioning'],
703 )
704 metadata = {
705 'test_key': 'True',
706 'snapshot_policy': 'monthly',
707 }
708 backend_metadata = {
709 k: v for k, v in
710 metadata.items() if k in CONF.driver_updatable_subnet_metadata}
712 self.mock_object(
713 db_api, 'share_server_get_all_by_host_and_or_share_subnet',
714 mock.Mock(return_value=['fake_share_server']))
715 mock_call = self.mock_object(
716 self.api.share_rpcapi,
717 'update_share_network_subnet_from_metadata')
719 self.api.update_share_network_subnet_from_metadata(
720 self.context, 'fake_sn_id', 'fake_sn_subnet_id', metadata)
721 mock_call.assert_called_once_with(
722 self.context, 'fake_sn_id', 'fake_sn_subnet_id',
723 'fake_share_server', backend_metadata)
725 def test_update_share_from_metadata(self):
726 CONF.set_default(
727 "driver_updatable_metadata",
728 ['dedupe', 'snapshot_policy', 'thin_provisioning'],
729 )
730 metadata = {
731 'dedupe': 'True',
732 'snapshot_policy': 'monthly',
733 'max_share_size': '10'
734 }
735 backend_metadata = {
736 k: v for k, v in metadata.items() if k != 'max_share_size'}
738 self.mock_object(self.api, 'get', mock.Mock(return_value='fake_share'))
739 mock_call = self.mock_object(
740 self.api.share_rpcapi,
741 'update_share_from_metadata'
742 )
744 self.api.update_share_from_metadata(self.context, 'fake_id', metadata)
745 mock_call.assert_called_once_with(
746 self.context, 'fake_share', backend_metadata)
748 @ddt.data(True, False)
749 def test_create_public_and_private_share(self, is_public):
750 share, share_data = self._setup_create_mocks(is_public=is_public)
751 az = share_data.pop('availability_zone')
753 self.api.create(
754 self.context,
755 share_data['share_proto'],
756 share_data['size'],
757 share_data['display_name'],
758 share_data['display_description'],
759 availability_zone=az
760 )
762 share['status'] = constants.STATUS_CREATING
763 share['host'] = None
765 self.assertSubDictMatch(share_data,
766 db_api.share_create.call_args[0][1])
768 @ddt.data(
769 {},
770 {
771 constants.ExtraSpecs.SNAPSHOT_SUPPORT: True,
772 },
773 {
774 constants.ExtraSpecs.SNAPSHOT_SUPPORT: False,
775 constants.ExtraSpecs.CREATE_SHARE_FROM_SNAPSHOT_SUPPORT: False,
776 },
777 {
778 constants.ExtraSpecs.SNAPSHOT_SUPPORT: True,
779 constants.ExtraSpecs.CREATE_SHARE_FROM_SNAPSHOT_SUPPORT: False,
780 },
781 {
782 constants.ExtraSpecs.SNAPSHOT_SUPPORT: True,
783 constants.ExtraSpecs.CREATE_SHARE_FROM_SNAPSHOT_SUPPORT: True,
784 }
785 )
786 def test_create_default_snapshot_semantics(self, extra_specs):
787 share, share_data = self._setup_create_mocks(is_public=False)
788 az = share_data.pop('availability_zone')
789 share_type = fakes.fake_share_type(extra_specs=extra_specs)
791 self.api.create(
792 self.context,
793 share_data['share_proto'],
794 share_data['size'],
795 share_data['display_name'],
796 share_data['display_description'],
797 availability_zone=az,
798 share_type=share_type
799 )
801 share['status'] = constants.STATUS_CREATING
802 share['host'] = None
804 share_data.update(extra_specs)
805 if extra_specs.get('snapshot_support') is None:
806 share_data['snapshot_support'] = False
807 if extra_specs.get('create_share_from_snapshot_support') is None:
808 share_data['create_share_from_snapshot_support'] = False
810 self.assertSubDictMatch(share_data,
811 db_api.share_create.call_args[0][1])
813 @ddt.data(*constants.SUPPORTED_SHARE_PROTOCOLS)
814 def test_create_share_valid_protocol(self, proto):
815 share, share_data = self._setup_create_mocks(protocol=proto)
816 az = share_data.pop('availability_zone')
818 all_protos = ','.join(
819 proto for proto in constants.SUPPORTED_SHARE_PROTOCOLS)
820 data = dict(DEFAULT=dict(enabled_share_protocols=all_protos))
821 with test_utils.create_temp_config_with_opts(data):
822 self.api.create(
823 self.context, proto, share_data['size'],
824 share_data['display_name'],
825 share_data['display_description'],
826 availability_zone=az)
828 share['status'] = constants.STATUS_CREATING
829 share['host'] = None
831 self.assertSubDictMatch(share_data,
832 db_api.share_create.call_args[0][1])
834 @ddt.data(
835 {'get_all_azs_return': [], 'subnet_by_az_side_effect': []},
836 {'get_all_azs_return': [{'name': 'az1', 'id': 'az_id_1'}],
837 'subnet_by_az_side_effect': [None]},
838 {'get_all_azs_return': [{'name': 'az1', 'id': 'az_id_1'}],
839 'subnet_by_az_side_effect': ['fake_sns_1']},
840 {'get_all_azs_return': [{'name': 'az1', 'id': 'az_id_1'},
841 {'name': 'az2', 'id': 'az_id_2'}],
842 'subnet_by_az_side_effect': [None, 'fake_sns_2']}
843 )
844 @ddt.unpack
845 def test__get_all_availability_zones_with_subnets(
846 self, get_all_azs_return, subnet_by_az_side_effect):
847 fake_share_network_id = 'fake_sn_id'
848 self.mock_object(db_api, 'availability_zone_get_all',
849 mock.Mock(return_value=get_all_azs_return))
850 self.mock_object(
851 db_api, 'share_network_subnets_get_all_by_availability_zone_id',
852 mock.Mock(side_effect=subnet_by_az_side_effect))
853 expected_az_names = ([], {})
854 expected_get_az_calls = []
855 for index, value in enumerate(get_all_azs_return):
856 expected_get_az_calls.append(mock.call(
857 self.context, share_network_id=fake_share_network_id,
858 availability_zone_id=value['id']))
859 if subnet_by_az_side_effect[index] is not None:
860 expected_az_names = ([value['name']], {value['id']: True})
862 get_all_subnets = self.api._get_all_availability_zones_with_subnets
863 compatible_azs = get_all_subnets(self.context, fake_share_network_id)
865 db_api.availability_zone_get_all.assert_called_once_with(
866 self.context)
867 db_get_azs_with_subnet = (
868 db_api.share_network_subnets_get_all_by_availability_zone_id)
869 db_get_azs_with_subnet.assert_has_calls(expected_get_az_calls)
871 self.assertEqual(expected_az_names, compatible_azs)
873 def test_create_share_with_share_type_size_limit(self):
874 self.assertRaises(exception.InvalidInput,
875 self.api.create,
876 self.context,
877 'nfs',
878 1,
879 'display_name',
880 'display_description',
881 share_type=self.sized_sha_type)
882 self.assertRaises(exception.InvalidInput,
883 self.api.create,
884 self.context,
885 'nfs',
886 5,
887 'display_name',
888 'display_description',
889 share_type=self.sized_sha_type)
891 @ddt.data(
892 {'availability_zones': None, 'compatible_azs_name': ['fake_az_1'],
893 'compatible_azs_multiple': {}},
894 {'availability_zones': ['fake_az_2'],
895 'compatible_azs_name': ['fake_az_2'], 'compatible_azs_multiple': {}},
896 {'availability_zones': ['fake_az_1', 'faze_az_2', 'fake_az_3'],
897 'compatible_azs_name': ['fake_az_3'],
898 'compatible_azs_multiple': {'fake_az_3': 1}}
899 )
900 @ddt.unpack
901 def test_create_share_with_subnets(self, availability_zones,
902 compatible_azs_name,
903 compatible_azs_multiple):
904 share, share_data = self._setup_create_mocks()
905 reservation = 'fake'
906 self.mock_object(quota.QUOTAS, 'reserve',
907 mock.Mock(return_value=reservation))
908 self.mock_object(self.api, '_get_all_availability_zones_with_subnets',
909 mock.Mock(return_value=[compatible_azs_name,
910 compatible_azs_multiple]))
911 self.mock_object(quota.QUOTAS, 'commit')
912 self.mock_object(self.api, 'create_instance')
913 self.mock_object(db_api, 'share_get')
914 fake_share_network_id = 'fake_sn_id'
916 if availability_zones:
917 expected_azs = (
918 [az for az in availability_zones if az in compatible_azs_name])
919 else:
920 expected_azs = compatible_azs_name
922 az_multiple_sn_support_map = None
923 if compatible_azs_multiple != {}:
924 az_multiple_sn_support_map = compatible_azs_multiple
926 self.api.create(
927 self.context,
928 share_data['share_proto'],
929 share_data['size'],
930 share_data['display_name'],
931 share_data['display_description'],
932 share_network_id=fake_share_network_id,
933 availability_zones=availability_zones,
934 az_request_multiple_subnet_support_map=az_multiple_sn_support_map)
935 share['status'] = constants.STATUS_CREATING
936 share['host'] = None
938 quota.QUOTAS.reserve.assert_called_once()
939 get_all_azs_sns = self.api._get_all_availability_zones_with_subnets
940 get_all_azs_sns.assert_called_once_with(
941 self.context, fake_share_network_id)
942 quota.QUOTAS.commit.assert_called_once()
943 self.api.create_instance.assert_called_once_with(
944 self.context, share, share_network_id=fake_share_network_id,
945 host=None, availability_zone=None, share_group=None,
946 share_group_snapshot_member=None, share_type_id=None,
947 availability_zones=expected_azs,
948 az_request_multiple_subnet_support_map=compatible_azs_multiple,
949 snapshot_host=None,
950 scheduler_hints=None, mount_point_name=None,
951 encryption_key_ref=None,
952 )
953 db_api.share_get.assert_called_once()
955 @ddt.data(
956 {'availability_zones': None, 'compatible_azs_name': [],
957 'compatible_azs_multiple': []},
958 {'availability_zones': ['fake_az_1'],
959 'compatible_azs_name': ['fake_az_2'], 'compatible_azs_multiple': []}
960 )
961 @ddt.unpack
962 def test_create_share_with_subnets_invalid_azs(self, availability_zones,
963 compatible_azs_name,
964 compatible_azs_multiple):
965 share, share_data = self._setup_create_mocks()
966 reservation = 'fake'
967 self.mock_object(quota.QUOTAS, 'reserve',
968 mock.Mock(return_value=reservation))
969 self.mock_object(self.api, '_get_all_availability_zones_with_subnets',
970 mock.Mock(return_value=[compatible_azs_name,
971 compatible_azs_multiple]))
972 self.mock_object(quota.QUOTAS, 'commit')
973 self.mock_object(self.api, 'create_instance')
974 self.mock_object(db_api, 'share_get')
975 fake_share_network_id = 'fake_sn_id'
977 self.assertRaises(
978 exception.InvalidInput,
979 self.api.create,
980 self.context, share_data['share_proto'], share_data['size'],
981 share_data['display_name'], share_data['display_description'],
982 share_network_id=fake_share_network_id,
983 availability_zones=availability_zones)
985 quota.QUOTAS.reserve.assert_called_once()
986 get_all_azs_sns = self.api._get_all_availability_zones_with_subnets
987 get_all_azs_sns.assert_called_once_with(
988 self.context, fake_share_network_id)
990 def test_prefix_with_missing_extra_spec_mount_point_name_support(self):
991 share, share_data = self._setup_create_mocks(is_public=True)
992 az = share_data.pop('availability_zone')
993 extra_specs = {'replication_type': 'readable',
994 'mount_point_name_support': False}
995 self.mock_object(
996 self.api, 'get_share_attributes_from_share_type',
997 mock.Mock(return_value=extra_specs))
999 self.assertRaises(
1000 exception.InvalidInput,
1001 self.api.create,
1002 self.context, share_data['share_proto'], share_data['size'],
1003 share_data['display_name'], share_data['display_description'],
1004 availability_zones=az,
1005 mount_point_name='fake_mp')
1007 def test_configure_default_prefix(self):
1008 share_type = {'extra_specs': {}}
1009 conf = dict(DEFAULT=dict(default_mount_point_prefix="manila_"))
1010 with test_utils.create_temp_config_with_opts(conf):
1011 self.context.project_id = 'project_id'
1012 mount_point_name = 'mount_point'
1013 result = self.api._prefix_mount_point_name(
1014 share_type, self.context, mount_point_name
1015 )
1016 self.assertEqual(result, 'manila_mount_point')
1018 def test_configure_empty_default_prefix(self):
1019 share_type = {'extra_specs': {}}
1020 conf = dict(DEFAULT=dict(default_mount_point_prefix=""))
1021 with test_utils.create_temp_config_with_opts(conf):
1022 self.context.project_id = 'project_id'
1023 mount_point_name = 'mount_point'
1024 result = self.api._prefix_mount_point_name(
1025 share_type, self.context, mount_point_name
1026 )
1027 self.assertEqual(result, 'mount_point')
1029 def test_prefix_with_valid_mount_point_name(self):
1030 share_type = {
1031 'extra_specs': {
1032 constants.ExtraSpecs.PROVISIONING_MOUNT_POINT_PREFIX:
1033 'prefix_',
1034 }
1035 }
1036 self.context.project_id = 'project_id'
1037 mount_point_name = 'mount_point'
1038 result = self.api._prefix_mount_point_name(
1039 share_type, self.context, mount_point_name
1040 )
1041 self.assertEqual(result, 'prefix_mount_point')
1043 def test_empty_prefix_with_valid_mount_point_name(self):
1044 share_type = {
1045 'extra_specs': {
1046 constants.ExtraSpecs.PROVISIONING_MOUNT_POINT_PREFIX: '',
1047 }
1048 }
1049 self.context.project_id = 'project_id'
1050 mount_point_name = 'mount_point'
1051 result = self.api._prefix_mount_point_name(
1052 share_type, self.context, mount_point_name
1053 )
1054 self.assertEqual(result, 'mount_point')
1056 def test_prefix_with_valid_missing_extra_spec_mount_point_name(self):
1057 share_type = {
1058 'extra_specs': {},
1059 }
1060 self.context.project_id = 'project_id'
1061 mount_point_name = 'mount_point'
1062 result = self.api._prefix_mount_point_name(
1063 share_type, self.context, mount_point_name
1064 )
1065 self.assertEqual(result, 'project_id_mount_point')
1067 def test_prefix_with_invalid_mount_point_name(self):
1068 share_type = \
1069 {
1070 'extra_specs':
1071 {
1072 constants.ExtraSpecs.PROVISIONING_MOUNT_POINT_PREFIX:
1073 'prefix',
1074 }
1075 }
1076 self.context.project_id = 'project_id'
1077 mount_point_name = 'invalid*name'
1078 self.assertRaises(
1079 exception.InvalidInput,
1080 self.api._prefix_mount_point_name,
1081 share_type,
1082 self.context,
1083 mount_point_name
1084 )
1086 def test_prefix_with_too_long_mount_point_name(self):
1087 share_type = \
1088 {
1089 'extra_specs':
1090 {
1091 constants.ExtraSpecs.PROVISIONING_MOUNT_POINT_PREFIX:
1092 'prefix',
1093 }
1094 }
1095 self.context.project_id = 'project_id'
1096 mount_point_name = 'a' * 256
1097 self.assertRaises(
1098 exception.InvalidInput,
1099 self.api._prefix_mount_point_name,
1100 share_type,
1101 self.context,
1102 mount_point_name
1103 )
1105 @ddt.data(
1106 None, '', 'fake', 'nfsfake', 'cifsfake', 'glusterfsfake', 'hdfsfake')
1107 def test_create_share_invalid_protocol(self, proto):
1108 share, share_data = self._setup_create_mocks(protocol=proto)
1110 all_protos = ','.join(
1111 proto for proto in constants.SUPPORTED_SHARE_PROTOCOLS)
1112 data = dict(DEFAULT=dict(enabled_share_protocols=all_protos))
1113 with test_utils.create_temp_config_with_opts(data):
1114 self.assertRaises(
1115 exception.InvalidInput,
1116 self.api.create,
1117 self.context, proto, share_data['size'],
1118 share_data['display_name'],
1119 share_data['display_description'])
1121 @ddt.data({'overs': {'gigabytes': 'fake'},
1122 'expected_exception': exception.ShareSizeExceedsAvailableQuota,
1123 'replication_type': None},
1124 {'overs': {'shares': 'fake'},
1125 'expected_exception': exception.ShareLimitExceeded,
1126 'replication_type': None},
1127 {'overs': {'replica_gigabytes': 'fake'},
1128 'expected_exception':
1129 exception.ShareReplicaSizeExceedsAvailableQuota,
1130 'replication_type': constants.REPLICATION_TYPE_READABLE},
1131 {'overs': {'share_replicas': 'fake'},
1132 'expected_exception': exception.ShareReplicasLimitExceeded,
1133 'replication_type': constants.REPLICATION_TYPE_READABLE})
1134 @ddt.unpack
1135 def test_create_share_over_quota(self, overs, expected_exception,
1136 replication_type):
1137 extra_specs = {'replication_type': replication_type}
1138 share_type = db_utils.create_share_type(extra_specs=extra_specs)
1139 share_type = db_api.share_type_get(self.context, share_type['id'])
1140 share, share_data = self._setup_create_mocks(
1141 share_type_id=share_type['id'])
1143 az = share_data.pop('availability_zone')
1145 usages = {'gigabytes': {'reserved': 5, 'in_use': 5},
1146 'shares': {'reserved': 10, 'in_use': 10},
1147 'replica_gigabytes': {'reserved': 5, 'in_use': 5},
1148 'share_replicas': {'reserved': 10, 'in_use': 10}}
1150 quotas = {'gigabytes': 5, 'shares': 10,
1151 'replica_gigabytes': 5, 'share_replicas': 10}
1153 exc = exception.OverQuota(overs=overs, usages=usages, quotas=quotas)
1154 self.mock_object(quota.QUOTAS, 'reserve', mock.Mock(side_effect=exc))
1156 if replication_type:
1157 # Prevent the raising of an exception, to force the call to the
1158 # function check_if_replica_quotas_exceeded
1159 self.mock_object(self.api, 'check_if_share_quotas_exceeded')
1161 self.assertRaises(
1162 expected_exception,
1163 self.api.create,
1164 self.context,
1165 share_data['share_proto'],
1166 share_data['size'],
1167 share_data['display_name'],
1168 share_data['display_description'],
1169 availability_zone=az,
1170 share_type=share_type
1171 )
1173 if replication_type:
1174 quota.QUOTAS.reserve.assert_called_once_with(
1175 self.context, share_type_id=share_type['id'],
1176 gigabytes=1, shares=1, share_replicas=1, replica_gigabytes=1)
1177 else:
1178 quota.QUOTAS.reserve.assert_called_once_with(
1179 self.context, share_type_id=share_type['id'],
1180 shares=1, gigabytes=share_data['size'])
1182 @ddt.data({'overs': {'per_share_gigabytes': 'fake'},
1183 'expected_exception': exception.ShareSizeExceedsLimit})
1184 @ddt.unpack
1185 def test_create_share_over_per_share_quota(self, overs,
1186 expected_exception):
1187 share, share_data = self._setup_create_mocks()
1189 quota.CONF.set_default("per_share_gigabytes", 5, 'quota')
1190 share_data['size'] = 20
1192 usages = {'per_share_gigabytes': {'reserved': 0, 'in_use': 0}}
1193 quotas = {'per_share_gigabytes': 10}
1194 exc = exception.OverQuota(overs=overs, usages=usages, quotas=quotas)
1195 self.mock_object(quota.QUOTAS, 'reserve', mock.Mock(side_effect=exc))
1197 self.assertRaises(
1198 expected_exception,
1199 self.api.create,
1200 self.context,
1201 share_data['share_proto'],
1202 share_data['size'],
1203 share_data['display_name'],
1204 share_data['display_description']
1205 )
1207 @ddt.data(
1208 {'overs': {'encryption_keys': 'fake'},
1209 'expected_exception': (
1210 exception.EncryptionKeysLimitExceeded)
1211 })
1212 @ddt.unpack
1213 def test_create_share_over_encryption_keys_quota(self, overs,
1214 expected_exception):
1215 share, share_data = self._setup_create_mocks()
1216 quota.CONF.set_default("encryption_keys", 2, 'quota')
1217 share_data['encryption_key_ref'] = uuidutils.generate_uuid()
1219 usages = {'encryption_keys': {'reserved': 0, 'in_use': 2}}
1220 quotas = {'encryption_keys': 2}
1221 exc = exception.OverQuota(overs=overs, usages=usages, quotas=quotas)
1222 self.mock_object(quota.QUOTAS, 'reserve', mock.Mock(side_effect=exc))
1223 self.mock_object(db_api, 'share_server_get_all_with_filters',
1224 mock.Mock(return_value={}))
1225 self.mock_object(barbican_api, 'create_secret_access')
1226 self.mock_object(db_api, 'encryption_keys_get_count',
1227 mock.Mock(return_value=2))
1228 self.assertRaises(
1229 expected_exception,
1230 self.api.create,
1231 self.context,
1232 share_data['share_proto'],
1233 share_data['size'],
1234 share_data['display_name'],
1235 share_data['display_description'],
1236 encryption_key_ref=share_data['encryption_key_ref']
1237 )
1239 @ddt.data(exception.QuotaError, exception.InvalidShare)
1240 def test_create_share_error_on_quota_commit(self, expected_exception):
1241 share, share_data = self._setup_create_mocks()
1242 reservation = 'fake'
1243 self.mock_object(quota.QUOTAS, 'reserve',
1244 mock.Mock(return_value=reservation))
1245 self.mock_object(quota.QUOTAS, 'commit',
1246 mock.Mock(side_effect=expected_exception('fake')))
1247 self.mock_object(quota.QUOTAS, 'rollback')
1248 self.mock_object(db_api, 'share_delete')
1250 self.assertRaises(
1251 expected_exception,
1252 self.api.create,
1253 self.context,
1254 share_data['share_proto'],
1255 share_data['size'],
1256 share_data['display_name'],
1257 share_data['display_description']
1258 )
1260 quota.QUOTAS.rollback.assert_called_once_with(
1261 self.context, reservation, share_type_id=None)
1262 db_api.share_delete.assert_called_once_with(self.context, share['id'])
1264 def test_create_share_instance_with_host_and_az(self):
1265 host, share, share_instance = self._setup_create_instance_mocks()
1267 self.api.create_instance(self.context, share, host=host,
1268 availability_zone='fake',
1269 share_type_id='fake_share_type')
1271 db_api.share_instance_create.assert_called_once_with(
1272 self.context, share['id'],
1273 {
1274 'share_network_id': None,
1275 'status': constants.STATUS_CREATING,
1276 'scheduled_at': self.dt_utc,
1277 'host': host,
1278 'availability_zone_id': 'fake_id',
1279 'share_type_id': 'fake_share_type',
1280 'cast_rules_to_readonly': False,
1281 'mount_point_name': None,
1282 'encryption_key_ref': None
1283 }
1284 )
1285 db_api.share_type_get.assert_called_once_with(
1286 self.context, share_instance['share_type_id'])
1287 self.api.share_rpcapi.create_share_instance.assert_called_once_with(
1288 self.context,
1289 share_instance,
1290 host,
1291 request_spec=mock.ANY,
1292 filter_properties={'scheduler_hints': None},
1293 snapshot_id=share['snapshot_id'],
1294 )
1295 self.assertFalse(
1296 self.api.scheduler_rpcapi.create_share_instance.called)
1298 def test_create_share_instance_with_mount_point_name(self):
1299 host, share, share_instance = self._setup_create_instance_mocks()
1301 self.api.create_instance(self.context, share, host=host,
1302 availability_zone='fake',
1303 share_type_id='fake_share_type',
1304 mount_point_name='fake_mp')
1306 db_api.share_instance_create.assert_called_once_with(
1307 self.context, share['id'],
1308 {
1309 'share_network_id': None,
1310 'status': constants.STATUS_CREATING,
1311 'scheduled_at': self.dt_utc,
1312 'host': host,
1313 'availability_zone_id': 'fake_id',
1314 'share_type_id': 'fake_share_type',
1315 'cast_rules_to_readonly': False,
1316 'mount_point_name': 'fake_mp',
1317 'encryption_key_ref': None
1318 }
1319 )
1321 def test_create_share_instance_without_host(self):
1322 _, share, share_instance = self._setup_create_instance_mocks()
1324 self.api.create_instance(self.context, share)
1326 (self.api.scheduler_rpcapi.create_share_instance.
1327 assert_called_once_with(
1328 self.context, request_spec=mock.ANY,
1329 filter_properties={'scheduler_hints': None}))
1330 self.assertFalse(self.api.share_rpcapi.create_share_instance.called)
1332 def test_create_share_instance_from_snapshot(self):
1333 snapshot, share, _, _ = self._setup_create_from_snapshot_mocks()
1335 request_spec, share_instance = (
1336 self.api.create_share_instance_and_get_request_spec(
1337 self.context, share)
1338 )
1340 self.assertIsNotNone(share_instance)
1341 self.assertEqual(share['id'],
1342 request_spec['share_instance_properties']['share_id'])
1343 self.assertEqual(share['snapshot_id'], request_spec['snapshot_id'])
1345 self.assertFalse(
1346 self.api.share_rpcapi.create_share_instance_and_get_request_spec
1347 .called)
1349 def test_create_instance_share_group_snapshot_member(self):
1350 fake_req_spec = {
1351 'share_properties': 'fake_share_properties',
1352 'share_instance_properties': 'fake_share_instance_properties',
1353 }
1354 share = fakes.fake_share()
1355 member_info = {
1356 'host': 'host',
1357 'share_network_id': 'share_network_id',
1358 'share_server_id': 'share_server_id',
1359 }
1361 fake_instance = fakes.fake_share_instance(
1362 share_id=share['id'], **member_info)
1363 sg_snap_member = {'share_instance': fake_instance}
1364 self.mock_policy_check = self.mock_object(
1365 policy, 'check_policy', mock.Mock(return_value=True))
1366 mock_share_rpcapi_call = self.mock_object(self.share_rpcapi,
1367 'create_share_instance')
1368 mock_scheduler_rpcapi_call = self.mock_object(self.scheduler_rpcapi,
1369 'create_share_instance')
1370 mock_db_share_instance_update = self.mock_object(
1371 db_api, 'share_instance_update')
1372 self.mock_object(
1373 share_api.API, 'create_share_instance_and_get_request_spec',
1374 mock.Mock(return_value=(fake_req_spec, fake_instance)))
1376 retval = self.api.create_instance(
1377 self.context, fakes.fake_share(),
1378 share_group_snapshot_member=sg_snap_member)
1380 self.assertIsNone(retval)
1381 mock_db_share_instance_update.assert_called_once_with(
1382 self.context, fake_instance['id'], member_info)
1383 self.assertFalse(mock_scheduler_rpcapi_call.called)
1384 self.assertFalse(mock_share_rpcapi_call.called)
1386 def test_get_share_attributes_from_share_type(self):
1388 share_type = {
1389 'extra_specs': {
1390 'snapshot_support': True,
1391 'create_share_from_snapshot_support': False,
1392 'revert_to_snapshot_support': False,
1393 'mount_snapshot_support': False,
1394 'mount_point_name_support': False,
1395 'replication_type': 'dr',
1396 }
1397 }
1399 result = self.api.get_share_attributes_from_share_type(share_type)
1401 self.assertEqual(share_type['extra_specs'], result)
1403 @ddt.data({}, {'extra_specs': {}}, None)
1404 def test_get_share_attributes_from_share_type_defaults(self, share_type):
1406 result = self.api.get_share_attributes_from_share_type(share_type)
1408 expected = {
1409 'snapshot_support': False,
1410 'create_share_from_snapshot_support': False,
1411 'revert_to_snapshot_support': False,
1412 'mount_snapshot_support': False,
1413 'mount_point_name_support': False,
1414 'replication_type': None,
1415 }
1416 self.assertEqual(expected, result)
1418 @ddt.data({'extra_specs': {'snapshot_support': 'fake'}},
1419 {'extra_specs': {'create_share_from_snapshot_support': 'fake'}})
1420 def test_get_share_attributes_from_share_type_invalid(self, share_type):
1422 self.assertRaises(exception.InvalidExtraSpec,
1423 self.api.get_share_attributes_from_share_type,
1424 share_type)
1426 @ddt.data(
1427 {'replication_type': 'dr', 'dhss': False, 'share_server_id': None},
1428 {'replication_type': 'readable', 'dhss': False,
1429 'share_server_id': None},
1430 {'replication_type': None, 'dhss': False, 'share_server_id': None},
1431 {'replication_type': None, 'dhss': True, 'share_server_id': 'fake'}
1432 )
1433 @ddt.unpack
1434 def test_manage_new(self, replication_type, dhss, share_server_id):
1435 share_data = {
1436 'host': 'fake',
1437 'export_location_path': 'fake',
1438 'share_proto': 'fake',
1439 'share_type_id': 'fake',
1440 }
1441 if dhss:
1442 share_data['share_server_id'] = share_server_id
1443 driver_options = {}
1444 date = datetime.datetime(1, 1, 1, 1, 1, 1)
1445 timeutils.utcnow.return_value = date
1446 fake_subnet = db_utils.create_share_network_subnet(
1447 share_network_id='fake')
1448 share_server = db_utils.create_share_server(
1449 status=constants.STATUS_ACTIVE, id=share_server_id,
1450 share_network_subnets=[fake_subnet])
1451 share_network = db_utils.create_share_network(id='fake')
1452 fake_share_data = {
1453 'id': 'fakeid',
1454 'status': constants.STATUS_CREATING,
1455 }
1456 fake_type = {
1457 'id': 'fake_type_id',
1458 'extra_specs': {
1459 'snapshot_support': False,
1460 'replication_type': replication_type,
1461 'create_share_from_snapshot_support': False,
1462 'revert_to_snapshot_support': False,
1463 'mount_snapshot_support': False,
1464 'mount_point_name_support': False,
1465 'driver_handles_share_servers': dhss,
1466 },
1467 }
1469 share = db_api.share_create(self.context, fake_share_data)
1471 self.mock_object(self.scheduler_rpcapi, 'manage_share')
1472 self.mock_object(db_api, 'share_create',
1473 mock.Mock(return_value=share))
1474 self.mock_object(db_api, 'export_locations_update')
1475 self.mock_object(db_api, 'share_get',
1476 mock.Mock(return_value=share))
1477 self.mock_object(share_types, 'get_share_type',
1478 mock.Mock(return_value=fake_type))
1479 self.mock_object(db_api, 'share_server_get',
1480 mock.Mock(return_value=share_server))
1481 self.mock_object(db_api, 'share_instance_get_all',
1482 mock.Mock(return_value=[]))
1483 self.mock_object(db_api, 'share_network_get',
1484 mock.Mock(return_value=share_network))
1486 self.api.manage(self.context, copy.deepcopy(share_data),
1487 driver_options)
1489 share_data.update({
1490 'user_id': self.context.user_id,
1491 'project_id': self.context.project_id,
1492 'status': constants.STATUS_MANAGING,
1493 'scheduled_at': date,
1494 'snapshot_support': fake_type['extra_specs']['snapshot_support'],
1495 'create_share_from_snapshot_support':
1496 fake_type['extra_specs']['create_share_from_snapshot_support'],
1497 'revert_to_snapshot_support':
1498 fake_type['extra_specs']['revert_to_snapshot_support'],
1499 'mount_snapshot_support':
1500 fake_type['extra_specs']['mount_snapshot_support'],
1501 'mount_point_name_support':
1502 fake_type['extra_specs']['mount_point_name_support'],
1503 'replication_type': replication_type,
1504 })
1506 expected_request_spec = self._get_request_spec_dict(
1507 share, fake_type, self.context, size=0,
1508 share_proto=share_data['share_proto'],
1509 host=share_data['host'])
1511 if dhss:
1512 share_data.update({
1513 'share_network_id': fake_subnet['share_network_id']})
1514 export_location = share_data.pop('export_location_path')
1515 filters = {'export_location_path': export_location,
1516 'host': share_data['host']
1517 }
1518 if share_server_id:
1519 filters['share_server_id'] = share_server_id
1520 db_api.share_instance_get_all.assert_called_once_with(
1521 self.context, filters=filters)
1522 db_api.share_create.assert_called_once_with(self.context, share_data)
1523 db_api.share_get.assert_called_once_with(self.context, share['id'])
1524 db_api.export_locations_update.assert_called_once_with(
1525 self.context, share.instance['id'], export_location)
1526 self.scheduler_rpcapi.manage_share.assert_called_once_with(
1527 self.context, share['id'], driver_options, expected_request_spec)
1528 if dhss:
1529 db_api.share_server_get.assert_called_once_with(
1530 self.context, share_data['share_server_id'])
1532 @ddt.data((True, exception.InvalidInput, True),
1533 (True, exception.InvalidInput, False),
1534 (False, exception.InvalidInput, True),
1535 (True, exception.InvalidInput, True))
1536 @ddt.unpack
1537 def test_manage_new_dhss_true_and_false(self, dhss, exception_type,
1538 has_share_server_id):
1539 share_data = {
1540 'host': 'fake',
1541 'export_location_path': 'fake',
1542 'share_proto': 'fake',
1543 'share_type_id': 'fake',
1544 }
1545 if has_share_server_id:
1546 share_data['share_server_id'] = 'fake'
1548 driver_options = {}
1549 date = datetime.datetime(1, 1, 1, 1, 1, 1)
1550 timeutils.utcnow.return_value = date
1551 fake_type = {
1552 'id': 'fake_type_id',
1553 'extra_specs': {
1554 'snapshot_support': False,
1555 'create_share_from_snapshot_support': False,
1556 'revert_to_snapshot_support': False,
1557 'mount_snapshot_support': False,
1558 'mount_point_name_support': False,
1559 'driver_handles_share_servers': dhss,
1560 },
1561 }
1563 self.mock_object(share_types, 'get_share_type',
1564 mock.Mock(return_value=fake_type))
1565 self.mock_object(db_api, 'share_instance_get_all',
1566 mock.Mock(return_value=[]))
1568 self.assertRaises(exception_type,
1569 self.api.manage,
1570 self.context,
1571 share_data=share_data,
1572 driver_options=driver_options
1573 )
1574 share_types.get_share_type.assert_called_once_with(
1575 self.context, share_data['share_type_id']
1576 )
1577 filters = {'export_location_path': share_data['export_location_path'],
1578 'host': share_data['host']
1579 }
1580 if has_share_server_id:
1581 filters['share_server_id'] = 'fake'
1582 db_api.share_instance_get_all.assert_called_once_with(
1583 self.context, filters=filters)
1585 def test_manage_new_share_server_not_found(self):
1586 share_data = {
1587 'host': 'fake',
1588 'export_location_path': 'fake',
1589 'share_proto': 'fake',
1590 'share_type_id': 'fake',
1591 'share_server_id': 'fake'
1593 }
1594 driver_options = {}
1595 date = datetime.datetime(1, 1, 1, 1, 1, 1)
1596 timeutils.utcnow.return_value = date
1598 fake_type = {
1599 'id': 'fake_type_id',
1600 'extra_specs': {
1601 'snapshot_support': False,
1602 'replication_type': 'dr',
1603 'create_share_from_snapshot_support': False,
1604 'revert_to_snapshot_support': False,
1605 'mount_snapshot_support': False,
1606 'mount_point_name_support': False,
1607 'driver_handles_share_servers': True,
1608 },
1609 }
1611 self.mock_object(share_types, 'get_share_type',
1612 mock.Mock(return_value=fake_type))
1613 self.mock_object(db_api, 'share_instance_get_all',
1614 mock.Mock(return_value=[]))
1616 self.assertRaises(exception.InvalidInput,
1617 self.api.manage,
1618 self.context,
1619 share_data=share_data,
1620 driver_options=driver_options
1621 )
1622 share_types.get_share_type.assert_called_once_with(
1623 self.context, share_data['share_type_id']
1624 )
1625 db_api.share_instance_get_all.assert_called_once_with(
1626 self.context, filters={
1627 'export_location_path': share_data['export_location_path'],
1628 'host': share_data['host'],
1629 'share_server_id': share_data['share_server_id']
1630 }
1631 )
1633 def test_manage_new_share_server_not_active(self):
1634 share_data = {
1635 'host': 'fake',
1636 'export_location_path': 'fake',
1637 'share_proto': 'fake',
1638 'share_type_id': 'fake',
1639 'share_server_id': 'fake'
1641 }
1642 fake_share_data = {
1643 'id': 'fakeid',
1644 'status': constants.STATUS_ERROR,
1645 }
1646 driver_options = {}
1647 date = datetime.datetime(1, 1, 1, 1, 1, 1)
1648 timeutils.utcnow.return_value = date
1650 fake_type = {
1651 'id': 'fake_type_id',
1652 'extra_specs': {
1653 'snapshot_support': False,
1654 'replication_type': 'dr',
1655 'create_share_from_snapshot_support': False,
1656 'revert_to_snapshot_support': False,
1657 'mount_snapshot_support': False,
1658 'mount_point_name_support': False,
1659 'driver_handles_share_servers': True,
1660 },
1661 }
1663 share = db_api.share_create(self.context, fake_share_data)
1665 self.mock_object(share_types, 'get_share_type',
1666 mock.Mock(return_value=fake_type))
1667 self.mock_object(db_api, 'share_instance_get_all',
1668 mock.Mock(return_value=[]))
1669 self.mock_object(db_api, 'share_server_get',
1670 mock.Mock(return_value=share))
1672 self.assertRaises(exception.InvalidShareServer,
1673 self.api.manage,
1674 self.context,
1675 share_data=share_data,
1676 driver_options=driver_options
1677 )
1678 share_types.get_share_type.assert_called_once_with(
1679 self.context, share_data['share_type_id']
1680 )
1681 db_api.share_instance_get_all.assert_called_once_with(
1682 self.context, filters={
1683 'export_location_path': share_data['export_location_path'],
1684 'host': share_data['host'],
1685 'share_server_id': share_data['share_server_id']
1686 }
1687 )
1688 db_api.share_server_get.assert_called_once_with(
1689 self.context, share_data['share_server_id']
1690 )
1692 @ddt.data(constants.STATUS_MANAGE_ERROR, constants.STATUS_AVAILABLE)
1693 def test_manage_duplicate(self, status):
1694 share_data = {
1695 'host': 'fake',
1696 'export_location_path': 'fake',
1697 'share_proto': 'fake',
1698 'share_type_id': 'fake',
1699 }
1700 driver_options = {}
1701 fake_type = {
1702 'id': 'fake_type_id',
1703 'extra_specs': {
1704 'snapshot_support': False,
1705 'create_share_from_snapshot_support': False,
1706 'driver_handles_share_servers': False,
1707 },
1708 }
1709 already_managed = [{'id': 'fake', 'status': status}]
1710 self.mock_object(db_api, 'share_instance_get_all',
1711 mock.Mock(return_value=already_managed))
1712 self.mock_object(share_types, 'get_share_type',
1713 mock.Mock(return_value=fake_type))
1714 self.assertRaises(exception.InvalidShare, self.api.manage,
1715 self.context, share_data, driver_options)
1717 def _get_request_spec_dict(self, share, share_type, context, **kwargs):
1719 if share is None: 1719 ↛ 1720line 1719 didn't jump to line 1720 because the condition on line 1719 was never true
1720 share = {'instance': {}}
1722 share_instance = share['instance']
1724 share_properties = {
1725 'size': kwargs.get('size', share.get('size')),
1726 'user_id': kwargs.get('user_id', share.get('user_id')),
1727 'project_id': kwargs.get('project_id', share.get('project_id')),
1728 'metadata': db_api.share_metadata_get(context, share['id']),
1729 'snapshot_support': kwargs.get(
1730 'snapshot_support',
1731 share_type['extra_specs']['snapshot_support']),
1732 'create_share_from_snapshot_support': kwargs.get(
1733 'create_share_from_snapshot_support',
1734 share_type['extra_specs'].get(
1735 'create_share_from_snapshot_support')),
1736 'revert_to_snapshot_support': kwargs.get(
1737 'revert_to_snapshot_support',
1738 share_type['extra_specs'].get('revert_to_snapshot_support')),
1739 'mount_snapshot_support': kwargs.get(
1740 'mount_snapshot_support',
1741 share_type['extra_specs'].get('mount_snapshot_support')),
1742 'mount_point_name_support': kwargs.get(
1743 'mount_point_name_support',
1744 share_type['extra_specs'].get('mount_point_name_support')),
1745 'share_proto': kwargs.get('share_proto', share.get('share_proto')),
1746 'share_type_id': share_type['id'],
1747 'is_public': kwargs.get('is_public', share.get('is_public')),
1748 'share_group_id': kwargs.get(
1749 'share_group_id', share.get('share_group_id')),
1750 'source_share_group_snapshot_member_id': kwargs.get(
1751 'source_share_group_snapshot_member_id',
1752 share.get('source_share_group_snapshot_member_id')),
1753 'snapshot_id': kwargs.get('snapshot_id', share.get('snapshot_id')),
1754 }
1755 share_instance_properties = {
1756 'availability_zone_id': kwargs.get(
1757 'availability_zone_id',
1758 share_instance.get('availability_zone_id')),
1759 'share_network_id': kwargs.get(
1760 'share_network_id', share_instance.get('share_network_id')),
1761 'share_server_id': kwargs.get(
1762 'share_server_id', share_instance.get('share_server_id')),
1763 'share_id': kwargs.get('share_id', share_instance.get('share_id')),
1764 'host': kwargs.get('host', share_instance.get('host')),
1765 'status': kwargs.get('status', share_instance.get('status')),
1766 }
1768 request_spec = {
1769 'share_properties': share_properties,
1770 'share_instance_properties': share_instance_properties,
1771 'share_type': share_type,
1772 'share_id': share.get('id'),
1773 }
1774 return request_spec
1776 def test_unmanage(self):
1778 share = db_utils.create_share(
1779 id='fakeid',
1780 host='fake',
1781 size='1',
1782 status=constants.STATUS_AVAILABLE,
1783 user_id=self.context.user_id,
1784 project_id=self.context.project_id,
1785 task_state=None)
1787 self.mock_object(db_api, 'share_update', mock.Mock())
1788 self.api.unmanage(self.context, share)
1790 self.share_rpcapi.unmanage_share.assert_called_once_with(
1791 self.context, mock.ANY)
1792 db_api.share_update.assert_called_once_with(
1793 mock.ANY, share['id'], mock.ANY)
1795 def test_unmanage_task_state_busy(self):
1797 share = db_utils.create_share(
1798 id='fakeid',
1799 host='fake',
1800 size='1',
1801 status=constants.STATUS_AVAILABLE,
1802 user_id=self.context.user_id,
1803 project_id=self.context.project_id,
1804 task_state=constants.TASK_STATE_MIGRATION_IN_PROGRESS)
1806 self.assertRaises(exception.ShareBusyException, self.api.unmanage,
1807 self.context, share)
1809 def test_unmanage_locked_share(self):
1810 self.mock_object(
1811 self.api.db,
1812 'resource_lock_get_all',
1813 mock.Mock(return_value=([{'id': 'l1'}, {'id': 'l2'}], None))
1814 )
1815 share = db_utils.create_share(
1816 id='fakeid',
1817 host='fake',
1818 size='1',
1819 status=constants.STATUS_AVAILABLE,
1820 user_id=self.context.user_id,
1821 project_id=self.context.project_id,
1822 task_state=None)
1823 self.mock_object(db_api, 'share_update', mock.Mock())
1825 self.assertRaises(exception.InvalidShare,
1826 self.api.unmanage,
1827 self.context,
1828 share)
1830 # lock check decorator executed first, nothing else is invoked
1831 self.share_rpcapi.unmanage_share.assert_not_called()
1832 db_api.share_update.assert_not_called()
1834 @mock.patch.object(quota.QUOTAS, 'reserve',
1835 mock.Mock(return_value='reservation'))
1836 @mock.patch.object(quota.QUOTAS, 'commit', mock.Mock())
1837 def test_create_snapshot(self):
1838 snapshot = db_utils.create_snapshot(
1839 with_share=True, status=constants.STATUS_CREATING, size=1)
1840 share = snapshot['share']
1842 fake_name = 'fakename'
1843 fake_desc = 'fakedesc'
1844 options = {
1845 'share_id': share['id'],
1846 'user_id': self.context.user_id,
1847 'project_id': self.context.project_id,
1848 'status': constants.STATUS_CREATING,
1849 'progress': '0%',
1850 'share_size': share['size'],
1851 'size': 1,
1852 'display_name': fake_name,
1853 'display_description': fake_desc,
1854 'share_proto': share['share_proto'],
1855 }
1856 with mock.patch.object(db_api, 'share_snapshot_create',
1857 mock.Mock(return_value=snapshot)):
1858 self.api.create_snapshot(self.context, share, fake_name,
1859 fake_desc)
1860 share_api.policy.check_policy.assert_called_once_with(
1861 self.context, 'share', 'create_snapshot', share)
1862 quota.QUOTAS.reserve.assert_called_once_with(
1863 self.context, share_type_id=None,
1864 snapshot_gigabytes=1, snapshots=1)
1865 quota.QUOTAS.commit.assert_called_once_with(
1866 self.context, 'reservation', share_type_id=None)
1867 db_api.share_snapshot_create.assert_called_once_with(
1868 self.context, options)
1870 def test_create_snapshot_space_quota_exceeded(self):
1872 share = fakes.fake_share(
1873 id=uuidutils.generate_uuid(), size=1, project_id='fake_project',
1874 user_id='fake_user', has_replicas=False, status='available')
1875 usages = {'snapshot_gigabytes': {'reserved': 10, 'in_use': 0}}
1876 quotas = {'snapshot_gigabytes': 10}
1877 side_effect = exception.OverQuota(
1878 overs='snapshot_gigabytes', usages=usages, quotas=quotas)
1879 self.mock_object(
1880 quota.QUOTAS, 'reserve', mock.Mock(side_effect=side_effect))
1881 mock_snap_create = self.mock_object(db_api, 'share_snapshot_create')
1883 self.assertRaises(exception.SnapshotSizeExceedsAvailableQuota,
1884 self.api.create_snapshot,
1885 self.context,
1886 share,
1887 'fake_name',
1888 'fake_description')
1889 mock_snap_create.assert_not_called()
1891 def test_create_snapshot_count_quota_exceeded(self):
1893 share = fakes.fake_share(
1894 id=uuidutils.generate_uuid(), size=1, project_id='fake_project',
1895 user_id='fake_user', has_replicas=False, status='available')
1896 usages = {'snapshots': {'reserved': 10, 'in_use': 0}}
1897 quotas = {'snapshots': 10}
1898 side_effect = exception.OverQuota(
1899 overs='snapshots', usages=usages, quotas=quotas)
1900 self.mock_object(
1901 quota.QUOTAS, 'reserve', mock.Mock(side_effect=side_effect))
1902 mock_snap_create = self.mock_object(db_api, 'share_snapshot_create')
1904 self.assertRaises(exception.SnapshotLimitExceeded,
1905 self.api.create_snapshot,
1906 self.context,
1907 share,
1908 'fake_name',
1909 'fake_description')
1910 mock_snap_create.assert_not_called()
1912 def test_manage_snapshot_share_not_found(self):
1913 snapshot = fakes.fake_snapshot(share_id='fake_share',
1914 as_primitive=True)
1915 mock_share_get_call = self.mock_object(
1916 db_api, 'share_get', mock.Mock(side_effect=exception.NotFound))
1917 mock_db_snapshot_call = self.mock_object(
1918 db_api, 'share_snapshot_get_all_for_share')
1920 self.assertRaises(exception.ShareNotFound,
1921 self.api.manage_snapshot,
1922 self.context,
1923 snapshot,
1924 {})
1925 self.assertFalse(mock_db_snapshot_call.called)
1926 mock_share_get_call.assert_called_once_with(
1927 self.context, snapshot['share_id'])
1929 def test_manage_snapshot_share_has_replicas(self):
1930 share_ref = fakes.fake_share(
1931 has_replicas=True, status=constants.STATUS_AVAILABLE)
1932 self.mock_object(
1933 db_api, 'share_get', mock.Mock(return_value=share_ref))
1934 snapshot = fakes.fake_snapshot(create_instance=True, as_primitive=True)
1935 mock_db_snapshot_get_all_for_share_call = self.mock_object(
1936 db_api, 'share_snapshot_get_all_for_share')
1938 self.assertRaises(exception.InvalidShare,
1939 self.api.manage_snapshot,
1940 context,
1941 snapshot,
1942 {})
1943 self.assertFalse(mock_db_snapshot_get_all_for_share_call.called)
1945 def test_manage_snapshot_already_managed(self):
1946 share_ref = fakes.fake_share(
1947 has_replicas=False, status=constants.STATUS_AVAILABLE)
1948 snapshot = fakes.fake_snapshot(create_instance=True, as_primitive=True)
1949 self.mock_object(
1950 db_api, 'share_get', mock.Mock(return_value=share_ref))
1951 mock_db_snapshot_call = self.mock_object(
1952 db_api, 'share_snapshot_get_all_for_share', mock.Mock(
1953 return_value=[snapshot]))
1954 mock_db_snapshot_create_call = self.mock_object(
1955 db_api, 'share_snapshot_create')
1957 self.assertRaises(exception.ManageInvalidShareSnapshot,
1958 self.api.manage_snapshot,
1959 self.context,
1960 snapshot,
1961 {})
1962 mock_db_snapshot_call.assert_called_once_with(
1963 self.context, snapshot['share_id'])
1964 self.assertFalse(mock_db_snapshot_create_call.called)
1966 def test_manage_snapshot(self):
1967 share_ref = fakes.fake_share(
1968 has_replicas=False, status=constants.STATUS_AVAILABLE,
1969 host='fake_host')
1970 existing_snapshot = fakes.fake_snapshot(
1971 create_instance=True, share_id=share_ref['id'])
1972 self.mock_object(db_api, 'share_snapshot_get_all_for_share',
1973 mock.Mock(return_value=[existing_snapshot]))
1974 snapshot_data = {
1975 'share_id': share_ref['id'],
1976 'provider_location': 'someproviderlocation',
1977 }
1978 expected_snapshot_data = {
1979 'user_id': self.context.user_id,
1980 'project_id': self.context.project_id,
1981 'status': constants.STATUS_MANAGING,
1982 'share_size': share_ref['size'],
1983 'progress': '0%',
1984 'share_proto': share_ref['share_proto'],
1985 }
1986 expected_snapshot_data.update(**snapshot_data)
1987 snapshot = fakes.fake_snapshot(
1988 create_instance=True, **expected_snapshot_data)
1989 self.mock_object(
1990 db_api, 'share_get', mock.Mock(return_value=share_ref))
1991 mock_db_snapshot_create_call = self.mock_object(
1992 db_api, 'share_snapshot_create', mock.Mock(return_value=snapshot))
1993 mock_rpc_call = self.mock_object(self.share_rpcapi, 'manage_snapshot',
1994 mock.Mock(return_value=snapshot))
1996 new_snap = self.api.manage_snapshot(
1997 self.context, snapshot_data, {})
1999 self.assertEqual(new_snap, snapshot)
2000 mock_db_snapshot_create_call.assert_called_once_with(
2001 self.context, expected_snapshot_data)
2002 mock_rpc_call.assert_called_once_with(
2003 self.context, snapshot, share_ref['host'], {})
2005 def test_manage_share_server(self):
2006 """Tests manage share server"""
2007 host = 'fake_host'
2008 fake_share_network = {
2009 'id': 'fake_net_id'
2010 }
2011 fake_share_net_subnet = [{
2012 'id': 'fake_subnet_id',
2013 'share_network_id': fake_share_network['id']
2014 }]
2015 identifier = 'fake_identifier'
2016 values = {
2017 'host': host,
2018 'share_network_subnets': [fake_share_net_subnet],
2019 'status': constants.STATUS_MANAGING,
2020 'is_auto_deletable': False,
2021 'identifier': identifier,
2022 }
2024 server_managing = {
2025 'id': 'fake_server_id',
2026 'status': constants.STATUS_MANAGING,
2027 'host': host,
2028 'share_network_subnets': [fake_share_net_subnet],
2029 'is_auto_deletable': False,
2030 'identifier': identifier,
2031 }
2033 mock_share_server_search = self.mock_object(
2034 db_api, 'share_server_search_by_identifier',
2035 mock.Mock(side_effect=exception.ShareServerNotFound('fake')))
2037 mock_share_server_get = self.mock_object(
2038 db_api, 'share_server_get',
2039 mock.Mock(
2040 return_value=server_managing)
2041 )
2042 mock_share_server_create = self.mock_object(
2043 db_api, 'share_server_create',
2044 mock.Mock(return_value=server_managing)
2045 )
2046 result = self.api.manage_share_server(
2047 self.context, 'fake_identifier', host, fake_share_net_subnet,
2048 {'opt1': 'val1', 'opt2': 'val2'}
2049 )
2051 mock_share_server_create.assert_called_once_with(
2052 self.context, values)
2054 mock_share_server_get.assert_called_once_with(
2055 self.context, 'fake_server_id')
2057 mock_share_server_search.assert_called_once_with(
2058 self.context, 'fake_identifier')
2060 result_dict = {
2061 'host': result['host'],
2062 'share_network_subnets': result['share_network_subnets'],
2063 'status': result['status'],
2064 'is_auto_deletable': result['is_auto_deletable'],
2065 'identifier': result['identifier'],
2066 }
2067 self.assertEqual(values, result_dict)
2069 def test_manage_share_server_invalid(self):
2071 server = {'identifier': 'fake_server'}
2073 mock_share_server_search = self.mock_object(
2074 db_api, 'share_server_search_by_identifier',
2075 mock.Mock(return_value=[server]))
2077 self.assertRaises(
2078 exception.InvalidInput, self.api.manage_share_server,
2079 self.context, 'invalid_identifier', 'fake_host', 'fake_share_net',
2080 {})
2082 mock_share_server_search.assert_called_once_with(
2083 self.context, 'invalid_identifier')
2085 def test_unmanage_snapshot(self):
2086 fake_host = 'fake_host'
2087 snapshot_data = {
2088 'status': constants.STATUS_UNMANAGING,
2089 'terminated_at': timeutils.utcnow(),
2090 }
2091 snapshot = fakes.fake_snapshot(
2092 create_instance=True, share_instance_id='id2', **snapshot_data)
2093 mock_db_snap_update_call = self.mock_object(
2094 db_api, 'share_snapshot_update', mock.Mock(return_value=snapshot))
2095 mock_rpc_call = self.mock_object(
2096 self.share_rpcapi, 'unmanage_snapshot')
2098 retval = self.api.unmanage_snapshot(
2099 self.context, snapshot, fake_host)
2101 self.assertIsNone(retval)
2102 mock_db_snap_update_call.assert_called_once_with(
2103 self.context, snapshot['id'], snapshot_data)
2104 mock_rpc_call.assert_called_once_with(
2105 self.context, snapshot, fake_host)
2107 def test_unmanage_share_server(self):
2108 shr1 = {}
2109 share_server = db_utils.create_share_server(**shr1)
2110 update_data = {'status': constants.STATUS_UNMANAGING,
2111 'terminated_at': timeutils.utcnow()}
2113 mock_share_instance_get_all = self.mock_object(
2114 db_api, 'share_instance_get_all_by_share_server',
2115 mock.Mock(return_value={}))
2116 mock_share_group_get_all = self.mock_object(
2117 db_api, 'share_group_get_all_by_share_server',
2118 mock.Mock(return_value={}))
2119 mock_share_server_update = self.mock_object(
2120 db_api, 'share_server_update',
2121 mock.Mock(return_value=share_server))
2123 mock_rpc = self.mock_object(
2124 self.api.share_rpcapi, 'unmanage_share_server')
2126 self.api.unmanage_share_server(self.context, share_server, True)
2128 mock_share_instance_get_all.assert_called_once_with(
2129 self.context, share_server['id']
2130 )
2131 mock_share_group_get_all.assert_called_once_with(
2132 self.context, share_server['id']
2133 )
2134 mock_share_server_update.assert_called_once_with(
2135 self.context, share_server['id'], update_data
2136 )
2138 mock_rpc.assert_called_once_with(
2139 self.context, share_server, force=True)
2141 def test_unmanage_share_server_in_use(self):
2142 fake_share = db_utils.create_share()
2143 fake_share_server = db_utils.create_share_server()
2145 fake_share_instance = db_utils.create_share_instance(
2146 share_id=fake_share['id'])
2147 share_instance_get_all_mock = self.mock_object(
2148 db_api, 'share_instance_get_all_by_share_server',
2149 mock.Mock(return_value=fake_share_instance)
2150 )
2152 self.assertRaises(exception.ShareServerInUse,
2153 self.api.unmanage_share_server,
2154 self.context,
2155 fake_share_server, True)
2156 share_instance_get_all_mock.assert_called_once_with(
2157 self.context, fake_share_server['id']
2158 )
2160 def test_unmanage_share_server_in_use_share_groups(self):
2161 fake_share_server = db_utils.create_share_server()
2162 fake_share_groups = db_utils.create_share_group()
2164 share_instance_get_all_mock = self.mock_object(
2165 db_api, 'share_instance_get_all_by_share_server',
2166 mock.Mock(return_value={})
2167 )
2168 group_get_all_mock = self.mock_object(
2169 db_api, 'share_group_get_all_by_share_server',
2170 mock.Mock(return_value=fake_share_groups)
2171 )
2173 self.assertRaises(exception.ShareServerInUse,
2174 self.api.unmanage_share_server,
2175 self.context,
2176 fake_share_server, True)
2177 share_instance_get_all_mock.assert_called_once_with(
2178 self.context, fake_share_server['id']
2179 )
2180 group_get_all_mock.assert_called_once_with(
2181 self.context, fake_share_server['id']
2182 )
2184 @ddt.data(True, False)
2185 def test_revert_to_snapshot(self, has_replicas):
2187 share = fakes.fake_share(id=uuidutils.generate_uuid(),
2188 has_replicas=has_replicas)
2189 self.mock_object(db_api, 'share_get', mock.Mock(return_value=share))
2190 mock_handle_revert_to_snapshot_quotas = self.mock_object(
2191 self.api, '_handle_revert_to_snapshot_quotas',
2192 mock.Mock(return_value='fake_reservations'))
2193 mock_revert_to_replicated_snapshot = self.mock_object(
2194 self.api, '_revert_to_replicated_snapshot')
2195 mock_revert_to_snapshot = self.mock_object(
2196 self.api, '_revert_to_snapshot')
2197 snapshot = fakes.fake_snapshot(share_id=share['id'])
2199 self.api.revert_to_snapshot(self.context, share, snapshot)
2201 mock_handle_revert_to_snapshot_quotas.assert_called_once_with(
2202 self.context, share, snapshot)
2203 if not has_replicas:
2204 self.assertFalse(mock_revert_to_replicated_snapshot.called)
2205 mock_revert_to_snapshot.assert_called_once_with(
2206 self.context, share, snapshot, 'fake_reservations')
2207 else:
2208 mock_revert_to_replicated_snapshot.assert_called_once_with(
2209 self.context, share, snapshot, 'fake_reservations')
2210 self.assertFalse(mock_revert_to_snapshot.called)
2212 @ddt.data(None, 'fake_reservations')
2213 def test_revert_to_snapshot_exception(self, reservations):
2215 share = fakes.fake_share(id=uuidutils.generate_uuid(),
2216 has_replicas=False)
2217 self.mock_object(db_api, 'share_get', mock.Mock(return_value=share))
2218 self.mock_object(
2219 self.api, '_handle_revert_to_snapshot_quotas',
2220 mock.Mock(return_value=reservations))
2221 side_effect = exception.ReplicationException(reason='error')
2222 self.mock_object(
2223 self.api, '_revert_to_snapshot',
2224 mock.Mock(side_effect=side_effect))
2225 mock_quotas_rollback = self.mock_object(quota.QUOTAS, 'rollback')
2226 snapshot = fakes.fake_snapshot(share_id=share['id'])
2228 self.assertRaises(exception.ReplicationException,
2229 self.api.revert_to_snapshot,
2230 self.context,
2231 share,
2232 snapshot)
2234 if reservations is not None:
2235 mock_quotas_rollback.assert_called_once_with(
2236 self.context, reservations,
2237 share_type_id=share['instance']['share_type_id'])
2238 else:
2239 self.assertFalse(mock_quotas_rollback.called)
2241 def test_handle_revert_to_snapshot_quotas(self):
2243 share = fakes.fake_share(
2244 id=uuidutils.generate_uuid(), size=1, project_id='fake_project',
2245 user_id='fake_user', has_replicas=False)
2246 snapshot = fakes.fake_snapshot(
2247 id=uuidutils.generate_uuid(), share_id=share['id'], size=1)
2248 mock_quotas_reserve = self.mock_object(quota.QUOTAS, 'reserve')
2250 result = self.api._handle_revert_to_snapshot_quotas(
2251 self.context, share, snapshot)
2253 self.assertIsNone(result)
2254 self.assertFalse(mock_quotas_reserve.called)
2256 def test_handle_revert_to_snapshot_quotas_different_size(self):
2258 share = fakes.fake_share(
2259 id=uuidutils.generate_uuid(), size=1, project_id='fake_project',
2260 user_id='fake_user', has_replicas=False)
2261 snapshot = fakes.fake_snapshot(
2262 id=uuidutils.generate_uuid(), share_id=share['id'], size=2)
2263 mock_quotas_reserve = self.mock_object(
2264 quota.QUOTAS, 'reserve',
2265 mock.Mock(return_value='fake_reservations'))
2267 result = self.api._handle_revert_to_snapshot_quotas(
2268 self.context, share, snapshot)
2270 self.assertEqual('fake_reservations', result)
2271 mock_quotas_reserve.assert_called_once_with(
2272 self.context, project_id='fake_project', gigabytes=1,
2273 share_type_id=share['instance']['share_type_id'],
2274 user_id='fake_user')
2276 def test_handle_revert_to_snapshot_quotas_quota_exceeded(self):
2278 share = fakes.fake_share(
2279 id=uuidutils.generate_uuid(), size=1, project_id='fake_project',
2280 user_id='fake_user', has_replicas=False)
2281 snapshot = fakes.fake_snapshot(
2282 id=uuidutils.generate_uuid(), share_id=share['id'], size=2)
2283 usages = {'gigabytes': {'reserved': 10, 'in_use': 0}}
2284 quotas = {'gigabytes': 10}
2285 side_effect = exception.OverQuota(
2286 overs='fake', usages=usages, quotas=quotas)
2287 self.mock_object(
2288 quota.QUOTAS, 'reserve', mock.Mock(side_effect=side_effect))
2290 self.assertRaises(exception.ShareSizeExceedsAvailableQuota,
2291 self.api._handle_revert_to_snapshot_quotas,
2292 self.context,
2293 share,
2294 snapshot)
2296 def test__revert_to_snapshot(self):
2298 share = fakes.fake_share(
2299 id=uuidutils.generate_uuid(), size=1, project_id='fake_project',
2300 user_id='fake_user', has_replicas=False)
2301 snapshot = fakes.fake_snapshot(
2302 id=uuidutils.generate_uuid(), share_id=share['id'], size=2)
2303 mock_share_update = self.mock_object(db_api, 'share_update')
2304 mock_share_snapshot_update = self.mock_object(
2305 db_api, 'share_snapshot_update')
2306 mock_revert_rpc_call = self.mock_object(
2307 self.share_rpcapi, 'revert_to_snapshot')
2309 self.api._revert_to_snapshot(
2310 self.context, share, snapshot, 'fake_reservations')
2312 mock_share_update.assert_called_once_with(
2313 self.context, share['id'], {'status': constants.STATUS_REVERTING})
2314 mock_share_snapshot_update.assert_called_once_with(
2315 self.context, snapshot['id'],
2316 {'status': constants.STATUS_RESTORING})
2317 mock_revert_rpc_call.assert_called_once_with(
2318 self.context, share, snapshot, share['instance']['host'],
2319 'fake_reservations')
2321 def test_revert_to_replicated_snapshot(self):
2323 share = fakes.fake_share(
2324 has_replicas=True, status=constants.STATUS_AVAILABLE)
2325 snapshot = fakes.fake_snapshot(share_instance_id='id1')
2326 snapshot_instance = fakes.fake_snapshot_instance(
2327 base_snapshot=snapshot, id='sid1')
2328 replicas = [
2329 fakes.fake_replica(
2330 id='rid1', replica_state=constants.REPLICA_STATE_ACTIVE),
2331 fakes.fake_replica(
2332 id='rid2', replica_state=constants.REPLICA_STATE_IN_SYNC),
2333 ]
2334 self.mock_object(
2335 db_api, 'share_replicas_get_available_active_replica',
2336 mock.Mock(return_value=replicas[0]))
2337 self.mock_object(
2338 db_api, 'share_snapshot_instance_get_all_with_filters',
2339 mock.Mock(return_value=[snapshot_instance]))
2340 mock_share_replica_update = self.mock_object(
2341 db_api, 'share_replica_update')
2342 mock_share_snapshot_instance_update = self.mock_object(
2343 db_api, 'share_snapshot_instance_update')
2344 mock_revert_rpc_call = self.mock_object(
2345 self.share_rpcapi, 'revert_to_snapshot')
2347 self.api._revert_to_replicated_snapshot(
2348 self.context, share, snapshot, 'fake_reservations')
2350 mock_share_replica_update.assert_called_once_with(
2351 self.context, 'rid1', {'status': constants.STATUS_REVERTING})
2352 mock_share_snapshot_instance_update.assert_called_once_with(
2353 self.context, 'sid1', {'status': constants.STATUS_RESTORING})
2354 mock_revert_rpc_call.assert_called_once_with(
2355 self.context, share, snapshot, replicas[0]['host'],
2356 'fake_reservations')
2358 def test_revert_to_replicated_snapshot_no_active_replica(self):
2360 share = fakes.fake_share(
2361 has_replicas=True, status=constants.STATUS_AVAILABLE)
2362 snapshot = fakes.fake_snapshot(share_instance_id='id1')
2363 self.mock_object(
2364 db_api, 'share_replicas_get_available_active_replica',
2365 mock.Mock(return_value=None))
2367 self.assertRaises(exception.ReplicationException,
2368 self.api._revert_to_replicated_snapshot,
2369 self.context,
2370 share,
2371 snapshot,
2372 'fake_reservations')
2374 def test_revert_to_replicated_snapshot_no_snapshot_instance(self):
2376 share = fakes.fake_share(
2377 has_replicas=True, status=constants.STATUS_AVAILABLE)
2378 snapshot = fakes.fake_snapshot(share_instance_id='id1')
2379 replicas = [
2380 fakes.fake_replica(
2381 id='rid1', replica_state=constants.REPLICA_STATE_ACTIVE),
2382 fakes.fake_replica(
2383 id='rid2', replica_state=constants.REPLICA_STATE_IN_SYNC),
2384 ]
2385 self.mock_object(
2386 db_api, 'share_replicas_get_available_active_replica',
2387 mock.Mock(return_value=replicas[0]))
2388 self.mock_object(
2389 db_api, 'share_snapshot_instance_get_all_with_filters',
2390 mock.Mock(return_value=[None]))
2392 self.assertRaises(exception.ReplicationException,
2393 self.api._revert_to_replicated_snapshot,
2394 self.context,
2395 share,
2396 snapshot,
2397 'fake_reservations')
2399 def test_create_snapshot_for_replicated_share(self):
2400 share = fakes.fake_share(
2401 has_replicas=True, status=constants.STATUS_AVAILABLE)
2402 snapshot = fakes.fake_snapshot(
2403 create_instance=True, share_instance_id='id2')
2404 replicas = [
2405 fakes.fake_replica(
2406 id='id1', replica_state=constants.REPLICA_STATE_ACTIVE),
2407 fakes.fake_replica(
2408 id='id2', replica_state=constants.REPLICA_STATE_IN_SYNC)
2409 ]
2410 self.mock_object(share_api.policy, 'check_policy')
2411 self.mock_object(quota.QUOTAS, 'reserve',
2412 mock.Mock(return_value='reservation'))
2413 self.mock_object(
2414 db_api, 'share_snapshot_create', mock.Mock(return_value=snapshot))
2415 self.mock_object(db_api, 'share_replicas_get_all_by_share',
2416 mock.Mock(return_value=replicas))
2417 self.mock_object(
2418 db_api, 'share_snapshot_get', mock.Mock(return_value=snapshot))
2419 self.mock_object(quota.QUOTAS, 'commit')
2420 mock_instance_create_call = self.mock_object(
2421 db_api, 'share_snapshot_instance_create')
2422 mock_snapshot_rpc_call = self.mock_object(
2423 self.share_rpcapi, 'create_snapshot')
2424 mock_replicated_snapshot_rpc_call = self.mock_object(
2425 self.share_rpcapi, 'create_replicated_snapshot')
2426 snapshot_instance_args = {
2427 'status': constants.STATUS_CREATING,
2428 'progress': '0%',
2429 'share_instance_id': 'id1',
2430 }
2432 retval = self.api.create_snapshot(
2433 self.context, share, 'fake_name', 'fake_description')
2435 self.assertEqual(snapshot['id'], retval['id'])
2436 mock_instance_create_call.assert_called_once_with(
2437 self.context, snapshot['id'], snapshot_instance_args)
2438 self.assertFalse(mock_snapshot_rpc_call.called)
2439 self.assertTrue(mock_replicated_snapshot_rpc_call.called)
2441 @mock.patch.object(db_api, 'share_instance_get_all_by_share_server',
2442 mock.Mock(return_value=[]))
2443 @mock.patch.object(db_api, 'share_group_get_all_by_share_server',
2444 mock.Mock(return_value=[]))
2445 def test_delete_share_server_no_dependent_shares(self):
2446 server = {'id': 'fake_share_server_id'}
2447 server_returned = {
2448 'id': 'fake_share_server_id',
2449 }
2450 self.mock_object(db_api, 'share_server_update',
2451 mock.Mock(return_value=server_returned))
2452 self.api.delete_share_server(self.context, server)
2453 db_api.share_instance_get_all_by_share_server.assert_called_once_with(
2454 self.context, server['id'])
2455 (db_api.share_group_get_all_by_share_server.
2456 assert_called_once_with(self.context, server['id']))
2457 self.share_rpcapi.delete_share_server.assert_called_once_with(
2458 self.context, server_returned)
2460 @mock.patch.object(db_api, 'share_instance_get_all_by_share_server',
2461 mock.Mock(return_value=['fake_share', ]))
2462 @mock.patch.object(db_api, 'share_group_get_all_by_share_server',
2463 mock.Mock(return_value=[]))
2464 def test_delete_share_server_dependent_share_exists(self):
2465 server = {'id': 'fake_share_server_id'}
2466 self.assertRaises(exception.ShareServerInUse,
2467 self.api.delete_share_server,
2468 self.context,
2469 server)
2470 db_api.share_instance_get_all_by_share_server.assert_called_once_with(
2471 self.context, server['id'])
2473 @mock.patch.object(db_api, 'share_instance_get_all_by_share_server',
2474 mock.Mock(return_value=[]))
2475 @mock.patch.object(db_api, 'share_group_get_all_by_share_server',
2476 mock.Mock(return_value=['fake_group', ]))
2477 def test_delete_share_server_dependent_group_exists(self):
2478 server = {'id': 'fake_share_server_id'}
2479 self.assertRaises(exception.ShareServerInUse,
2480 self.api.delete_share_server,
2481 self.context,
2482 server)
2484 db_api.share_instance_get_all_by_share_server.assert_called_once_with(
2485 self.context, server['id'])
2486 (db_api.share_group_get_all_by_share_server.
2487 assert_called_once_with(self.context, server['id']))
2489 @mock.patch.object(db_api, 'share_snapshot_instance_update', mock.Mock())
2490 def test_delete_snapshot(self):
2491 snapshot = db_utils.create_snapshot(
2492 with_share=True, status=constants.STATUS_AVAILABLE)
2493 share = snapshot['share']
2495 with mock.patch.object(db_api, 'share_get',
2496 mock.Mock(return_value=share)):
2497 self.api.delete_snapshot(self.context, snapshot)
2498 self.share_rpcapi.delete_snapshot.assert_called_once_with(
2499 self.context, snapshot, share['host'], force=False,
2500 deferred_delete=False)
2501 share_api.policy.check_policy.assert_called_once_with(
2502 self.context, 'share', 'delete_snapshot', snapshot)
2503 db_api.share_snapshot_instance_update.assert_called_once_with(
2504 self.context,
2505 snapshot['instance']['id'],
2506 {'status': constants.STATUS_DELETING})
2507 db_api.share_get.assert_called_once_with(
2508 self.context, snapshot['share_id'])
2510 @ddt.data(True, False)
2511 def test_delete_snapshot_deferred(self, force):
2512 CONF.set_default("is_deferred_deletion_enabled", True)
2513 snapshot = db_utils.create_snapshot(
2514 with_share=True, status=constants.STATUS_AVAILABLE)
2515 share = snapshot['share']
2517 self.mock_object(db_api, 'share_snapshot_instance_update',
2518 mock.Mock())
2520 with mock.patch.object(db_api, 'share_get',
2521 mock.Mock(return_value=share)):
2522 self.api.delete_snapshot(self.context, snapshot, force=force)
2523 if force:
2524 self.share_rpcapi.delete_snapshot.assert_called_once_with(
2525 self.context, snapshot, share['host'], force=True,
2526 deferred_delete=False)
2527 db_api.share_snapshot_instance_update.assert_called_once_with(
2528 self.context,
2529 snapshot['instance']['id'],
2530 {'status': constants.STATUS_DELETING})
2531 else:
2532 self.share_rpcapi.delete_snapshot.assert_called_once_with(
2533 self.context, snapshot, share['host'], force=False,
2534 deferred_delete=True)
2535 db_api.share_snapshot_instance_update.assert_called_once_with(
2536 self.context,
2537 snapshot['instance']['id'],
2538 {'status': constants.STATUS_DEFERRED_DELETING})
2540 share_api.policy.check_policy.assert_called_once_with(
2541 self.context, 'share', 'delete_snapshot', snapshot)
2542 db_api.share_get.assert_called_once_with(
2543 self.context, snapshot['share_id'])
2545 def test_delete_snapshot_wrong_status(self):
2546 snapshot = db_utils.create_snapshot(
2547 with_share=True, status=constants.STATUS_CREATING)
2549 self.assertRaises(exception.InvalidShareSnapshot,
2550 self.api.delete_snapshot,
2551 self.context,
2552 snapshot)
2553 share_api.policy.check_policy.assert_called_once_with(
2554 self.context, 'share', 'delete_snapshot', snapshot)
2556 @ddt.data(constants.STATUS_MANAGING, constants.STATUS_ERROR_DELETING,
2557 constants.STATUS_CREATING, constants.STATUS_AVAILABLE)
2558 def test_delete_snapshot_force_delete(self, status):
2559 share = fakes.fake_share(id=uuidutils.generate_uuid(),
2560 has_replicas=False)
2561 snapshot = fakes.fake_snapshot(aggregate_status=status, share=share)
2562 snapshot_instance = fakes.fake_snapshot_instance(
2563 base_snapshot=snapshot)
2564 self.mock_object(db_api, 'share_get', mock.Mock(return_value=share))
2565 self.mock_object(
2566 db_api, 'share_snapshot_instance_get_all_with_filters',
2567 mock.Mock(return_value=[snapshot_instance]))
2568 mock_instance_update_call = self.mock_object(
2569 db_api, 'share_snapshot_instance_update')
2570 mock_rpc_call = self.mock_object(self.share_rpcapi, 'delete_snapshot')
2572 retval = self.api.delete_snapshot(self.context, snapshot, force=True)
2574 self.assertIsNone(retval)
2575 mock_instance_update_call.assert_called_once_with(
2576 self.context, snapshot_instance['id'],
2577 {'status': constants.STATUS_DELETING})
2578 mock_rpc_call.assert_called_once_with(
2579 self.context, snapshot, share['instance']['host'], force=True,
2580 deferred_delete=False)
2582 @ddt.data(True, False)
2583 def test_delete_snapshot_replicated_snapshot(self, force):
2584 share = fakes.fake_share(has_replicas=True)
2585 snapshot = fakes.fake_snapshot(
2586 create_instance=True, share_id=share['id'],
2587 status=constants.STATUS_ERROR)
2588 snapshot_instance = fakes.fake_snapshot_instance(
2589 base_snapshot=snapshot)
2590 expected_update_calls = [
2591 mock.call(self.context, x, {'status': constants.STATUS_DELETING})
2592 for x in (snapshot['instance']['id'], snapshot_instance['id'])
2593 ]
2594 self.mock_object(db_api, 'share_get', mock.Mock(return_value=share))
2595 self.mock_object(
2596 db_api, 'share_snapshot_instance_get_all_with_filters',
2597 mock.Mock(return_value=[snapshot['instance'], snapshot_instance]))
2598 mock_db_update_call = self.mock_object(
2599 db_api, 'share_snapshot_instance_update')
2600 mock_snapshot_rpc_call = self.mock_object(
2601 self.share_rpcapi, 'delete_snapshot')
2602 mock_replicated_snapshot_rpc_call = self.mock_object(
2603 self.share_rpcapi, 'delete_replicated_snapshot')
2605 retval = self.api.delete_snapshot(self.context, snapshot, force=force)
2607 self.assertIsNone(retval)
2608 self.assertEqual(2, mock_db_update_call.call_count)
2609 mock_db_update_call.assert_has_calls(expected_update_calls)
2610 mock_replicated_snapshot_rpc_call.assert_called_once_with(
2611 self.context, snapshot, share['instance']['host'],
2612 share_id=share['id'], force=force)
2613 self.assertFalse(mock_snapshot_rpc_call.called)
2615 def test_create_snapshot_if_share_not_available(self):
2616 share = db_utils.create_share(status=constants.STATUS_ERROR)
2617 self.assertRaises(exception.InvalidShare,
2618 self.api.create_snapshot,
2619 self.context,
2620 share,
2621 'fakename',
2622 'fakedesc')
2623 share_api.policy.check_policy.assert_called_once_with(
2624 self.context, 'share', 'create_snapshot', share)
2626 def test_create_snapshot_invalid_task_state(self):
2627 share = db_utils.create_share(
2628 status=constants.STATUS_AVAILABLE,
2629 task_state=constants.TASK_STATE_MIGRATION_IN_PROGRESS)
2630 self.assertRaises(exception.ShareBusyException,
2631 self.api.create_snapshot,
2632 self.context,
2633 share,
2634 'fakename',
2635 'fakedesc')
2636 share_api.policy.check_policy.assert_called_once_with(
2637 self.context, 'share', 'create_snapshot', share)
2639 def test_create_snapshot_fail(self):
2640 share = fakes.fake_share(
2641 has_replicas=False, status=constants.STATUS_AVAILABLE)
2642 mock_db_share_snapshot_create = self.mock_object(
2643 db_api, 'share_snapshot_create', mock.Mock(
2644 side_effect=exception.NotFound))
2646 self.mock_object(quota.QUOTAS, 'rollback')
2648 self.assertRaises(exception.NotFound,
2649 self.api.create_snapshot,
2650 self.context, share,
2651 'fake_name', 'fake_desc')
2653 self.assertTrue(mock_db_share_snapshot_create.called)
2654 quota.QUOTAS.rollback.assert_called_once_with(
2655 self.context,
2656 mock.ANY,
2657 share_type_id=share['instance']['share_type_id'])
2659 def test_create_snapshot_quota_commit_fail(self):
2660 share = fakes.fake_share(
2661 has_replicas=False, status=constants.STATUS_AVAILABLE)
2662 snapshot = fakes.fake_snapshot(
2663 create_instance=True, share_instance_id='id2')
2664 self.mock_object(
2665 quota.QUOTAS, 'commit', mock.Mock(
2666 side_effect=exception.QuotaError('fake')))
2668 self.mock_object(db_api, 'share_snapshot_create', mock.Mock(
2669 return_value=snapshot))
2670 self.mock_object(db_api, 'share_snapshot_instance_delete')
2671 self.mock_object(quota.QUOTAS, 'rollback')
2673 self.assertRaises(exception.QuotaError,
2674 self.api.create_snapshot,
2675 self.context, share,
2676 'fake_name', 'fake_desc')
2678 quota.QUOTAS.rollback.assert_called_once_with(
2679 self.context,
2680 mock.ANY,
2681 share_type_id=share['instance']['share_type_id'])
2683 @ddt.data({'use_scheduler': False, 'valid_host': 'fake',
2684 'az': None},
2685 {'use_scheduler': True, 'valid_host': None,
2686 'az': None},
2687 {'use_scheduler': True, 'valid_host': None,
2688 'az': "fakeaz2"})
2689 @ddt.unpack
2690 def test_create_from_snapshot(self, use_scheduler, valid_host, az):
2691 snapshot, share, share_data, request_spec = (
2692 self._setup_create_from_snapshot_mocks(
2693 use_scheduler=use_scheduler, host=valid_host)
2694 )
2695 share_type = fakes.fake_share_type()
2697 self.mock_object(db_api, 'share_snapshot_get',
2698 mock.Mock(return_value=snapshot))
2699 mock_get_share_type_call = self.mock_object(
2700 share_types, 'get_share_type', mock.Mock(return_value=share_type))
2702 self.api.create(
2703 self.context,
2704 share_data['share_proto'],
2705 None, # NOTE(u_glide): Get share size from snapshot
2706 share_data['display_name'],
2707 share_data['display_description'],
2708 snapshot_id=snapshot['id'],
2709 availability_zone=az,
2710 )
2712 expected_az = snapshot['share']['availability_zone'] if not az else az
2713 share_data.pop('availability_zone')
2715 mock_get_share_type_call.assert_called_once_with(
2716 self.context, share['share_type_id'])
2717 self.assertSubDictMatch(share_data,
2718 db_api.share_create.call_args[0][1])
2719 self.api.create_instance.assert_called_once_with(
2720 self.context, share, share_network_id=share['share_network_id'],
2721 host=valid_host, share_type_id=share_type['id'],
2722 availability_zone=expected_az,
2723 share_group=None, share_group_snapshot_member=None,
2724 availability_zones=None,
2725 az_request_multiple_subnet_support_map=None,
2726 snapshot_host=snapshot['share']['instance']['host'],
2727 scheduler_hints=None, mount_point_name=None,
2728 encryption_key_ref=None)
2729 share_api.policy.check_policy.assert_called_once_with(
2730 self.context, 'share_snapshot', 'get_snapshot',
2731 snapshot, do_raise=False)
2732 quota.QUOTAS.reserve.assert_called_once_with(
2733 self.context, share_type_id=share_type['id'],
2734 gigabytes=1, shares=1)
2735 quota.QUOTAS.commit.assert_called_once_with(
2736 self.context, 'reservation', share_type_id=share_type['id'])
2738 def test_create_share_with_share_group(self):
2739 extra_specs = {'replication_type': constants.REPLICATION_TYPE_READABLE}
2740 share_type = db_utils.create_share_type(extra_specs=extra_specs)
2741 share_type = db_api.share_type_get(self.context, share_type['id'])
2742 group = db_utils.create_share_group(
2743 status=constants.STATUS_AVAILABLE,
2744 share_types=[share_type['id']])
2745 share, share_data = self._setup_create_mocks(
2746 share_type_id=share_type['id'],
2747 share_group_id=group['id'])
2749 share_instance = db_utils.create_share_instance(
2750 share_id=share['id'])
2751 sg_snap_member = {
2752 'id': 'fake_sg_snap_member_id',
2753 'share_instance': share_instance
2754 }
2756 az = share_data.pop('availability_zone')
2758 self.mock_object(quota.QUOTAS, 'reserve',
2759 mock.Mock(return_value='reservation'))
2760 self.mock_object(quota.QUOTAS, 'commit')
2762 self.api.create(
2763 self.context,
2764 share_data['share_proto'],
2765 share_data['size'],
2766 share_data['display_name'],
2767 share_data['display_description'],
2768 availability_zone=az,
2769 share_type=share_type,
2770 share_group_id=group['id'],
2771 share_group_snapshot_member=sg_snap_member,
2772 )
2773 quota.QUOTAS.reserve.assert_called_once_with(
2774 self.context, share_type_id=share_type['id'],
2775 gigabytes=1, shares=1, share_replicas=1, replica_gigabytes=1)
2776 quota.QUOTAS.commit.assert_called_once_with(
2777 self.context, 'reservation', share_type_id=share_type['id']
2778 )
2780 def test_create_share_share_type_contains_replication_type(self):
2781 extra_specs = {'replication_type': constants.REPLICATION_TYPE_READABLE}
2782 share_type = db_utils.create_share_type(extra_specs=extra_specs)
2783 share_type = db_api.share_type_get(self.context, share_type['id'])
2784 share, share_data = self._setup_create_mocks(
2785 share_type_id=share_type['id'])
2786 az = share_data.pop('availability_zone')
2788 self.mock_object(quota.QUOTAS, 'reserve',
2789 mock.Mock(return_value='reservation'))
2790 self.mock_object(quota.QUOTAS, 'commit')
2792 self.api.create(
2793 self.context,
2794 share_data['share_proto'],
2795 share_data['size'],
2796 share_data['display_name'],
2797 share_data['display_description'],
2798 availability_zone=az,
2799 share_type=share_type
2800 )
2801 quota.QUOTAS.reserve.assert_called_once_with(
2802 self.context, share_type_id=share_type['id'],
2803 gigabytes=1, shares=1, share_replicas=1, replica_gigabytes=1)
2804 quota.QUOTAS.commit.assert_called_once_with(
2805 self.context, 'reservation', share_type_id=share_type['id']
2806 )
2808 def test_create_from_snapshot_az_different_from_source(self):
2809 snapshot, share, share_data, request_spec = (
2810 self._setup_create_from_snapshot_mocks(use_scheduler=False)
2811 )
2813 self.assertRaises(exception.InvalidInput, self.api.create,
2814 self.context, share_data['share_proto'],
2815 share_data['size'],
2816 share_data['display_name'],
2817 share_data['display_description'],
2818 snapshot_id=snapshot['id'],
2819 availability_zone='fake_different_az')
2821 def test_create_from_snapshot_with_different_share_type(self):
2822 snapshot, share, share_data, request_spec = (
2823 self._setup_create_from_snapshot_mocks()
2824 )
2826 share_type = {'id': 'super_fake_share_type'}
2828 self.assertRaises(exception.InvalidInput, self.api.create,
2829 self.context, share_data['share_proto'],
2830 share_data['size'],
2831 share_data['display_name'],
2832 share_data['display_description'],
2833 snapshot_id=snapshot['id'],
2834 availability_zone=share_data['availability_zone'],
2835 share_type=share_type)
2837 def test_get_snapshot(self):
2838 fake_get_snap = {'fake_key': 'fake_val'}
2839 with mock.patch.object(db_api, 'share_snapshot_get',
2840 mock.Mock(return_value=fake_get_snap)):
2841 rule = self.api.get_snapshot(self.context, 'fakeid')
2842 self.assertEqual(fake_get_snap, rule)
2843 share_api.policy.check_policy.assert_called_once_with(
2844 self.context, 'share_snapshot', 'get_snapshot', rule,
2845 do_raise=False)
2846 db_api.share_snapshot_get.assert_called_once_with(
2847 self.context, 'fakeid')
2849 def test_get_snapshot_non_admin_deferred_state(self):
2850 fake_get_snap = {
2851 'fake_key': 'fake_val', 'status': 'deferred_deleting'
2852 }
2853 with mock.patch.object(db_api, 'share_snapshot_get',
2854 mock.Mock(return_value=fake_get_snap)):
2855 self.mock_object(
2856 policy, 'check_policy', mock.Mock(side_effect=[True, False]))
2857 self.assertRaises(exception.NotFound, self.api.get_snapshot,
2858 self.context, 'fakeid')
2860 def test_get_snapshot_not_authorized(self):
2861 fake_get_snap = {'fake_key': 'fake_val'}
2862 share_api.policy.check_policy.return_value = False
2863 with mock.patch.object(db_api, 'share_snapshot_get',
2864 mock.Mock(return_value=fake_get_snap)):
2865 self.assertRaises(exception.NotFound,
2866 self.api.get_snapshot,
2867 self.context, 'fakeid')
2868 share_api.policy.check_policy.assert_called_once_with(
2869 self.context, 'share_snapshot', 'get_snapshot',
2870 fake_get_snap, do_raise=False)
2871 db_api.share_snapshot_get.assert_called_once_with(
2872 self.context, 'fakeid')
2874 def test_create_from_snapshot_not_available(self):
2875 snapshot = db_utils.create_snapshot(
2876 with_share=True, status=constants.STATUS_ERROR)
2877 self.assertRaises(exception.InvalidShareSnapshot, self.api.create,
2878 self.context, 'nfs', '1', 'fakename',
2879 'fakedesc', snapshot_id=snapshot['id'],
2880 availability_zone='fakeaz')
2882 def test_create_from_snapshot_larger_size(self):
2883 snapshot = db_utils.create_snapshot(
2884 size=100, status=constants.STATUS_AVAILABLE, with_share=True)
2885 self.assertRaises(exception.InvalidInput, self.api.create,
2886 self.context, 'nfs', 1, 'fakename', 'fakedesc',
2887 availability_zone='fakeaz',
2888 snapshot_id=snapshot['id'])
2890 def test_create_share_wrong_size_0(self):
2891 self.assertRaises(exception.InvalidInput, self.api.create,
2892 self.context, 'nfs', 0, 'fakename', 'fakedesc',
2893 availability_zone='fakeaz')
2895 def test_create_share_wrong_size_some(self):
2896 self.assertRaises(exception.InvalidInput, self.api.create,
2897 self.context, 'nfs', 'some', 'fakename',
2898 'fakedesc', availability_zone='fakeaz')
2900 @ddt.data(constants.STATUS_AVAILABLE, constants.STATUS_ERROR)
2901 def test_delete(self, status):
2902 share = self._setup_delete_mocks(status)
2904 self.api.delete(self.context, share)
2906 self.api.delete_instance.assert_called_once_with(
2907 utils.IsAMatcher(context.RequestContext),
2908 utils.IsAMatcher(models.ShareInstance), force=False
2909 )
2910 db_api.share_snapshot_get_all_for_share.assert_called_once_with(
2911 utils.IsAMatcher(context.RequestContext), share['id'])
2913 def test_delete_quota_with_different_user(self):
2914 share = self._setup_delete_mocks(constants.STATUS_AVAILABLE)
2915 diff_user_context = context.RequestContext(
2916 user_id='fake2',
2917 project_id='fake',
2918 is_admin=False
2919 )
2921 self.api.delete(diff_user_context, share)
2923 def test_delete_wrong_status(self):
2924 share = fakes.fake_share(status='wrongstatus')
2925 self.mock_object(db_api, 'share_get', mock.Mock(return_value=share))
2926 self.assertRaises(exception.InvalidShare, self.api.delete,
2927 self.context, share)
2929 def test_delete_share_has_replicas(self):
2930 share = self._setup_delete_mocks(constants.STATUS_AVAILABLE,
2931 replication_type='writable')
2932 db_utils.create_share_replica(share_id=share['id'],
2933 replica_state='in_sync')
2934 db_utils.create_share_replica(share_id=share['id'],
2935 replica_state='out_of_sync')
2937 self.assertRaises(exception.Conflict, self.api.delete,
2938 self.context, share)
2940 @mock.patch.object(db_api, 'count_share_group_snapshot_members_in_share',
2941 mock.Mock(return_value=2))
2942 def test_delete_dependent_share_group_snapshot_members(self):
2943 share_server_id = 'fake-ss-id'
2944 share = self._setup_delete_mocks(constants.STATUS_AVAILABLE,
2945 share_server_id)
2947 self.assertRaises(exception.InvalidShare, self.api.delete,
2948 self.context, share)
2950 @mock.patch.object(db_api, 'share_instance_delete', mock.Mock())
2951 def test_delete_no_host(self):
2952 share = self._setup_delete_mocks(constants.STATUS_AVAILABLE, host=None)
2954 self.api.delete(self.context, share)
2955 db_api.share_instance_delete.assert_called_once_with(
2956 utils.IsAMatcher(context.RequestContext), share.instance['id'],
2957 need_to_update_usages=True)
2959 def test_delete_share_with_snapshots(self):
2960 share = self._setup_delete_mocks(constants.STATUS_AVAILABLE,
2961 snapshots=['fake'])
2963 self.assertRaises(
2964 exception.InvalidShare,
2965 self.api.delete,
2966 self.context,
2967 share
2968 )
2970 def test_delete_share_invalid_task_state(self):
2971 share = db_utils.create_share(
2972 status=constants.STATUS_AVAILABLE,
2973 task_state=constants.TASK_STATE_MIGRATION_IN_PROGRESS)
2975 self.assertRaises(exception.ShareBusyException,
2976 self.api.delete,
2977 self.context, share)
2979 def test_delete_share_quota_error(self):
2980 share = self._setup_delete_mocks(constants.STATUS_AVAILABLE)
2981 self.mock_object(quota.QUOTAS, 'reserve',
2982 mock.Mock(side_effect=exception.QuotaError('fake')))
2984 self.api.delete(self.context, share)
2986 def test_delete_locked_share(self):
2987 self.mock_object(
2988 self.api.db,
2989 'resource_lock_get_all',
2990 mock.Mock(return_value=([{'id': 'l1'}, {'id': 'l2'}], None))
2991 )
2992 share = self._setup_delete_mocks('available')
2994 self.assertRaises(exception.InvalidShare,
2995 self.api.delete,
2996 self.context,
2997 share)
2999 # lock check decorator executed first, nothing else is invoked
3000 self.api.delete_instance.assert_not_called()
3001 db_api.share_snapshot_get_all_for_share.assert_not_called()
3003 @ddt.data({'status': constants.STATUS_AVAILABLE, 'force': False},
3004 {'status': constants.STATUS_ERROR, 'force': True})
3005 @ddt.unpack
3006 def test_delete_share_instance(self, status, force):
3007 instance = self._setup_delete_share_instance_mocks(
3008 status=status, share_server_id='fake')
3010 self.api.delete_instance(self.context, instance, force=force)
3012 db_api.share_instance_update.assert_called_once_with(
3013 self.context,
3014 instance['id'],
3015 {'status': constants.STATUS_DELETING,
3016 'terminated_at': self.dt_utc}
3017 )
3018 self.api.share_rpcapi.delete_share_instance.\
3019 assert_called_once_with(
3020 self.context,
3021 instance,
3022 force=force,
3023 deferred_delete=False
3024 )
3025 db_api.share_server_update(
3026 self.context,
3027 instance['share_server_id'],
3028 {'updated_at': self.dt_utc}
3029 )
3031 @ddt.data({'status': constants.STATUS_DEFERRED_DELETING, 'force': True},
3032 {'status': constants.STATUS_AVAILABLE, 'force': False},
3033 {'status': constants.STATUS_AVAILABLE, 'force': True})
3034 @ddt.unpack
3035 def test_delete_share_instance_deferred(self, status, force):
3036 CONF.set_default("is_deferred_deletion_enabled", True)
3037 instance = self._setup_delete_share_instance_mocks(
3038 status=status, share_server_id='fake')
3040 self.api.delete_instance(self.context, instance, force=force)
3041 if force:
3042 if status != constants.STATUS_DEFERRED_DELETING:
3043 db_api.share_instance_update.assert_called_once_with(
3044 self.context,
3045 instance['id'],
3046 {'status': constants.STATUS_DELETING,
3047 'terminated_at': self.dt_utc}
3048 )
3049 self.api.share_rpcapi.delete_share_instance.\
3050 assert_called_once_with(
3051 self.context,
3052 instance,
3053 force=True,
3054 deferred_delete=False
3055 )
3056 else:
3057 db_api.share_instance_update.assert_called_once_with(
3058 self.context,
3059 instance['id'],
3060 {'status': constants.STATUS_DEFERRED_DELETING,
3061 'terminated_at': self.dt_utc}
3062 )
3063 self.api.share_rpcapi.delete_share_instance.\
3064 assert_called_once_with(
3065 self.context,
3066 instance,
3067 force=False,
3068 deferred_delete=True
3069 )
3070 db_api.share_server_update(
3071 self.context,
3072 instance['share_server_id'],
3073 {'updated_at': self.dt_utc}
3074 )
3076 def test_delete_share_instance_invalid_status(self):
3077 instance = self._setup_delete_share_instance_mocks(
3078 status=constants.STATUS_CREATING, share_server_id='fake')
3080 self.assertRaises(
3081 exception.InvalidShareInstance,
3082 self.api.delete_instance,
3083 self.context,
3084 instance
3085 )
3087 def test_get(self):
3088 share = db_utils.create_share()
3089 with mock.patch.object(db_api, 'share_get',
3090 mock.Mock(return_value=share)):
3091 result = self.api.get(self.context, 'fakeid')
3092 self.assertEqual(share, result)
3093 share_api.policy.check_policy.assert_called_once_with(
3094 self.context, 'share', 'get', share, do_raise=False)
3095 db_api.share_get.assert_called_once_with(
3096 self.context, 'fakeid')
3098 def test_get_admin_deferred_state(self):
3099 rv = {
3100 'id': 'fake_id',
3101 'is_public': False,
3102 'name': 'bar',
3103 'status': constants.STATUS_ERROR_DEFERRED_DELETING,
3104 'project_id': 'fake_pid_2',
3105 'share_server_id': 'fake_server_3',
3106 }
3108 self.mock_object(db_api, 'share_get',
3109 mock.Mock(return_value=rv))
3110 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=True)
3111 self.mock_object(
3112 policy, 'check_policy', mock.Mock(side_effect=[True, True]))
3113 share = self.api.get(ctx, 'fake_id')
3114 self.assertEqual(rv, share)
3116 def test_get_non_admin_deferred_state(self):
3117 rv = {
3118 'id': 'fake_id',
3119 'is_public': False,
3120 'name': 'bar',
3121 'status': constants.STATUS_ERROR_DEFERRED_DELETING,
3122 'project_id': 'fake_pid_2',
3123 'share_server_id': 'fake_server_3',
3124 }
3126 self.mock_object(db_api, 'share_get',
3127 mock.Mock(return_value=rv))
3128 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
3129 self.mock_object(
3130 policy, 'check_policy', mock.Mock(side_effect=[True, False]))
3132 self.assertRaises(
3133 exception.NotFound,
3134 self.api.get, ctx, 'fake_id')
3136 def test_get_not_authorized(self):
3137 share = db_utils.create_share(
3138 is_public=False,
3139 project_id='5db325fc4de14fe1a860ff69f190c78c')
3140 share_api.policy.check_policy.return_value = False
3141 ctx = context.RequestContext('df6d65cc1f8946ba86be06b8140ec4b3',
3142 'e8133457b853436591a7e4610e7ce679',
3143 is_admin=False)
3144 with mock.patch.object(db_api, 'share_get',
3145 mock.Mock(return_value=share)):
3147 self.assertRaises(exception.NotFound,
3148 self.api.get,
3149 ctx,
3150 share['id'])
3151 share_api.policy.check_policy.assert_called_once_with(
3152 ctx, 'share', 'get', share, do_raise=False)
3153 db_api.share_get.assert_called_once_with(ctx, share['id'])
3155 @mock.patch.object(db_api, 'share_snapshot_get_all_by_project',
3156 mock.Mock())
3157 def test_get_all_snapshots_admin_not_all_tenants(self):
3158 ctx = context.RequestContext('fakeuid', 'fakepid', is_admin=True)
3159 mock_policy = self.mock_object(share_api.policy, 'check_policy',
3160 mock.Mock(return_value=False))
3161 self.api.get_all_snapshots(ctx)
3162 mock_policy.assert_has_calls([
3163 mock.call(ctx, 'share_snapshot', 'get_all_snapshots'),
3164 mock.call(
3165 ctx, 'share_snapshot',
3166 'list_snapshots_in_deferred_deletion_states',
3167 do_raise=False)])
3168 db_api.share_snapshot_get_all_by_project.assert_called_once_with(
3169 ctx, 'fakepid', limit=None, offset=None, sort_dir='desc',
3170 sort_key='share_id', filters={})
3172 @mock.patch.object(db_api, 'share_snapshot_get_all', mock.Mock())
3173 def test_get_all_snapshots_admin_all_tenants(self):
3174 mock_policy = self.mock_object(
3175 share_api.policy, 'check_policy',
3176 mock.Mock(side_effect=[False, True, False]))
3177 self.api.get_all_snapshots(self.context,
3178 search_opts={'all_tenants': 1})
3179 mock_policy.assert_has_calls([
3180 mock.call(self.context, 'share_snapshot', 'get_all_snapshots'),
3181 mock.call(
3182 self.context, 'share_snapshot',
3183 'list_all_projects',
3184 do_raise=False),
3185 mock.call(
3186 self.context, 'share_snapshot',
3187 'list_snapshots_in_deferred_deletion_states',
3188 do_raise=False)])
3189 db_api.share_snapshot_get_all.assert_called_once_with(
3190 self.context, limit=None, offset=None, sort_dir='desc',
3191 sort_key='share_id', filters={})
3193 @mock.patch.object(db_api, 'share_snapshot_get_all_by_project',
3194 mock.Mock())
3195 def test_get_all_snapshots_not_admin(self):
3196 ctx = context.RequestContext('fakeuid', 'fakepid', is_admin=False)
3197 mock_policy = self.mock_object(share_api.policy, 'check_policy',
3198 mock.Mock(return_value=False))
3199 self.api.get_all_snapshots(ctx)
3200 mock_policy.assert_has_calls([
3201 mock.call(ctx, 'share_snapshot', 'get_all_snapshots'),
3202 mock.call(
3203 ctx, 'share_snapshot',
3204 'list_snapshots_in_deferred_deletion_states',
3205 do_raise=False)])
3206 db_api.share_snapshot_get_all_by_project.assert_called_once_with(
3207 ctx, 'fakepid', limit=None, offset=None, sort_dir='desc',
3208 sort_key='share_id', filters={})
3210 def test_get_all_snapshots_not_admin_search_opts(self):
3211 search_opts = {'size': 'fakesize'}
3212 fake_objs = [{'name': 'fakename1'}, search_opts]
3213 ctx = context.RequestContext('fakeuid', 'fakepid', is_admin=False)
3214 self.mock_object(db_api, 'share_snapshot_get_all_by_project',
3215 mock.Mock(return_value=fake_objs))
3216 mock_policy = self.mock_object(share_api.policy, 'check_policy',
3217 mock.Mock(return_value=False))
3219 result = self.api.get_all_snapshots(ctx, search_opts)
3221 self.assertEqual(fake_objs, result)
3222 mock_policy.assert_has_calls([
3223 mock.call(ctx, 'share_snapshot', 'get_all_snapshots'),
3224 mock.call(
3225 ctx, 'share_snapshot',
3226 'list_snapshots_in_deferred_deletion_states',
3227 do_raise=False)])
3228 db_api.share_snapshot_get_all_by_project.assert_called_once_with(
3229 ctx, 'fakepid', limit=None, offset=None, sort_dir='desc',
3230 sort_key='share_id', filters=search_opts)
3232 @ddt.data(({'name': 'fo'}, 0, []), ({'description': 'd'}, 0, []),
3233 ({'name': 'foo', 'description': 'd'}, 0, []),
3234 ({'name': 'foo'}, 1, [{'name': 'foo', 'description': 'ds'}]),
3235 ({'description': 'ds'}, 1, [{'name': 'foo',
3236 'description': 'ds'}]),
3237 ({'name~': 'foo', 'description~': 'ds'}, 2,
3238 [{'name': 'foo', 'description': 'ds'},
3239 {'name': 'foo1', 'description': 'ds1'}]),
3240 ({'name': 'foo', 'description~': 'ds'}, 1,
3241 [{'name': 'foo', 'description': 'ds'}]),
3242 ({'name~': 'foo', 'description': 'ds'}, 1,
3243 [{'name': 'foo', 'description': 'ds'}]))
3244 @ddt.unpack
3245 def test_get_all_snapshots_filter_by_name_and_description(
3246 self, search_opts, get_snapshot_number, res_snapshots):
3247 fake_objs = [{'name': 'fo2', 'description': 'd2'},
3248 {'name': 'foo', 'description': 'ds'},
3249 {'name': 'foo1', 'description': 'ds1'}]
3250 ctx = context.RequestContext('fakeuid', 'fakepid', is_admin=False)
3251 self.mock_object(db_api, 'share_snapshot_get_all_by_project',
3252 mock.Mock(return_value=res_snapshots))
3253 mock_policy = self.mock_object(share_api.policy, 'check_policy')
3255 result = self.api.get_all_snapshots(ctx, search_opts)
3257 self.assertEqual(get_snapshot_number, len(result))
3258 if get_snapshot_number == 2:
3259 self.assertEqual(fake_objs[1:], result)
3260 elif get_snapshot_number == 1:
3261 self.assertEqual(fake_objs[1:2], result)
3263 mock_policy.assert_has_calls([
3264 mock.call(ctx, 'share_snapshot', 'get_all_snapshots'),
3265 mock.call(
3266 ctx, 'share_snapshot',
3267 'list_snapshots_in_deferred_deletion_states',
3268 do_raise=False)])
3269 db_api.share_snapshot_get_all_by_project.assert_called_once_with(
3270 ctx, 'fakepid', limit=None, offset=None, sort_dir='desc',
3271 sort_key='share_id', filters=search_opts)
3273 def test_get_all_snapshots_with_sorting_valid(self):
3274 self.mock_object(
3275 db_api, 'share_snapshot_get_all_by_project',
3276 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SNAPSHOTS[0]))
3277 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
3278 mock_policy = self.mock_object(share_api.policy, 'check_policy',
3279 mock.Mock(return_value=False))
3280 snapshots = self.api.get_all_snapshots(
3281 ctx, sort_key='status', sort_dir='asc')
3282 mock_policy.assert_has_calls([
3283 mock.call(ctx, 'share_snapshot', 'get_all_snapshots'),
3284 mock.call(
3285 ctx, 'share_snapshot',
3286 'list_snapshots_in_deferred_deletion_states',
3287 do_raise=False)])
3289 db_api.share_snapshot_get_all_by_project.assert_called_once_with(
3290 ctx, 'fake_pid_1', limit=None, offset=None, sort_dir='asc',
3291 sort_key='status', filters={})
3292 self.assertEqual(_FAKE_LIST_OF_ALL_SNAPSHOTS[0], snapshots)
3294 def test_get_all_snapshots_sort_key_invalid(self):
3295 self.mock_object(
3296 db_api, 'share_snapshot_get_all_by_project',
3297 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SNAPSHOTS[0]))
3298 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
3299 self.assertRaises(
3300 exception.InvalidInput,
3301 self.api.get_all_snapshots,
3302 ctx,
3303 sort_key=1,
3304 )
3305 share_api.policy.check_policy.assert_called_once_with(
3306 ctx, 'share_snapshot', 'get_all_snapshots')
3308 def test_get_all_snapshots_sort_dir_invalid(self):
3309 self.mock_object(
3310 db_api, 'share_snapshot_get_all_by_project',
3311 mock.Mock(return_value=_FAKE_LIST_OF_ALL_SNAPSHOTS[0]))
3312 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
3313 self.assertRaises(
3314 exception.InvalidInput,
3315 self.api.get_all_snapshots,
3316 ctx,
3317 sort_dir=1,
3318 )
3319 share_api.policy.check_policy.assert_called_once_with(
3320 ctx, 'share_snapshot', 'get_all_snapshots')
3322 def test_allow_access_rule_already_exists(self):
3323 share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
3324 fake_access = db_utils.create_access(share_id=share['id'])
3325 self.mock_object(self.api.db, 'share_access_create')
3327 self.assertRaises(
3328 exception.ShareAccessExists, self.api.allow_access,
3329 self.context, share, fake_access['access_type'],
3330 fake_access['access_to'], fake_access['access_level'])
3331 self.assertFalse(self.api.db.share_access_create.called)
3333 def test_allow_access_invalid_access_level(self):
3334 share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
3335 self.mock_object(self.api.db, 'share_access_create')
3337 self.assertRaises(
3338 exception.InvalidShareAccess, self.api.allow_access,
3339 self.context, share, 'user', 'alice', access_level='execute')
3340 self.assertFalse(self.api.db.share_access_create.called)
3342 @ddt.data({'host': None},
3343 {'status': constants.STATUS_ERROR_DELETING,
3344 'access_rules_status': constants.STATUS_ACTIVE},
3345 {'host': None, 'access_rules_status': constants.STATUS_ERROR},
3346 {'access_rules_status': constants.STATUS_ERROR})
3347 def test_allow_access_invalid_instance(self, params):
3348 share = db_utils.create_share(host='fake')
3349 db_utils.create_share_instance(share_id=share['id'])
3350 db_utils.create_share_instance(share_id=share['id'], **params)
3351 self.mock_object(self.api.db, 'share_access_create')
3353 self.assertRaises(exception.InvalidShare, self.api.allow_access,
3354 self.context, share, 'ip', '10.0.0.1')
3355 self.assertFalse(self.api.db.share_access_create.called)
3357 @ddt.data(*(constants.ACCESS_LEVELS + (None,)))
3358 def test_allow_access(self, level):
3359 share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
3360 values = {
3361 'share_id': share['id'],
3362 'access_type': 'fake_access_type',
3363 'access_to': 'fake_access_to',
3364 'access_level': level,
3365 'metadata': None,
3366 }
3367 fake_access = copy.deepcopy(values)
3368 fake_access.update({
3369 'id': 'fake_access_id',
3370 'state': constants.STATUS_ACTIVE,
3371 'deleted': 'fake_deleted',
3372 'deleted_at': 'fake_deleted_at',
3373 'instance_mappings': ['foo', 'bar'],
3374 })
3375 self.mock_object(db_api, 'share_get',
3376 mock.Mock(return_value=share))
3377 self.mock_object(db_api, 'share_access_create',
3378 mock.Mock(return_value=fake_access))
3379 self.mock_object(db_api, 'share_access_get',
3380 mock.Mock(return_value=fake_access))
3381 self.mock_object(db_api, 'share_access_get_all_by_type_and_access',
3382 mock.Mock(return_value=[]))
3383 self.mock_object(self.api, 'allow_access_to_instance')
3385 access = self.api.allow_access(
3386 self.context, share, fake_access['access_type'],
3387 fake_access['access_to'], level)
3389 self.assertEqual(fake_access, access)
3390 db_api.share_access_create.assert_called_once_with(
3391 self.context, values)
3392 self.api.allow_access_to_instance.assert_called_once_with(
3393 self.context, share.instance)
3395 def test_allow_access_to_instance(self):
3396 share = db_utils.create_share(host='fake')
3397 rpc_method = self.mock_object(self.api.share_rpcapi, 'update_access')
3399 self.api.allow_access_to_instance(self.context, share.instance)
3401 rpc_method.assert_called_once_with(self.context, share.instance)
3403 @ddt.data({'host': None},
3404 {'status': constants.STATUS_ERROR_DELETING,
3405 'access_rules_status': constants.STATUS_ACTIVE},
3406 {'host': None, 'access_rules_status': constants.STATUS_ERROR},
3407 {'access_rules_status': constants.STATUS_ERROR})
3408 def test_deny_access_invalid_instance(self, params):
3409 share = db_utils.create_share(host='fake')
3410 db_utils.create_share_instance(share_id=share['id'])
3411 db_utils.create_share_instance(share_id=share['id'], **params)
3412 access_rule = db_utils.create_access(share_id=share['id'])
3413 self.mock_object(self.api, 'deny_access_to_instance')
3415 self.assertRaises(exception.InvalidShare, self.api.deny_access,
3416 self.context, share, access_rule)
3417 self.assertFalse(self.api.deny_access_to_instance.called)
3419 def test_deny_access(self):
3420 share = db_utils.create_share(
3421 host='fake', status=constants.STATUS_AVAILABLE,
3422 access_rules_status=constants.STATUS_ACTIVE)
3423 access_rule = db_utils.create_access(share_id=share['id'])
3424 self.mock_object(self.api, 'deny_access_to_instance')
3426 retval = self.api.deny_access(self.context, share, access_rule)
3428 self.assertIsNone(retval)
3429 self.api.deny_access_to_instance.assert_called_once_with(
3430 self.context, share.instance, access_rule)
3432 def test_deny_access_to_instance(self):
3433 share = db_utils.create_share(host='fake')
3434 share_instance = db_utils.create_share_instance(
3435 share_id=share['id'], host='fake')
3436 access = db_utils.create_access(share_id=share['id'])
3437 rpc_method = self.mock_object(self.api.share_rpcapi, 'update_access')
3438 self.mock_object(db_api, 'share_instance_access_get',
3439 mock.Mock(return_value=access.instance_mappings[0]))
3440 mock_share_instance_rules_status_update = self.mock_object(
3441 self.api.access_helper,
3442 'get_and_update_share_instance_access_rules_status')
3443 mock_access_rule_state_update = self.mock_object(
3444 self.api.access_helper,
3445 'get_and_update_share_instance_access_rule')
3447 self.api.deny_access_to_instance(self.context, share_instance, access)
3449 rpc_method.assert_called_once_with(self.context, share_instance)
3450 mock_access_rule_state_update.assert_called_once_with(
3451 self.context, access['id'],
3452 updates={'state': constants.ACCESS_STATE_QUEUED_TO_DENY},
3453 share_instance_id=share_instance['id'])
3454 expected_conditional_change = {
3455 constants.STATUS_ACTIVE: constants.SHARE_INSTANCE_RULES_SYNCING,
3456 }
3457 mock_share_instance_rules_status_update.assert_called_once_with(
3458 self.context, share_instance_id=share_instance['id'],
3459 conditionally_change=expected_conditional_change)
3461 def test_access_get(self):
3462 with mock.patch.object(db_api, 'share_access_get',
3463 mock.Mock(return_value={'share_id': 'fake'})):
3464 self.mock_object(self.api, 'get')
3465 rule = self.api.access_get(self.context, 'fakeid')
3466 self.assertEqual({'share_id': 'fake'}, rule)
3467 db_api.share_access_get.assert_called_once_with(
3468 self.context, 'fakeid')
3469 self.api.get.assert_called_once_with(self.context, 'fake')
3471 def test_access_get_all(self):
3472 share = db_utils.create_share(id='fakeid')
3474 values = {
3475 'fakeacc0id': {
3476 'id': 'fakeacc0id',
3477 'access_type': 'fakeacctype',
3478 'access_to': 'fakeaccto',
3479 'access_level': 'rw',
3480 'share_id': share['id'],
3481 },
3482 'fakeacc1id': {
3483 'id': 'fakeacc1id',
3484 'access_type': 'fakeacctype',
3485 'access_to': 'fakeaccto',
3486 'access_level': 'rw',
3487 'share_id': share['id'],
3488 },
3489 }
3490 rules = [
3491 db_utils.create_access(**values['fakeacc0id']),
3492 db_utils.create_access(**values['fakeacc1id']),
3493 ]
3495 # add state property
3496 values['fakeacc0id']['state'] = constants.STATUS_ACTIVE
3497 values['fakeacc1id']['state'] = constants.STATUS_ACTIVE
3499 self.mock_object(db_api, 'share_access_get_all_for_share',
3500 mock.Mock(return_value=rules))
3501 actual = self.api.access_get_all(self.context, share)
3503 self.assertEqual(rules, actual)
3504 share_api.policy.check_policy.assert_called_once_with(
3505 self.context, 'share', 'access_get_all')
3506 db_api.share_access_get_all_for_share.assert_called_once_with(
3507 self.context, 'fakeid', filters=None)
3509 def test_share_metadata_get(self):
3510 metadata = {'a': 'b', 'c': 'd'}
3511 share_id = uuidutils.generate_uuid()
3512 db_api.share_create(self.context,
3513 {'id': share_id, 'metadata': metadata})
3514 self.assertEqual(metadata,
3515 db_api.share_metadata_get(self.context, share_id))
3517 def test_share_metadata_update(self):
3518 metadata1 = {'a': '1', 'c': '2'}
3519 metadata2 = {'a': '3', 'd': '5'}
3520 should_be = {'a': '3', 'c': '2', 'd': '5'}
3521 share_id = uuidutils.generate_uuid()
3522 db_api.share_create(self.context,
3523 {'id': share_id, 'metadata': metadata1})
3524 db_api.share_metadata_update(self.context, share_id, metadata2, False)
3525 self.assertEqual(should_be,
3526 db_api.share_metadata_get(self.context, share_id))
3528 def test_share_metadata_update_delete(self):
3529 metadata1 = {'a': '1', 'c': '2'}
3530 metadata2 = {'a': '3', 'd': '4'}
3531 should_be = metadata2
3532 share_id = uuidutils.generate_uuid()
3533 db_api.share_create(self.context,
3534 {'id': share_id, 'metadata': metadata1})
3535 db_api.share_metadata_update(self.context, share_id, metadata2, True)
3536 self.assertEqual(should_be,
3537 db_api.share_metadata_get(self.context, share_id))
3539 def test_extend_invalid_status(self):
3540 invalid_status = 'fake'
3541 share = db_utils.create_share(status=invalid_status)
3542 new_size = 123
3544 self.assertRaises(exception.InvalidShare,
3545 self.api.extend, self.context, share, new_size)
3547 def test_extend_invalid_task_state(self):
3548 share = db_utils.create_share(
3549 status=constants.STATUS_AVAILABLE,
3550 task_state=constants.TASK_STATE_MIGRATION_IN_PROGRESS)
3551 new_size = 123
3553 self.assertRaises(exception.ShareBusyException,
3554 self.api.extend, self.context, share, new_size)
3556 def test_extend_invalid_size(self):
3557 share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
3558 size=200)
3559 new_size = 123
3561 self.assertRaises(exception.InvalidInput,
3562 self.api.extend, self.context, share, new_size)
3564 def test_extend_share_over_per_share_quota(self):
3565 quota.CONF.set_default("per_share_gigabytes", 5, 'quota')
3566 share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
3567 size=4)
3568 new_size = 6
3569 self.assertRaises(exception.ShareSizeExceedsLimit,
3570 self.api.extend, self.context, share, new_size)
3572 def test_extend_with_share_type_size_limit(self):
3573 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=False)
3574 share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
3575 size=3)
3576 self.mock_object(share_types, 'get_share_type',
3577 mock.Mock(return_value=self.sized_sha_type))
3578 self.mock_policy_check = self.mock_object(
3579 policy, 'check_policy', mock.Mock(return_value=False))
3581 new_size = 5
3583 self.assertRaises(exception.InvalidInput,
3584 self.api.extend, ctx,
3585 share, new_size)
3587 def test_extend_with_share_type_size_limit_admin(self):
3588 ctx = context.RequestContext('fake_uid', 'fake_pid_1', is_admin=True)
3589 share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
3590 size=3)
3591 self.mock_object(share_types, 'get_share_type',
3592 mock.Mock(return_value=self.sized_sha_type))
3593 self.mock_policy_check = self.mock_object(
3594 policy, 'check_policy', mock.Mock(return_value=True))
3596 new_size = 7
3598 self.assertRaises(exception.InvalidInput,
3599 self.api.extend, ctx,
3600 share, new_size)
3602 def _setup_extend_mocks(self, supports_replication):
3603 replica_list = []
3604 if supports_replication:
3605 replica_list.append({'id': 'fake_replica_id'})
3606 replica_list.append({'id': 'fake_replica_id_2'})
3607 self.mock_object(db_api, 'share_replicas_get_all_by_share',
3608 mock.Mock(return_value=replica_list))
3610 @ddt.data(
3611 (False, 'gigabytes', exception.ShareSizeExceedsAvailableQuota),
3612 (True, 'replica_gigabytes',
3613 exception.ShareReplicaSizeExceedsAvailableQuota)
3614 )
3615 @ddt.unpack
3616 def test_extend_quota_error(self, supports_replication, quota_key,
3617 expected_exception):
3618 self._setup_extend_mocks(supports_replication)
3619 share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
3620 size=100)
3621 new_size = 123
3622 replica_amount = len(
3623 db_api.share_replicas_get_all_by_share.return_value)
3624 value_to_be_extended = new_size - share['size']
3625 usages = {quota_key: {'reserved': 11, 'in_use': 12}}
3626 quotas = {quota_key: 13}
3627 overs = {quota_key: new_size}
3628 exc = exception.OverQuota(usages=usages, quotas=quotas, overs=overs)
3629 expected_deltas = {
3630 'project_id': share['project_id'],
3631 'gigabytes': value_to_be_extended,
3632 'user_id': share['user_id'],
3633 'share_type_id': share['instance']['share_type_id']
3634 }
3635 if supports_replication:
3636 expected_deltas.update(
3637 {'replica_gigabytes': value_to_be_extended * replica_amount})
3638 self.mock_object(quota.QUOTAS, 'reserve', mock.Mock(side_effect=exc))
3640 self.assertRaises(expected_exception,
3641 self.api.extend, self.context, share, new_size)
3642 quota.QUOTAS.reserve.assert_called_once_with(
3643 mock.ANY, **expected_deltas
3644 )
3646 def test_extend_quota_user(self):
3647 self._setup_extend_mocks(False)
3648 share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
3649 size=100)
3650 diff_user_context = context.RequestContext(
3651 user_id='fake2',
3652 project_id='fake',
3653 is_admin=False
3654 )
3655 fake_type = {
3656 'id': 'fake_type_id',
3657 'extra_specs': {
3658 'snapshot_support': False,
3659 'create_share_from_snapshot_support': False,
3660 'driver_handles_share_servers': False,
3661 },
3662 }
3663 new_size = 123
3664 size_increase = int(new_size) - share['size']
3665 self.mock_object(quota.QUOTAS, 'reserve')
3666 self.mock_object(share_types, 'get_share_type',
3667 mock.Mock(return_value=fake_type))
3669 self.api.extend(diff_user_context, share, new_size)
3671 quota.QUOTAS.reserve.assert_called_once_with(
3672 diff_user_context,
3673 project_id=share['project_id'],
3674 gigabytes=size_increase,
3675 share_type_id=None,
3676 user_id=share['user_id']
3677 )
3679 @ddt.data(True, False)
3680 def test_extend_valid(self, supports_replication):
3681 self._setup_extend_mocks(supports_replication)
3682 share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
3683 size=100)
3684 new_size = 123
3685 size_increase = int(new_size) - share['size']
3686 replica_amount = len(
3687 db_api.share_replicas_get_all_by_share.return_value)
3689 expected_deltas = {
3690 'project_id': share['project_id'],
3691 'gigabytes': size_increase,
3692 'user_id': share['user_id'],
3693 'share_type_id': share['instance']['share_type_id']
3694 }
3695 if supports_replication:
3696 new_replica_size = size_increase * replica_amount
3697 expected_deltas.update({'replica_gigabytes': new_replica_size})
3698 self.mock_object(self.api, 'update')
3699 self.mock_object(self.api.scheduler_rpcapi, 'extend_share')
3700 self.mock_object(quota.QUOTAS, 'reserve')
3701 self.mock_object(share_types, 'get_share_type')
3702 self.mock_object(share_types, 'provision_filter_on_size')
3703 self.mock_object(self.api, '_get_request_spec_dict')
3705 self.api.extend(self.context, share, new_size)
3707 self.api.update.assert_called_once_with(
3708 self.context, share, {'status': constants.STATUS_EXTENDING})
3710 self.api.scheduler_rpcapi.extend_share.assert_called_once_with(
3711 self.context, share['id'], new_size, mock.ANY, mock.ANY
3712 )
3713 quota.QUOTAS.reserve.assert_called_once_with(
3714 self.context, **expected_deltas)
3716 def test_shrink_invalid_status(self):
3717 invalid_status = 'fake'
3718 share = db_utils.create_share(status=invalid_status)
3720 self.assertRaises(exception.InvalidShare,
3721 self.api.shrink, self.context, share, 123)
3723 def test_shrink_invalid_task_state(self):
3724 share = db_utils.create_share(
3725 status=constants.STATUS_AVAILABLE,
3726 task_state=constants.TASK_STATE_MIGRATION_IN_PROGRESS)
3728 self.assertRaises(exception.ShareBusyException,
3729 self.api.shrink, self.context, share, 123)
3731 @ddt.data(300, 0, -1)
3732 def test_shrink_invalid_size(self, new_size):
3733 share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
3734 size=200)
3736 self.assertRaises(exception.InvalidInput,
3737 self.api.shrink, self.context, share, new_size)
3739 @ddt.data(constants.STATUS_AVAILABLE,
3740 constants.STATUS_SHRINKING_POSSIBLE_DATA_LOSS_ERROR)
3741 def test_shrink_valid(self, share_status):
3742 share = db_utils.create_share(status=share_status, size=100)
3743 new_size = 50
3744 self.mock_object(self.api, 'update')
3745 self.mock_object(self.api.share_rpcapi, 'shrink_share')
3747 self.api.shrink(self.context, share, new_size)
3749 self.api.update.assert_called_once_with(
3750 self.context, share, {'status': constants.STATUS_SHRINKING})
3751 self.api.share_rpcapi.shrink_share.assert_called_once_with(
3752 self.context, share, new_size
3753 )
3755 def test_shrink_with_share_type_size_limit(self):
3756 share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
3757 size=3)
3758 self.mock_object(share_types, 'get_share_type',
3759 mock.Mock(return_value=self.sized_sha_type))
3760 new_size = 1
3762 self.assertRaises(exception.InvalidInput,
3763 self.api.shrink, self.context,
3764 share, new_size)
3766 def test_snapshot_allow_access(self):
3767 access_to = '1.1.1.1'
3768 access_type = 'ip'
3769 share = db_utils.create_share()
3770 snapshot = db_utils.create_snapshot(share_id=share['id'],
3771 status=constants.STATUS_AVAILABLE)
3772 access = db_utils.create_snapshot_access(
3773 share_snapshot_id=snapshot['id'])
3774 values = {'share_snapshot_id': snapshot['id'],
3775 'access_type': access_type,
3776 'access_to': access_to}
3778 existing_access_check = self.mock_object(
3779 db_api, 'share_snapshot_check_for_existing_access',
3780 mock.Mock(return_value=False))
3781 access_create = self.mock_object(
3782 db_api, 'share_snapshot_access_create',
3783 mock.Mock(return_value=access))
3784 self.mock_object(self.api.share_rpcapi, 'snapshot_update_access')
3786 out = self.api.snapshot_allow_access(self.context, snapshot,
3787 access_type, access_to)
3789 self.assertEqual(access, out)
3790 existing_access_check.assert_called_once_with(
3791 utils.IsAMatcher(context.RequestContext), snapshot['id'],
3792 access_type, access_to)
3793 access_create.assert_called_once_with(
3794 utils.IsAMatcher(context.RequestContext), values)
3796 def test_snapshot_allow_access_instance_exception(self):
3797 access_to = '1.1.1.1'
3798 access_type = 'ip'
3799 share = db_utils.create_share()
3800 snapshot = db_utils.create_snapshot(share_id=share['id'])
3801 existing_access_check = self.mock_object(
3802 db_api, 'share_snapshot_check_for_existing_access',
3803 mock.Mock(return_value=False))
3805 self.assertRaises(exception.InvalidShareSnapshotInstance,
3806 self.api.snapshot_allow_access, self.context,
3807 snapshot, access_type, access_to)
3809 existing_access_check.assert_called_once_with(
3810 utils.IsAMatcher(context.RequestContext), snapshot['id'],
3811 access_type, access_to)
3813 def test_snapshot_allow_access_access_exists_exception(self):
3814 access_to = '1.1.1.1'
3815 access_type = 'ip'
3816 share = db_utils.create_share()
3817 snapshot = db_utils.create_snapshot(share_id=share['id'])
3818 db_utils.create_snapshot_access(
3819 share_snapshot_id=snapshot['id'], access_to=access_to,
3820 access_type=access_type)
3822 existing_access_check = self.mock_object(
3823 db_api, 'share_snapshot_check_for_existing_access',
3824 mock.Mock(return_value=True))
3826 self.assertRaises(exception.ShareSnapshotAccessExists,
3827 self.api.snapshot_allow_access, self.context,
3828 snapshot, access_type, access_to)
3830 existing_access_check.assert_called_once_with(
3831 utils.IsAMatcher(context.RequestContext), snapshot['id'],
3832 access_type, access_to)
3834 def test_snapshot_deny_access(self):
3835 share = db_utils.create_share()
3836 snapshot = db_utils.create_snapshot(share_id=share['id'],
3837 status=constants.STATUS_AVAILABLE)
3838 access = db_utils.create_snapshot_access(
3839 share_snapshot_id=snapshot['id'])
3840 mapping = {'id': 'fake_id',
3841 'state': constants.STATUS_ACTIVE,
3842 'access_id': access['id']}
3844 access_get = self.mock_object(
3845 db_api, 'share_snapshot_instance_access_get',
3846 mock.Mock(return_value=mapping))
3847 access_update_state = self.mock_object(
3848 db_api, 'share_snapshot_instance_access_update')
3849 update_access = self.mock_object(self.api.share_rpcapi,
3850 'snapshot_update_access')
3852 self.api.snapshot_deny_access(self.context, snapshot, access)
3854 access_get.assert_called_once_with(
3855 utils.IsAMatcher(context.RequestContext), access['id'],
3856 snapshot['instance']['id'])
3857 access_update_state.assert_called_once_with(
3858 utils.IsAMatcher(context.RequestContext), access['id'],
3859 snapshot.instance['id'],
3860 {'state': constants.ACCESS_STATE_QUEUED_TO_DENY})
3861 update_access.assert_called_once_with(
3862 utils.IsAMatcher(context.RequestContext), snapshot['instance'])
3864 def test_snapshot_deny_access_exception(self):
3865 share = db_utils.create_share()
3866 snapshot = db_utils.create_snapshot(share_id=share['id'])
3867 access = db_utils.create_snapshot_access(
3868 share_snapshot_id=snapshot['id'])
3870 self.assertRaises(exception.InvalidShareSnapshotInstance,
3871 self.api.snapshot_deny_access, self.context,
3872 snapshot, access)
3874 def test_snapshot_access_get_all(self):
3875 share = db_utils.create_share()
3876 snapshot = db_utils.create_snapshot(share_id=share['id'])
3877 access = []
3878 access.append(db_utils.create_snapshot_access(
3879 share_snapshot_id=snapshot['id']))
3881 self.mock_object(
3882 db_api, 'share_snapshot_access_get_all_for_share_snapshot',
3883 mock.Mock(return_value=access))
3885 out = self.api.snapshot_access_get_all(self.context, snapshot)
3887 self.assertEqual(access, out)
3889 def test_snapshot_access_get(self):
3890 share = db_utils.create_share()
3891 snapshot = db_utils.create_snapshot(share_id=share['id'])
3892 access = db_utils.create_snapshot_access(
3893 share_snapshot_id=snapshot['id'])
3895 self.mock_object(
3896 db_api, 'share_snapshot_access_get',
3897 mock.Mock(return_value=access))
3899 out = self.api.snapshot_access_get(self.context, access['id'])
3901 self.assertEqual(access, out)
3903 def test_snapshot_export_locations_get(self):
3904 share = db_utils.create_share()
3905 snapshot = db_utils.create_snapshot(share_id=share['id'])
3907 self.mock_object(
3908 db_api, 'share_snapshot_export_locations_get',
3909 mock.Mock(return_value=''))
3911 out = self.api.snapshot_export_locations_get(self.context, snapshot)
3913 self.assertEqual('', out)
3915 def test_snapshot_export_location_get(self):
3916 fake_el = '/fake_export_location'
3918 self.mock_object(
3919 db_api, 'share_snapshot_instance_export_location_get',
3920 mock.Mock(return_value=fake_el))
3922 out = self.api.snapshot_export_location_get(self.context, 'fake_id')
3924 self.assertEqual(fake_el, out)
3926 @ddt.data(True, False)
3927 def test__modify_quotas_for_share_migration(self, new_replication_type):
3928 extra_specs = (
3929 {'replication_type': 'readable'} if new_replication_type else {})
3930 share = db_utils.create_share()
3931 share_type = db_utils.create_share_type(extra_specs=extra_specs)
3933 expected_deltas = {
3934 'project_id': share['project_id'],
3935 'user_id': share['user_id'],
3936 'shares': 1,
3937 'gigabytes': share['size'],
3938 'share_type_id': share_type['id']
3939 }
3941 if new_replication_type:
3942 expected_deltas.update({
3943 'share_replicas': 1,
3944 'replica_gigabytes': share['size'],
3945 })
3946 reservations = 'reservations'
3948 mock_specs_get = self.mock_object(
3949 self.api, 'get_share_attributes_from_share_type',
3950 mock.Mock(return_value=extra_specs))
3951 mock_reserve = self.mock_object(
3952 quota.QUOTAS, 'reserve', mock.Mock(return_value=reservations))
3953 mock_commit = self.mock_object(quota.QUOTAS, 'commit')
3955 self.api._modify_quotas_for_share_migration(
3956 self.context, share, share_type)
3958 mock_specs_get.assert_called_once_with(share_type)
3959 mock_reserve.assert_called_once_with(
3960 self.context, **expected_deltas)
3961 mock_commit.assert_called_once_with(
3962 self.context, reservations, project_id=share['project_id'],
3963 user_id=share['user_id'], share_type_id=share_type['id'])
3965 @ddt.data(
3966 ('replica_gigabytes', exception.ShareReplicaSizeExceedsAvailableQuota),
3967 ('share_replicas', exception.ShareReplicasLimitExceeded),
3968 ('gigabytes', exception.ShareSizeExceedsAvailableQuota)
3969 )
3970 @ddt.unpack
3971 def test__modify_quotas_for_share_migration_reservation_failed(
3972 self, over_resource, expected_exception):
3973 extra_specs = {'replication_type': 'readable'}
3974 share = db_utils.create_share()
3975 share_type = db_utils.create_share_type(extra_specs=extra_specs)
3976 expected_deltas = {
3977 'project_id': share['project_id'],
3978 'user_id': share['user_id'],
3979 'share_replicas': 1,
3980 'shares': 1,
3981 'gigabytes': share['size'],
3982 'replica_gigabytes': share['size'],
3983 'share_type_id': share_type['id']
3984 }
3985 usages = {
3986 over_resource: {
3987 'reserved': 'fake',
3988 'in_use': 'fake'
3989 }
3990 }
3991 quotas = {
3992 over_resource: 'fake'
3993 }
3995 effect_exc = exception.OverQuota(
3996 overs=[over_resource], usages=usages, quotas=quotas)
3997 mock_specs_get = self.mock_object(
3998 self.api, 'get_share_attributes_from_share_type',
3999 mock.Mock(return_value=extra_specs))
4000 mock_reserve = self.mock_object(
4001 quota.QUOTAS, 'reserve', mock.Mock(side_effect=effect_exc))
4003 self.assertRaises(
4004 expected_exception,
4005 self.api._modify_quotas_for_share_migration,
4006 self.context, share, share_type
4007 )
4009 mock_specs_get.assert_called_once_with(share_type)
4010 mock_reserve.assert_called_once_with(self.context, **expected_deltas)
4012 @ddt.data({'share_type': True, 'share_net': True, 'dhss': True},
4013 {'share_type': False, 'share_net': True, 'dhss': True},
4014 {'share_type': False, 'share_net': False, 'dhss': True},
4015 {'share_type': True, 'share_net': False, 'dhss': False},
4016 {'share_type': False, 'share_net': False, 'dhss': False})
4017 @ddt.unpack
4018 def test_migration_start(self, share_type, share_net, dhss):
4019 host = 'fake2@backend#pool'
4020 service = {'availability_zone_id': 'fake_az_id',
4021 'availability_zone': {'name': 'fake_az1'}}
4022 share_network = None
4023 share_network_id = None
4024 if share_net:
4025 share_network = db_utils.create_share_network(id='fake_net_id')
4026 share_network_id = share_network['id']
4028 fake_type = {
4029 'id': 'fake_type_id',
4030 'extra_specs': {
4031 'snapshot_support': False,
4032 'create_share_from_snapshot_support': False,
4033 'revert_to_snapshot_support': False,
4034 'mount_snapshot_support': False,
4035 'mount_point_name_support': False,
4036 'driver_handles_share_servers': dhss,
4037 },
4038 }
4040 if share_type:
4041 fake_type_2 = {
4042 'id': 'fake_type_2_id',
4043 'extra_specs': {
4044 'snapshot_support': False,
4045 'create_share_from_snapshot_support': False,
4046 'revert_to_snapshot_support': False,
4047 'mount_snapshot_support': False,
4048 'mount_point_name_support': False,
4049 'driver_handles_share_servers': dhss,
4050 'availability_zones': 'fake_az1,fake_az2',
4051 },
4052 }
4053 else:
4054 fake_type_2 = fake_type
4056 share = db_utils.create_share(
4057 status=constants.STATUS_AVAILABLE,
4058 host='fake@backend#pool', share_type_id=fake_type['id'],
4059 share_network_id=share_network_id)
4061 request_spec = self._get_request_spec_dict(
4062 share, fake_type_2, self.context, size=0,
4063 availability_zone_id='fake_az_id',
4064 share_network_id=share_network_id)
4066 self.mock_object(self.scheduler_rpcapi, 'migrate_share_to_host')
4067 self.mock_object(share_types, 'get_share_type',
4068 mock.Mock(return_value=fake_type))
4069 self.mock_object(utils, 'validate_service_host')
4070 self.mock_object(db_api, 'share_instance_update')
4071 self.mock_object(db_api, 'share_update')
4072 self.mock_object(db_api, 'service_get_by_args',
4073 mock.Mock(return_value=service))
4074 self.mock_object(share_api.API, '_modify_quotas_for_share_migration')
4076 if share_type:
4077 self.api.migration_start(self.context, share, host, False, True,
4078 True, True, True, share_network,
4079 fake_type_2)
4080 else:
4081 self.api.migration_start(self.context, share, host, False, True,
4082 True, True, True, share_network, None)
4084 self.scheduler_rpcapi.migrate_share_to_host.assert_called_once_with(
4085 self.context, share['id'], host, False, True, True, True, True,
4086 share_network_id, fake_type_2['id'], request_spec)
4087 if not share_type:
4088 share_types.get_share_type.assert_called_once_with(
4089 self.context, fake_type['id'])
4090 utils.validate_service_host.assert_called_once_with(
4091 self.context, 'fake2@backend')
4092 db_api.service_get_by_args.assert_called_once_with(
4093 self.context, 'fake2@backend', 'manila-share')
4094 db_api.share_update.assert_called_once_with(
4095 self.context, share['id'],
4096 {'task_state': constants.TASK_STATE_MIGRATION_STARTING})
4097 db_api.share_instance_update.assert_called_once_with(
4098 self.context, share.instance['id'],
4099 {'status': constants.STATUS_MIGRATING})
4100 if share_type:
4101 (share_api.API._modify_quotas_for_share_migration.
4102 assert_called_once_with(self.context, share, fake_type_2))
4104 def test_migration_start_with_new_share_type_limit(self):
4105 host = 'fake2@backend#pool'
4106 self.mock_object(utils, 'validate_service_host')
4107 share = db_utils.create_share(
4108 status=constants.STATUS_AVAILABLE,
4109 size=1)
4110 self.assertRaises(exception.InvalidInput,
4111 self.api.migration_start,
4112 self.context,
4113 share, host, False, True,
4114 True, True, True, None,
4115 self.sized_sha_type)
4117 def test_migration_start_destination_az_unsupported(self):
4118 host = 'fake2@backend#pool'
4119 host_without_pool = host.split('#')[0]
4120 service = {'availability_zone_id': 'fake_az_id',
4121 'availability_zone': {'name': 'fake_az3'}}
4122 share_network = db_utils.create_share_network(id='fake_net_id')
4123 share_network_id = share_network['id']
4124 existing_share_type = {
4125 'id': '4b5b0920-a294-401b-bb7d-c55b425e1cad',
4126 'name': 'fake_type_1',
4127 'extra_specs': {
4128 'snapshot_support': False,
4129 'create_share_from_snapshot_support': False,
4130 'revert_to_snapshot_support': False,
4131 'mount_snapshot_support': False,
4132 'mount_point_name_support': False,
4133 'driver_handles_share_servers': 'true',
4134 'availability_zones': 'fake_az3'
4135 },
4136 }
4137 new_share_type = {
4138 'id': 'fa844ae2-494d-4da9-95e7-37ac6a26f635',
4139 'name': 'fake_type_2',
4140 'extra_specs': {
4141 'snapshot_support': False,
4142 'create_share_from_snapshot_support': False,
4143 'revert_to_snapshot_support': False,
4144 'mount_snapshot_support': False,
4145 'mount_point_name_support': False,
4146 'driver_handles_share_servers': 'true',
4147 'availability_zones': 'fake_az1,fake_az2',
4148 },
4149 }
4150 share = db_utils.create_share(
4151 status=constants.STATUS_AVAILABLE,
4152 host='fake@backend#pool', share_type_id=existing_share_type['id'],
4153 share_network_id=share_network_id)
4154 self.mock_object(self.api, '_get_request_spec_dict')
4155 self.mock_object(self.scheduler_rpcapi, 'migrate_share_to_host')
4156 self.mock_object(share_types, 'get_share_type')
4157 self.mock_object(utils, 'validate_service_host')
4158 self.mock_object(db_api, 'share_instance_update')
4159 self.mock_object(db_api, 'share_update')
4160 self.mock_object(db_api, 'service_get_by_args',
4161 mock.Mock(return_value=service))
4162 self.mock_object(share_api.API, '_modify_quotas_for_share_migration')
4164 self.assertRaises(exception.InvalidShare,
4165 self.api.migration_start,
4166 self.context, share, host, False, True, True,
4167 True, False, new_share_network=share_network,
4168 new_share_type=new_share_type)
4169 utils.validate_service_host.assert_called_once_with(
4170 self.context, host_without_pool)
4171 share_types.get_share_type.assert_not_called()
4172 db_api.share_update.assert_not_called()
4173 db_api.service_get_by_args.assert_called_once_with(
4174 self.context, host_without_pool, 'manila-share')
4175 self.api._get_request_spec_dict.assert_not_called()
4176 db_api.share_instance_update.assert_not_called()
4177 self.scheduler_rpcapi.migrate_share_to_host.assert_not_called()
4179 @ddt.data({'force_host_assisted': True, 'writable': True,
4180 'preserve_metadata': False, 'preserve_snapshots': False,
4181 'nondisruptive': False},
4182 {'force_host_assisted': True, 'writable': False,
4183 'preserve_metadata': True, 'preserve_snapshots': False,
4184 'nondisruptive': False},
4185 {'force_host_assisted': True, 'writable': False,
4186 'preserve_metadata': False, 'preserve_snapshots': True,
4187 'nondisruptive': False},
4188 {'force_host_assisted': True, 'writable': False,
4189 'preserve_metadata': False, 'preserve_snapshots': False,
4190 'nondisruptive': True})
4191 @ddt.unpack
4192 def test_migration_start_invalid_host_and_driver_assisted_params(
4193 self, force_host_assisted, writable, preserve_metadata,
4194 preserve_snapshots, nondisruptive):
4196 self.assertRaises(
4197 exception.InvalidInput, self.api.migration_start, self.context,
4198 'some_share', 'some_host', force_host_assisted, preserve_metadata,
4199 writable, preserve_snapshots, nondisruptive)
4201 @ddt.data(True, False)
4202 def test_migration_start_invalid_share_network_type_combo(self, dhss):
4203 host = 'fake2@backend#pool'
4204 share_network = None
4205 if not dhss:
4206 share_network = db_utils.create_share_network(id='fake_net_id')
4208 fake_type = {
4209 'id': 'fake_type_id',
4210 'extra_specs': {
4211 'snapshot_support': False,
4212 'driver_handles_share_servers': not dhss,
4213 },
4214 }
4216 fake_type_2 = {
4217 'id': 'fake_type_2_id',
4218 'extra_specs': {
4219 'snapshot_support': False,
4220 'driver_handles_share_servers': dhss,
4221 },
4222 }
4224 share = db_utils.create_share(
4225 status=constants.STATUS_AVAILABLE,
4226 host='fake@backend#pool', share_type_id=fake_type['id'])
4228 self.mock_object(utils, 'validate_service_host')
4229 self.mock_object(share_api.API, '_modify_quotas_for_share_migration')
4231 self.assertRaises(
4232 exception.InvalidInput, self.api.migration_start, self.context,
4233 share, host, False, True, True, True, True, share_network,
4234 fake_type_2)
4236 utils.validate_service_host.assert_called_once_with(
4237 self.context, 'fake2@backend')
4239 def test_migration_start_status_unavailable(self):
4240 host = 'fake2@backend#pool'
4241 share = db_utils.create_share(
4242 status=constants.STATUS_ERROR)
4244 self.assertRaises(exception.InvalidShare, self.api.migration_start,
4245 self.context, share, host, False, True, True, True,
4246 True)
4248 def test_migration_start_access_rules_status_error(self):
4249 host = 'fake2@backend#pool'
4250 instance = db_utils.create_share_instance(
4251 share_id='fake_share_id',
4252 access_rules_status=constants.STATUS_ERROR,
4253 status=constants.STATUS_AVAILABLE)
4254 share = db_utils.create_share(
4255 id='fake_share_id',
4256 instances=[instance])
4258 self.assertRaises(exception.InvalidShare, self.api.migration_start,
4259 self.context, share, host, False, True, True, True,
4260 True)
4262 def test_migration_start_task_state_invalid(self):
4263 host = 'fake2@backend#pool'
4264 share = db_utils.create_share(
4265 status=constants.STATUS_AVAILABLE,
4266 task_state=constants.TASK_STATE_MIGRATION_IN_PROGRESS)
4268 self.assertRaises(exception.ShareBusyException,
4269 self.api.migration_start,
4270 self.context, share, host, False, True, True, True,
4271 True)
4273 def test_migration_start_host_assisted_with_snapshots(self):
4274 host = 'fake2@backend#pool'
4275 share = db_utils.create_share(
4276 host='fake@backend#pool', status=constants.STATUS_AVAILABLE)
4277 self.mock_object(db_api, 'share_snapshot_get_all_for_share',
4278 mock.Mock(return_value=True))
4280 self.assertRaises(exception.Conflict, self.api.migration_start,
4281 self.context, share, host, True, False, False, False,
4282 False)
4284 def test_migration_start_with_snapshots(self):
4285 host = 'fake2@backend#pool'
4287 fake_type = {
4288 'id': 'fake_type_id',
4289 'extra_specs': {
4290 'snapshot_support': True,
4291 'driver_handles_share_servers': False,
4292 },
4293 }
4295 service = {'availability_zone_id': 'fake_az_id',
4296 'availability_zone': {'name': 'fake_az'}}
4297 self.mock_object(db_api, 'service_get_by_args',
4298 mock.Mock(return_value=service))
4299 self.mock_object(utils, 'validate_service_host')
4300 self.mock_object(share_types, 'get_share_type',
4301 mock.Mock(return_value=fake_type))
4303 share = db_utils.create_share(
4304 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
4305 share_type_id=fake_type['id'])
4307 request_spec = self._get_request_spec_dict(
4308 share, fake_type, self.context, availability_zone_id='fake_az_id')
4310 self.api.migration_start(self.context, share, host, False, True, True,
4311 True, True)
4313 self.scheduler_rpcapi.migrate_share_to_host.assert_called_once_with(
4314 self.context, share['id'], host, False, True, True, True, True,
4315 None, 'fake_type_id', request_spec)
4317 def test_migration_start_has_replicas(self):
4318 host = 'fake2@backend#pool'
4319 share = db_utils.create_share(
4320 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
4321 replication_type='dr')
4322 for i in range(1, 4):
4323 db_utils.create_share_replica(
4324 share_id=share['id'], replica_state='in_sync')
4325 self.mock_object(db_api, 'share_snapshot_get_all_for_share',
4326 mock.Mock(return_value=True))
4327 mock_log = self.mock_object(share_api, 'LOG')
4328 mock_snapshot_get_call = self.mock_object(
4329 db_api, 'share_snapshot_get_all_for_share')
4330 # Share was updated after adding replicas, grabbing it again.
4331 share = db_api.share_get(self.context, share['id'])
4333 self.assertRaises(exception.Conflict, self.api.migration_start,
4334 self.context, share, host, False, True, True, True,
4335 True)
4336 self.assertTrue(mock_log.error.called)
4337 self.assertFalse(mock_snapshot_get_call.called)
4339 def test_migration_start_is_member_of_group(self):
4340 group = db_utils.create_share_group()
4341 share = db_utils.create_share(
4342 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
4343 share_group_id=group['id'])
4344 mock_log = self.mock_object(share_api, 'LOG')
4346 self.assertRaises(exception.InvalidShare, self.api.migration_start,
4347 self.context, share, 'fake_host', False, True, True,
4348 True, True)
4349 self.assertTrue(mock_log.error.called)
4351 def test_migration_start_invalid_host(self):
4352 host = 'fake@backend#pool'
4353 share = db_utils.create_share(
4354 host='fake2@backend', status=constants.STATUS_AVAILABLE)
4356 self.mock_object(db_api, 'share_snapshot_get_all_for_share',
4357 mock.Mock(return_value=False))
4359 self.assertRaises(exception.ServiceNotFound,
4360 self.api.migration_start,
4361 self.context, share, host, False, True, True, True,
4362 True)
4364 @ddt.data({'dhss': True, 'new_share_network_id': 'fake_net_id',
4365 'new_share_type_id': 'fake_type_id'},
4366 {'dhss': False, 'new_share_network_id': None,
4367 'new_share_type_id': 'fake_type_id'},
4368 {'dhss': True, 'new_share_network_id': 'fake_net_id',
4369 'new_share_type_id': None})
4370 @ddt. unpack
4371 def test_migration_start_same_data_as_source(
4372 self, dhss, new_share_network_id, new_share_type_id):
4373 host = 'fake@backend#pool'
4375 fake_type_src = {
4376 'id': 'fake_type_id',
4377 'extra_specs': {
4378 'snapshot_support': True,
4379 'driver_handles_share_servers': True,
4380 },
4381 }
4383 new_share_type_param = None
4384 if new_share_type_id:
4385 new_share_type_param = {
4386 'id': new_share_type_id,
4387 'extra_specs': {
4388 'snapshot_support': True,
4389 'driver_handles_share_servers': dhss,
4390 },
4391 }
4393 new_share_net_param = None
4394 if new_share_network_id:
4395 new_share_net_param = db_utils.create_share_network(
4396 id=new_share_network_id)
4398 share = db_utils.create_share(
4399 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
4400 share_type_id=fake_type_src['id'],
4401 share_network_id=new_share_network_id)
4403 self.mock_object(utils, 'validate_service_host')
4404 self.mock_object(db_api, 'share_update')
4405 self.mock_object(share_types, 'get_share_type',
4406 mock.Mock(return_value=fake_type_src))
4408 result = self.api.migration_start(
4409 self.context, share, host, False, True, True, True, True,
4410 new_share_net_param, new_share_type_param)
4412 self.assertEqual(200, result)
4414 db_api.share_update.assert_called_once_with(
4415 self.context, share['id'],
4416 {'task_state': constants.TASK_STATE_MIGRATION_SUCCESS})
4418 @ddt.data({}, {'replication_type': None})
4419 def test_create_share_replica_invalid_share_type(self, attributes):
4420 share = fakes.fake_share(id='FAKE_SHARE_ID', **attributes)
4421 mock_request_spec_call = self.mock_object(
4422 self.api, 'create_share_instance_and_get_request_spec')
4423 mock_db_update_call = self.mock_object(db_api, 'share_replica_update')
4424 mock_scheduler_rpcapi_call = self.mock_object(
4425 self.api.scheduler_rpcapi, 'create_share_replica')
4427 self.assertRaises(exception.InvalidShare,
4428 self.api.create_share_replica,
4429 self.context, share)
4430 self.assertFalse(mock_request_spec_call.called)
4431 self.assertFalse(mock_db_update_call.called)
4432 self.assertFalse(mock_scheduler_rpcapi_call.called)
4434 def test_create_share_replica_busy_share(self):
4435 share = fakes.fake_share(
4436 id='FAKE_SHARE_ID',
4437 task_state='doing_something_real_important',
4438 is_busy=True,
4439 replication_type='dr')
4440 mock_request_spec_call = self.mock_object(
4441 self.api, 'create_share_instance_and_get_request_spec')
4442 mock_db_update_call = self.mock_object(db_api, 'share_replica_update')
4443 mock_scheduler_rpcapi_call = self.mock_object(
4444 self.api.scheduler_rpcapi, 'create_share_replica')
4446 self.assertRaises(exception.ShareBusyException,
4447 self.api.create_share_replica,
4448 self.context, share)
4449 self.assertFalse(mock_request_spec_call.called)
4450 self.assertFalse(mock_db_update_call.called)
4451 self.assertFalse(mock_scheduler_rpcapi_call.called)
4453 @ddt.data(None, [])
4454 def test_create_share_replica_no_active_replica(self, active_replicas):
4455 share = fakes.fake_share(
4456 id='FAKE_SHARE_ID', replication_type='dr')
4457 mock_request_spec_call = self.mock_object(
4458 self.api, 'create_share_instance_and_get_request_spec')
4459 mock_db_update_call = self.mock_object(db_api, 'share_replica_update')
4460 mock_scheduler_rpcapi_call = self.mock_object(
4461 self.api.scheduler_rpcapi, 'create_share_replica')
4462 self.mock_object(db_api, 'share_replicas_get_available_active_replica',
4463 mock.Mock(return_value=active_replicas))
4465 self.assertRaises(exception.ReplicationException,
4466 self.api.create_share_replica,
4467 self.context, share)
4468 self.assertFalse(mock_request_spec_call.called)
4469 self.assertFalse(mock_db_update_call.called)
4470 self.assertFalse(mock_scheduler_rpcapi_call.called)
4472 @ddt.data(None, 'fake-share-type')
4473 def test_create_share_replica_type_doesnt_support_AZ(self, st_name):
4474 share_type = fakes.fake_share_type(
4475 name=st_name,
4476 extra_specs={'availability_zones': 'zone 1,zone 3'})
4477 share = fakes.fake_share(
4478 id='FAKE_SHARE_ID', replication_type='dr',
4479 availability_zone='zone 2')
4480 share['instance'].update({
4481 'share_type': share_type,
4482 'share_type_id': '359b9851-2bd5-4404-89a9-5cd22bbc5fb9',
4483 })
4484 mock_request_spec_call = self.mock_object(
4485 self.api, 'create_share_instance_and_get_request_spec')
4486 mock_db_update_call = self.mock_object(db_api, 'share_replica_update')
4487 mock_scheduler_rpcapi_call = self.mock_object(
4488 self.api.scheduler_rpcapi, 'create_share_replica')
4489 self.mock_object(share_types, 'get_share_type',
4490 mock.Mock(return_value=share_type))
4491 self.mock_object(db_api, 'share_replicas_get_available_active_replica',
4492 mock.Mock(return_value=mock.Mock(
4493 return_value={'host': 'fake_ar_host'})))
4495 self.assertRaises(exception.InvalidShare,
4496 self.api.create_share_replica,
4497 self.context, share, availability_zone='zone 2')
4498 share_types.get_share_type.assert_called_once_with(
4499 self.context, '359b9851-2bd5-4404-89a9-5cd22bbc5fb9')
4500 self.assertFalse(mock_request_spec_call.called)
4501 self.assertFalse(mock_db_update_call.called)
4502 self.assertFalse(mock_scheduler_rpcapi_call.called)
4504 def test_create_share_replica_subnet_not_found(self):
4505 request_spec = fakes.fake_replica_request_spec()
4506 replica = request_spec['share_instance_properties']
4507 extra_specs = {
4508 'availability_zones': 'FAKE_AZ,FAKE_AZ2',
4509 'replication_type': constants.REPLICATION_TYPE_DR
4510 }
4511 share_type = db_utils.create_share_type(extra_specs=extra_specs)
4512 share_type = db_api.share_type_get(self.context, share_type['id'])
4513 az_name = 'FAKE_AZ'
4514 share = db_utils.create_share(
4515 id=replica['share_id'], replication_type='dr')
4516 self.mock_object(db_api, 'share_replicas_get_available_active_replica',
4517 mock.Mock(return_value=mock.Mock(
4518 return_value={'host': 'fake_ar_host'})))
4519 self.mock_object(share_types, 'get_share_type',
4520 mock.Mock(return_value=share_type))
4521 self.mock_object(db_api, 'availability_zone_get')
4522 self.mock_object(
4523 db_api, 'share_network_subnets_get_all_by_availability_zone_id',
4524 mock.Mock(return_value=None))
4526 self.assertRaises(exception.InvalidShare,
4527 self.api.create_share_replica,
4528 self.context,
4529 share,
4530 availability_zone=az_name,
4531 share_network_id='fake_id')
4532 (db_api.share_replicas_get_available_active_replica
4533 .assert_called_once_with(self.context, share['id']))
4534 self.assertTrue(share_types.get_share_type.called)
4535 db_api.availability_zone_get.assert_called_once_with(
4536 self.context, az_name)
4537 self.assertTrue(
4538 (db_api.share_network_subnets_get_all_by_availability_zone_id.
4539 called))
4541 def test_create_share_replica_az_not_found(self):
4542 request_spec = fakes.fake_replica_request_spec()
4543 replica = request_spec['share_instance_properties']
4544 extra_specs = {
4545 'availability_zones': 'FAKE_AZ,FAKE_AZ2',
4546 'replication_type': constants.REPLICATION_TYPE_DR
4547 }
4548 share_type = db_utils.create_share_type(extra_specs=extra_specs)
4549 share_type = db_api.share_type_get(self.context, share_type['id'])
4550 az_name = 'FAKE_AZ'
4551 share = db_utils.create_share(
4552 id=replica['share_id'], replication_type='dr')
4553 self.mock_object(db_api, 'share_replicas_get_available_active_replica',
4554 mock.Mock(return_value=mock.Mock(
4555 return_value={'host': 'fake_ar_host'})))
4556 self.mock_object(share_types, 'get_share_type',
4557 mock.Mock(return_value=share_type))
4558 side_effect = exception.AvailabilityZoneNotFound(id=az_name)
4559 self.mock_object(db_api, 'availability_zone_get',
4560 mock.Mock(side_effect=side_effect))
4562 self.assertRaises(exception.InvalidInput,
4563 self.api.create_share_replica,
4564 self.context,
4565 share,
4566 availability_zone=az_name,
4567 share_network_id='fake_id')
4568 (db_api.share_replicas_get_available_active_replica
4569 .assert_called_once_with(self.context, share['id']))
4570 self.assertTrue(share_types.get_share_type.called)
4571 db_api.availability_zone_get.assert_called_once_with(
4572 self.context, az_name)
4574 @ddt.data(
4575 {'availability_zones': '', 'compatible_azs_name': ['fake_az_1'],
4576 'compatible_azs_multiple': []},
4577 {'availability_zones': 'fake_az_1,fake_az_2',
4578 'compatible_azs_name': ['fake_az_2'], 'compatible_azs_multiple': []}
4579 )
4580 @ddt.unpack
4581 def test_create_share_replica_azs_with_subnets(self, availability_zones,
4582 compatible_azs_name,
4583 compatible_azs_multiple):
4584 request_spec = fakes.fake_replica_request_spec()
4585 replica = request_spec['share_instance_properties']
4586 share_network_id = 'fake_share_network_id'
4587 extra_specs = {
4588 'availability_zones': availability_zones,
4589 'replication_type': constants.REPLICATION_TYPE_DR
4590 }
4591 share_type = db_utils.create_share_type(extra_specs=extra_specs)
4592 share_type = db_api.share_type_get(self.context, share_type['id'])
4593 share = db_utils.create_share(
4594 id=replica['share_id'], replication_type='dr',
4595 share_type_id=share_type['id'])
4596 cast_rules_to_readonly = (
4597 share['replication_type'] == constants.REPLICATION_TYPE_READABLE)
4598 fake_replica = fakes.fake_replica(id=replica['id'])
4599 fake_request_spec = fakes.fake_replica_request_spec()
4601 self.mock_object(db_api, 'share_replicas_get_available_active_replica',
4602 mock.Mock(return_value={'host': 'fake_ar_host'}))
4603 self.mock_object(share_types, 'get_share_type',
4604 mock.Mock(return_value=share_type))
4605 mock_get_all_az_subnet = self.mock_object(
4606 self.api, '_get_all_availability_zones_with_subnets',
4607 mock.Mock(return_value=[compatible_azs_name,
4608 compatible_azs_multiple]))
4610 if availability_zones == '':
4611 expected_azs = compatible_azs_name
4612 else:
4613 availability_zones = [
4614 t for t in availability_zones.split(',') if availability_zones]
4615 expected_azs = (
4616 [az for az in availability_zones if az in compatible_azs_name])
4618 self.mock_object(
4619 self.api, 'create_share_instance_and_get_request_spec',
4620 mock.Mock(return_value=(fake_request_spec, fake_replica)))
4621 self.mock_object(db_api, 'share_replica_update')
4622 mock_snapshot_get_all_call = self.mock_object(
4623 db_api, 'share_snapshot_get_all_for_share',
4624 mock.Mock(return_value=[]))
4625 mock_sched_rpcapi_call = self.mock_object(
4626 self.api.scheduler_rpcapi, 'create_share_replica')
4628 self.api.create_share_replica(
4629 self.context, share, share_network_id=share_network_id)
4631 (db_api.share_replicas_get_available_active_replica
4632 .assert_called_once_with(self.context, share['id']))
4633 self.assertTrue(share_types.get_share_type.called)
4634 mock_get_all_az_subnet.assert_called_once_with(
4635 self.context, share_network_id
4636 )
4637 (self.api.create_share_instance_and_get_request_spec.
4638 assert_called_once_with(
4639 self.context, share, availability_zone=None,
4640 share_network_id=share_network_id, share_type_id=share_type['id'],
4641 availability_zones=expected_azs,
4642 az_request_multiple_subnet_support_map={},
4643 cast_rules_to_readonly=cast_rules_to_readonly))
4644 db_api.share_replica_update.assert_called_once()
4645 mock_snapshot_get_all_call.assert_called_once()
4646 mock_sched_rpcapi_call.assert_called_once()
4648 @ddt.data(
4649 {'availability_zones': '', 'compatible_azs_name': [],
4650 'compatible_azs_multiple': []},
4651 {'availability_zones': 'fake_az_1,fake_az_2',
4652 'compatible_azs_name': ['fake_az_3'], 'compatible_azs_multiple': []}
4653 )
4654 @ddt.unpack
4655 def test_create_share_replica_azs_with_subnets_invalid_input(
4656 self, availability_zones,
4657 compatible_azs_name, compatible_azs_multiple):
4658 request_spec = fakes.fake_replica_request_spec()
4659 replica = request_spec['share_instance_properties']
4660 share_network_id = 'fake_share_network_id'
4661 extra_specs = {
4662 'availability_zones': availability_zones,
4663 'replication_type': constants.REPLICATION_TYPE_DR
4664 }
4665 share_type = db_utils.create_share_type(extra_specs=extra_specs)
4666 share_type = db_api.share_type_get(self.context, share_type['id'])
4667 share = db_utils.create_share(
4668 id=replica['share_id'], replication_type='dr',
4669 share_type_id=share_type['id'])
4671 self.mock_object(db_api, 'share_replicas_get_available_active_replica',
4672 mock.Mock(return_value={'host': 'fake_ar_host'}))
4673 self.mock_object(share_types, 'get_share_type',
4674 mock.Mock(return_value=share_type))
4675 mock_get_all_az_subnet = self.mock_object(
4676 self.api, '_get_all_availability_zones_with_subnets',
4677 mock.Mock(return_value=[compatible_azs_name,
4678 compatible_azs_multiple]))
4680 self.assertRaises(
4681 exception.InvalidInput,
4682 self.api.create_share_replica,
4683 self.context, share, share_network_id=share_network_id)
4685 (db_api.share_replicas_get_available_active_replica
4686 .assert_called_once_with(self.context, share['id']))
4687 self.assertTrue(share_types.get_share_type.called)
4688 mock_get_all_az_subnet.assert_called_once_with(
4689 self.context, share_network_id
4690 )
4692 @ddt.data({'has_snapshots': True,
4693 'az_id': {},
4694 'extra_specs': {
4695 'replication_type': constants.REPLICATION_TYPE_DR,
4696 },
4697 'share_network_id': None},
4698 {'has_snapshots': False,
4699 'az_id': {},
4700 'extra_specs': {
4701 'availability_zones': 'FAKE_AZ,FAKE_AZ2',
4702 'replication_type': constants.REPLICATION_TYPE_DR,
4703 },
4704 'share_network_id': None},
4705 {'has_snapshots': True,
4706 'az_id': {},
4707 'extra_specs': {
4708 'availability_zones': 'FAKE_AZ,FAKE_AZ2',
4709 'replication_type': constants.REPLICATION_TYPE_READABLE,
4710 },
4711 'share_network_id': None},
4712 {'has_snapshots': False,
4713 'az_id': {'fake_zone_id': False},
4714 'extra_specs': {
4715 'replication_type': constants.REPLICATION_TYPE_READABLE,
4716 },
4717 'share_network_id': 'fake_sn_id'})
4718 @ddt.unpack
4719 def test_create_share_replica(self, has_snapshots, extra_specs,
4720 share_network_id, az_id):
4721 subnets = db_utils.create_share_network_subnet(
4722 id='fakeid', share_network_id='fake_network_id')
4723 az = {'id': 'fake_zone_id'}
4724 request_spec = fakes.fake_replica_request_spec()
4725 replication_type = extra_specs['replication_type']
4726 replica = request_spec['share_instance_properties']
4727 share_type = db_utils.create_share_type(extra_specs=extra_specs)
4728 share_type = db_api.share_type_get(self.context, share_type['id'])
4729 share = db_utils.create_share(
4730 id=replica['share_id'], replication_type=replication_type,
4731 share_type_id=share_type['id'])
4732 snapshots = (
4733 [fakes.fake_snapshot(), fakes.fake_snapshot()]
4734 if has_snapshots else []
4735 )
4736 cast_rules_to_readonly = (
4737 replication_type == constants.REPLICATION_TYPE_READABLE)
4739 fake_replica = fakes.fake_replica(id=replica['id'])
4740 fake_request_spec = fakes.fake_replica_request_spec()
4741 self.mock_object(db_api, 'share_replicas_get_available_active_replica',
4742 mock.Mock(return_value={'host': 'fake_ar_host'}))
4743 self.mock_object(share_types, 'get_share_type',
4744 mock.Mock(return_value=share_type))
4745 self.mock_object(db_api, 'availability_zone_get',
4746 mock.Mock(return_value=az))
4747 self.mock_object(
4748 db_api, 'share_network_subnets_get_all_by_availability_zone_id',
4749 mock.Mock(return_value=[subnets]))
4750 self.mock_object(
4751 share_api.API, 'create_share_instance_and_get_request_spec',
4752 mock.Mock(return_value=(fake_request_spec, fake_replica)))
4753 self.mock_object(db_api, 'share_replica_update')
4754 mock_sched_rpcapi_call = self.mock_object(
4755 self.api.scheduler_rpcapi, 'create_share_replica')
4756 mock_snapshot_get_all_call = self.mock_object(
4757 db_api, 'share_snapshot_get_all_for_share',
4758 mock.Mock(return_value=snapshots))
4759 mock_snapshot_instance_create_call = self.mock_object(
4760 db_api, 'share_snapshot_instance_create')
4761 expected_snap_instance_create_call_count = 2 if has_snapshots else 0
4763 result = self.api.create_share_replica(
4764 self.context, share, availability_zone='FAKE_AZ',
4765 share_network_id=share_network_id)
4767 self.assertTrue(mock_sched_rpcapi_call.called)
4768 self.assertEqual(replica, result)
4769 share_types.get_share_type.assert_called_once_with(
4770 self.context, share_type['id'])
4771 mock_snapshot_get_all_call.assert_called_once_with(
4772 self.context, fake_replica['share_id'])
4773 self.assertEqual(expected_snap_instance_create_call_count,
4774 mock_snapshot_instance_create_call.call_count)
4775 expected_azs = extra_specs.get('availability_zones', '')
4776 expected_azs = expected_azs.split(',') if expected_azs else []
4777 (share_api.API.create_share_instance_and_get_request_spec.
4778 assert_called_once_with(
4779 self.context, share, availability_zone='FAKE_AZ',
4780 share_network_id=share_network_id, share_type_id=share_type['id'],
4781 availability_zones=expected_azs,
4782 az_request_multiple_subnet_support_map=az_id,
4783 cast_rules_to_readonly=cast_rules_to_readonly))
4785 def test_delete_last_active_replica(self):
4786 fake_replica = fakes.fake_replica(
4787 share_id='FAKE_SHARE_ID',
4788 replica_state=constants.REPLICA_STATE_ACTIVE)
4789 self.mock_object(db_api, 'share_replicas_get_all_by_share',
4790 mock.Mock(return_value=[fake_replica]))
4791 mock_log = self.mock_object(share_api.LOG, 'info')
4793 self.assertRaises(
4794 exception.ReplicationException, self.api.delete_share_replica,
4795 self.context, fake_replica)
4796 self.assertFalse(mock_log.called)
4798 @ddt.data(True, False)
4799 def test_delete_share_replica_no_host(self, has_snapshots):
4800 snapshots = [{'id': 'xyz'}, {'id': 'abc'}, {'id': 'pqr'}]
4801 snapshots = snapshots if has_snapshots else []
4802 replica = fakes.fake_replica('FAKE_ID', host='')
4803 mock_sched_rpcapi_call = self.mock_object(
4804 self.share_rpcapi, 'delete_share_replica')
4805 mock_db_replica_delete_call = self.mock_object(
4806 db_api, 'share_replica_delete')
4807 mock_db_update_call = self.mock_object(db_api, 'share_replica_update')
4808 mock_snapshot_get_call = self.mock_object(
4809 db_api, 'share_snapshot_instance_get_all_with_filters',
4810 mock.Mock(return_value=snapshots))
4811 mock_snapshot_instance_delete_call = self.mock_object(
4812 db_api, 'share_snapshot_instance_delete')
4814 self.api.delete_share_replica(self.context, replica)
4816 self.assertFalse(mock_sched_rpcapi_call.called)
4817 mock_db_replica_delete_call.assert_called_once_with(
4818 self.context, replica['id'])
4819 mock_db_update_call.assert_called_once_with(
4820 self.context, replica['id'],
4821 {'status': constants.STATUS_DELETING, 'terminated_at': mock.ANY})
4822 mock_snapshot_get_call.assert_called_once_with(
4823 self.context, {'share_instance_ids': replica['id']})
4824 self.assertEqual(
4825 len(snapshots), mock_snapshot_instance_delete_call.call_count)
4827 @ddt.data(True, False)
4828 def test_delete_share_replica(self, force):
4829 replica = fakes.fake_replica('FAKE_ID', host='HOSTA@BackendB#PoolC')
4830 mock_sched_rpcapi_call = self.mock_object(
4831 self.share_rpcapi, 'delete_share_replica')
4832 mock_db_update_call = self.mock_object(db_api, 'share_replica_update')
4834 self.api.delete_share_replica(self.context, replica, force=force)
4836 mock_sched_rpcapi_call.assert_called_once_with(
4837 self.context, replica, force=force)
4838 mock_db_update_call.assert_called_once_with(
4839 self.context, replica['id'],
4840 {'status': constants.STATUS_DELETING,
4841 'terminated_at': mock.ANY})
4843 @ddt.data(constants.STATUS_CREATING, constants.STATUS_DELETING,
4844 constants.STATUS_ERROR, constants.STATUS_EXTENDING,
4845 constants.STATUS_REPLICATION_CHANGE, constants.STATUS_MANAGING,
4846 constants.STATUS_ERROR_DELETING)
4847 def test_promote_share_replica_non_available_status(self, status):
4848 replica = fakes.fake_replica(
4849 status=status, replica_state=constants.REPLICA_STATE_IN_SYNC)
4850 mock_rpcapi_promote_share_replica_call = self.mock_object(
4851 self.share_rpcapi, 'promote_share_replica')
4853 self.assertRaises(exception.ReplicationException,
4854 self.api.promote_share_replica,
4855 self.context,
4856 replica)
4857 self.assertFalse(mock_rpcapi_promote_share_replica_call.called)
4859 @ddt.data(constants.REPLICA_STATE_OUT_OF_SYNC, constants.STATUS_ERROR)
4860 def test_promote_share_replica_out_of_sync_non_admin(self, replica_state):
4861 fake_user_context = context.RequestContext(
4862 user_id=None, project_id=None, is_admin=False,
4863 read_deleted='no', overwrite=False)
4864 replica = fakes.fake_replica(
4865 status=constants.STATUS_AVAILABLE,
4866 replica_state=replica_state)
4867 mock_rpcapi_promote_share_replica_call = self.mock_object(
4868 self.share_rpcapi, 'promote_share_replica')
4870 self.assertRaises(exception.AdminRequired,
4871 self.api.promote_share_replica,
4872 fake_user_context,
4873 replica)
4874 self.assertFalse(mock_rpcapi_promote_share_replica_call.called)
4876 @ddt.data(constants.REPLICA_STATE_OUT_OF_SYNC, constants.STATUS_ERROR)
4877 def test_promote_share_replica_admin_authorized(self, replica_state):
4878 replica = fakes.fake_replica(
4879 status=constants.STATUS_AVAILABLE,
4880 replica_state=replica_state, host='HOSTA@BackendB#PoolC')
4881 self.mock_object(db_api, 'share_replica_get',
4882 mock.Mock(return_value=replica))
4883 mock_rpcapi_promote_share_replica_call = self.mock_object(
4884 self.share_rpcapi, 'promote_share_replica')
4885 mock_db_update_call = self.mock_object(db_api, 'share_replica_update')
4887 retval = self.api.promote_share_replica(
4888 self.context, replica)
4890 self.assertEqual(replica, retval)
4891 mock_db_update_call.assert_called_once_with(
4892 self.context, replica['id'],
4893 {'status': constants.STATUS_REPLICATION_CHANGE})
4894 mock_rpcapi_promote_share_replica_call.assert_called_once_with(
4895 self.context, replica, quiesce_wait_time=None)
4897 def test_promote_share_replica(self):
4898 replica = fakes.fake_replica('FAKE_ID', host='HOSTA@BackendB#PoolC')
4899 self.mock_object(db_api, 'share_replica_get',
4900 mock.Mock(return_value=replica))
4901 self.mock_object(db_api, 'share_replica_update')
4902 mock_sched_rpcapi_call = self.mock_object(
4903 self.share_rpcapi, 'promote_share_replica')
4905 result = self.api.promote_share_replica(self.context, replica)
4907 mock_sched_rpcapi_call.assert_called_once_with(
4908 self.context, replica, quiesce_wait_time=None)
4909 self.assertEqual(replica, result)
4911 def test_update_share_replica_no_host(self):
4912 replica = fakes.fake_replica('FAKE_ID')
4913 replica['host'] = None
4914 mock_rpcapi_update_share_replica_call = self.mock_object(
4915 self.share_rpcapi, 'update_share_replica')
4917 self.assertRaises(exception.InvalidHost,
4918 self.api.update_share_replica,
4919 self.context,
4920 replica)
4921 self.assertFalse(mock_rpcapi_update_share_replica_call.called)
4923 def test_update_share_replica(self):
4924 replica = fakes.fake_replica('FAKE_ID', host='HOSTA@BackendB#PoolC')
4925 mock_rpcapi_update_share_replica_call = self.mock_object(
4926 self.share_rpcapi, 'update_share_replica')
4928 retval = self.api.update_share_replica(self.context, replica)
4930 self.assertTrue(mock_rpcapi_update_share_replica_call.called)
4931 self.assertIsNone(retval)
4933 @ddt.data({'overs': {'replica_gigabytes': 'fake'},
4934 'expected_exception':
4935 exception.ShareReplicaSizeExceedsAvailableQuota},
4936 {'overs': {'share_replicas': 'fake'},
4937 'expected_exception': exception.ShareReplicasLimitExceeded})
4938 @ddt.unpack
4939 def test_create_share_replica_over_quota(self, overs, expected_exception):
4940 request_spec = fakes.fake_replica_request_spec()
4941 replica = request_spec['share_instance_properties']
4942 share = db_utils.create_share(replication_type='dr',
4943 id=replica['share_id'])
4944 share_type = db_utils.create_share_type()
4945 share_type = db_api.share_type_get(self.context, share_type['id'])
4946 usages = {'replica_gigabytes': {'reserved': 5, 'in_use': 5},
4947 'share_replicas': {'reserved': 5, 'in_use': 5}}
4948 quotas = {'share_replicas': 5, 'replica_gigabytes': 5}
4949 exc = exception.OverQuota(overs=overs, usages=usages, quotas=quotas)
4951 self.mock_object(quota.QUOTAS, 'reserve', mock.Mock(side_effect=exc))
4952 self.mock_object(db_api, 'share_replicas_get_available_active_replica',
4953 mock.Mock(return_value={'host': 'fake_ar_host'}))
4954 self.mock_object(share_types, 'get_share_type',
4955 mock.Mock(return_value=share_type))
4957 self.assertRaises(
4958 expected_exception,
4959 self.api.create_share_replica,
4960 self.context,
4961 share
4962 )
4963 quota.QUOTAS.reserve.assert_called_once_with(
4964 self.context, share_type_id=share_type['id'],
4965 share_replicas=1, replica_gigabytes=share['size'])
4966 (db_api.share_replicas_get_available_active_replica
4967 .assert_called_once_with(self.context, share['id']))
4968 share_types.get_share_type.assert_called_once_with(
4969 self.context, share['instance']['share_type_id'])
4971 def test_create_share_replica_error_on_quota_commit(self):
4972 request_spec = fakes.fake_replica_request_spec()
4973 replica = request_spec['share_instance_properties']
4974 share_type = db_utils.create_share_type()
4975 fake_replica = fakes.fake_replica(id=replica['id'])
4976 share = db_utils.create_share(replication_type='dr',
4977 id=fake_replica['share_id'],
4978 share_type_id=share_type['id'])
4979 share_network_id = None
4980 share_type = db_api.share_type_get(self.context, share_type['id'])
4981 expected_azs = share_type['extra_specs'].get('availability_zones', '')
4982 expected_azs = expected_azs.split(',') if expected_azs else []
4984 reservation = 'fake'
4985 self.mock_object(quota.QUOTAS, 'reserve',
4986 mock.Mock(return_value=reservation))
4987 self.mock_object(quota.QUOTAS, 'commit',
4988 mock.Mock(side_effect=exception.QuotaError('fake')))
4989 self.mock_object(db_api, 'share_replica_delete')
4990 self.mock_object(quota.QUOTAS, 'rollback')
4991 self.mock_object(db_api, 'share_replicas_get_available_active_replica',
4992 mock.Mock(return_value={'host': 'fake_ar_host'}))
4993 self.mock_object(share_types, 'get_share_type',
4994 mock.Mock(return_value=share_type))
4995 self.mock_object(
4996 share_api.API, 'create_share_instance_and_get_request_spec',
4997 mock.Mock(return_value=(request_spec, fake_replica)))
4999 self.assertRaises(
5000 exception.QuotaError,
5001 self.api.create_share_replica,
5002 self.context,
5003 share
5004 )
5006 db_api.share_replica_delete.assert_called_once_with(
5007 self.context, replica['id'], need_to_update_usages=False)
5008 quota.QUOTAS.rollback.assert_called_once_with(
5009 self.context, reservation,
5010 share_type_id=share['instance']['share_type_id'])
5011 (db_api.share_replicas_get_available_active_replica.
5012 assert_called_once_with(self.context, share['id']))
5013 share_types.get_share_type.assert_called_once_with(
5014 self.context, share['instance']['share_type_id'])
5015 (share_api.API.create_share_instance_and_get_request_spec.
5016 assert_called_once_with(self.context, share, availability_zone=None,
5017 share_network_id=share_network_id,
5018 share_type_id=share_type['id'],
5019 availability_zones=expected_azs,
5020 az_request_multiple_subnet_support_map={},
5021 cast_rules_to_readonly=False))
5023 def test_migration_complete(self):
5025 instance1 = db_utils.create_share_instance(
5026 share_id='fake_id', status=constants.STATUS_MIGRATING)
5027 instance2 = db_utils.create_share_instance(
5028 share_id='fake_id', status=constants.STATUS_MIGRATING_TO)
5029 share = db_utils.create_share(
5030 id='fake_id',
5031 task_state=constants.TASK_STATE_DATA_COPYING_COMPLETED,
5032 instances=[instance1, instance2])
5034 self.mock_object(db_api, 'share_instance_get',
5035 mock.Mock(return_value=instance1))
5036 self.mock_object(self.api.share_rpcapi, 'migration_complete')
5038 self.api.migration_complete(self.context, share)
5040 self.api.share_rpcapi.migration_complete.assert_called_once_with(
5041 self.context, instance1, instance2['id'])
5043 @ddt.data(constants.TASK_STATE_DATA_COPYING_STARTING,
5044 constants.TASK_STATE_MIGRATION_SUCCESS,
5045 constants.TASK_STATE_DATA_COPYING_IN_PROGRESS,
5046 constants.TASK_STATE_MIGRATION_ERROR,
5047 constants.TASK_STATE_MIGRATION_CANCELLED,
5048 None)
5049 def test_migration_complete_task_state_invalid(self, task_state):
5051 share = db_utils.create_share(
5052 id='fake_id',
5053 task_state=task_state)
5055 self.assertRaises(exception.InvalidShare, self.api.migration_complete,
5056 self.context, share)
5058 def test_migration_complete_status_invalid(self):
5060 instance1 = db_utils.create_share_instance(
5061 share_id='fake_id', status=constants.STATUS_ERROR)
5062 instance2 = db_utils.create_share_instance(
5063 share_id='fake_id', status=constants.STATUS_ERROR)
5064 share = db_utils.create_share(
5065 id='fake_id',
5066 task_state=constants.TASK_STATE_DATA_COPYING_COMPLETED,
5067 instances=[instance1, instance2])
5069 self.assertRaises(exception.ShareMigrationFailed,
5070 self.api.migration_complete, self.context,
5071 share)
5073 @ddt.data(None, Exception('fake'))
5074 def test_migration_cancel(self, exc):
5076 share = db_utils.create_share(
5077 id='fake_id',
5078 task_state=constants.TASK_STATE_DATA_COPYING_IN_PROGRESS)
5079 services = ['fake_service']
5081 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
5082 self.mock_object(db_api, 'service_get_all_by_topic',
5083 mock.Mock(return_value=services))
5084 self.mock_object(data_rpc.DataAPI, 'data_copy_cancel',
5085 mock.Mock(side_effect=[exc]))
5087 if exc:
5088 self.assertRaises(
5089 exception.ShareMigrationError, self.api.migration_cancel,
5090 self.context, share)
5091 else:
5092 self.api.migration_cancel(self.context, share)
5094 data_rpc.DataAPI.data_copy_cancel.assert_called_once_with(
5095 self.context, share['id'])
5096 db_api.service_get_all_by_topic.assert_called_once_with(
5097 self.context, 'manila-data')
5099 def test_migration_cancel_service_down(self):
5100 service = 'fake_service'
5101 instance1 = db_utils.create_share_instance(
5102 share_id='fake_id', status=constants.STATUS_MIGRATING)
5103 instance2 = db_utils.create_share_instance(
5104 share_id='fake_id', status=constants.STATUS_MIGRATING_TO)
5105 share = db_utils.create_share(
5106 id='fake_id',
5107 task_state=constants.TASK_STATE_DATA_COPYING_IN_PROGRESS,
5108 instances=[instance1, instance2])
5110 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=False))
5111 self.mock_object(db_api, 'share_instance_get',
5112 mock.Mock(return_value=instance1))
5113 self.mock_object(db_api, 'service_get_all_by_topic',
5114 mock.Mock(return_value=service))
5116 self.assertRaises(exception.InvalidShare,
5117 self.api.migration_cancel, self.context, share)
5119 def test_migration_cancel_driver(self):
5121 service = 'fake_service'
5122 instance1 = db_utils.create_share_instance(
5123 share_id='fake_id',
5124 status=constants.STATUS_MIGRATING,
5125 host='some_host')
5126 instance2 = db_utils.create_share_instance(
5127 share_id='fake_id',
5128 status=constants.STATUS_MIGRATING_TO)
5129 share = db_utils.create_share(
5130 id='fake_id',
5131 task_state=constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
5132 instances=[instance1, instance2])
5134 self.mock_object(db_api, 'share_instance_get',
5135 mock.Mock(return_value=instance1))
5136 self.mock_object(self.api.share_rpcapi, 'migration_cancel')
5137 self.mock_object(db_api, 'service_get_by_args',
5138 mock.Mock(return_value=service))
5139 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
5141 self.api.migration_cancel(self.context, share)
5143 self.api.share_rpcapi.migration_cancel.assert_called_once_with(
5144 self.context, instance1, instance2['id'])
5145 db_api.service_get_by_args.assert_called_once_with(
5146 self.context, instance1['host'], 'manila-share')
5148 @ddt.data(constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
5149 constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE,
5150 constants.TASK_STATE_DATA_COPYING_COMPLETED)
5151 def test_migration_cancel_driver_service_down(self, task_state):
5153 service = 'fake_service'
5154 instance1 = db_utils.create_share_instance(
5155 share_id='fake_id',
5156 status=constants.STATUS_MIGRATING,
5157 host='some_host')
5158 instance2 = db_utils.create_share_instance(
5159 share_id='fake_id',
5160 status=constants.STATUS_MIGRATING_TO)
5161 share = db_utils.create_share(
5162 id='fake_id',
5163 task_state=task_state,
5164 instances=[instance1, instance2])
5166 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=False))
5167 self.mock_object(db_api, 'share_instance_get',
5168 mock.Mock(return_value=instance1))
5169 self.mock_object(db_api, 'service_get_by_args',
5170 mock.Mock(return_value=service))
5172 self.assertRaises(exception.InvalidShare,
5173 self.api.migration_cancel, self.context, share)
5175 @ddt.data(constants.TASK_STATE_DATA_COPYING_STARTING,
5176 constants.TASK_STATE_MIGRATION_SUCCESS,
5177 constants.TASK_STATE_MIGRATION_ERROR,
5178 constants.TASK_STATE_MIGRATION_CANCELLED,
5179 None)
5180 def test_migration_cancel_task_state_invalid(self, task_state):
5182 share = db_utils.create_share(
5183 id='fake_id',
5184 task_state=task_state)
5186 self.assertRaises(exception.InvalidShare, self.api.migration_cancel,
5187 self.context, share)
5189 @ddt.data({'total_progress': 50}, Exception('fake'))
5190 def test_migration_get_progress(self, expected):
5192 share = db_utils.create_share(
5193 id='fake_id',
5194 task_state=constants.TASK_STATE_DATA_COPYING_IN_PROGRESS)
5195 services = ['fake_service']
5197 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
5198 self.mock_object(db_api, 'service_get_all_by_topic',
5199 mock.Mock(return_value=services))
5200 self.mock_object(data_rpc.DataAPI, 'data_copy_get_progress',
5201 mock.Mock(side_effect=[expected]))
5203 if not isinstance(expected, Exception):
5204 result = self.api.migration_get_progress(self.context, share)
5205 self.assertEqual(expected, result)
5206 else:
5207 self.assertRaises(
5208 exception.ShareMigrationError, self.api.migration_get_progress,
5209 self.context, share)
5211 data_rpc.DataAPI.data_copy_get_progress.assert_called_once_with(
5212 self.context, share['id'])
5213 db_api.service_get_all_by_topic.assert_called_once_with(
5214 self.context, 'manila-data')
5216 def test_migration_get_progress_service_down(self):
5217 instance1 = db_utils.create_share_instance(
5218 share_id='fake_id', status=constants.STATUS_MIGRATING)
5219 instance2 = db_utils.create_share_instance(
5220 share_id='fake_id', status=constants.STATUS_MIGRATING_TO)
5221 share = db_utils.create_share(
5222 id='fake_id',
5223 task_state=constants.TASK_STATE_DATA_COPYING_IN_PROGRESS,
5224 instances=[instance1, instance2])
5225 services = ['fake_service']
5227 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=False))
5228 self.mock_object(db_api, 'service_get_all_by_topic',
5229 mock.Mock(return_value=services))
5230 self.mock_object(db_api, 'share_instance_get',
5231 mock.Mock(return_value=instance1))
5233 self.assertRaises(exception.InvalidShare,
5234 self.api.migration_get_progress, self.context, share)
5236 def test_migration_get_progress_driver(self):
5238 expected = {'total_progress': 50}
5239 instance1 = db_utils.create_share_instance(
5240 share_id='fake_id',
5241 status=constants.STATUS_MIGRATING,
5242 host='some_host')
5243 instance2 = db_utils.create_share_instance(
5244 share_id='fake_id',
5245 status=constants.STATUS_MIGRATING_TO)
5246 share = db_utils.create_share(
5247 id='fake_id',
5248 task_state=constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
5249 instances=[instance1, instance2])
5250 service = 'fake_service'
5252 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
5253 self.mock_object(db_api, 'service_get_by_args',
5254 mock.Mock(return_value=service))
5255 self.mock_object(db_api, 'share_instance_get',
5256 mock.Mock(return_value=instance1))
5257 self.mock_object(self.api.share_rpcapi, 'migration_get_progress',
5258 mock.Mock(return_value=expected))
5260 result = self.api.migration_get_progress(self.context, share)
5262 self.assertEqual(expected, result)
5264 self.api.share_rpcapi.migration_get_progress.assert_called_once_with(
5265 self.context, instance1, instance2['id'])
5266 db_api.service_get_by_args.assert_called_once_with(
5267 self.context, instance1['host'], 'manila-share')
5269 def test_migration_get_progress_driver_error(self):
5271 instance1 = db_utils.create_share_instance(
5272 share_id='fake_id',
5273 status=constants.STATUS_MIGRATING,
5274 host='some_host')
5275 instance2 = db_utils.create_share_instance(
5276 share_id='fake_id',
5277 status=constants.STATUS_MIGRATING_TO)
5278 share = db_utils.create_share(
5279 id='fake_id',
5280 task_state=constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
5281 instances=[instance1, instance2])
5282 service = 'fake_service'
5284 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
5285 self.mock_object(db_api, 'service_get_by_args',
5286 mock.Mock(return_value=service))
5287 self.mock_object(db_api, 'share_instance_get',
5288 mock.Mock(return_value=instance1))
5289 self.mock_object(self.api.share_rpcapi, 'migration_get_progress',
5290 mock.Mock(side_effect=Exception('fake')))
5292 self.assertRaises(exception.ShareMigrationError,
5293 self.api.migration_get_progress, self.context, share)
5295 self.api.share_rpcapi.migration_get_progress.assert_called_once_with(
5296 self.context, instance1, instance2['id'])
5298 def test_migration_get_progress_driver_service_down(self):
5299 service = 'fake_service'
5300 instance1 = db_utils.create_share_instance(
5301 share_id='fake_id',
5302 status=constants.STATUS_MIGRATING,
5303 host='some_host')
5304 instance2 = db_utils.create_share_instance(
5305 share_id='fake_id',
5306 status=constants.STATUS_MIGRATING_TO)
5307 share = db_utils.create_share(
5308 id='fake_id',
5309 task_state=constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
5310 instances=[instance1, instance2])
5312 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=False))
5313 self.mock_object(db_api, 'share_instance_get',
5314 mock.Mock(return_value=instance1))
5315 self.mock_object(db_api, 'service_get_by_args',
5316 mock.Mock(return_value=service))
5318 self.assertRaises(exception.InvalidShare,
5319 self.api.migration_get_progress, self.context, share)
5321 @ddt.data(constants.TASK_STATE_MIGRATION_STARTING,
5322 constants.TASK_STATE_MIGRATION_DRIVER_STARTING,
5323 constants.TASK_STATE_DATA_COPYING_STARTING,
5324 constants.TASK_STATE_MIGRATION_IN_PROGRESS)
5325 def test_migration_get_progress_task_state_progress_0(self, task_state):
5327 share = db_utils.create_share(
5328 id='fake_id',
5329 task_state=task_state)
5330 expected = {'total_progress': 0}
5332 result = self.api.migration_get_progress(self.context, share)
5334 self.assertEqual(expected, result)
5336 @ddt.data(constants.TASK_STATE_MIGRATION_SUCCESS,
5337 constants.TASK_STATE_DATA_COPYING_ERROR,
5338 constants.TASK_STATE_MIGRATION_CANCELLED,
5339 constants.TASK_STATE_MIGRATION_COMPLETING,
5340 constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE,
5341 constants.TASK_STATE_DATA_COPYING_COMPLETED,
5342 constants.TASK_STATE_DATA_COPYING_COMPLETING,
5343 constants.TASK_STATE_DATA_COPYING_CANCELLED,
5344 constants.TASK_STATE_MIGRATION_ERROR)
5345 def test_migration_get_progress_task_state_progress_100(self, task_state):
5347 share = db_utils.create_share(
5348 id='fake_id',
5349 task_state=task_state)
5350 expected = {'total_progress': 100}
5352 result = self.api.migration_get_progress(self.context, share)
5354 self.assertEqual(expected, result)
5356 def test_migration_get_progress_task_state_None(self):
5358 share = db_utils.create_share(id='fake_id', task_state=None)
5360 self.assertRaises(exception.InvalidShare,
5361 self.api.migration_get_progress, self.context, share)
5363 @ddt.data(None, {'invalid_progress': None}, {})
5364 def test_migration_get_progress_invalid(self, progress):
5366 instance1 = db_utils.create_share_instance(
5367 share_id='fake_id',
5368 status=constants.STATUS_MIGRATING,
5369 host='some_host')
5370 instance2 = db_utils.create_share_instance(
5371 share_id='fake_id',
5372 status=constants.STATUS_MIGRATING_TO)
5373 share = db_utils.create_share(
5374 id='fake_id',
5375 task_state=constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
5376 instances=[instance1, instance2])
5377 service = 'fake_service'
5379 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
5380 self.mock_object(db_api, 'service_get_by_args',
5381 mock.Mock(return_value=service))
5382 self.mock_object(db_api, 'share_instance_get',
5383 mock.Mock(return_value=instance1))
5385 self.mock_object(self.api.share_rpcapi, 'migration_get_progress',
5386 mock.Mock(return_value=progress))
5388 self.assertRaises(exception.InvalidShare,
5389 self.api.migration_get_progress, self.context, share)
5391 self.api.share_rpcapi.migration_get_progress.assert_called_once_with(
5392 self.context, instance1, instance2['id'])
5394 @ddt.data(True, False)
5395 def test__migration_initial_checks(self, create_share_network):
5396 type_data = {
5397 'extra_specs': {
5398 'availability_zones': 'fake_az1,fake_az2'
5399 }
5400 }
5401 fake_server_host = 'fake@backend'
5402 fake_share_server = db_utils.create_share_server(host=fake_server_host)
5403 share_type = db_utils.create_share_type(**type_data)
5404 share_type = db_api.share_type_get(self.context, share_type['id'])
5405 fake_share = db_utils.create_share(
5406 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
5407 share_type_id=share_type['id'])
5408 fake_az = {
5409 'id': 'fake_az_id',
5410 'name': 'fake_az1'
5411 }
5412 fake_share_network = (
5413 db_utils.create_share_network() if create_share_network else None)
5414 expected_network_change = create_share_network is True
5416 fake_share_network_id = (
5417 fake_share_network['id']
5418 if create_share_network else fake_share['share_network_id'])
5419 fake_subnet = db_utils.create_share_network_subnet(
5420 availability_zone_id=fake_az['id'])
5422 fake_host = 'test@fake'
5423 service = {'availability_zone_id': fake_az['id'],
5424 'availability_zone': {'name': fake_az['name']}}
5426 mock_shares_get_all = self.mock_object(
5427 db_api, 'share_get_all_by_share_server',
5428 mock.Mock(return_value=[fake_share]))
5429 mock_shares_in_recycle_bin_get_all = self.mock_object(
5430 db_api, 'share_get_all_soft_deleted',
5431 mock.Mock(return_value=[]))
5432 mock_get_type = self.mock_object(
5433 share_types, 'get_share_type', mock.Mock(return_value=share_type))
5434 mock_validate_service = self.mock_object(
5435 utils, 'validate_service_host')
5436 mock_service_get = self.mock_object(
5437 db_api, 'service_get_by_args', mock.Mock(return_value=service))
5438 mock_az_get = self.mock_object(
5439 db_api, 'availability_zone_get', mock.Mock(return_value=fake_az))
5440 mock_get_subnet = self.mock_object(
5441 db_api, 'share_network_subnets_get_all_by_availability_zone_id',
5442 mock.Mock(return_value=[fake_subnet]))
5444 exp_shares, exp_types, exp_service, exp_network_id, net_change = (
5445 self.api._migration_initial_checks(
5446 self.context, fake_share_server, fake_host,
5447 fake_share_network))
5449 self.assertEqual(exp_shares, [fake_share])
5450 self.assertEqual(exp_types, [share_type])
5451 self.assertEqual(exp_service, service)
5452 self.assertEqual(exp_network_id, fake_share_network_id)
5453 self.assertIs(expected_network_change, net_change)
5454 mock_shares_get_all.assert_has_calls([
5455 mock.call(self.context, fake_share_server['id']),
5456 mock.call(self.context, fake_share_server['id'])])
5457 mock_shares_in_recycle_bin_get_all.assert_has_calls([
5458 mock.call(self.context, fake_share_server['id'])])
5459 mock_get_type.assert_called_once_with(self.context, share_type['id'])
5460 mock_validate_service.assert_called_once_with(self.context, fake_host)
5461 mock_service_get.assert_called_once_with(
5462 self.context, fake_host, 'manila-share')
5463 mock_get_subnet.assert_called_once_with(
5464 self.context, fake_share_network_id, fake_az['id'])
5465 mock_az_get.assert_called_once_with(
5466 self.context, service['availability_zone']['name']
5467 )
5469 def test_share_server_migration_get_destination(self):
5470 fake_source_server_id = 'fake_source_id'
5471 server_data = {
5472 'id': 'fake',
5473 'source_share_server_id': fake_source_server_id,
5474 'status': constants.STATUS_SERVER_MIGRATING_TO,
5475 }
5476 server = db_utils.create_share_server(**server_data)
5477 mock_get_all = self.mock_object(
5478 db_api, 'share_server_get_all_with_filters',
5479 mock.Mock(return_value=[server]))
5480 filters = {
5481 'status': constants.STATUS_SERVER_MIGRATING_TO,
5482 'source_share_server_id': fake_source_server_id,
5483 }
5485 filtered_server = self.api.share_server_migration_get_destination(
5486 self.context, fake_source_server_id,
5487 status=constants.STATUS_SERVER_MIGRATING_TO
5488 )
5489 self.assertEqual(filtered_server['id'], server['id'])
5490 mock_get_all.assert_called_once_with(self.context, filters=filters)
5492 def test_share_server_migration_get_destination_no_share_server(
5493 self):
5495 fake_source_server_id = 'fake_source_id'
5496 server_data = {
5497 'id': 'fake',
5498 'source_share_server_id': fake_source_server_id,
5499 'status': constants.STATUS_SERVER_MIGRATING_TO,
5500 }
5501 db_utils.create_share_server(**server_data)
5502 mock_get_all = self.mock_object(
5503 db_api, 'share_server_get_all_with_filters',
5504 mock.Mock(return_value=[]))
5505 filters = {
5506 'status': constants.STATUS_SERVER_MIGRATING_TO,
5507 'source_share_server_id': fake_source_server_id,
5508 }
5510 self.assertRaises(
5511 exception.InvalidShareServer,
5512 self.api.share_server_migration_get_destination,
5513 self.context, fake_source_server_id,
5514 status=constants.STATUS_SERVER_MIGRATING_TO
5515 )
5516 mock_get_all.assert_called_once_with(self.context, filters=filters)
5518 def test_share_server_migration_get_destination_multiple_servers(self):
5519 fake_source_server_id = 'fake_source_id'
5520 server_data = {
5521 'id': 'fake',
5522 'source_share_server_id': fake_source_server_id,
5523 'status': constants.STATUS_SERVER_MIGRATING_TO,
5524 }
5525 server_1 = db_utils.create_share_server(**server_data)
5526 server_data['id'] = 'fake_id_2'
5527 server_2 = db_utils.create_share_server(**server_data)
5528 mock_get_all = self.mock_object(
5529 db_api, 'share_server_get_all_with_filters',
5530 mock.Mock(return_value=[server_1, server_2]))
5531 filters = {
5532 'status': constants.STATUS_SERVER_MIGRATING_TO,
5533 'source_share_server_id': fake_source_server_id,
5534 }
5536 self.assertRaises(
5537 exception.InvalidShareServer,
5538 self.api.share_server_migration_get_destination,
5539 self.context, fake_source_server_id,
5540 status=constants.STATUS_SERVER_MIGRATING_TO
5541 )
5542 mock_get_all.assert_called_once_with(self.context, filters=filters)
5544 def test__migration_initial_checks_no_shares(self):
5545 fake_share_server = fakes.fake_share_server_get()
5546 fake_share_network = {}
5547 fake_host = 'test@fake'
5548 mock_shares_get_all = self.mock_object(
5549 db_api, 'share_get_all_by_share_server',
5550 mock.Mock(return_value=[]))
5552 self.assertRaises(
5553 exception.InvalidShareServer,
5554 self.api._migration_initial_checks,
5555 self.context, fake_share_server, fake_host, fake_share_network,
5556 )
5557 mock_shares_get_all.assert_called_once_with(
5558 self.context, fake_share_server['id'])
5560 def test__migration_initial_checks_server_not_active(self):
5561 fake_share_server = fakes.fake_share_server_get()
5562 fake_share_server['status'] = 'error'
5563 fake_share = fakes.fake_share()
5564 fake_share_network = {}
5565 fake_host = 'test@fake'
5567 mock_shares_get_all = self.mock_object(
5568 db_api, 'share_get_all_by_share_server',
5569 mock.Mock(return_value=[fake_share]))
5571 self.assertRaises(
5572 exception.InvalidShareServer,
5573 self.api._migration_initial_checks,
5574 self.context, fake_share_server, fake_host, fake_share_network,
5575 )
5576 mock_shares_get_all.assert_called_once_with(
5577 self.context, fake_share_server['id'])
5579 def test__migration_initial_checks_share_group_related_to_server(self):
5580 fake_share_server = db_utils.create_share_server()
5581 fake_share = db_utils.create_share()
5582 fake_share_group = db_utils.create_share_group()
5583 fake_share_network = {}
5584 fake_host = 'test@fake'
5586 mock_shares_get_all = self.mock_object(
5587 db_api, 'share_get_all_by_share_server',
5588 mock.Mock(return_value=[fake_share]))
5589 mock_get_groups = self.mock_object(
5590 db_api, 'share_group_get_all_by_share_server',
5591 mock.Mock(return_value=[fake_share_group]))
5593 self.assertRaises(
5594 exception.InvalidShareServer,
5595 self.api._migration_initial_checks,
5596 self.context, fake_share_server, fake_host, fake_share_network,
5597 )
5598 mock_shares_get_all.assert_called_once_with(
5599 self.context, fake_share_server['id'])
5600 mock_get_groups.assert_called_once_with(self.context,
5601 fake_share_server['id'])
5603 def _setup_mocks_for_initial_checks(self, fake_share, share_type, service,
5604 fake_az, fake_subnet):
5605 self.mock_object(
5606 db_api, 'share_get_all_by_share_server',
5607 mock.Mock(return_value=[fake_share]))
5608 self.mock_object(
5609 db_api, 'share_group_get_all_by_share_server',
5610 mock.Mock(return_value=[]))
5611 self.mock_object(
5612 share_types, 'get_share_type', mock.Mock(return_value=share_type))
5613 self.mock_object(
5614 utils, 'validate_service_host')
5615 self.mock_object(
5616 db_api, 'service_get_by_args', mock.Mock(return_value=service))
5617 self.mock_object(
5618 db_api, 'availability_zone_get', mock.Mock(return_value=fake_az))
5619 self.mock_object(
5620 db_api, 'share_network_subnets_get_all_by_availability_zone_id',
5621 mock.Mock(return_value=fake_subnet))
5623 def test__migration_initial_checks_share_not_available(self):
5624 fake_share_server = fakes.fake_share_server_get()
5625 fake_share_server['host'] = 'fake@backend'
5626 type_data = {
5627 'extra_specs': {
5628 'availability_zones': 'fake_az1,fake_az2'
5629 }
5630 }
5631 fake_server_host = 'fake@backend'
5632 fake_share_server = db_utils.create_share_server(host=fake_server_host)
5633 share_type = db_utils.create_share_type(**type_data)
5634 share_type = db_api.share_type_get(self.context, share_type['id'])
5635 fake_share = db_utils.create_share(
5636 host='fake@backend#pool', status=constants.STATUS_ERROR,
5637 share_type_id=share_type['id'])
5638 fake_az = {
5639 'id': 'fake_az_id',
5640 'name': 'fake_az1'
5641 }
5642 fake_share_network = None
5643 fake_share_network_id = fake_share['share_network_id']
5644 fake_subnet = db_utils.create_share_network_subnet(
5645 availability_zone_id=fake_az['id'])
5646 fake_host = 'test@fake'
5647 service = {'availability_zone_id': fake_az['id'],
5648 'availability_zone': {'name': fake_az['name']}}
5649 self._setup_mocks_for_initial_checks(fake_share, share_type, service,
5650 fake_az, fake_subnet)
5652 self.assertRaises(
5653 exception.InvalidShareServer,
5654 self.api._migration_initial_checks,
5655 self.context, fake_share_server, fake_host, fake_share_network,
5656 )
5657 db_api.share_get_all_by_share_server.assert_has_calls([
5658 mock.call(self.context, fake_share_server['id']),
5659 mock.call(self.context, fake_share_server['id'])])
5660 share_types.get_share_type.assert_called_once_with(
5661 self.context, share_type['id'])
5662 utils.validate_service_host.assert_called_once_with(
5663 self.context, fake_host)
5664 db_api.service_get_by_args.assert_called_once_with(
5665 self.context, fake_host, 'manila-share')
5666 db_api.availability_zone_get.assert_called_once_with(
5667 self.context, service['availability_zone']['name']
5668 )
5669 (db_api.share_network_subnets_get_all_by_availability_zone_id.
5670 assert_called_once_with(
5671 self.context, fake_share_network_id, fake_az['id']))
5672 db_api.share_group_get_all_by_share_server.assert_called_once_with(
5673 self.context, fake_share_server['id'])
5675 def test__migration_initial_checks_share_with_replicas(self):
5676 fake_share_server = fakes.fake_share_server_get()
5677 fake_share_server['host'] = 'fake@backend'
5678 type_data = {
5679 'extra_specs': {
5680 'availability_zones': 'fake_az1,fake_az2'
5681 }
5682 }
5683 fake_server_host = 'fake@backend'
5684 fake_share_server = db_utils.create_share_server(host=fake_server_host)
5685 share_type = db_utils.create_share_type(**type_data)
5686 share_type = db_api.share_type_get(self.context, share_type['id'])
5687 fake_share = db_utils.create_share(
5688 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
5689 replication_type='dr', share_type_id=share_type['id'])
5690 for i in range(1, 4):
5691 db_utils.create_share_replica(
5692 share_id=fake_share['id'], replica_state='in_sync')
5693 fake_share = db_api.share_get(self.context, fake_share['id'])
5694 fake_az = {
5695 'id': 'fake_az_id',
5696 'name': 'fake_az1'
5697 }
5698 fake_share_network = None
5699 fake_share_network_id = fake_share['share_network_id']
5700 fake_subnet = db_utils.create_share_network_subnet(
5701 availability_zone_id=fake_az['id'])
5702 fake_host = 'test@fake'
5703 service = {'availability_zone_id': fake_az['id'],
5704 'availability_zone': {'name': fake_az['name']}}
5705 self._setup_mocks_for_initial_checks(fake_share, share_type, service,
5706 fake_az, fake_subnet)
5708 self.assertRaises(
5709 exception.InvalidShareServer,
5710 self.api._migration_initial_checks,
5711 self.context, fake_share_server, fake_host, fake_share_network,
5712 )
5713 db_api.share_get_all_by_share_server.assert_has_calls([
5714 mock.call(self.context, fake_share_server['id']),
5715 mock.call(self.context, fake_share_server['id'])])
5716 share_types.get_share_type.assert_called_once_with(
5717 self.context, share_type['id'])
5718 utils.validate_service_host.assert_called_once_with(
5719 self.context, fake_host)
5720 db_api.service_get_by_args.assert_called_once_with(
5721 self.context, fake_host, 'manila-share')
5722 db_api.availability_zone_get.assert_called_once_with(
5723 self.context, service['availability_zone']['name']
5724 )
5725 (db_api.share_network_subnets_get_all_by_availability_zone_id.
5726 assert_called_once_with(
5727 self.context, fake_share_network_id, fake_az['id']))
5728 db_api.share_group_get_all_by_share_server.assert_called_once_with(
5729 self.context, fake_share_server['id'])
5731 def test__migration_initial_checks_share_in_share_group(self):
5732 fake_share_server = fakes.fake_share_server_get()
5733 fake_share_server['host'] = 'fake@backend'
5734 type_data = {
5735 'extra_specs': {
5736 'availability_zones': 'fake_az1,fake_az2'
5737 }
5738 }
5739 fake_server_host = 'fake@backend'
5740 fake_share_server = db_utils.create_share_server(host=fake_server_host)
5741 share_type = db_utils.create_share_type(**type_data)
5742 share_type = db_api.share_type_get(self.context, share_type['id'])
5743 fake_share = db_utils.create_share(
5744 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
5745 share_type_id=share_type['id'], share_group_id='fake_group_id')
5746 fake_az = {
5747 'id': 'fake_az_id',
5748 'name': 'fake_az1'
5749 }
5750 fake_share_network = None
5751 fake_share_network_id = fake_share['share_network_id']
5752 fake_subnet = db_utils.create_share_network_subnet(
5753 availability_zone_id=fake_az['id'])
5754 fake_host = 'test@fake'
5755 service = {'availability_zone_id': fake_az['id'],
5756 'availability_zone': {'name': fake_az['name']}}
5757 self._setup_mocks_for_initial_checks(fake_share, share_type, service,
5758 fake_az, fake_subnet)
5759 mock_snapshots_get = self.mock_object(
5760 db_api, 'share_snapshot_get_all_for_share',
5761 mock.Mock(return_value=[]))
5763 self.assertRaises(
5764 exception.InvalidShareServer,
5765 self.api._migration_initial_checks,
5766 self.context, fake_share_server, fake_host, fake_share_network,
5767 )
5768 db_api.share_get_all_by_share_server.assert_has_calls([
5769 mock.call(self.context, fake_share_server['id']),
5770 mock.call(self.context, fake_share_server['id'])])
5771 share_types.get_share_type.assert_called_once_with(
5772 self.context, share_type['id'])
5773 utils.validate_service_host.assert_called_once_with(
5774 self.context, fake_host)
5775 db_api.service_get_by_args.assert_called_once_with(
5776 self.context, fake_host, 'manila-share')
5777 db_api.availability_zone_get.assert_called_once_with(
5778 self.context, service['availability_zone']['name']
5779 )
5780 (db_api.share_network_subnets_get_all_by_availability_zone_id.
5781 assert_called_once_with(
5782 self.context, fake_share_network_id, fake_az['id']))
5783 mock_snapshots_get.assert_called_once_with(
5784 self.context, fake_share['id'])
5785 db_api.share_group_get_all_by_share_server.assert_called_once_with(
5786 self.context, fake_share_server['id'])
5788 def test__migration_initial_checks_same_backend_and_network(self):
5789 fake_server_host = 'fake@backend'
5790 fake_share_network = {'id': 'fake_share_network_id'}
5791 fake_share_server = db_utils.create_share_server(host=fake_server_host)
5792 fake_share = db_utils.create_share(
5793 host=fake_server_host, status=constants.STATUS_AVAILABLE,
5794 share_group_id='fake_group_id',
5795 share_network_id=fake_share_network['id'])
5797 mock_shares_get_all = self.mock_object(
5798 db_api, 'share_get_all_by_share_server',
5799 mock.Mock(return_value=[fake_share]))
5801 self.assertRaises(
5802 exception.InvalidShareServer,
5803 self.api._migration_initial_checks,
5804 self.context, fake_share_server, fake_server_host,
5805 fake_share_network,
5806 )
5807 mock_shares_get_all.assert_called_once_with(
5808 self.context, fake_share_server['id'])
5810 def test__migration_initial_checks_another_migration_found(self):
5811 fake_server_host = 'fake@backend2'
5812 fake_share_network = {'id': 'fake_share_network_id'}
5813 fake_share_server = db_utils.create_share_server(host=fake_server_host)
5814 fake_share = db_utils.create_share(
5815 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
5816 share_group_id='fake_group_id', share_network=fake_share_network)
5818 mock_shares_get_all = self.mock_object(
5819 db_api, 'share_get_all_by_share_server',
5820 mock.Mock(return_value=[fake_share]))
5821 mock_shares_get_servers_filters = self.mock_object(
5822 db_api, 'share_server_get_all_with_filters',
5823 mock.Mock(return_value=['fake_share_server']))
5825 self.assertRaises(
5826 exception.InvalidShareServer,
5827 self.api._migration_initial_checks,
5828 self.context, fake_share_server, fake_server_host,
5829 fake_share_network,
5830 )
5831 mock_shares_get_all.assert_called_once_with(
5832 self.context, fake_share_server['id'])
5833 filters = {'source_share_server_id': fake_share_server['id'],
5834 'status': constants.STATUS_SERVER_MIGRATING_TO}
5835 mock_shares_get_servers_filters.assert_called_once_with(
5836 self.context, filters=filters)
5838 def test_share_server_migration_get_request_spec_dict(self):
5839 share_instances = [
5840 db_utils.create_share_instance(share_id='fake_id')
5841 for i in range(1, 3)]
5842 snapshot_instances = [
5843 db_utils.create_snapshot_instance(
5844 snapshot_id='fake_' + str(i), share_instance_id='fake')
5845 for i in range(1, 3)]
5846 shares_req_spec = [{} for instance in share_instances]
5847 total_shares_size = sum(
5848 [instance.get('size', 0) for instance in share_instances])
5849 total_snapshots_size = sum(
5850 [instance.get('size', 0) for instance in snapshot_instances])
5851 expected_result = {
5852 'shares_size': total_shares_size,
5853 'snapshots_size': total_snapshots_size,
5854 'shares_req_spec': shares_req_spec,
5855 }
5856 fake_share_type = db_utils.create_share_type()
5857 get_type_calls = []
5858 get_request_spec_calls = []
5859 for instance in share_instances:
5860 get_type_calls.append(
5861 mock.call(self.context, instance['share_type_id']))
5862 get_request_spec_calls.append(
5863 mock.call(self.context, instance, fake_share_type))
5865 mock_get_type = self.mock_object(
5866 share_types, 'get_share_type',
5867 mock.Mock(return_value=fake_share_type))
5868 mock_get_request_spec = self.mock_object(
5869 self.api, '_get_request_spec_dict', mock.Mock(return_value={}))
5871 result = self.api.get_share_server_migration_request_spec_dict(
5872 self.context, share_instances, snapshot_instances)
5874 self.assertEqual(result, expected_result)
5875 mock_get_type.assert_has_calls(get_type_calls)
5876 mock_get_request_spec.assert_has_calls(get_request_spec_calls)
5878 def test__migration_initial_checks_instance_rules_error_status(self):
5879 fake_share_server = fakes.fake_share_server_get()
5880 fake_share_server['host'] = 'fake@backend'
5881 type_data = {
5882 'extra_specs': {
5883 'availability_zones': 'fake_az1,fake_az2'
5884 }
5885 }
5886 fake_server_host = 'fake@backend'
5887 fake_share_server = db_utils.create_share_server(host=fake_server_host)
5888 share_type = db_utils.create_share_type(**type_data)
5889 share_type = db_api.share_type_get(self.context, share_type['id'])
5890 fake_share = db_utils.create_share(
5891 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
5892 share_type_id=share_type['id'], share_group_id='fake_group_id')
5893 fake_share['instance']['access_rules_status'] = constants.STATUS_ERROR
5894 fake_az = {
5895 'id': 'fake_az_id',
5896 'name': 'fake_az1'
5897 }
5898 fake_share_network = None
5899 fake_share_network_id = fake_share['share_network_id']
5900 fake_subnet = db_utils.create_share_network_subnet(
5901 availability_zone_id=fake_az['id'])
5902 fake_host = 'test@fake'
5903 service = {'availability_zone_id': fake_az['id'],
5904 'availability_zone': {'name': fake_az['name']}}
5905 self._setup_mocks_for_initial_checks(fake_share, share_type, service,
5906 fake_az, fake_subnet)
5908 mock_snapshots_get = self.mock_object(
5909 db_api, 'share_snapshot_get_all_for_share',
5910 mock.Mock(return_value=[]))
5912 self.assertRaises(
5913 exception.InvalidShareServer,
5914 self.api._migration_initial_checks,
5915 self.context, fake_share_server, fake_host, fake_share_network,
5916 )
5918 db_api.share_get_all_by_share_server.assert_has_calls([
5919 mock.call(self.context, fake_share_server['id']),
5920 mock.call(self.context, fake_share_server['id'])])
5921 share_types.get_share_type.assert_called_once_with(
5922 self.context, share_type['id'])
5923 utils.validate_service_host.assert_called_once_with(
5924 self.context, fake_host)
5925 db_api.service_get_by_args.assert_called_once_with(
5926 self.context, fake_host, 'manila-share')
5927 db_api.availability_zone_get.assert_called_once_with(
5928 self.context, service['availability_zone']['name']
5929 )
5930 (db_api.share_network_subnets_get_all_by_availability_zone_id.
5931 assert_called_once_with(
5932 self.context, fake_share_network_id, fake_az['id']))
5933 mock_snapshots_get.assert_called_once_with(
5934 self.context, fake_share['id'])
5935 db_api.share_group_get_all_by_share_server.assert_called_once_with(
5936 self.context, fake_share_server['id'])
5938 def test__migration_initial_checks_dest_az_not_match_host_az(self):
5939 type_data = {
5940 'extra_specs': {
5941 'availability_zones': 'zone1,zone2'
5942 }
5943 }
5944 fake_server_host = 'fake@backend'
5945 fake_share_server = db_utils.create_share_server(host=fake_server_host)
5946 share_type = db_utils.create_share_type(**type_data)
5947 share_type = db_api.share_type_get(self.context, share_type['id'])
5948 fake_share = db_utils.create_share(
5949 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
5950 share_type_id=share_type['id'])
5951 fake_share_network = {}
5952 fake_host = 'test@fake'
5953 service = {'availability_zone_id': 'fake_az_id',
5954 'availability_zone': {'name': 'fake_az1'}}
5956 mock_shares_get_all = self.mock_object(
5957 db_api, 'share_get_all_by_share_server',
5958 mock.Mock(return_value=[fake_share]))
5959 mock_get_type = self.mock_object(
5960 share_types, 'get_share_type', mock.Mock(return_value=share_type))
5961 mock_validate_service = self.mock_object(
5962 utils, 'validate_service_host')
5963 mock_service_get = self.mock_object(
5964 db_api, 'service_get_by_args', mock.Mock(return_value=service))
5966 self.assertRaises(
5967 exception.InvalidShareServer,
5968 self.api._migration_initial_checks,
5969 self.context, fake_share_server, fake_host, fake_share_network,
5970 )
5971 mock_shares_get_all.assert_called_once_with(
5972 self.context, fake_share_server['id'])
5973 mock_get_type.assert_called_once_with(self.context, share_type['id'])
5974 mock_validate_service.assert_called_once_with(self.context, fake_host)
5975 mock_service_get.assert_called_once_with(
5976 self.context, fake_host, 'manila-share')
5978 def test__migration_initial_checks_no_matching_subnet(self):
5979 type_data = {
5980 'extra_specs': {
5981 'availability_zones': 'fake_az1,fake_az2'
5982 }
5983 }
5984 fake_server_host = 'fake@backend'
5985 fake_share_server = db_utils.create_share_server(host=fake_server_host)
5986 share_type = db_utils.create_share_type(**type_data)
5987 share_type = db_api.share_type_get(self.context, share_type['id'])
5988 fake_share = db_utils.create_share(
5989 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
5990 share_type_id=share_type['id'])
5991 fake_share_network = db_utils.create_share_network()
5992 fake_az = {
5993 'id': 'fake_az_id',
5994 'name': 'fake_az1'
5995 }
5997 db_utils.create_share_network_subnet(
5998 availability_zone_id='fake',
5999 share_network_id=fake_share_network['id'])
6000 fake_share_network = db_api.share_network_get(
6001 self.context, fake_share_network['id'])
6002 fake_host = 'test@fake'
6003 service = {'availability_zone_id': fake_az['id'],
6004 'availability_zone': {'name': fake_az['name']}}
6006 mock_shares_get_all = self.mock_object(
6007 db_api, 'share_get_all_by_share_server',
6008 mock.Mock(return_value=[fake_share]))
6009 mock_get_type = self.mock_object(
6010 share_types, 'get_share_type', mock.Mock(return_value=share_type))
6011 mock_validate_service = self.mock_object(
6012 utils, 'validate_service_host')
6013 mock_service_get = self.mock_object(
6014 db_api, 'service_get_by_args', mock.Mock(return_value=service))
6015 mock_az_get = self.mock_object(
6016 db_api, 'availability_zone_get', mock.Mock(return_value=fake_az))
6017 mock_get_subnet = self.mock_object(
6018 db_api, 'share_network_subnets_get_all_by_availability_zone_id',
6019 mock.Mock(return_value=None))
6021 self.assertRaises(
6022 exception.InvalidShareServer,
6023 self.api._migration_initial_checks,
6024 self.context, fake_share_server, fake_host, fake_share_network,
6025 )
6026 mock_shares_get_all.assert_called_once_with(
6027 self.context, fake_share_server['id'])
6028 mock_get_type.assert_called_once_with(self.context, share_type['id'])
6029 mock_validate_service.assert_called_once_with(self.context, fake_host)
6030 mock_service_get.assert_called_once_with(
6031 self.context, fake_host, 'manila-share')
6032 mock_get_subnet.assert_called_once_with(
6033 self.context, fake_share_network['id'], fake_az['id'])
6034 mock_az_get.assert_called_once_with(
6035 self.context, service['availability_zone']['name']
6036 )
6038 def test_server_migration_check_nondisruptive_and_network_change(self):
6039 fake_shares = [db_utils.create_share() for i in range(2)]
6040 fake_types = [{'id': 'fake_type_id'}]
6041 fake_share_server = db_utils.create_share_server()
6042 dest_host = fake_share_server['host']
6043 service = {
6044 'availability_zone_id': 'fake_az_id',
6045 'availability_zone': {'name': 'fake_az_name'}
6046 }
6047 fake_share_network = db_utils.create_share_network()
6048 network_has_changed = True
6049 writable = preserve_snapshots = False
6050 nondisruptive = True
6051 expected_result = {
6052 'compatible': False,
6053 'writable': writable,
6054 'nondisruptive': False,
6055 'preserve_snapshots': preserve_snapshots,
6056 'share_network_id': fake_share_network['id'],
6057 'migration_cancel': False,
6058 'migration_get_progress': False
6059 }
6061 mock_initial_checks = self.mock_object(
6062 self.api, '_migration_initial_checks',
6063 mock.Mock(
6064 return_value=[fake_shares, fake_types, service,
6065 fake_share_network['id'], network_has_changed]))
6067 check_result = self.api.share_server_migration_check(
6068 self.context, fake_share_server, dest_host, writable,
6069 nondisruptive, preserve_snapshots, fake_share_network
6070 )
6072 self.assertEqual(expected_result, check_result)
6073 mock_initial_checks.assert_called_once_with(
6074 self.context, fake_share_server, dest_host, fake_share_network)
6076 def test_server_migration_start_nondisruptive_and_network_change(self):
6077 fake_shares = [db_utils.create_share() for i in range(2)]
6078 fake_types = [{'id': 'fake_type_id'}]
6079 fake_share_server = db_utils.create_share_server()
6080 dest_host = fake_share_server['host']
6081 service = {
6082 'availability_zone_id': 'fake_az_id',
6083 'availability_zone': {'name': 'fake_az_name'}
6084 }
6085 fake_share_network = db_utils.create_share_network()
6086 network_has_changed = True
6087 writable = preserve_snapshots = False
6088 nondisruptive = True
6090 mock_initial_checks = self.mock_object(
6091 self.api, '_migration_initial_checks',
6092 mock.Mock(
6093 return_value=[fake_shares, fake_types, service,
6094 fake_share_network['id'], network_has_changed]))
6096 self.assertRaises(
6097 exception.InvalidInput,
6098 self.api.share_server_migration_start,
6099 self.context, fake_share_server, dest_host, writable,
6100 nondisruptive, preserve_snapshots, fake_share_network
6101 )
6103 mock_initial_checks.assert_called_once_with(
6104 self.context, fake_share_server, dest_host, fake_share_network)
6106 def test_share_server_migration_check(self):
6107 type_data = {
6108 'extra_specs': {
6109 'availability_zones': 'fake_az1,fake_az2'
6110 }
6111 }
6112 fake_share_server = db_utils.create_share_server()
6113 share_type = db_utils.create_share_type(**type_data)
6114 share_type = db_api.share_type_get(self.context, share_type['id'])
6115 fake_share = db_utils.create_share(
6116 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
6117 share_type_id=share_type['id'])
6118 fake_shares = [fake_share]
6119 fake_types = [share_type]
6120 fake_share_network = db_utils.create_share_network()
6121 fake_az = {
6122 'id': 'fake_az_id',
6123 'name': 'fake_az1'
6124 }
6125 writable = True
6126 nondisruptive = True
6127 preserve_snapshots = True
6128 fake_share_network = db_api.share_network_get(
6129 self.context, fake_share_network['id'])
6130 fake_host = 'test@fake'
6131 service = {'availability_zone_id': fake_az['id'],
6132 'availability_zone': {'name': fake_az['name']}}
6133 expected_result = {
6134 'requested_capabilities': {},
6135 'supported_capabilities': {}
6136 }
6138 mock_initial_checks = self.mock_object(
6139 self.api, '_migration_initial_checks',
6140 mock.Mock(return_value=[fake_shares, fake_types, service,
6141 fake_share_network['id'], False]))
6142 # NOTE(carloss): Returning an "empty" dictionary should be enough for
6143 # this test case. The unit test to check the values being returned to
6144 # the user should be placed in the share manager, where the dict is
6145 # populated with the real info. At this level we only forward the
6146 # received response to the user.
6147 mock_migration_check = self.mock_object(
6148 self.share_rpcapi, 'share_server_migration_check',
6149 mock.Mock(return_value=expected_result))
6151 result = self.api.share_server_migration_check(
6152 self.context, fake_share_server, fake_host, writable,
6153 nondisruptive, preserve_snapshots, fake_share_network
6154 )
6156 mock_initial_checks.assert_called_once_with(
6157 self.context, fake_share_server, fake_host, fake_share_network)
6158 mock_migration_check.assert_called_once_with(
6159 self.context, fake_share_server['id'], fake_host, writable,
6160 nondisruptive, preserve_snapshots, fake_share_network['id']
6161 )
6162 self.assertEqual(result, expected_result)
6164 def test_share_server_migration_start(self):
6165 type_data = {
6166 'extra_specs': {
6167 'availability_zones': 'fake_az1,fake_az2'
6168 }
6169 }
6170 fake_share_server = db_utils.create_share_server()
6171 share_type = db_utils.create_share_type(**type_data)
6172 share_type = db_api.share_type_get(self.context, share_type['id'])
6173 fake_shares = [db_utils.create_share(
6174 host='fake@backend#pool', status=constants.STATUS_AVAILABLE,
6175 share_type_id=share_type['id'],
6176 share_server_id=fake_share_server['id']) for x in range(4)]
6177 fake_snapshots = [
6178 db_utils.create_snapshot(share_id=fake_shares[0]['id'])]
6179 instance_ids = [share['instance']['id'] for share in fake_shares]
6180 snap_instances = []
6181 snap_instance_ids = []
6182 for fake_share in fake_shares:
6183 for snapshot in fake_snapshots:
6184 snap_instances.append({'id': snapshot['instance']['id']})
6185 snap_instance_ids.append(snapshot['instance']['id'])
6186 fake_types = [share_type]
6187 fake_share_network = db_utils.create_share_network()
6188 writable = True
6189 nondisruptive = True
6190 preserve_snapshots = True
6191 fake_share_network = db_api.share_network_get(
6192 self.context, fake_share_network['id'])
6193 fake_host = 'test@fake'
6194 service = {'availability_zone_id': 'fake_az_id',
6195 'availability_zone': {'name': 'fake_az1'}}
6196 server_expected_update = {
6197 'task_state': constants.TASK_STATE_MIGRATION_STARTING,
6198 'status': constants.STATUS_SERVER_MIGRATING
6199 }
6200 share_expected_update = {
6201 'status': constants.STATUS_SERVER_MIGRATING
6202 }
6203 mock_initial_checks = self.mock_object(
6204 self.api, '_migration_initial_checks',
6205 mock.Mock(return_value=[fake_shares, fake_types, service,
6206 fake_share_network['id'], False]))
6207 mock_migration_start = self.mock_object(
6208 self.share_rpcapi, 'share_server_migration_start')
6209 mock_server_update = self.mock_object(db_api, 'share_server_update')
6210 mock_snapshots_get = self.mock_object(
6211 db_api, 'share_snapshot_instance_get_all_with_filters',
6212 mock.Mock(return_value=snap_instances))
6213 mock_update_instances = self.mock_object(
6214 db_api, 'share_and_snapshot_instances_status_update')
6216 self.api.share_server_migration_start(
6217 self.context, fake_share_server, fake_host, writable,
6218 nondisruptive, preserve_snapshots, fake_share_network
6219 )
6221 mock_initial_checks.assert_called_once_with(
6222 self.context, fake_share_server, fake_host, fake_share_network)
6223 mock_migration_start.assert_called_once_with(
6224 self.context, fake_share_server, fake_host, writable,
6225 nondisruptive, preserve_snapshots, fake_share_network['id']
6226 )
6227 mock_server_update.assert_called_once_with(
6228 self.context, fake_share_server['id'], server_expected_update)
6229 mock_snapshots_get.assert_called()
6230 mock_update_instances.assert_called_once_with(
6231 self.context, share_expected_update,
6232 current_expected_status=constants.STATUS_AVAILABLE,
6233 share_instance_ids=instance_ids,
6234 snapshot_instance_ids=snap_instance_ids)
6236 @ddt.data(
6237 (constants.STATUS_ACTIVE, None),
6238 (constants.STATUS_SERVER_MIGRATING,
6239 constants.TASK_STATE_MIGRATION_STARTING)
6240 )
6241 @ddt.unpack
6242 def test_share_server_migration_complete_invalid_status(self, status,
6243 task_state):
6244 fake_host = 'fakehost@fakebackend'
6245 fake_share_server = db_utils.create_share_server(
6246 status=status, task_state=task_state, host=fake_host)
6247 self.assertRaises(
6248 exception.InvalidShareServer,
6249 self.api.share_server_migration_complete,
6250 self.context, fake_share_server)
6252 def test_share_server_migration_complete(self):
6253 fake_service_host = 'fakehost@fakebackend'
6254 fake_share_server = db_utils.create_share_server(
6255 status=constants.STATUS_SERVER_MIGRATING,
6256 task_state=constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE,
6257 host=fake_service_host)
6258 fake_share_server_dest = db_utils.create_share_server(
6259 status=constants.STATUS_SERVER_MIGRATING_TO,
6260 host=fake_service_host)
6261 fake_service = {'availability_zone_id': 'fake_az_id',
6262 'availability_zone': {'name': 'fake_az1'}}
6264 mock_get_destination = self.mock_object(
6265 self.api, 'share_server_migration_get_destination',
6266 mock.Mock(return_value=fake_share_server_dest))
6267 mock_validate_service_host = self.mock_object(
6268 utils, 'validate_service_host',
6269 mock.Mock(return_value=fake_service))
6270 mock_migration_complete = self.mock_object(
6271 self.share_rpcapi, 'share_server_migration_complete')
6273 result = self.api.share_server_migration_complete(
6274 self.context, fake_share_server)
6276 expected = {
6277 'destination_share_server_id': fake_share_server_dest['id']
6278 }
6279 self.assertEqual(expected, result)
6280 mock_get_destination.assert_called_once_with(
6281 self.context, fake_share_server['id'],
6282 status=constants.STATUS_SERVER_MIGRATING_TO)
6283 mock_validate_service_host.assert_called_once_with(
6284 self.context, fake_service_host)
6285 mock_migration_complete.assert_called_once_with(
6286 self.context, fake_share_server['host'], fake_share_server,
6287 fake_share_server_dest
6288 )
6290 @ddt.data(
6291 (constants.STATUS_ACTIVE, None),
6292 (constants.STATUS_SERVER_MIGRATING,
6293 constants.TASK_STATE_MIGRATION_STARTING)
6294 )
6295 @ddt.unpack
6296 def test_share_server_migration_cancel_server_not_migrating(
6297 self, status, task_state):
6298 fake_share_server = db_utils.create_share_server(
6299 status=status, task_state=task_state)
6301 self.mock_object(self.api, '_migration_validate_error_message',
6302 mock.Mock(return_value=None))
6304 self.assertRaises(
6305 exception.InvalidShareServer,
6306 self.api.share_server_migration_cancel,
6307 self.context,
6308 fake_share_server
6309 )
6311 @ddt.data(constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE,
6312 constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS)
6313 def test_share_server_migration_cancel_service_not_up(self, task_state):
6314 fake_service_host = 'host@backend'
6315 fake_share_server = db_utils.create_share_server(
6316 status=constants.STATUS_SERVER_MIGRATING,
6317 task_state=task_state,
6318 host=fake_service_host)
6319 fake_share_server_dest = db_utils.create_share_server(
6320 status=constants.STATUS_SERVER_MIGRATING_TO,
6321 host=fake_service_host)
6323 mock_get_destination = self.mock_object(
6324 self.api, 'share_server_migration_get_destination',
6325 mock.Mock(return_value=fake_share_server_dest))
6326 mock_validate_service_host = self.mock_object(
6327 utils, 'validate_service_host',
6328 mock.Mock(side_effect=exception.ServiceIsDown(
6329 service="fake_service")))
6331 self.assertRaises(
6332 exception.ServiceIsDown,
6333 self.api.share_server_migration_cancel,
6334 self.context,
6335 fake_share_server
6336 )
6337 mock_get_destination.assert_called_once_with(
6338 self.context, fake_share_server['id'],
6339 status=constants.STATUS_SERVER_MIGRATING_TO)
6340 mock_validate_service_host.assert_called_once_with(
6341 self.context, fake_service_host)
6343 @ddt.data(constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE,
6344 constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS)
6345 def test_share_server_migration_cancel(self, task_state):
6346 fake_service_host = 'host@backend'
6347 fake_share_server = db_utils.create_share_server(
6348 status=constants.STATUS_SERVER_MIGRATING,
6349 task_state=task_state,
6350 host=fake_service_host)
6351 fake_share_server_dest = db_utils.create_share_server(
6352 status=constants.STATUS_SERVER_MIGRATING_TO,
6353 host=fake_service_host)
6354 fake_service = {'availability_zone_id': 'fake_az_id',
6355 'availability_zone': {'name': 'fake_az1'}}
6357 mock_get_destination = self.mock_object(
6358 self.api, 'share_server_migration_get_destination',
6359 mock.Mock(return_value=fake_share_server_dest))
6360 mock_validate_service_host = self.mock_object(
6361 utils, 'validate_service_host',
6362 mock.Mock(return_value=fake_service))
6364 self.api.share_server_migration_cancel(
6365 self.context, fake_share_server)
6367 mock_get_destination.assert_called_once_with(
6368 self.context, fake_share_server['id'],
6369 status=constants.STATUS_SERVER_MIGRATING_TO)
6370 mock_validate_service_host.assert_called_once_with(
6371 self.context, fake_service_host)
6373 def test_share_server_migration_get_progress_not_migrating(self):
6374 fake_share_server = db_utils.create_share_server(
6375 status=constants.STATUS_ACTIVE)
6376 self.assertRaises(
6377 exception.InvalidShareServer,
6378 self.api.share_server_migration_get_progress,
6379 self.context, fake_share_server['id']
6380 )
6382 def test_share_server_migration_get_progress_service_not_up(self):
6383 fake_service_host = 'host@backend'
6384 fake_share_server = db_utils.create_share_server(
6385 status=constants.STATUS_SERVER_MIGRATING,
6386 task_state=constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
6387 host=fake_service_host)
6388 fake_share_server_dest = db_utils.create_share_server(
6389 status=constants.STATUS_SERVER_MIGRATING_TO,
6390 host=fake_service_host)
6392 mock_get_destination = self.mock_object(
6393 self.api, 'share_server_migration_get_destination',
6394 mock.Mock(return_value=fake_share_server_dest))
6395 mock_validate_service_host = self.mock_object(
6396 utils, 'validate_service_host',
6397 mock.Mock(side_effect=exception.ServiceIsDown(
6398 service="fake_service")))
6400 self.assertRaises(
6401 exception.ServiceIsDown,
6402 self.api.share_server_migration_get_progress,
6403 self.context, fake_share_server['id']
6404 )
6406 mock_get_destination.assert_called_once_with(
6407 self.context, fake_share_server['id'],
6408 status=constants.STATUS_SERVER_MIGRATING_TO)
6409 mock_validate_service_host.assert_called_once_with(
6410 self.context, fake_service_host)
6412 def test_share_server_migration_get_progress_rpcapi_exception(self):
6413 fake_service_host = 'host@backend'
6414 fake_share_server = db_utils.create_share_server(
6415 status=constants.STATUS_SERVER_MIGRATING,
6416 task_state=constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
6417 host=fake_service_host)
6418 fake_share_server_dest = db_utils.create_share_server(
6419 status=constants.STATUS_SERVER_MIGRATING_TO,
6420 host=fake_service_host)
6421 fake_service = {'availability_zone_id': 'fake_az_id',
6422 'availability_zone': {'name': 'fake_az1'}}
6424 mock_server_get = self.mock_object(
6425 db_api, 'share_server_get',
6426 mock.Mock(return_value=fake_share_server))
6427 mock_get_destination = self.mock_object(
6428 self.api, 'share_server_migration_get_destination',
6429 mock.Mock(return_value=fake_share_server_dest))
6430 mock_validate_service_host = self.mock_object(
6431 utils, 'validate_service_host',
6432 mock.Mock(return_value=fake_service))
6433 mock_migration_get_progress = self.mock_object(
6434 self.share_rpcapi, 'share_server_migration_get_progress',
6435 mock.Mock(side_effect=Exception))
6437 self.assertRaises(
6438 exception.ShareServerMigrationError,
6439 self.api.share_server_migration_get_progress,
6440 self.context,
6441 fake_share_server['id']
6442 )
6444 mock_server_get.assert_called_once_with(self.context,
6445 fake_share_server['id'])
6446 mock_get_destination.assert_called_once_with(
6447 self.context, fake_share_server['id'],
6448 status=constants.STATUS_SERVER_MIGRATING_TO)
6449 mock_validate_service_host.assert_called_once_with(
6450 self.context, fake_service_host)
6451 mock_migration_get_progress.assert_called_once_with(
6452 self.context, fake_share_server_dest['host'], fake_share_server,
6453 fake_share_server_dest)
6455 @ddt.data(constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
6456 constants.TASK_STATE_MIGRATION_SUCCESS)
6457 def test_share_server_migration_get_progress(self, task_state):
6458 fake_service_host = 'host@backend'
6459 fake_share_server = db_utils.create_share_server(
6460 status=constants.STATUS_SERVER_MIGRATING,
6461 task_state=task_state, host=fake_service_host)
6462 fake_share_server_dest = db_utils.create_share_server(
6463 status=constants.STATUS_SERVER_MIGRATING_TO,
6464 host=fake_service_host)
6465 fake_service = {'availability_zone_id': 'fake_az_id',
6466 'availability_zone': {'name': 'fake_az1'}}
6468 mock_server_get = self.mock_object(
6469 db_api, 'share_server_get',
6470 mock.Mock(return_value=fake_share_server))
6471 mock_get_destination = self.mock_object(
6472 self.api, 'share_server_migration_get_destination',
6473 mock.Mock(return_value=fake_share_server_dest))
6474 mock_validate_service_host = self.mock_object(
6475 utils, 'validate_service_host',
6476 mock.Mock(return_value=fake_service))
6477 mock_migration_get_progress = self.mock_object(
6478 self.share_rpcapi, 'share_server_migration_get_progress',
6479 mock.Mock(return_value={'total_progress': 50}))
6480 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
6482 result = self.api.share_server_migration_get_progress(
6483 self.context, fake_share_server['id'])
6485 self.assertIn('total_progress', result)
6486 mock_server_get.assert_called_once_with(self.context,
6487 fake_share_server['id'])
6488 if task_state == constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS:
6489 mock_get_destination.assert_called_once_with(
6490 self.context, fake_share_server['id'],
6491 status=constants.STATUS_SERVER_MIGRATING_TO)
6492 mock_validate_service_host.assert_called_once_with(
6493 self.context, fake_service_host)
6494 mock_migration_get_progress.assert_called_once_with(
6495 self.context, fake_share_server_dest['host'],
6496 fake_share_server, fake_share_server_dest)
6498 @ddt.data(constants.STATUS_SERVER_MIGRATING_TO,
6499 constants.STATUS_SERVER_MIGRATING)
6500 def test_share_server_migration_get_progress_invalid_share_server(self,
6501 status):
6502 fake_service_host = 'host@backend'
6503 fake_share_server = db_utils.create_share_server(
6504 status=status,
6505 task_state=None,
6506 host=fake_service_host)
6507 mock_server_get = self.mock_object(
6508 db_api, 'share_server_get',
6509 mock.Mock(return_value=fake_share_server))
6510 mock_get_progress_state = self.mock_object(
6511 self.api, '_migration_get_progress_state',
6512 mock.Mock(return_value=None))
6513 self.mock_object(self.api, 'share_server_migration_get_destination')
6515 self.assertRaises(
6516 exception.InvalidShareServer,
6517 self.api.share_server_migration_get_progress,
6518 self.context, fake_share_server['id'])
6520 mock_server_get.assert_called_once_with(self.context,
6521 fake_share_server['id'])
6522 if status == constants.STATUS_SERVER_MIGRATING:
6523 mock_get_progress_state.assert_called_once_with(fake_share_server)
6525 def test_share_server_migration_get_progress_source_not_found(self):
6526 fake_dest_hare_server = db_utils.create_share_server(
6527 status=constants.STATUS_ACTIVE,
6528 task_state=constants.TASK_STATE_MIGRATION_SUCCESS)
6529 mock_server_get = self.mock_object(
6530 db_api, 'share_server_get',
6531 mock.Mock(side_effect=exception.ShareServerNotFound(
6532 share_server_id='fake_id')))
6533 mock_get_destination = self.mock_object(
6534 self.api, 'share_server_migration_get_destination',
6535 mock.Mock(return_value=fake_dest_hare_server))
6537 result = self.api.share_server_migration_get_progress(
6538 self.context, 'fake_source_server_id')
6539 expected = {
6540 'total_progress': 100,
6541 'destination_share_server_id': fake_dest_hare_server['id'],
6542 'task_state': constants.TASK_STATE_MIGRATION_SUCCESS,
6543 }
6545 self.assertEqual(expected, result)
6546 mock_server_get.assert_called_once_with(self.context,
6547 'fake_source_server_id')
6548 mock_get_destination.assert_called_once_with(
6549 self.context, 'fake_source_server_id',
6550 status=constants.STATUS_ACTIVE)
6552 def test_share_server_migration_get_progress_has_destination_only(self):
6553 mock_server_get = self.mock_object(
6554 db_api, 'share_server_get',
6555 mock.Mock(side_effect=exception.ShareServerNotFound(
6556 share_server_id='fake_id')))
6557 mock_get_destination = self.mock_object(
6558 self.api, 'share_server_migration_get_destination',
6559 mock.Mock(side_effect=exception.InvalidShareServer(reason='')))
6561 self.assertRaises(
6562 exception.InvalidShareServer,
6563 self.api.share_server_migration_get_progress,
6564 self.context, 'fake_src_server_id')
6566 mock_server_get.assert_called_once_with(self.context,
6567 'fake_src_server_id')
6568 mock_get_destination.assert_called_once_with(
6569 self.context, 'fake_src_server_id', status=constants.STATUS_ACTIVE)
6571 def test_share_server_migration_get_progress_not_determinated(self):
6572 fake_service_host = 'host@backend'
6573 fake_share_server = db_utils.create_share_server(
6574 status=constants.STATUS_SERVER_MIGRATING,
6575 task_state=None,
6576 host=fake_service_host)
6577 mock_server_get = self.mock_object(
6578 db_api, 'share_server_get',
6579 mock.Mock(return_value=fake_share_server))
6580 mock_get_destination = self.mock_object(
6581 self.api, 'share_server_migration_get_destination',
6582 mock.Mock(side_effect=exception.InvalidShareServer(reason='')))
6583 mock_get_progress_state = self.mock_object(
6584 self.api, '_migration_get_progress_state',
6585 mock.Mock(return_value={'total_progress': 0}))
6587 result = self.api.share_server_migration_get_progress(
6588 self.context, 'fake_source_server_id')
6590 expected = {
6591 'total_progress': 0,
6592 'destination_share_server_id': '',
6593 'task_state': '',
6594 }
6596 self.assertEqual(expected, result)
6597 mock_server_get.assert_called_once_with(self.context,
6598 'fake_source_server_id')
6599 mock_get_destination.assert_called_once_with(
6600 self.context, fake_share_server['id'],
6601 status=constants.STATUS_SERVER_MIGRATING_TO)
6602 mock_get_progress_state.assert_called_once_with(fake_share_server)
6604 def test_migration_get_progress_race(self):
6606 instance1 = db_utils.create_share_instance(
6607 share_id='fake_id',
6608 status=constants.STATUS_MIGRATING,
6609 host='some_host')
6610 instance2 = db_utils.create_share_instance(
6611 share_id='fake_id',
6612 status=constants.STATUS_MIGRATING_TO)
6613 share = db_utils.create_share(
6614 id='fake_id',
6615 task_state=constants.TASK_STATE_MIGRATION_DRIVER_IN_PROGRESS,
6616 instances=[instance1, instance2])
6617 share_ref = fakes.fake_share(
6618 id='fake_id',
6619 task_state=constants.TASK_STATE_MIGRATION_DRIVER_PHASE1_DONE)
6620 service = 'fake_service'
6621 expected = {'total_progress': 100}
6623 self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
6624 self.mock_object(db_api, 'service_get_by_args',
6625 mock.Mock(return_value=service))
6626 self.mock_object(db_api, 'share_instance_get',
6627 mock.Mock(return_value=instance1))
6628 self.mock_object(db_api, 'share_get',
6629 mock.Mock(return_value=share_ref))
6630 self.mock_object(self.api.share_rpcapi, 'migration_get_progress',
6631 mock.Mock(side_effect=exception.InvalidShare('fake')))
6633 result = self.api.migration_get_progress(self.context, share)
6634 self.assertEqual(expected, result)
6636 self.api.share_rpcapi.migration_get_progress.assert_called_once_with(
6637 self.context, instance1, instance2['id'])
6639 def test__share_network_update_initial_checks_network_not_active(self):
6640 share_network = db_utils.create_share_network(
6641 status=constants.STATUS_NETWORK_CHANGE)
6642 new_sec_service = db_utils.create_security_service(
6643 share_network_id=share_network['id'], type='ldap')
6645 self.assertRaises(
6646 webob_exc.HTTPBadRequest,
6647 self.api._share_network_update_initial_checks,
6648 self.context, share_network, new_sec_service
6649 )
6651 def test__share_network_update_initial_checks_server_not_active(self):
6652 share_subnet = db_utils.create_share_network_subnet(
6653 id='fakeid', share_network_id='fakenetid')
6654 db_utils.create_share_server(
6655 share_network_subnets=[share_subnet],
6656 status=constants.STATUS_ERROR,
6657 security_service_update_support=True)
6658 share_network = db_utils.create_share_network(id='fakenetid')
6659 new_sec_service = db_utils.create_security_service(
6660 share_network_id='fakenetid', type='ldap')
6662 self.assertRaises(
6663 exception.InvalidShareNetwork,
6664 self.api._share_network_update_initial_checks,
6665 self.context, share_network, new_sec_service,
6666 )
6668 def test__share_network_update_initial_checks_shares_not_available(self):
6669 share_subnet = db_utils.create_share_network_subnet(
6670 id='fakeid', share_network_id='fake_network_id')
6671 db_utils.create_share_server(share_network_subnets=[share_subnet],
6672 security_service_update_support=True)
6673 share_network = db_utils.create_share_network(
6674 id='fake_network_id')
6675 new_sec_service = db_utils.create_security_service(
6676 share_network_id='fake_network_id', type='ldap')
6677 shares = [db_utils.create_share(status=constants.STATUS_ERROR)]
6679 self.mock_object(utils, 'validate_service_host')
6680 self.mock_object(
6681 self.api, 'get_all', mock.Mock(return_value=shares))
6683 self.assertRaises(
6684 exception.InvalidShareNetwork,
6685 self.api._share_network_update_initial_checks,
6686 self.context, share_network, new_sec_service
6687 )
6688 utils.validate_service_host.assert_called_once_with(
6689 utils.IsAMatcher(context.RequestContext), 'host1')
6690 self.api.get_all.assert_called_once_with(
6691 self.context,
6692 search_opts={'share_network_id': share_network['id']})
6694 def test__share_network_update_initial_checks_rules_in_error(self):
6695 share_subnet = db_utils.create_share_network_subnet(
6696 id='fakeid', share_network_id='fake_network_id')
6697 db_utils.create_share_server(share_network_subnets=[share_subnet],
6698 security_service_update_support=True)
6699 share_network = db_utils.create_share_network(
6700 id='fake_network_id')
6701 new_sec_service = db_utils.create_security_service(
6702 share_network_id='fake_network_id', type='ldap')
6703 shares = [db_utils.create_share(status=constants.STATUS_AVAILABLE)]
6704 shares[0]['instance']['access_rules_status'] = (
6705 constants.ACCESS_STATE_ERROR)
6707 self.mock_object(utils, 'validate_service_host')
6708 self.mock_object(
6709 self.api, 'get_all', mock.Mock(return_value=shares))
6711 self.assertRaises(
6712 exception.InvalidShareNetwork,
6713 self.api._share_network_update_initial_checks,
6714 self.context, share_network, new_sec_service
6715 )
6716 utils.validate_service_host.assert_called_once_with(
6717 utils.IsAMatcher(context.RequestContext), 'host1')
6718 self.api.get_all.assert_called_once_with(
6719 self.context,
6720 search_opts={'share_network_id': share_network['id']})
6722 def test__share_network_update_initial_checks_share_is_busy(self):
6723 share_subnet = db_utils.create_share_network_subnet(
6724 id='fakeid', share_network_id='fake_net_id')
6725 db_utils.create_share_server(share_network_subnets=[share_subnet],
6726 security_service_update_support=True)
6727 share_network = db_utils.create_share_network(id='fake_net_id')
6728 new_sec_service = db_utils.create_security_service(
6729 share_network_id='fake_net_id', type='ldap')
6730 shares = [db_utils.create_share(status=constants.STATUS_AVAILABLE)]
6732 self.mock_object(utils, 'validate_service_host')
6733 self.mock_object(
6734 self.api, 'get_all', mock.Mock(return_value=shares))
6735 self.mock_object(
6736 self.api, '_check_is_share_busy',
6737 mock.Mock(side_effect=exception.ShareBusyException(message='fake'))
6738 )
6740 self.assertRaises(
6741 exception.InvalidShareNetwork,
6742 self.api._share_network_update_initial_checks,
6743 self.context, share_network, new_sec_service
6744 )
6745 utils.validate_service_host.assert_called_once_with(
6746 utils.IsAMatcher(context.RequestContext), 'host1')
6747 self.api.get_all.assert_called_once_with(
6748 self.context,
6749 search_opts={'share_network_id': share_network['id']})
6750 self.api._check_is_share_busy.assert_called_once_with(shares[0])
6752 def test__share_network_update_initial_checks_unsupported_server(self):
6753 share_subnet = db_utils.create_share_network_subnet(
6754 id='fakeid', share_network_id='fake_net_id')
6755 db_utils.create_share_server(share_network_subnets=[share_subnet],
6756 security_service_update_support=False)
6757 share_network = db_utils.create_share_network(id='fake_net_id')
6759 self.assertRaises(
6760 exception.InvalidShareNetwork,
6761 self.api._share_network_update_initial_checks,
6762 self.context, share_network, None
6763 )
6765 def test__share_network_update_initial_checks_update_different_types(self):
6766 db_utils.create_share_server(share_network_subnet_id='fakeid',
6767 security_service_update_support=True)
6768 db_utils.create_share_network_subnet(
6769 id='fakeid', share_network_id='fake_net_id')
6770 share_network = db_utils.create_share_network(id='fake_net_id')
6771 new_sec_service = db_utils.create_security_service(
6772 share_network_id='fake_net_id', type='ldap')
6773 curr_sec_service = db_utils.create_security_service(
6774 share_network_id='fake_net_id', type='kerberos')
6776 self.assertRaises(
6777 exception.InvalidSecurityService,
6778 self.api._share_network_update_initial_checks,
6779 self.context, share_network, new_sec_service,
6780 current_security_service=curr_sec_service
6781 )
6783 def test__share_network_update_initial_checks_add_type_conflict(self):
6784 db_utils.create_share_server(share_network_subnet_id='fakeid',
6785 security_service_update_support=True)
6786 db_utils.create_share_network_subnet(
6787 id='fakeid', share_network_id='fake_net_id')
6788 share_network = db_utils.create_share_network(id='fake_net_id')
6789 db_utils.create_security_service(
6790 share_network_id='fake_net_id', type='ldap')
6791 share_network = db_api.share_network_get(self.context,
6792 share_network['id'])
6793 new_sec_service = db_utils.create_security_service(
6794 share_network_id='fake_net_id', type='ldap')
6796 self.assertRaises(
6797 exception.InvalidSecurityService,
6798 self.api._share_network_update_initial_checks,
6799 self.context, share_network, new_sec_service,
6800 )
6802 def test_update_share_network_security_service_no_share_servers(self):
6803 mock_initial_checks = self.mock_object(
6804 self.api, '_share_network_update_initial_checks',
6805 mock.Mock(return_value=([], [])))
6806 mock_get_key = self.mock_object(
6807 self.api, 'get_security_service_update_key')
6808 fake_share_network = {'id': 'fake_share_net_id'}
6809 fake_sec_service = {'id': 'fake_sec_serv_id'}
6811 self.api.update_share_network_security_service(
6812 self.context, fake_share_network, fake_sec_service,
6813 current_security_service=None)
6815 mock_initial_checks.assert_called_once_with(
6816 self.context, fake_share_network, fake_sec_service,
6817 current_security_service=None)
6818 mock_get_key.assert_not_called()
6820 def test_update_share_network_security_service_without_check(self):
6821 mock_initial_checks = self.mock_object(
6822 self.api, '_share_network_update_initial_checks',
6823 mock.Mock(return_value=(['fake_server'], ['fake_host'])))
6824 mock_get_key = self.mock_object(
6825 self.api, 'get_security_service_update_key',
6826 mock.Mock(return_value=None))
6827 fake_share_network = {'id': 'fake_share_net_id'}
6828 fake_sec_service = {'id': 'fake_sec_serv_id'}
6830 self.assertRaises(exception.InvalidShareNetwork,
6831 self.api.update_share_network_security_service,
6832 self.context, fake_share_network, fake_sec_service)
6834 mock_initial_checks.assert_called_once_with(
6835 self.context, fake_share_network, fake_sec_service,
6836 current_security_service=None)
6837 mock_get_key.assert_called_once_with(
6838 'hosts_check', fake_sec_service['id'],
6839 current_security_service_id=None)
6841 def test_update_share_network_security_service_update_hosts_failure(self):
6842 mock_initial_checks = self.mock_object(
6843 self.api, '_share_network_update_initial_checks',
6844 mock.Mock(return_value=(['fake_server'], ['fake_host'])))
6845 mock_get_key = self.mock_object(
6846 self.api, 'get_security_service_update_key',
6847 mock.Mock(return_value='fake_key'))
6848 mock_async_db_get = self.mock_object(
6849 db_api, 'async_operation_data_get',
6850 mock.Mock(return_value='fake_value'))
6851 mock_validate_host = self.mock_object(
6852 self.api, '_security_service_update_validate_hosts',
6853 mock.Mock(side_effect=Exception))
6854 mock_async_db_delete = self.mock_object(
6855 db_api, 'async_operation_data_delete')
6856 fake_share_network = {'id': 'fake_share_net_id'}
6857 fake_sec_service = {'id': 'fake_sec_serv_id'}
6859 self.assertRaises(exception.InvalidShareNetwork,
6860 self.api.update_share_network_security_service,
6861 self.context, fake_share_network, fake_sec_service)
6863 mock_initial_checks.assert_called_once_with(
6864 self.context, fake_share_network, fake_sec_service,
6865 current_security_service=None)
6866 mock_get_key.assert_called_once_with(
6867 'hosts_check', fake_sec_service['id'],
6868 current_security_service_id=None)
6869 mock_async_db_get.assert_called_once_with(
6870 self.context, fake_share_network['id'], 'fake_key')
6871 mock_validate_host.assert_called_once_with(
6872 self.context, fake_share_network, ['fake_host'], ['fake_server'],
6873 new_security_service_id=fake_sec_service['id'],
6874 current_security_service_id=None)
6875 mock_async_db_delete.assert_called_once_with(
6876 self.context, fake_share_network['id'], 'fake_key')
6878 def test_update_share_network_security_service_backend_host_failure(self):
6879 share_network = db_utils.create_share_network()
6880 security_service = db_utils.create_security_service()
6881 backend_host = 'fakehost'
6883 mock_initial_checks = self.mock_object(
6884 self.api, '_share_network_update_initial_checks',
6885 mock.Mock(return_value=(['fake_server'], [backend_host])))
6886 mock_get_update_key = self.mock_object(
6887 self.api, 'get_security_service_update_key',
6888 mock.Mock(return_value='fake_key'))
6889 mock_db_async_op = self.mock_object(
6890 db_api, 'async_operation_data_get',
6891 mock.Mock(return_value='fake_update_value'))
6892 mock_validate_host = self.mock_object(
6893 self.api, '_security_service_update_validate_hosts',
6894 mock.Mock(return_value=(False, None)))
6896 self.assertRaises(
6897 exception.InvalidShareNetwork,
6898 self.api.update_share_network_security_service,
6899 self.context, share_network, security_service)
6901 mock_initial_checks.assert_called_once_with(
6902 self.context, share_network, security_service,
6903 current_security_service=None)
6904 mock_db_async_op.assert_called_once_with(
6905 self.context, share_network['id'], 'fake_key')
6906 mock_get_update_key.assert_called_once_with(
6907 'hosts_check', security_service['id'],
6908 current_security_service_id=None)
6909 mock_validate_host.assert_called_once_with(
6910 self.context, share_network, [backend_host], ['fake_server'],
6911 new_security_service_id=security_service['id'],
6912 current_security_service_id=None)
6914 def test_update_share_network_security_service(self):
6915 share_network = db_utils.create_share_network()
6916 security_service = db_utils.create_security_service()
6917 backend_hosts = ['fakehost']
6918 fake_update_key = 'fake_key'
6919 servers = [
6920 db_utils.create_share_server() for i in range(2)]
6921 server_ids = [server['id'] for server in servers]
6923 mock_initial_checks = self.mock_object(
6924 self.api, '_share_network_update_initial_checks',
6925 mock.Mock(return_value=(servers, backend_hosts)))
6926 mock_get_update_key = self.mock_object(
6927 self.api, 'get_security_service_update_key',
6928 mock.Mock(return_value=fake_update_key))
6929 mock_db_async_op = self.mock_object(
6930 db_api, 'async_operation_data_get',
6931 mock.Mock(return_value='fake_update_value'))
6932 mock_validate_host = self.mock_object(
6933 self.api, '_security_service_update_validate_hosts',
6934 mock.Mock(return_value=(True, None)))
6935 mock_network_update = self.mock_object(
6936 db_api, 'share_network_update')
6937 mock_servers_update = self.mock_object(
6938 db_api, 'share_servers_update')
6939 mock_update_security_services = self.mock_object(
6940 self.share_rpcapi, 'update_share_network_security_service')
6941 mock_db_async_op_del = self.mock_object(
6942 db_api, 'async_operation_data_delete',)
6944 self.api.update_share_network_security_service(
6945 self.context, share_network, security_service)
6947 mock_initial_checks.assert_called_once_with(
6948 self.context, share_network, security_service,
6949 current_security_service=None)
6950 mock_db_async_op.assert_called_once_with(
6951 self.context, share_network['id'], fake_update_key)
6952 mock_get_update_key.assert_called_once_with(
6953 'hosts_check', security_service['id'],
6954 current_security_service_id=None)
6955 mock_validate_host.assert_called_once_with(
6956 self.context, share_network, backend_hosts, servers,
6957 new_security_service_id=security_service['id'],
6958 current_security_service_id=None)
6959 mock_network_update.assert_called_once_with(
6960 self.context, share_network['id'],
6961 {'status': constants.STATUS_NETWORK_CHANGE})
6962 mock_servers_update.assert_called_once_with(
6963 self.context, server_ids,
6964 {'status': constants.STATUS_SERVER_NETWORK_CHANGE}
6965 )
6966 mock_update_security_services.assert_called_once_with(
6967 self.context, backend_hosts[0], share_network['id'],
6968 security_service['id'], current_security_service_id=None)
6969 mock_db_async_op_del.assert_called_once_with(
6970 self.context, share_network['id'], fake_update_key)
6972 def test__security_service_update_validate_hosts_new_check(self):
6973 curr_sec_service_id = "fake_curr_sec_serv_id"
6974 new_sec_service_id = "fake_new_sec_serv_id"
6975 fake_key = (curr_sec_service_id + '_' + new_sec_service_id +
6976 '_' + 'hosts_check')
6977 fake_share_network = {'id': 'fake_network_id'}
6978 backend_hosts = {'hostA', 'hostB'}
6979 fake_return = 'fake_update'
6980 mock_get_key = self.mock_object(
6981 self.api, 'get_security_service_update_key',
6982 mock.Mock(return_value=fake_key))
6983 mock_do_update_validate = self.mock_object(
6984 self.api, '_do_update_validate_hosts',
6985 mock.Mock(return_value=fake_return))
6987 res = self.api._security_service_update_validate_hosts(
6988 self.context, fake_share_network, backend_hosts, None,
6989 new_security_service_id=new_sec_service_id,
6990 current_security_service_id=curr_sec_service_id)
6992 self.assertEqual(fake_return, res)
6993 mock_get_key.assert_called_once_with(
6994 'hosts_check', new_sec_service_id,
6995 current_security_service_id=curr_sec_service_id)
6996 mock_do_update_validate.assert_called_once_with(
6997 self.context, fake_share_network['id'], backend_hosts, fake_key,
6998 new_security_service_id=new_sec_service_id,
6999 current_security_service_id=curr_sec_service_id)
7001 @ddt.data(True, False)
7002 def test__do_update_validate_hosts(self, update_security_service):
7003 curr_sec_service_id = None
7004 new_sec_service_id = None
7005 new_share_network_subnet = 'fake_new_share_network_subnet'
7006 if update_security_service:
7007 curr_sec_service_id = "fake_curr_sec_serv_id"
7008 new_sec_service_id = "fake_new_sec_serv_id"
7009 new_share_network_subnet = None
7011 fake_key = 'fake_key'
7012 fake_share_network_id = 'fake_network_id'
7013 backend_hosts = {'hostA', 'hostB'}
7014 hosts_to_validate = {}
7015 for bh in backend_hosts:
7016 hosts_to_validate[bh] = None
7017 mock_async_data_get = self.mock_object(
7018 db_api, 'async_operation_data_get', mock.Mock(return_value=None))
7019 mock_async_data_update = self.mock_object(
7020 db_api, 'async_operation_data_update')
7021 mock_check_update_allocations = self.mock_object(
7022 self.share_rpcapi, 'check_update_share_server_network_allocations')
7023 mock_check_update_services = self.mock_object(
7024 self.share_rpcapi, 'check_update_share_network_security_service')
7026 compatible, hosts_info = self.api._do_update_validate_hosts(
7027 self.context, fake_share_network_id, backend_hosts, fake_key,
7028 new_share_network_subnet=new_share_network_subnet,
7029 new_security_service_id=new_sec_service_id,
7030 current_security_service_id=curr_sec_service_id)
7032 self.assertIsNone(compatible)
7033 self.assertEqual(hosts_to_validate, hosts_info)
7034 mock_async_data_get.assert_called_once_with(
7035 self.context, fake_share_network_id, fake_key)
7036 mock_async_data_update.assert_called_once_with(
7037 self.context, fake_share_network_id,
7038 {fake_key: json.dumps(hosts_to_validate)})
7039 mock_share_api_check_calls = []
7040 for host in backend_hosts:
7041 if update_security_service:
7042 mock_share_api_check_calls.append(
7043 mock.call(self.context, host, fake_share_network_id,
7044 new_sec_service_id,
7045 current_security_service_id=curr_sec_service_id))
7046 else:
7047 mock_share_api_check_calls.append(
7048 mock.call(self.context, host, fake_share_network_id,
7049 new_share_network_subnet))
7050 if update_security_service:
7051 mock_check_update_services.assert_has_calls(
7052 mock_share_api_check_calls)
7053 mock_check_update_allocations.assert_not_called()
7054 else:
7055 mock_check_update_allocations.assert_has_calls(
7056 mock_share_api_check_calls)
7057 mock_check_update_services.assert_not_called()
7059 @ddt.data(
7060 {'update_security_service': True, 'new_host': None,
7061 'host_support': None, 'exp_result': None},
7062 {'update_security_service': True, 'new_host': None,
7063 'host_support': False, 'exp_result': False},
7064 {'update_security_service': True, 'new_host': None,
7065 'host_support': True, 'exp_result': True},
7066 {'update_security_service': True, 'new_host': 'hostC',
7067 'host_support': None, 'exp_result': None},
7068 {'update_security_service': True, 'new_host': 'hostC',
7069 'host_support': False, 'exp_result': False},
7070 {'update_security_service': True, 'new_host': 'hostC',
7071 'host_support': True, 'exp_result': None},
7072 {'update_security_service': False, 'new_host': None,
7073 'host_support': None, 'exp_result': None},
7074 {'update_security_service': False, 'new_host': None,
7075 'host_support': False, 'exp_result': False},
7076 {'update_security_service': False, 'new_host': None,
7077 'host_support': True, 'exp_result': True},
7078 {'update_security_service': False, 'new_host': 'hostC',
7079 'host_support': None, 'exp_result': None},
7080 {'update_security_service': False, 'new_host': 'hostC',
7081 'host_support': False, 'exp_result': False},
7082 {'update_security_service': False, 'new_host': 'hostC',
7083 'host_support': True, 'exp_result': None},
7084 )
7085 @ddt.unpack
7086 def test__do_update_validate_hosts_all(
7087 self, update_security_service, new_host, host_support, exp_result):
7088 curr_sec_service_id = None
7089 new_sec_service_id = None
7090 new_share_network_subnet = 'fake_new_share_network_subnet'
7091 if update_security_service:
7092 curr_sec_service_id = "fake_curr_sec_serv_id"
7093 new_sec_service_id = "fake_new_sec_serv_id"
7094 new_share_network_subnet = None
7096 fake_key = 'fake_key'
7097 fake_share_network_id = 'fake_network_id'
7098 backend_hosts = ['hostA', 'hostB']
7099 hosts_to_validate = {}
7100 for bh in backend_hosts:
7101 hosts_to_validate[bh] = host_support
7102 json_orig_hosts = json.dumps(hosts_to_validate)
7104 if new_host:
7105 backend_hosts.append(new_host)
7106 hosts_to_validate[new_host] = None
7108 mock_async_data_get = self.mock_object(
7109 db_api, 'async_operation_data_get',
7110 mock.Mock(return_value=json_orig_hosts))
7111 mock_async_data_update = self.mock_object(
7112 db_api, 'async_operation_data_update')
7113 mock_check_update_allocations = self.mock_object(
7114 self.share_rpcapi, 'check_update_share_server_network_allocations')
7115 mock_check_update_services = self.mock_object(
7116 self.share_rpcapi, 'check_update_share_network_security_service')
7118 result, hosts_info = self.api._do_update_validate_hosts(
7119 self.context, fake_share_network_id, backend_hosts, fake_key,
7120 new_share_network_subnet=new_share_network_subnet,
7121 new_security_service_id=new_sec_service_id,
7122 current_security_service_id=curr_sec_service_id)
7124 self.assertEqual(exp_result, result)
7125 self.assertEqual(hosts_to_validate, hosts_info)
7126 mock_async_data_get.assert_called_once_with(
7127 self.context, fake_share_network_id, fake_key)
7129 # we fail earlier if one one the host answer False.
7130 if new_host and host_support is not False:
7131 mock_async_data_update.assert_called_once_with(
7132 self.context, fake_share_network_id,
7133 {fake_key: json.dumps(hosts_to_validate)})
7134 if update_security_service:
7135 mock_check_update_services.assert_called_once_with(
7136 self.context, new_host, fake_share_network_id,
7137 new_sec_service_id,
7138 current_security_service_id=curr_sec_service_id)
7139 else:
7140 mock_check_update_allocations.assert_called_once_with(
7141 self.context, new_host, fake_share_network_id,
7142 new_share_network_subnet)
7144 def test_soft_delete_share_already_soft_deleted(self):
7145 share = fakes.fake_share(id='fake_id',
7146 status=constants.STATUS_AVAILABLE,
7147 is_soft_deleted=True)
7148 self.assertRaises(exception.InvalidShare,
7149 self.api.soft_delete, self.context, share)
7151 def test_soft_delete_invalid_status(self):
7152 invalid_status = 'fake'
7153 share = fakes.fake_share(id='fake_id',
7154 status=invalid_status,
7155 is_soft_deleted=False)
7157 self.assertRaises(exception.InvalidShare,
7158 self.api.soft_delete, self.context, share)
7160 def test_soft_delete_share_with_replicas(self):
7161 share = fakes.fake_share(id='fake_id',
7162 has_replicas=True,
7163 status=constants.STATUS_AVAILABLE,
7164 is_soft_deleted=False)
7166 self.assertRaises(exception.Conflict,
7167 self.api.soft_delete, self.context, share)
7169 def test_soft_delete_share_with_snapshot(self):
7170 share = fakes.fake_share(id='fake_id',
7171 status=constants.STATUS_AVAILABLE,
7172 has_replicas=False,
7173 is_soft_deleted=False)
7174 snapshot = fakes.fake_snapshot(create_instance=True, as_primitive=True)
7175 mock_db_snapshot_call = self.mock_object(
7176 db_api, 'share_snapshot_get_all_for_share', mock.Mock(
7177 return_value=[snapshot]))
7179 self.assertRaises(exception.InvalidShare,
7180 self.api.soft_delete, self.context, share)
7182 mock_db_snapshot_call.assert_called_once_with(
7183 self.context, share['id'])
7185 @mock.patch.object(db_api, 'count_share_group_snapshot_members_in_share',
7186 mock.Mock(return_value=2))
7187 def test_soft_delete_share_with_group_snapshot_members(self):
7188 share = fakes.fake_share(id='fake_id',
7189 status=constants.STATUS_AVAILABLE,
7190 has_replicas=False,
7191 is_soft_deleted=False)
7192 self.mock_object(db_api, 'share_backups_get_all',
7193 mock.Mock(return_value=[]))
7195 self.assertRaises(exception.InvalidShare,
7196 self.api.soft_delete, self.context, share)
7198 def test_soft_delete_locked_share(self):
7199 self.mock_object(
7200 self.api.db,
7201 'resource_lock_get_all',
7202 mock.Mock(return_value=([{'id': 'l1'}, {'id': 'l2'}], None))
7203 )
7204 share = self._setup_delete_mocks('available')
7205 self.mock_object(db_api, 'share_soft_delete')
7207 self.assertRaises(exception.InvalidShare,
7208 self.api.soft_delete,
7209 self.context,
7210 share)
7212 # lock check decorator executed first, nothing else is invoked
7213 db_api.share_soft_delete.assert_not_called()
7214 db_api.share_snapshot_get_all_for_share.assert_not_called()
7216 def test_soft_delete_share(self):
7217 share = fakes.fake_share(id='fake_id',
7218 status=constants.STATUS_AVAILABLE,
7219 has_replicas=False,
7220 is_soft_deleted=False)
7221 self.mock_object(db_api, 'share_snapshot_get_all_for_share',
7222 mock.Mock(return_value=[]))
7223 self.mock_object(db_api, 'share_backups_get_all',
7224 mock.Mock(return_value=[]))
7225 self.mock_object(db_api, 'count_share_group_snapshot_members_in_share',
7226 mock.Mock(return_value=0))
7227 self.mock_object(db_api, 'share_soft_delete')
7228 self.mock_object(self.api, '_check_is_share_busy')
7229 self.api.soft_delete(self.context, share)
7230 self.api._check_is_share_busy.assert_called_once_with(share)
7232 def test_restore_share(self):
7233 share = fakes.fake_share(id='fake_id',
7234 status=constants.STATUS_AVAILABLE,
7235 is_soft_deleted=True)
7236 self.mock_object(db_api, 'share_restore')
7237 self.api.restore(self.context, share)
7239 def test__share_server_update_allocations_validate_hosts(self):
7240 update_return = 'fake_return'
7241 mock_do_update = self.mock_object(
7242 self.api, '_do_update_validate_hosts',
7243 mock.Mock(return_value=update_return))
7245 backend_hosts = 'fake_hosts'
7246 update_key = 'fake_key'
7247 share_network_id = 'fake_net_id'
7248 subnet = {
7249 'neutron_net_id': 'fake_net_id',
7250 'neutron_subnet_id': 'fake_subnet_id',
7251 'availability_zone_id': 'fake_availability_zone_id',
7252 }
7253 res = self.api._share_server_update_allocations_validate_hosts(
7254 self.context, backend_hosts, update_key,
7255 share_network_id=share_network_id,
7256 neutron_net_id=subnet['neutron_net_id'],
7257 neutron_subnet_id=subnet['neutron_subnet_id'],
7258 availability_zone_id=subnet['availability_zone_id'])
7260 self.assertEqual(update_return, res)
7261 mock_do_update.assert_called_once_with(
7262 self.context, share_network_id, backend_hosts, update_key,
7263 new_share_network_subnet=subnet)
7265 def test_get_share_server_update_allocations_key(self):
7266 availability_zone_id = None
7267 share_network_id = 'fake_share_network_id'
7268 expected_key = ('share_server_update_allocations_' +
7269 share_network_id + '_' + str(availability_zone_id) +
7270 '_' + 'hosts_check')
7271 res = self.api.get_share_server_update_allocations_key(
7272 share_network_id, availability_zone_id)
7274 self.assertEqual(expected_key, res)
7276 def test__share_server_update_allocations_initial_checks(self):
7277 share_network = db_utils.create_share_network()
7278 share1 = db_utils.create_share(
7279 share_network_id=share_network['id'],
7280 status=constants.STATUS_AVAILABLE)
7281 server_host = 'fake_host'
7282 share_server = db_utils.create_share_server(host=server_host)
7283 mock_validate_service_host = self.mock_object(
7284 utils, 'validate_service_host')
7285 mock_share_get_all_by_share_server = self.mock_object(
7286 self.api.db, 'share_get_all_by_share_server',
7287 mock.Mock(return_value=[share1]))
7288 mock_share_is_busy = self.mock_object(
7289 self.api, '_check_is_share_busy')
7291 res_hosts = self.api._share_server_update_allocations_initial_checks(
7292 self.context, share_network, [share_server])
7294 self.assertEqual(set([server_host]), res_hosts)
7295 mock_validate_service_host.assert_called_once()
7296 mock_share_get_all_by_share_server.assert_called_once_with(
7297 self.context, share_server['id'])
7298 mock_share_is_busy.assert_called_once_with(share1)
7300 def test__share_server_update_allocations_initial_checks_no_support(self):
7301 fake_share_network = {
7302 'id': 'fake_sn_id',
7303 'network_allocation_update_support': False,
7304 'status': constants.STATUS_NETWORK_ACTIVE,
7305 }
7306 sn_subnet = db_utils.create_share_network_subnet()
7308 self.assertRaises(
7309 exception.InvalidShareNetwork,
7310 self.api._share_server_update_allocations_initial_checks,
7311 self.context,
7312 fake_share_network,
7313 sn_subnet)
7315 def test__share_server_update_allocations_initial_checks_inactive(self):
7316 share_network = db_utils.create_share_network()
7317 share_server = db_utils.create_share_server(
7318 status=constants.STATUS_INACTIVE)
7320 self.assertRaises(
7321 exception.InvalidShareNetwork,
7322 self.api._share_server_update_allocations_initial_checks,
7323 self.context,
7324 share_network,
7325 [share_server])
7327 def test__share_server_update_allocations_initial_checks_shares_na(self):
7328 share_network = db_utils.create_share_network()
7329 share1 = db_utils.create_share(
7330 share_network_id=share_network['id'],
7331 status=constants.STATUS_ERROR)
7332 share_server = db_utils.create_share_server()
7333 mock_validate_service_host = self.mock_object(
7334 utils, 'validate_service_host')
7335 mock_share_get_all_by_share_server = self.mock_object(
7336 self.api.db, 'share_get_all_by_share_server',
7337 mock.Mock(return_value=[share1]))
7339 self.assertRaises(
7340 exception.InvalidShareNetwork,
7341 self.api._share_server_update_allocations_initial_checks,
7342 self.context,
7343 share_network,
7344 [share_server])
7346 mock_validate_service_host.assert_called_once()
7347 mock_share_get_all_by_share_server.assert_called_once_with(
7348 self.context, share_server['id'])
7350 def test__share_server_update_allocations_initial_checks_rules_na(self):
7351 share_network = db_utils.create_share_network()
7352 share1 = db_utils.create_share(
7353 share_network_id=share_network['id'],
7354 status=constants.STATUS_AVAILABLE)
7355 share_server = db_utils.create_share_server()
7356 share1['instance']['access_rules_status'] = constants.STATUS_INACTIVE
7357 mock_validate_service_host = self.mock_object(
7358 utils, 'validate_service_host')
7359 mock_share_get_all_by_share_server = self.mock_object(
7360 self.api.db, 'share_get_all_by_share_server',
7361 mock.Mock(return_value=[share1]))
7363 self.assertRaises(
7364 exception.InvalidShareNetwork,
7365 self.api._share_server_update_allocations_initial_checks,
7366 self.context,
7367 share_network,
7368 [share_server])
7370 mock_validate_service_host.assert_called_once()
7371 mock_share_get_all_by_share_server.assert_called_once_with(
7372 self.context, share_server['id'])
7374 def test__share_server_update_allocations_initial_checks_share_busy(self):
7375 share_network = db_utils.create_share_network()
7376 share1 = db_utils.create_share(
7377 share_network_id=share_network['id'],
7378 status=constants.STATUS_AVAILABLE)
7379 share_server = db_utils.create_share_server()
7380 mock_validate_service_host = self.mock_object(
7381 utils, 'validate_service_host')
7382 mock_share_get_all_by_share_server = self.mock_object(
7383 self.api.db, 'share_get_all_by_share_server',
7384 mock.Mock(return_value=[share1]))
7385 mock_share_is_busy = self.mock_object(
7386 self.api, '_check_is_share_busy',
7387 mock.Mock(side_effect=exception.ShareBusyException(message='fake'))
7388 )
7390 self.assertRaises(
7391 exception.InvalidShareNetwork,
7392 self.api._share_server_update_allocations_initial_checks,
7393 self.context,
7394 share_network,
7395 [share_server])
7397 mock_validate_service_host.assert_called_once()
7398 mock_share_get_all_by_share_server.assert_called_once_with(
7399 self.context, share_server['id'])
7400 mock_share_is_busy.assert_called_once_with(share1)
7402 def test_check_update_share_server_network_allocations(self):
7403 backend_hosts = 'fake_hosts'
7404 mock_initial_check = self.mock_object(
7405 self.api, '_share_server_update_allocations_initial_checks',
7406 mock.Mock(return_value=backend_hosts))
7407 update_key = 'fake_key'
7408 mock_get_key = self.mock_object(
7409 self.api, 'get_share_server_update_allocations_key',
7410 mock.Mock(return_value=update_key))
7411 mock_reset_data = self.mock_object(
7412 self.api.db, 'async_operation_data_delete')
7413 compatible = True
7414 hosts_info = {'fake_host': True}
7415 mock_validate_hosts = self.mock_object(
7416 self.api, '_share_server_update_allocations_validate_hosts',
7417 mock.Mock(return_value=(compatible, hosts_info)))
7419 share_network = {'id': 'fake_id'}
7420 new_share_network_subnet = {
7421 'share_servers': 'fake_servers',
7422 'availability_zone_id': 'fake_availability_zone_id',
7423 'neutron_net_id': 'fake_neutron_net_id',
7424 'neutron_subnet_id': 'fake_neutron_subnet_id',
7425 }
7426 res = self.api.check_update_share_server_network_allocations(
7427 self.context, share_network, new_share_network_subnet, True)
7429 self.assertEqual(
7430 {'compatible': compatible, 'hosts_check_result': hosts_info}, res)
7431 mock_initial_check.assert_called_once_with(
7432 self.context, share_network,
7433 new_share_network_subnet['share_servers'])
7434 mock_get_key.assert_called_once_with(
7435 share_network['id'],
7436 new_share_network_subnet['availability_zone_id'])
7437 mock_reset_data.assert_called_once_with(
7438 self.context, share_network['id'], update_key)
7439 mock_validate_hosts.assert_called_once_with(
7440 self.context, backend_hosts, update_key,
7441 share_network_id=share_network['id'],
7442 neutron_net_id=new_share_network_subnet['neutron_net_id'],
7443 neutron_subnet_id=new_share_network_subnet['neutron_subnet_id'],
7444 availability_zone_id=(
7445 new_share_network_subnet["availability_zone_id"]))
7447 def test_check_update_share_server_network_allocations_failed(self):
7448 backend_hosts = 'fake_hosts'
7449 self.mock_object(
7450 self.api, '_share_server_update_allocations_initial_checks',
7451 mock.Mock(return_value=backend_hosts))
7452 update_key = 'fake_key'
7453 self.mock_object(
7454 self.api, 'get_share_server_update_allocations_key',
7455 mock.Mock(return_value=update_key))
7456 self.mock_object(self.api.db, 'async_operation_data_delete')
7457 self.mock_object(
7458 self.api, '_share_server_update_allocations_validate_hosts',
7459 mock.Mock(side_effect=exception.InvalidShareNetwork(reason="msg")))
7461 share_network = {'id': 'fake_id'}
7462 new_share_network_subnet = {
7463 'share_servers': 'fake_servers',
7464 'availability_zone_id': 'fake_availability_zone_id',
7465 'neutron_net_id': 'fake_neutron_net_id',
7466 'neutron_subnet_id': 'fake_neutron_subnet_id',
7467 }
7468 self.assertRaises(
7469 exception.InvalidShareNetwork,
7470 self.api.check_update_share_server_network_allocations,
7471 self.context, share_network, new_share_network_subnet, True)
7473 def test_update_share_server_network_allocations(self):
7474 backend_host = 'fake_host'
7475 backend_hosts = [backend_host]
7476 mock_initial_check = self.mock_object(
7477 self.api, '_share_server_update_allocations_initial_checks',
7478 mock.Mock(return_value=backend_hosts))
7479 update_key = 'fake_key'
7480 mock_get_key = self.mock_object(
7481 self.api, 'get_share_server_update_allocations_key',
7482 mock.Mock(return_value=update_key))
7483 mock_get_data = self.mock_object(
7484 self.api.db, 'async_operation_data_get',
7485 mock.Mock(return_value='fake_update_value'))
7486 mock_validate_hosts = self.mock_object(
7487 self.api, '_share_server_update_allocations_validate_hosts',
7488 mock.Mock(return_value=(True, 'fake_host')))
7489 mock_net_update = self.mock_object(self.api.db, 'share_network_update')
7490 mock_server_update = self.mock_object(self.api.db,
7491 'share_servers_update')
7492 new_share_network_subnet_db = {'id': 'fake_subnet_id'}
7493 mock_subnet_create = self.mock_object(
7494 self.api.db, 'share_network_subnet_create',
7495 mock.Mock(return_value=new_share_network_subnet_db))
7496 mock_update_allocations = self.mock_object(
7497 self.api.share_rpcapi, 'update_share_server_network_allocations')
7498 mock_delete_data = self.mock_object(self.api.db,
7499 'async_operation_data_delete')
7501 share_network = {'id': 'fake_id'}
7502 server1 = {'id': 'fake_id'}
7503 new_share_network_subnet = {
7504 'share_servers': [server1],
7505 'availability_zone_id': 'fake_availability_zone_id',
7506 'neutron_net_id': 'fake_neutron_net_id',
7507 'neutron_subnet_id': 'fake_neutron_subnet_id',
7508 }
7509 res_subnet = self.api.update_share_server_network_allocations(
7510 self.context, share_network, new_share_network_subnet)
7512 self.assertEqual(new_share_network_subnet_db, res_subnet)
7513 mock_initial_check.assert_called_once_with(
7514 self.context, share_network,
7515 new_share_network_subnet['share_servers'])
7516 mock_get_key.assert_called_once_with(
7517 share_network['id'],
7518 new_share_network_subnet['availability_zone_id'])
7519 mock_get_data.assert_called_once_with(
7520 self.context, share_network['id'], update_key)
7521 mock_validate_hosts.assert_called_once_with(
7522 self.context, backend_hosts, update_key,
7523 share_network_id=share_network['id'],
7524 neutron_net_id=new_share_network_subnet['neutron_net_id'],
7525 neutron_subnet_id=new_share_network_subnet['neutron_subnet_id'],
7526 availability_zone_id=(
7527 new_share_network_subnet["availability_zone_id"]))
7528 mock_net_update.assert_called_once_with(
7529 self.context, share_network['id'],
7530 {'status': constants.STATUS_NETWORK_CHANGE})
7531 mock_server_update.assert_called_once_with(
7532 self.context, [server1['id']],
7533 {'status': constants.STATUS_SERVER_NETWORK_CHANGE})
7534 mock_subnet_create.assert_called_once_with(
7535 self.context, new_share_network_subnet)
7536 mock_update_allocations.assert_called_once_with(
7537 self.context, backend_host, share_network['id'],
7538 new_share_network_subnet_db['id'])
7539 mock_delete_data.assert_called_once_with(
7540 self.context, share_network['id'], update_key)
7542 def test_update_share_server_network_allocations_no_check(self):
7543 backend_host = 'fake_host'
7544 backend_hosts = [backend_host]
7545 self.mock_object(
7546 self.api, '_share_server_update_allocations_initial_checks',
7547 mock.Mock(return_value=backend_hosts))
7548 update_key = 'fake_key'
7549 self.mock_object(
7550 self.api, 'get_share_server_update_allocations_key',
7551 mock.Mock(return_value=update_key))
7552 self.mock_object(
7553 self.api.db, 'async_operation_data_get',
7554 mock.Mock(return_value=None))
7556 share_network = {'id': 'fake_id'}
7557 server1 = {'id': 'fake_id'}
7558 new_share_network_subnet = {
7559 'share_servers': [server1],
7560 'availability_zone_id': 'fake_availability_zone_id',
7561 'neutron_net_id': 'fake_neutron_net_id',
7562 'neutron_subnet_id': 'fake_neutron_subnet_id',
7563 }
7564 self.assertRaises(
7565 exception.InvalidShareNetwork,
7566 self.api.update_share_server_network_allocations,
7567 self.context,
7568 share_network,
7569 new_share_network_subnet)
7571 def test_update_share_server_network_allocations_fail_validation(self):
7572 backend_host = 'fake_host'
7573 backend_hosts = [backend_host]
7574 self.mock_object(
7575 self.api, '_share_server_update_allocations_initial_checks',
7576 mock.Mock(return_value=backend_hosts))
7577 update_key = 'fake_key'
7578 self.mock_object(
7579 self.api, 'get_share_server_update_allocations_key',
7580 mock.Mock(return_value=update_key))
7581 self.mock_object(
7582 self.api.db, 'async_operation_data_get',
7583 mock.Mock(return_value='fake_update_value'))
7584 self.mock_object(
7585 self.api, '_share_server_update_allocations_validate_hosts',
7586 mock.Mock(side_effect=exception.InvalidShareNetwork(
7587 reason='fake_reason')))
7588 mock_delete_data = self.mock_object(self.api.db,
7589 'async_operation_data_delete')
7591 share_network = {'id': 'fake_id'}
7592 server1 = {'id': 'fake_id'}
7593 new_share_network_subnet = {
7594 'share_servers': [server1],
7595 'availability_zone_id': 'fake_availability_zone_id',
7596 'neutron_net_id': 'fake_neutron_net_id',
7597 'neutron_subnet_id': 'fake_neutron_subnet_id',
7598 }
7599 self.assertRaises(
7600 exception.InvalidShareNetwork,
7601 self.api.update_share_server_network_allocations,
7602 self.context,
7603 share_network,
7604 new_share_network_subnet)
7606 mock_delete_data.assert_called_once_with(
7607 self.context, share_network['id'], update_key)
7609 @ddt.data(False, None)
7610 def test_update_share_server_network_allocations_check_fail(self, result):
7611 backend_host = 'fake_host'
7612 backend_hosts = [backend_host]
7613 self.mock_object(
7614 self.api, '_share_server_update_allocations_initial_checks',
7615 mock.Mock(return_value=backend_hosts))
7616 update_key = 'fake_key'
7617 self.mock_object(
7618 self.api, 'get_share_server_update_allocations_key',
7619 mock.Mock(return_value=update_key))
7620 self.mock_object(
7621 self.api.db, 'async_operation_data_get',
7622 mock.Mock(return_value='fake_update_value'))
7623 self.mock_object(
7624 self.api, '_share_server_update_allocations_validate_hosts',
7625 mock.Mock(return_value=(result, 'fake_host')))
7627 share_network = {'id': 'fake_id'}
7628 server1 = {'id': 'fake_id'}
7629 new_share_network_subnet = {
7630 'share_servers': [server1],
7631 'availability_zone_id': 'fake_availability_zone_id',
7632 'neutron_net_id': 'fake_neutron_net_id',
7633 'neutron_subnet_id': 'fake_neutron_subnet_id',
7634 }
7635 self.assertRaises(
7636 exception.InvalidShareNetwork,
7637 self.api.update_share_server_network_allocations,
7638 self.context,
7639 share_network,
7640 new_share_network_subnet)
7642 @ddt.data(None, {'driver': test})
7643 def test_create_share_backup(self, backup_opts):
7644 share = db_utils.create_share(is_public=True, status='available')
7645 backup_ref = db_utils.create_backup(share['id'], status='available')
7647 reservation = 'fake'
7648 self.mock_object(quota.QUOTAS, 'reserve',
7649 mock.Mock(return_value=reservation))
7650 self.mock_object(quota.QUOTAS, 'commit')
7651 self.mock_object(db_api, 'share_backup_create',
7652 mock.Mock(return_value=backup_ref))
7653 self.mock_object(db_api, 'share_backup_update', mock.Mock())
7654 self.mock_object(data_rpc.DataAPI, 'create_backup', mock.Mock())
7655 self.mock_object(self.share_rpcapi, 'create_backup', mock.Mock())
7657 backup = {
7658 'display_name': 'tmp_backup',
7659 'backup_options': backup_opts,
7660 'id': 'dbe28dff-ce7d-4c3d-a795-c31f6fee31ab',
7661 }
7662 self.api.create_share_backup(self.context, share, backup)
7664 quota.QUOTAS.reserve.assert_called_once()
7665 db_api.share_backup_create.assert_called_once()
7666 quota.QUOTAS.commit.assert_called_once()
7667 db_api.share_backup_update.assert_called_once()
7668 if backup_opts:
7669 self.share_rpcapi.create_backup.assert_called_once_with(
7670 self.context, backup_ref)
7671 else:
7672 data_rpc.DataAPI.create_backup.assert_called_once_with(
7673 self.context, backup_ref)
7675 @ddt.data('CEPHFS', 'CIFS')
7676 def test_create_generic_share_backup_invalid_protocol(self, share_proto):
7677 CONF.set_default(
7678 "data_manager_backup_supported_share_protocols", ["MANGO"])
7679 share = db_utils.create_share(
7680 is_public=True, status='available', share_proto=share_proto)
7681 backup_ref = db_utils.create_backup(share['id'], status='available')
7683 reservation = 'fake'
7684 self.mock_object(quota.QUOTAS, 'reserve',
7685 mock.Mock(return_value=reservation))
7686 self.mock_object(quota.QUOTAS, 'commit')
7687 self.mock_object(quota.QUOTAS, 'rollback')
7688 self.mock_object(db_api, 'share_backup_create',
7689 mock.Mock(return_value=backup_ref))
7690 self.mock_object(data_rpc.DataAPI, 'create_backup', mock.Mock())
7692 backup = {
7693 'display_name': 'tmp_backup',
7694 'backup_options': {},
7695 'id': 'dbe28dff-ce7d-4c3d-a795-c31f6fee31ab',
7696 }
7697 self.assertRaises(
7698 exception.InvalidShare,
7699 self.api.create_share_backup,
7700 self.context,
7701 share,
7702 backup,
7703 )
7705 quota.QUOTAS.reserve.assert_called_once_with(
7706 self.context, backups=1, backup_gigabytes=share['size']
7707 )
7708 db_api.share_backup_create.assert_not_called()
7709 quota.QUOTAS.rollback.assert_called_once_with(
7710 self.context, reservation)
7711 quota.QUOTAS.commit.assert_not_called()
7712 data_rpc.DataAPI.create_backup.assert_not_called()
7714 def test_create_share_backup_share_error_state(self):
7715 share = db_utils.create_share(is_public=True, status='error')
7716 backup = {
7717 'display_name': 'tmp_backup',
7718 'id': 'dbe28dff-ce7d-4c3d-a795-c31f6fee31ab',
7719 }
7720 self.assertRaises(exception.InvalidShare,
7721 self.api.create_share_backup,
7722 self.context, share, backup)
7724 def test_create_share_backup_share_busy_task_state(self):
7725 share = db_utils.create_share(
7726 is_public=True, task_state='data_copying_in_progress')
7727 backup = {
7728 'display_name': 'tmp_backup',
7729 'id': 'dbe28dff-ce7d-4c3d-a795-c31f6fee31ab',
7730 }
7732 self.assertRaises(exception.ShareBusyException,
7733 self.api.create_share_backup,
7734 self.context, share, backup)
7736 def test_create_share_backup_share_has_snapshots(self):
7737 share = db_utils.create_share(
7738 is_public=True, state='available')
7739 snapshot = db_utils.create_snapshot(
7740 share_id=share['id'], status='available', size=1)
7742 backup = {
7743 'display_name': 'tmp_backup',
7744 'id': 'dbe28dff-ce7d-4c3d-a795-c31f6fee31ab',
7745 }
7747 self.mock_object(db_api, 'share_snapshot_get_all_for_share',
7748 mock.Mock(return_value=[snapshot]))
7750 self.assertRaises(exception.InvalidShare,
7751 self.api.create_share_backup,
7752 self.context, share, backup)
7754 def test_create_share_backup_share_has_replicas(self):
7755 share = fakes.fake_share(id='fake_id',
7756 has_replicas=True,
7757 status=constants.STATUS_AVAILABLE,
7758 is_soft_deleted=False)
7759 backup = {
7760 'display_name': 'tmp_backup',
7761 'id': 'dbe28dff-ce7d-4c3d-a795-c31f6fee31ab',
7762 }
7764 self.assertRaises(exception.InvalidShare,
7765 self.api.create_share_backup,
7766 self.context, share, backup)
7768 @ddt.data({'overs': {'backup_gigabytes': 'fake'},
7769 'expected_exception':
7770 exception.ShareBackupSizeExceedsAvailableQuota},
7771 {'overs': {'backups': 'fake'},
7772 'expected_exception': exception.BackupLimitExceeded},)
7773 @ddt.unpack
7774 def test_create_share_backup_over_quota(self, overs, expected_exception):
7775 share = fakes.fake_share(id='fake_id',
7776 status=constants.STATUS_AVAILABLE,
7777 is_soft_deleted=False, size=5)
7778 backup = {
7779 'display_name': 'tmp_backup',
7780 'id': 'dbe28dff-ce7d-4c3d-a795-c31f6fee31ab',
7781 }
7783 usages = {'backup_gigabytes': {'reserved': 5, 'in_use': 5},
7784 'backups': {'reserved': 5, 'in_use': 5}}
7786 quotas = {'backup_gigabytes': 5, 'backups': 5}
7788 exc = exception.OverQuota(overs=overs, usages=usages, quotas=quotas)
7789 self.mock_object(quota.QUOTAS, 'reserve', mock.Mock(side_effect=exc))
7791 self.assertRaises(expected_exception, self.api.create_share_backup,
7792 self.context, share, backup)
7794 quota.QUOTAS.reserve.assert_called_once_with(
7795 self.context, backups=1, backup_gigabytes=share['size'])
7797 def test_create_share_backup_rollback_quota(self):
7798 share = db_utils.create_share(is_public=True, status='available')
7800 reservation = 'fake'
7801 self.mock_object(quota.QUOTAS, 'reserve',
7802 mock.Mock(return_value=reservation))
7803 self.mock_object(quota.QUOTAS, 'rollback')
7804 self.mock_object(db_api, 'share_backup_create',
7805 mock.Mock(side_effect=exception.ManilaException))
7806 self.mock_object(data_rpc.DataAPI, 'create_backup', mock.Mock())
7807 self.mock_object(self.share_rpcapi, 'create_backup', mock.Mock())
7809 backup = {
7810 'display_name': 'tmp_backup',
7811 'id': 'dbe28dff-ce7d-4c3d-a795-c31f6fee31ab',
7812 }
7813 self.assertRaises(exception.ManilaException,
7814 self.api.create_share_backup,
7815 self.context, share, backup)
7817 quota.QUOTAS.reserve.assert_called_once()
7818 db_api.share_backup_create.assert_called_once()
7819 quota.QUOTAS.rollback.assert_called_once_with(
7820 self.context, reservation)
7822 @ddt.data(CONF.share_topic, CONF.data_topic)
7823 def test_delete_share_backup(self, topic):
7824 share = db_utils.create_share(is_public=True, status='available')
7825 backup = db_utils.create_backup(share['id'], status='available')
7827 self.mock_object(db_api, 'share_backup_update', mock.Mock())
7828 self.mock_object(data_rpc.DataAPI, 'delete_backup', mock.Mock())
7829 self.mock_object(self.share_rpcapi, 'delete_backup', mock.Mock())
7831 backup.update({'topic': topic})
7832 self.api.delete_share_backup(self.context, backup)
7834 db_api.share_backup_update.assert_called_once()
7835 if topic == CONF.share_topic:
7836 self.share_rpcapi.delete_backup.assert_called_once_with(
7837 self.context, backup)
7838 else:
7839 data_rpc.DataAPI.delete_backup.assert_called_once_with(
7840 self.context, backup)
7842 @ddt.data(constants.STATUS_DELETING, constants.STATUS_CREATING)
7843 def test_delete_share_backup_invalid_state(self, state):
7844 share = db_utils.create_share(is_public=True, status='available')
7845 backup = db_utils.create_backup(share['id'], status=state)
7846 self.assertRaises(exception.InvalidBackup,
7847 self.api.delete_share_backup,
7848 self.context, backup)
7850 @ddt.data(CONF.share_topic, CONF.data_topic)
7851 def test_restore_share_backup(self, topic):
7852 share = db_utils.create_share(
7853 is_public=True, status='available', size=1)
7854 backup = db_utils.create_backup(
7855 share['id'], status='available', size=1)
7857 self.mock_object(self.api, 'get', mock.Mock(return_value=share))
7858 self.mock_object(db_api, 'share_backup_update', mock.Mock())
7859 self.mock_object(db_api, 'share_update', mock.Mock())
7860 self.mock_object(data_rpc.DataAPI, 'restore_backup', mock.Mock())
7861 self.mock_object(self.share_rpcapi, 'restore_backup', mock.Mock())
7863 backup.update({'topic': topic})
7864 self.api.restore_share_backup(self.context, backup)
7866 self.api.get.assert_called_once()
7867 db_api.share_update.assert_called_once()
7868 db_api.share_backup_update.assert_called_once()
7869 if topic == CONF.share_topic:
7870 self.share_rpcapi.restore_backup.assert_called_once_with(
7871 self.context, backup, share['id'])
7872 else:
7873 data_rpc.DataAPI.restore_backup.assert_called_once_with(
7874 self.context, backup, share['id'])
7876 def test_restore_share_backup_invalid_share_sizee(self):
7877 share = db_utils.create_share(
7878 is_public=True, status='available', size=1)
7879 backup = db_utils.create_backup(
7880 share['id'], status='available', size=2)
7881 self.assertRaises(exception.InvalidShare,
7882 self.api.restore_share_backup,
7883 self.context, backup)
7885 def test_restore_share_backup_invalid_share_state(self):
7886 share = db_utils.create_share(is_public=True, status='deleting')
7887 backup = db_utils.create_backup(share['id'], status='available')
7888 self.assertRaises(exception.InvalidShare,
7889 self.api.restore_share_backup,
7890 self.context, backup)
7892 def test_restore_share_backup_invalid_backup_state(self):
7893 share = db_utils.create_share(is_public=True, status='available')
7894 backup = db_utils.create_backup(share['id'], status='deleting')
7895 self.assertRaises(exception.InvalidBackup,
7896 self.api.restore_share_backup,
7897 self.context, backup)
7899 def test_update_share_backup(self):
7900 share = db_utils.create_share(is_public=True, status='available')
7901 backup = db_utils.create_backup(share['id'], status='available')
7902 self.mock_object(db_api, 'share_backup_update', mock.Mock())
7904 self.api.update_share_backup(self.context, backup,
7905 {'display_name': 'new_name'})
7907 db_api.share_backup_update.assert_called_once()
7910class OtherTenantsShareActionsTestCase(test.TestCase):
7911 def setUp(self):
7912 super(OtherTenantsShareActionsTestCase, self).setUp()
7913 self.api = share.API()
7915 def test_delete_other_tenants_public_share(self):
7916 share = db_utils.create_share(is_public=True)
7917 ctx = context.RequestContext(user_id='1111', project_id='2222')
7918 self.assertRaises(exception.PolicyNotAuthorized, self.api.delete, ctx,
7919 share)
7921 def test_update_other_tenants_public_share(self):
7922 share = db_utils.create_share(is_public=True)
7923 ctx = context.RequestContext(user_id='1111', project_id='2222')
7924 self.assertRaises(exception.PolicyNotAuthorized, self.api.update, ctx,
7925 share, {'display_name': 'newname'})
7927 def test_get_other_tenants_public_share(self):
7928 share = db_utils.create_share(is_public=True)
7929 ctx = context.RequestContext(user_id='1111', project_id='2222')
7930 self.mock_object(db_api, 'share_get',
7931 mock.Mock(return_value=share))
7932 result = self.api.get(ctx, 'fakeid')
7933 self.assertEqual(share, result)
7934 db_api.share_get.assert_called_once_with(ctx, 'fakeid')