723 lines
32 KiB
Python
723 lines
32 KiB
Python
# Copyright 2016 Hitachi Data Systems inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import itertools
|
|
|
|
import ddt
|
|
import mock
|
|
|
|
from manila.common import constants
|
|
from manila import context
|
|
from manila import db
|
|
from manila import exception
|
|
from manila.share import access
|
|
from manila import test
|
|
from manila.tests import db_utils
|
|
from manila import utils
|
|
|
|
|
|
class LockedOperationsTestCase(test.TestCase):
|
|
|
|
class FakeAccessHelper(object):
|
|
|
|
@access.locked_access_rules_operation
|
|
def some_access_rules_operation(self, context, share_instance_id=None):
|
|
pass
|
|
|
|
def setUp(self):
|
|
super(self.__class__, self).setUp()
|
|
self.access_helper = self.FakeAccessHelper()
|
|
self.context = context.RequestContext('fake_user', 'fake_project')
|
|
self.lock_call = self.mock_object(
|
|
utils, 'synchronized', mock.Mock(return_value=lambda f: f))
|
|
|
|
def test_locked_access_rules_operation(self, **replica):
|
|
|
|
self.access_helper.some_access_rules_operation(
|
|
self.context, share_instance_id='FAKE_INSTANCE_ID')
|
|
|
|
self.lock_call.assert_called_once_with(
|
|
"locked_access_rules_operation_by_share_instance_FAKE_INSTANCE_ID",
|
|
external=True)
|
|
|
|
|
|
@ddt.ddt
|
|
class ShareInstanceAccessDatabaseMixinTestCase(test.TestCase):
|
|
|
|
def setUp(self):
|
|
super(self.__class__, self).setUp()
|
|
self.driver = mock.Mock()
|
|
self.access_helper = access.ShareInstanceAccess(db, self.driver)
|
|
self.context = context.RequestContext('fake_user', 'fake_project')
|
|
self.mock_object(
|
|
utils, 'synchronized', mock.Mock(return_value=lambda f: f))
|
|
|
|
def test_get_and_update_access_rules_status_force_status(self):
|
|
share = db_utils.create_share(
|
|
access_rule_status=constants.STATUS_ACTIVE,
|
|
status=constants.STATUS_AVAILABLE)
|
|
share = db.share_get(self.context, share['id'])
|
|
self.assertEqual(constants.STATUS_ACTIVE, share['access_rules_status'])
|
|
|
|
self.access_helper.get_and_update_share_instance_access_rules_status(
|
|
self.context, status=constants.SHARE_INSTANCE_RULES_SYNCING,
|
|
share_instance_id=share['instance']['id'])
|
|
|
|
share = db.share_get(self.context, share['id'])
|
|
self.assertEqual(constants.SHARE_INSTANCE_RULES_SYNCING,
|
|
share['access_rules_status'])
|
|
|
|
@ddt.data((constants.SHARE_INSTANCE_RULES_SYNCING, True),
|
|
(constants.STATUS_ERROR, False))
|
|
@ddt.unpack
|
|
def test_get_and_update_access_rules_status_conditionally_change(
|
|
self, initial_status, change_allowed):
|
|
share = db_utils.create_share(access_rules_status=initial_status,
|
|
status=constants.STATUS_AVAILABLE)
|
|
share = db.share_get(self.context, share['id'])
|
|
self.assertEqual(initial_status, share['access_rules_status'])
|
|
|
|
conditionally_change = {
|
|
constants.SHARE_INSTANCE_RULES_SYNCING: constants.STATUS_ACTIVE,
|
|
}
|
|
|
|
updated_instance = (
|
|
self.access_helper.
|
|
get_and_update_share_instance_access_rules_status(
|
|
self.context, conditionally_change=conditionally_change,
|
|
share_instance_id=share['instance']['id'])
|
|
)
|
|
|
|
share = db.share_get(self.context, share['id'])
|
|
if change_allowed:
|
|
self.assertEqual(constants.STATUS_ACTIVE,
|
|
share['access_rules_status'])
|
|
self.assertIsNotNone(updated_instance)
|
|
else:
|
|
self.assertEqual(initial_status, share['access_rules_status'])
|
|
self.assertIsNone(updated_instance)
|
|
|
|
def test_get_and_update_all_access_rules_just_get(self):
|
|
share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
|
|
rule_1 = db_utils.create_access(share_id=share['id'])
|
|
rule_2 = db_utils.create_access(share_id=share['id'])
|
|
self.mock_object(db, 'share_instance_access_update')
|
|
|
|
rules = self.access_helper.get_and_update_share_instance_access_rules(
|
|
self.context, share_instance_id=share['instance']['id'])
|
|
|
|
self.assertEqual(2, len(rules))
|
|
rule_ids = [r['access_id'] for r in rules]
|
|
self.assertTrue(rule_1['id'] in rule_ids)
|
|
self.assertTrue(rule_2['id'] in rule_ids)
|
|
self.assertFalse(db.share_instance_access_update.called)
|
|
|
|
@ddt.data(
|
|
([constants.ACCESS_STATE_QUEUED_TO_APPLY], 2),
|
|
([constants.ACCESS_STATE_QUEUED_TO_APPLY,
|
|
constants.STATUS_ACTIVE], 1),
|
|
([constants.ACCESS_STATE_APPLYING], 2),
|
|
([constants.ACCESS_STATE_APPLYING, constants.ACCESS_STATE_ERROR], 1),
|
|
([constants.ACCESS_STATE_ACTIVE, constants.ACCESS_STATE_DENYING], 0))
|
|
@ddt.unpack
|
|
def test_get_and_update_all_access_rules_updates_conditionally_changed(
|
|
self, statuses, changes_allowed):
|
|
share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
|
|
db_utils.create_access(share_id=share['id'], state=statuses[0])
|
|
db_utils.create_access(share_id=share['id'], state=statuses[-1])
|
|
self.mock_object(db, 'share_instance_access_update', mock.Mock(
|
|
side_effect=db.share_instance_access_update))
|
|
updates = {
|
|
'access_key': 'renfrow2stars'
|
|
}
|
|
expected_updates = {
|
|
'access_key': 'renfrow2stars',
|
|
'state': constants.ACCESS_STATE_QUEUED_TO_DENY,
|
|
}
|
|
conditionally_change = {
|
|
constants.ACCESS_STATE_APPLYING:
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY,
|
|
constants.ACCESS_STATE_QUEUED_TO_APPLY:
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY,
|
|
}
|
|
|
|
rules = self.access_helper.get_and_update_share_instance_access_rules(
|
|
self.context, share_instance_id=share['instance']['id'],
|
|
updates=updates, conditionally_change=conditionally_change)
|
|
|
|
state_changed_rules = [
|
|
r for r in rules if
|
|
r['state'] == constants.ACCESS_STATE_QUEUED_TO_DENY
|
|
]
|
|
self.assertEqual(changes_allowed, len(state_changed_rules))
|
|
self.assertEqual(2, db.share_instance_access_update.call_count)
|
|
db.share_instance_access_update.assert_has_calls([
|
|
mock.call(self.context, mock.ANY, share['instance']['id'],
|
|
expected_updates),
|
|
] * changes_allowed)
|
|
|
|
def test_get_and_update_access_rule_just_get(self):
|
|
share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
|
|
expected_rule = db_utils.create_access(share_id=share['id'])
|
|
self.mock_object(db, 'share_instance_access_update')
|
|
|
|
actual_rule = (
|
|
self.access_helper.get_and_update_share_instance_access_rule(
|
|
self.context, expected_rule['id'],
|
|
share_instance_id=share['instance']['id'])
|
|
)
|
|
|
|
self.assertEqual(expected_rule['id'], actual_rule['access_id'])
|
|
self.assertFalse(db.share_instance_access_update.called)
|
|
|
|
@ddt.data(constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_DENYING,
|
|
constants.ACCESS_STATE_ACTIVE,
|
|
constants.ACCESS_STATE_QUEUED_TO_APPLY)
|
|
def test_get_and_update_access_rule_updates_conditionally_changed(
|
|
self, initial_state):
|
|
mock_debug_log = self.mock_object(access.LOG, 'debug')
|
|
share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
|
|
rule = db_utils.create_access(share_id=share['id'],
|
|
state=initial_state)
|
|
self.mock_object(db, 'share_instance_access_update', mock.Mock(
|
|
side_effect=db.share_instance_access_update))
|
|
updates = {
|
|
'access_key': 'renfrow2stars'
|
|
}
|
|
conditionally_change = {
|
|
constants.ACCESS_STATE_APPLYING:
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY,
|
|
constants.ACCESS_STATE_DENYING:
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY,
|
|
}
|
|
|
|
actual_rule = (
|
|
self.access_helper.get_and_update_share_instance_access_rule(
|
|
self.context, rule['id'], updates=updates,
|
|
share_instance_id=share['instance']['id'],
|
|
conditionally_change=conditionally_change)
|
|
)
|
|
self.assertEqual(rule['id'], actual_rule['access_id'])
|
|
if 'ing' in initial_state:
|
|
self.assertEqual(constants.ACCESS_STATE_QUEUED_TO_DENY,
|
|
actual_rule['state'])
|
|
self.assertFalse(mock_debug_log.called)
|
|
else:
|
|
self.assertEqual(initial_state, actual_rule['state'])
|
|
mock_debug_log.assert_called_once()
|
|
|
|
|
|
@ddt.ddt
|
|
class ShareInstanceAccessTestCase(test.TestCase):
|
|
def setUp(self):
|
|
super(ShareInstanceAccessTestCase, self).setUp()
|
|
self.driver = self.mock_class("manila.share.driver.ShareDriver",
|
|
mock.Mock())
|
|
self.access_helper = access.ShareInstanceAccess(db, self.driver)
|
|
self.context = context.RequestContext('fake_user', 'fake_project')
|
|
|
|
@ddt.data(constants.ACCESS_STATE_APPLYING, constants.ACCESS_STATE_DENYING)
|
|
def test_update_access_rules_an_update_is_in_progress(self, initial_state):
|
|
share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
|
|
share_instance = share['instance']
|
|
db_utils.create_access(share_id=share['id'], state=initial_state)
|
|
mock_debug_log = self.mock_object(access.LOG, 'debug')
|
|
self.mock_object(self.access_helper, '_update_access_rules')
|
|
get_and_update_call = self.mock_object(
|
|
self.access_helper, 'get_and_update_share_instance_access_rules',
|
|
mock.Mock(side_effect=self.access_helper.
|
|
get_and_update_share_instance_access_rules))
|
|
|
|
retval = self.access_helper.update_access_rules(
|
|
self.context, share_instance['id'])
|
|
|
|
expected_filters = {
|
|
'state': (constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_DENYING),
|
|
}
|
|
self.assertIsNone(retval)
|
|
mock_debug_log.assert_called_once()
|
|
get_and_update_call.assert_called_once_with(
|
|
self.context, filters=expected_filters,
|
|
share_instance_id=share_instance['id'])
|
|
self.assertFalse(self.access_helper._update_access_rules.called)
|
|
|
|
def test_update_access_rules_nothing_to_update(self):
|
|
share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
|
|
share_instance = share['instance']
|
|
db_utils.create_access(share_id=share['id'],
|
|
state=constants.STATUS_ACTIVE)
|
|
mock_debug_log = self.mock_object(access.LOG, 'debug')
|
|
self.mock_object(self.access_helper, '_update_access_rules')
|
|
get_and_update_call = self.mock_object(
|
|
self.access_helper, 'get_and_update_share_instance_access_rules',
|
|
mock.Mock(side_effect=self.access_helper.
|
|
get_and_update_share_instance_access_rules))
|
|
|
|
retval = self.access_helper.update_access_rules(
|
|
self.context, share_instance['id'])
|
|
|
|
expected_rule_filter_1 = {
|
|
'state': (constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_DENYING),
|
|
}
|
|
expected_rule_filter_2 = {
|
|
'state': (constants.ACCESS_STATE_QUEUED_TO_APPLY,
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY),
|
|
}
|
|
expected_conditionally_change = {
|
|
constants.ACCESS_STATE_QUEUED_TO_APPLY:
|
|
constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY:
|
|
constants.ACCESS_STATE_DENYING,
|
|
}
|
|
self.assertIsNone(retval)
|
|
mock_debug_log.assert_called_once()
|
|
get_and_update_call.assert_has_calls(
|
|
[
|
|
mock.call(self.context, filters=expected_rule_filter_1,
|
|
share_instance_id=share_instance['id']),
|
|
mock.call(self.context, filters=expected_rule_filter_2,
|
|
share_instance_id=share_instance['id'],
|
|
conditionally_change=expected_conditionally_change),
|
|
])
|
|
self.assertFalse(self.access_helper._update_access_rules.called)
|
|
|
|
@ddt.data(True, False)
|
|
def test_update_access_rules_delete_all_rules(self, delete_all_rules):
|
|
share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
|
|
share_instance = share['instance']
|
|
db_utils.create_access(
|
|
share_id=share['id'], state=constants.STATUS_ACTIVE)
|
|
db_utils.create_access(
|
|
share_id=share['id'], state=constants.ACCESS_STATE_QUEUED_TO_APPLY)
|
|
db_utils.create_access(
|
|
share_id=share['id'], state=constants.ACCESS_STATE_QUEUED_TO_DENY)
|
|
mock_debug_log = self.mock_object(access.LOG, 'debug')
|
|
self.mock_object(self.access_helper, '_update_access_rules')
|
|
get_and_update_call = self.mock_object(
|
|
self.access_helper, 'get_and_update_share_instance_access_rules',
|
|
mock.Mock(side_effect=self.access_helper.
|
|
get_and_update_share_instance_access_rules))
|
|
|
|
retval = self.access_helper.update_access_rules(
|
|
self.context, share_instance['id'],
|
|
delete_all_rules=delete_all_rules)
|
|
|
|
expected_rule_filter_1 = {
|
|
'state': (constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_DENYING),
|
|
}
|
|
expected_rule_filter_2 = {
|
|
'state': (constants.ACCESS_STATE_QUEUED_TO_APPLY,
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY),
|
|
}
|
|
expected_conditionally_change = {
|
|
constants.ACCESS_STATE_QUEUED_TO_APPLY:
|
|
constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY:
|
|
constants.ACCESS_STATE_DENYING,
|
|
}
|
|
expected_get_and_update_calls = []
|
|
if delete_all_rules:
|
|
deny_all_updates = {
|
|
'state': constants.ACCESS_STATE_QUEUED_TO_DENY,
|
|
}
|
|
expected_get_and_update_calls = [
|
|
mock.call(self.context, updates=deny_all_updates,
|
|
share_instance_id=share_instance['id']),
|
|
]
|
|
expected_get_and_update_calls.extend([
|
|
mock.call(self.context, filters=expected_rule_filter_1,
|
|
share_instance_id=share_instance['id']),
|
|
mock.call(self.context, filters=expected_rule_filter_2,
|
|
share_instance_id=share_instance['id'],
|
|
conditionally_change=expected_conditionally_change),
|
|
])
|
|
|
|
self.assertIsNone(retval)
|
|
mock_debug_log.assert_called_once()
|
|
get_and_update_call.assert_has_calls(expected_get_and_update_calls)
|
|
self.access_helper._update_access_rules.assert_called_once_with(
|
|
self.context, share_instance['id'], share_server=None)
|
|
|
|
@ddt.data(*itertools.product(
|
|
(True, False), (constants.ACCESS_STATE_ERROR,
|
|
constants.ACCESS_STATE_ACTIVE)))
|
|
@ddt.unpack
|
|
def test__update_access_rules_with_driver_updates(
|
|
self, driver_returns_updates, access_state):
|
|
expected_access_rules_status = (
|
|
constants.STATUS_ACTIVE
|
|
if access_state == constants.ACCESS_STATE_ACTIVE
|
|
else constants.SHARE_INSTANCE_RULES_ERROR
|
|
)
|
|
share = db_utils.create_share(
|
|
status=constants.STATUS_AVAILABLE,
|
|
access_rules_status=expected_access_rules_status)
|
|
share_instance_id = share['instance']['id']
|
|
rule_1 = db_utils.create_access(
|
|
share_id=share['id'], state=access_state)
|
|
rule_1 = db.share_instance_access_get(
|
|
self.context, rule_1['id'], share_instance_id)
|
|
rule_2 = db_utils.create_access(
|
|
share_id=share['id'], state=constants.ACCESS_STATE_APPLYING)
|
|
rule_2 = db.share_instance_access_get(
|
|
self.context, rule_2['id'], share_instance_id)
|
|
rule_3 = db_utils.create_access(
|
|
share_id=share['id'], state=constants.ACCESS_STATE_DENYING)
|
|
rule_3 = db.share_instance_access_get(
|
|
self.context, rule_3['id'], share_instance_id)
|
|
if driver_returns_updates:
|
|
driver_rule_updates = {
|
|
rule_3['access_id']: {'access_key': 'alic3h4sAcc355'},
|
|
rule_2['access_id']: {'state': access_state}
|
|
}
|
|
else:
|
|
driver_rule_updates = None
|
|
|
|
shr_instance_access_rules_status_update_call = self.mock_object(
|
|
self.access_helper,
|
|
'get_and_update_share_instance_access_rules_status',
|
|
mock.Mock(side_effect=self.access_helper.
|
|
get_and_update_share_instance_access_rules_status))
|
|
all_access_rules_update_call = self.mock_object(
|
|
self.access_helper, 'get_and_update_share_instance_access_rules',
|
|
mock.Mock(side_effect=self.access_helper.
|
|
get_and_update_share_instance_access_rules))
|
|
one_access_rule_update_call = self.mock_object(
|
|
self.access_helper, 'get_and_update_share_instance_access_rule',
|
|
mock.Mock(side_effect=self.access_helper.
|
|
get_and_update_share_instance_access_rule))
|
|
|
|
driver_call = self.mock_object(
|
|
self.access_helper.driver, 'update_access',
|
|
mock.Mock(return_value=driver_rule_updates))
|
|
self.mock_object(self.access_helper, '_check_needs_refresh',
|
|
mock.Mock(return_value=False))
|
|
|
|
retval = self.access_helper._update_access_rules(
|
|
self.context, share_instance_id, share_server='fake_server')
|
|
|
|
# Expected Values:
|
|
if access_state != constants.ACCESS_STATE_ERROR:
|
|
expected_rules_to_be_on_share = [r['id'] for r in (rule_1, rule_2)]
|
|
else:
|
|
expected_rules_to_be_on_share = [rule_2['id']]
|
|
|
|
expected_filters_1 = {
|
|
'state': (constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_ACTIVE,
|
|
constants.ACCESS_STATE_DENYING),
|
|
}
|
|
expected_filters_2 = {'state': constants.STATUS_ERROR}
|
|
expected_get_and_update_calls = [
|
|
mock.call(self.context, filters=expected_filters_1,
|
|
share_instance_id=share_instance_id),
|
|
mock.call(self.context, filters=expected_filters_2,
|
|
share_instance_id=share_instance_id),
|
|
]
|
|
expected_access_rules_status_change_cond1 = {
|
|
constants.STATUS_ACTIVE: constants.SHARE_INSTANCE_RULES_SYNCING,
|
|
}
|
|
if access_state == constants.SHARE_INSTANCE_RULES_ERROR:
|
|
expected_access_rules_status_change_cond2 = {
|
|
constants.SHARE_INSTANCE_RULES_SYNCING:
|
|
constants.SHARE_INSTANCE_RULES_ERROR,
|
|
}
|
|
else:
|
|
expected_access_rules_status_change_cond2 = {
|
|
constants.SHARE_INSTANCE_RULES_SYNCING:
|
|
constants.STATUS_ACTIVE,
|
|
constants.SHARE_INSTANCE_RULES_ERROR:
|
|
constants.STATUS_ACTIVE,
|
|
}
|
|
call_args = driver_call.call_args_list[0][0]
|
|
call_kwargs = driver_call.call_args_list[0][1]
|
|
access_rules_to_be_on_share = [r['id'] for r in call_args[2]]
|
|
|
|
# Asserts
|
|
self.assertIsNone(retval)
|
|
self.assertEqual(share_instance_id, call_args[1]['id'])
|
|
self.assertEqual(sorted(expected_rules_to_be_on_share),
|
|
sorted(access_rules_to_be_on_share))
|
|
self.assertEqual(1, len(call_kwargs['add_rules']))
|
|
self.assertEqual(rule_2['id'], call_kwargs['add_rules'][0]['id'])
|
|
self.assertEqual(1, len(call_kwargs['delete_rules']))
|
|
self.assertEqual(rule_3['id'], call_kwargs['delete_rules'][0]['id'])
|
|
self.assertEqual('fake_server', call_kwargs['share_server'])
|
|
shr_instance_access_rules_status_update_call.assert_has_calls([
|
|
mock.call(
|
|
self.context, share_instance_id=share_instance_id,
|
|
conditionally_change=expected_access_rules_status_change_cond1
|
|
),
|
|
mock.call(
|
|
self.context, share_instance_id=share_instance_id,
|
|
conditionally_change=expected_access_rules_status_change_cond2
|
|
),
|
|
])
|
|
|
|
if driver_returns_updates:
|
|
expected_conditional_state_updates = {
|
|
constants.ACCESS_STATE_APPLYING: access_state,
|
|
constants.ACCESS_STATE_DENYING: access_state,
|
|
constants.ACCESS_STATE_ACTIVE: access_state,
|
|
}
|
|
expected_access_rule_update_calls = [
|
|
mock.call(
|
|
self.context, rule_3['access_id'],
|
|
updates={'access_key': 'alic3h4sAcc355'},
|
|
share_instance_id=share_instance_id,
|
|
conditionally_change={}),
|
|
mock.call(
|
|
self.context, rule_2['access_id'],
|
|
updates=mock.ANY, share_instance_id=share_instance_id,
|
|
conditionally_change=expected_conditional_state_updates)
|
|
]
|
|
one_access_rule_update_call.assert_has_calls(
|
|
expected_access_rule_update_calls, any_order=True)
|
|
else:
|
|
self.assertFalse(one_access_rule_update_call.called)
|
|
expected_conditionally_change = {
|
|
constants.ACCESS_STATE_APPLYING: constants.ACCESS_STATE_ACTIVE,
|
|
}
|
|
expected_get_and_update_calls.append(
|
|
mock.call(self.context, share_instance_id=share_instance_id,
|
|
conditionally_change=expected_conditionally_change))
|
|
|
|
all_access_rules_update_call.assert_has_calls(
|
|
expected_get_and_update_calls, any_order=True)
|
|
|
|
share_instance = db.share_instance_get(
|
|
self.context, share_instance_id)
|
|
self.assertEqual(expected_access_rules_status,
|
|
share_instance['access_rules_status'])
|
|
|
|
@ddt.data(True, False)
|
|
def test__update_access_rules_recursive_driver_exception(self, drv_exc):
|
|
other = access.ShareInstanceAccess(db, None)
|
|
share = db_utils.create_share(
|
|
status=constants.STATUS_AVAILABLE,
|
|
access_rules_status=constants.SHARE_INSTANCE_RULES_SYNCING)
|
|
share_instance_id = share['instance']['id']
|
|
rule_4 = []
|
|
get_and_update_count = [1]
|
|
drv_count = [1]
|
|
|
|
def _get_and_update_side_effect(*args, **kwargs):
|
|
# The third call to this method needs to create a new access rule
|
|
mtd = other.get_and_update_share_instance_access_rules
|
|
if get_and_update_count[0] == 3:
|
|
rule_4.append(
|
|
db_utils.create_access(
|
|
state=constants.ACCESS_STATE_QUEUED_TO_APPLY,
|
|
share_id=share['id']))
|
|
get_and_update_count[0] += 1
|
|
return mtd(*args, **kwargs)
|
|
|
|
def _driver_side_effect(*args, **kwargs):
|
|
if drv_exc and drv_count[0] == 2:
|
|
raise exception.ManilaException('fake')
|
|
drv_count[0] += 1
|
|
|
|
rule_kwargs = {'share_id': share['id'], 'access_level': 'rw'}
|
|
rule_1 = db_utils.create_access(state=constants.ACCESS_STATE_APPLYING,
|
|
**rule_kwargs)
|
|
rule_2 = db_utils.create_access(state=constants.ACCESS_STATE_ACTIVE,
|
|
**rule_kwargs)
|
|
rule_3 = db_utils.create_access(state=constants.ACCESS_STATE_DENYING,
|
|
**rule_kwargs)
|
|
|
|
self.mock_object(self.access_helper,
|
|
'get_and_update_share_instance_access_rules',
|
|
mock.Mock(side_effect=_get_and_update_side_effect))
|
|
self.mock_object(self.access_helper.driver, 'update_access',
|
|
mock.Mock(side_effect=_driver_side_effect))
|
|
|
|
if drv_exc:
|
|
self.assertRaises(exception.ManilaException,
|
|
self.access_helper._update_access_rules,
|
|
self.context, share_instance_id)
|
|
else:
|
|
retval = self.access_helper._update_access_rules(self.context,
|
|
share_instance_id)
|
|
self.assertIsNone(retval)
|
|
|
|
expected_filters_1 = {
|
|
'state': (constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_ACTIVE,
|
|
constants.ACCESS_STATE_DENYING),
|
|
}
|
|
conditionally_change_2 = {
|
|
constants.ACCESS_STATE_APPLYING: constants.ACCESS_STATE_ACTIVE,
|
|
}
|
|
expected_filters_3 = {
|
|
'state': (constants.ACCESS_STATE_QUEUED_TO_APPLY,
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY),
|
|
}
|
|
expected_conditionally_change_3 = {
|
|
constants.ACCESS_STATE_QUEUED_TO_APPLY:
|
|
constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY:
|
|
constants.ACCESS_STATE_DENYING,
|
|
}
|
|
expected_conditionally_change_4 = {
|
|
constants.ACCESS_STATE_APPLYING: constants.ACCESS_STATE_ERROR,
|
|
constants.ACCESS_STATE_DENYING: constants.ACCESS_STATE_ERROR,
|
|
}
|
|
expected_get_and_update_calls = [
|
|
mock.call(self.context, filters=expected_filters_1,
|
|
share_instance_id=share_instance_id),
|
|
mock.call(self.context, share_instance_id=share_instance_id,
|
|
conditionally_change=conditionally_change_2),
|
|
mock.call(self.context, filters=expected_filters_3,
|
|
share_instance_id=share_instance_id,
|
|
conditionally_change=expected_conditionally_change_3),
|
|
mock.call(self.context, filters=expected_filters_1,
|
|
share_instance_id=share_instance_id),
|
|
]
|
|
|
|
if drv_exc:
|
|
expected_get_and_update_calls.append(
|
|
mock.call(
|
|
self.context, share_instance_id=share_instance_id,
|
|
conditionally_change=expected_conditionally_change_4))
|
|
else:
|
|
expected_get_and_update_calls.append(
|
|
mock.call(self.context, share_instance_id=share_instance_id,
|
|
conditionally_change=conditionally_change_2))
|
|
|
|
# Verify rule changes:
|
|
# 'denying' rule must not exist
|
|
self.assertRaises(exception.NotFound,
|
|
db.share_access_get,
|
|
self.context, rule_3['id'])
|
|
# 'applying' rule must be set to 'active'
|
|
rules_that_must_be_active = (rule_1, rule_2)
|
|
if not drv_exc:
|
|
rules_that_must_be_active += (rule_4[0], )
|
|
for rule in rules_that_must_be_active:
|
|
rule = db.share_access_get(self.context, rule['id'])
|
|
self.assertEqual(constants.ACCESS_STATE_ACTIVE,
|
|
rule['state'])
|
|
# access_rules_status must be as expected
|
|
expected_access_rules_status = (
|
|
constants.SHARE_INSTANCE_RULES_ERROR if drv_exc
|
|
else constants.STATUS_ACTIVE)
|
|
share_instance = db.share_instance_get(self.context, share_instance_id)
|
|
self.assertEqual(
|
|
expected_access_rules_status,
|
|
share_instance['access_rules_status'])
|
|
|
|
def test__update_access_rules_for_migration(self):
|
|
share = db_utils.create_share()
|
|
instance = db_utils.create_share_instance(
|
|
status=constants.STATUS_MIGRATING,
|
|
access_rules_status=constants.STATUS_ACTIVE,
|
|
cast_rules_to_readonly=True,
|
|
share_id=share['id'])
|
|
rule_kwargs = {'share_id': share['id'], 'access_level': 'rw'}
|
|
rule_1 = db_utils.create_access(
|
|
state=constants.ACCESS_STATE_ACTIVE, **rule_kwargs)
|
|
rule_1 = db.share_instance_access_get(
|
|
self.context, rule_1['id'], instance['id'])
|
|
rule_2 = db_utils.create_access(
|
|
state=constants.ACCESS_STATE_APPLYING, share_id=share['id'],
|
|
access_level='ro')
|
|
rule_2 = db.share_instance_access_get(
|
|
self.context, rule_2['id'], instance['id'])
|
|
|
|
driver_call = self.mock_object(
|
|
self.access_helper.driver, 'update_access',
|
|
mock.Mock(return_value=None))
|
|
self.mock_object(self.access_helper, '_check_needs_refresh',
|
|
mock.Mock(return_value=False))
|
|
|
|
retval = self.access_helper._update_access_rules(
|
|
self.context, instance['id'], share_server='fake_server')
|
|
|
|
call_args = driver_call.call_args_list[0][0]
|
|
call_kwargs = driver_call.call_args_list[0][1]
|
|
access_rules_to_be_on_share = [r['id'] for r in call_args[2]]
|
|
access_levels = [r['access_level'] for r in call_args[2]]
|
|
expected_rules_to_be_on_share = ([rule_1['id'], rule_2['id']])
|
|
|
|
self.assertIsNone(retval)
|
|
self.assertEqual(instance['id'], call_args[1]['id'])
|
|
self.assertEqual(sorted(expected_rules_to_be_on_share),
|
|
sorted(access_rules_to_be_on_share))
|
|
self.assertEqual(['ro'] * len(expected_rules_to_be_on_share),
|
|
access_levels)
|
|
self.assertEqual(0, len(call_kwargs['add_rules']))
|
|
self.assertEqual(0, len(call_kwargs['delete_rules']))
|
|
self.assertEqual('fake_server', call_kwargs['share_server'])
|
|
|
|
@ddt.data(True, False)
|
|
def test__check_needs_refresh(self, expected_needs_refresh):
|
|
states = (
|
|
[constants.ACCESS_STATE_QUEUED_TO_DENY,
|
|
constants.ACCESS_STATE_QUEUED_TO_APPLY] if expected_needs_refresh
|
|
else [constants.ACCESS_STATE_ACTIVE]
|
|
)
|
|
share = db_utils.create_share(
|
|
status=constants.STATUS_AVAILABLE,
|
|
access_rules_status=constants.SHARE_INSTANCE_RULES_SYNCING)
|
|
share_instance_id = share['instance']['id']
|
|
rule_kwargs = {'share_id': share['id'], 'access_level': 'rw'}
|
|
rule_1 = db_utils.create_access(state=states[0], **rule_kwargs)
|
|
db_utils.create_access(state=constants.ACCESS_STATE_ACTIVE,
|
|
**rule_kwargs)
|
|
db_utils.create_access(state=constants.ACCESS_STATE_DENYING,
|
|
**rule_kwargs)
|
|
rule_4 = db_utils.create_access(state=states[-1], **rule_kwargs)
|
|
|
|
get_and_update_call = self.mock_object(
|
|
self.access_helper, 'get_and_update_share_instance_access_rules',
|
|
mock.Mock(side_effect=self.access_helper.
|
|
get_and_update_share_instance_access_rules))
|
|
|
|
needs_refresh = self.access_helper._check_needs_refresh(
|
|
self.context, share_instance_id)
|
|
|
|
expected_filter = {
|
|
'state': (constants.ACCESS_STATE_QUEUED_TO_APPLY,
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY),
|
|
}
|
|
expected_conditionally_change = {
|
|
constants.ACCESS_STATE_QUEUED_TO_APPLY:
|
|
constants.ACCESS_STATE_APPLYING,
|
|
constants.ACCESS_STATE_QUEUED_TO_DENY:
|
|
constants.ACCESS_STATE_DENYING,
|
|
}
|
|
|
|
self.assertEqual(expected_needs_refresh, needs_refresh)
|
|
get_and_update_call.assert_called_once_with(
|
|
self.context, filters=expected_filter,
|
|
share_instance_id=share_instance_id,
|
|
conditionally_change=expected_conditionally_change)
|
|
|
|
rule_1 = db.share_instance_access_get(
|
|
self.context, rule_1['id'], share_instance_id)
|
|
rule_4 = db.share_instance_access_get(
|
|
self.context, rule_4['id'], share_instance_id)
|
|
|
|
if expected_needs_refresh:
|
|
self.assertEqual(constants.ACCESS_STATE_DENYING, rule_1['state'])
|
|
self.assertEqual(constants.ACCESS_STATE_APPLYING, rule_4['state'])
|
|
else:
|
|
self.assertEqual(states[0], rule_1['state'])
|
|
self.assertEqual(states[-1], rule_4['state'])
|