manila/manila/tests/share/test_access.py

852 lines
38 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 random
from unittest import mock
import ddt
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(LockedOperationsTestCase, 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(ShareInstanceAccessDatabaseMixinTestCase, 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.assertIn(rule_1['id'], rule_ids)
self.assertIn(rule_2['id'], 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.assertIsInstance(access_rules_to_be_on_share, list)
self.assertEqual(len(expected_rules_to_be_on_share),
len(access_rules_to_be_on_share))
for pool in expected_rules_to_be_on_share:
self.assertIn(pool, 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.assertIsInstance(access_rules_to_be_on_share, list)
self.assertEqual(len(expected_rules_to_be_on_share),
len(access_rules_to_be_on_share))
for pool in expected_rules_to_be_on_share:
self.assertIn(pool, 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'])
@ddt.data(('nfs', True, False), ('nfs', False, True),
('cifs', True, False), ('cifs', False, False),
('cephx', True, False), ('cephx', False, False))
@ddt.unpack
def test__update_rules_through_share_driver(self, proto,
enable_ipv6, filtered):
self.driver.ipv6_implemented = enable_ipv6
share_instance = {'share_proto': proto}
pass_rules, fail_rules = self._get_pass_rules_and_fail_rules()
pass_add_rules, fail_add_rules = self._get_pass_rules_and_fail_rules()
pass_delete_rules, fail_delete_rules = (
self._get_pass_rules_and_fail_rules())
test_rules = pass_rules + fail_rules
test_add_rules = pass_add_rules + fail_add_rules
test_delete_rules = pass_delete_rules + fail_delete_rules
fake_expect_driver_update_rules = pass_rules
update_access_call = self.mock_object(
self.access_helper.driver, 'update_access',
mock.Mock(return_value=pass_rules))
driver_update_rules = (
self.access_helper._update_rules_through_share_driver(
self.context, share_instance=share_instance,
access_rules_to_be_on_share=test_rules,
add_rules=test_add_rules,
delete_rules=test_delete_rules,
rules_to_be_removed_from_db=test_rules,
share_server=None))
if filtered:
update_access_call.assert_called_once_with(
self.context, share_instance,
pass_rules, add_rules=pass_add_rules,
delete_rules=pass_delete_rules, share_server=None)
else:
update_access_call.assert_called_once_with(
self.context, share_instance, test_rules,
add_rules=test_add_rules, delete_rules=test_delete_rules,
share_server=None)
self.assertEqual(fake_expect_driver_update_rules, driver_update_rules)
def _get_pass_rules_and_fail_rules(self):
random_value = str(random.randint(10, 32))
pass_rules = [
{
'access_type': 'ip',
'access_to': '1.1.1.' + random_value,
},
{
'access_type': 'ip',
'access_to': '1.1.%s.0/24' % random_value,
},
{
'access_type': 'user',
'access_to': 'fake_user' + random_value,
},
]
fail_rules = [
{
'access_type': 'ip',
'access_to': '1001::' + random_value,
},
{
'access_type': 'ip',
'access_to': '%s::/64' % random_value,
},
]
return pass_rules, fail_rules
def test_update_share_instances_access_rules_status(self):
mock_db_instances_update = self.mock_object(
db, 'share_instance_status_update')
share_instances = ['fake_instance_id', 'fake_instance_id_2']
self.access_helper.update_share_instances_access_rules_status(
self.context, 'fake_status', share_instances)
mock_db_instances_update.assert_called_once_with(
self.context, share_instances,
{'access_rules_status': 'fake_status'})
@ddt.data(True, False)
def test_reset_rules_to_queueing_states(self, reset_active):
share = db_utils.create_share(
status=constants.STATUS_AVAILABLE,
# if rules are applying/denying, status would be 'syncing', but,
# lets test the transition to syncing when asked to reset_active
access_rules_status=constants.STATUS_ACTIVE)
share_instance_id = share['instance']['id']
rule_kwargs = {'share_id': share['id'], 'access_level': 'rw'}
r1 = db_utils.create_access(
state=constants.ACCESS_STATE_APPLYING, **rule_kwargs)
r2 = db_utils.create_access(
state=constants.ACCESS_STATE_DENYING, **rule_kwargs)
r3 = db_utils.create_access(
state=constants.ACCESS_STATE_ACTIVE, **rule_kwargs)
r4 = db_utils.create_access(
state=constants.ACCESS_STATE_ACTIVE, **rule_kwargs)
self.access_helper.reset_rules_to_queueing_states(
self.context, share_instance_id, reset_active=reset_active)
rules = db.share_access_get_all_for_instance(
self.context, share_instance_id)
share_instance = db.share_instance_get(self.context, share_instance_id)
rules_dict = {r['access_id']: r for r in rules}
self.assertEqual(constants.SHARE_INSTANCE_RULES_SYNCING,
share_instance['access_rules_status'])
self.assertEqual(constants.ACCESS_STATE_QUEUED_TO_APPLY,
rules_dict[r1['id']]['state'])
self.assertEqual(constants.ACCESS_STATE_QUEUED_TO_DENY,
rules_dict[r2['id']]['state'])
expected_state_for_previously_active = (
constants.ACCESS_STATE_QUEUED_TO_APPLY
if reset_active else
constants.ACCESS_STATE_ACTIVE
)
self.assertEqual(expected_state_for_previously_active,
rules_dict[r3['id']]['state'])
self.assertEqual(expected_state_for_previously_active,
rules_dict[r4['id']]['state'])