manila/manila/tests/share/test_access.py

800 lines
35 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
import six
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.assertTrue(isinstance(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.assertTrue(isinstance(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 = six.text_type(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