Merge "Fix cannot deny ipv6 access rules"

This commit is contained in:
Jenkins 2017-08-03 00:43:55 +00:00 committed by Gerrit Code Review
commit 5757655f1d
4 changed files with 82 additions and 54 deletions

View File

@ -373,6 +373,13 @@ class ShareInstanceAccess(ShareInstanceAccessDatabaseMixin):
rules_to_be_removed_from_db, rules_to_be_removed_from_db,
share_server): share_server):
driver_rule_updates = {} driver_rule_updates = {}
share_protocol = share_instance['share_proto'].lower()
if (not self.driver.ipv6_implemented and
share_protocol == 'nfs'):
add_rules = self._filter_ipv6_rules(add_rules)
delete_rules = self._filter_ipv6_rules(delete_rules)
access_rules_to_be_on_share = self._filter_ipv6_rules(
access_rules_to_be_on_share)
try: try:
driver_rule_updates = self.driver.update_access( driver_rule_updates = self.driver.update_access(
context, context,
@ -463,10 +470,10 @@ class ShareInstanceAccess(ShareInstanceAccessDatabaseMixin):
return access_rules_to_be_on_share return access_rules_to_be_on_share
@staticmethod @staticmethod
def _filter_ipv6_rules(rules, share_instance_proto): def _filter_ipv6_rules(rules):
filtered = [] filtered = []
for rule in rules: for rule in rules:
if rule['access_type'] == 'ip' and share_instance_proto == 'nfs': if rule['access_type'] == 'ip':
ip_version = ipaddress.ip_network( ip_version = ipaddress.ip_network(
six.text_type(rule['access_to'])).version six.text_type(rule['access_to'])).version
if 6 == ip_version: if 6 == ip_version:
@ -496,13 +503,6 @@ class ShareInstanceAccess(ShareInstanceAccessDatabaseMixin):
access_rules_to_be_on_share = [ access_rules_to_be_on_share = [
r for r in existing_rules_in_db if r['id'] not in delete_rule_ids r for r in existing_rules_in_db if r['id'] not in delete_rule_ids
] ]
share = self.db.share_get(context, share_instance['share_id'])
si_proto = share['share_proto'].lower()
if not self.driver.ipv6_implemented:
add_rules = self._filter_ipv6_rules(add_rules, si_proto)
delete_rules = self._filter_ipv6_rules(delete_rules, si_proto)
access_rules_to_be_on_share = self._filter_ipv6_rules(
access_rules_to_be_on_share, si_proto)
return access_rules_to_be_on_share, add_rules, delete_rules return access_rules_to_be_on_share, add_rules, delete_rules
def _check_needs_refresh(self, context, share_instance_id): def _check_needs_refresh(self, context, share_instance_id):

View File

@ -13,10 +13,12 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import itertools
import ddt import ddt
import mock import mock
import random
import itertools
import six
from manila.common import constants from manila.common import constants
from manila import context from manila import context
@ -721,55 +723,71 @@ class ShareInstanceAccessTestCase(test.TestCase):
self.assertEqual(states[0], rule_1['state']) self.assertEqual(states[0], rule_1['state'])
self.assertEqual(states[-1], rule_4['state']) self.assertEqual(states[-1], rule_4['state'])
@ddt.data(('nfs', True), ('cifs', False), ('ceph', False)) @ddt.data(('nfs', True, False), ('nfs', False, True),
('cifs', True, False), ('cifs', False, False),
('cephx', True, False), ('cephx', False, False))
@ddt.unpack @ddt.unpack
def test__filter_ipv6_rules(self, proto, filtered): 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 = [ pass_rules = [
{ {
'access_type': 'ip', 'access_type': 'ip',
'access_to': '1.1.1.1' 'access_to': '1.1.1.' + random_value,
}, },
{ {
'access_type': 'ip', 'access_type': 'ip',
'access_to': '1.1.1.0/24' 'access_to': '1.1.%s.0/24' % random_value,
}, },
{ {
'access_type': 'user', 'access_type': 'user',
'access_to': 'fake_user' 'access_to': 'fake_user' + random_value,
}, },
] ]
fail_rules = [ fail_rules = [
{ {
'access_type': 'ip', 'access_type': 'ip',
'access_to': '1001::1001' 'access_to': '1001::' + random_value,
}, },
{ {
'access_type': 'ip', 'access_type': 'ip',
'access_to': '1001::/64' 'access_to': '%s::/64' % random_value,
}, },
] ]
test_rules = pass_rules + fail_rules return pass_rules, fail_rules
filtered_rules = self.access_helper._filter_ipv6_rules(
test_rules, proto)
if filtered:
self.assertEqual(pass_rules, filtered_rules)
else:
self.assertEqual(test_rules, filtered_rules)
def test__get_rules_to_send_to_driver(self):
self.driver.ipv6_implemented = False
share = db_utils.create_share(status=constants.STATUS_AVAILABLE)
share_instance = share['instance']
db_utils.create_access(share_id=share['id'], access_to='1001::/64',
state=constants.ACCESS_STATE_ACTIVE)
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))
access_rules_to_be_on_share, add_rules, delete_rules = (
self.access_helper._get_rules_to_send_to_driver(
self.context, share_instance))
self.assertEqual([], add_rules)
self.assertEqual([], delete_rules)

View File

@ -93,15 +93,17 @@ class ShareIpRulesForNFSTest(base.BaseSharesTest):
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND) @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@ddt.data(*itertools.chain( @ddt.data(*itertools.chain(
itertools.product({'1.0', '2.9', '2.37', LATEST_MICROVERSION}, itertools.product({'1.0', '2.9', '2.37', LATEST_MICROVERSION}, {4}),
{utils.rand_ip()}), itertools.product({'2.38', LATEST_MICROVERSION}, {6})
itertools.product({'2.37', LATEST_MICROVERSION},
{utils.rand_ipv6_ip()})
)) ))
@ddt.unpack @ddt.unpack
def test_create_delete_access_rules_with_one_ip(self, version, def test_create_delete_access_rules_with_one_ip(self, version,
access_to): ip_version):
if ip_version == 4:
access_to = utils.rand_ip()
else:
access_to = utils.rand_ipv6_ip()
# create rule # create rule
if utils.is_microversion_eq(version, '1.0'): if utils.is_microversion_eq(version, '1.0'):
rule = self.shares_client.create_access_rule( rule = self.shares_client.create_access_rule(
@ -145,14 +147,15 @@ class ShareIpRulesForNFSTest(base.BaseSharesTest):
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND) @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
@ddt.data(*itertools.chain( @ddt.data(*itertools.chain(
itertools.product({'1.0', '2.9', '2.37', LATEST_MICROVERSION}, itertools.product({'1.0', '2.9', '2.37', LATEST_MICROVERSION}, {4}),
{utils.rand_ip(network=True)}), itertools.product({'2.38', LATEST_MICROVERSION}, {6})
itertools.product({'2.37', LATEST_MICROVERSION},
{utils.rand_ipv6_ip(network=True)})
)) ))
@ddt.unpack @ddt.unpack
def test_create_delete_access_rule_with_cidr(self, version, access_to): def test_create_delete_access_rule_with_cidr(self, version, ip_version):
if ip_version == 4:
access_to = utils.rand_ip(network=True)
else:
access_to = utils.rand_ipv6_ip(network=True)
# create rule # create rule
if utils.is_microversion_eq(version, '1.0'): if utils.is_microversion_eq(version, '1.0'):
rule = self.shares_client.create_access_rule( rule = self.shares_client.create_access_rule(

View File

@ -0,0 +1,7 @@
---
fixes:
- The access-allow API accepts ipv6 rules and ignores them if the
configured backend does not support ipv6 access rules.
However, when the access-deny API is invoked to remove such
rules, they used to be stuck in "denying" state. This bug has been
fixed and ipv6 access rules can be denied successfully.