Enable IPv6 in manila(client)
Please read spec for design detail [1] Access-allow command now validates and allows access control to IPv6 clients. [1] f7202a6cfe32a057f752a4e393f848f8a0211c36 Partial-Implements: blueprint support-ipv6-access Change-Id: I88a1bd60e703bf9b434924ac347bbd74f72cec2b
This commit is contained in:

committed by
Goutham Pacha Ravi

parent
8d887f5221
commit
39b72e58c9
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
from tempest.lib import exceptions as tempest_lib_exc
|
from tempest.lib import exceptions as tempest_lib_exc
|
||||||
|
import testtools
|
||||||
|
|
||||||
from manilaclient import api_versions
|
from manilaclient import api_versions
|
||||||
from manilaclient import config
|
from manilaclient import config
|
||||||
@@ -65,6 +66,7 @@ class ShareAccessReadWriteBase(base.BaseTestCase):
|
|||||||
# API testing.
|
# API testing.
|
||||||
'user': ['foo_user_%d' % i for i in int_range],
|
'user': ['foo_user_%d' % i for i in int_range],
|
||||||
'cert': ['tenant_%d.example.com' % i for i in int_range],
|
'cert': ['tenant_%d.example.com' % i for i in int_range],
|
||||||
|
'ipv6': ['2001:db8::%d' % i for i in int_range],
|
||||||
}
|
}
|
||||||
|
|
||||||
def _test_create_list_access_rule_for_share(self, microversion):
|
def _test_create_list_access_rule_for_share(self, microversion):
|
||||||
@@ -170,6 +172,12 @@ class ShareAccessReadWriteBase(base.BaseTestCase):
|
|||||||
self._create_delete_access_rule(
|
self._create_delete_access_rule(
|
||||||
self.share_id, 'cert', self.access_to['cert'].pop(), microversion)
|
self.share_id, 'cert', self.access_to['cert'].pop(), microversion)
|
||||||
|
|
||||||
|
@ddt.data("2.38", api_versions.MAX_VERSION)
|
||||||
|
@testtools.skip("BUG: https://bugs.launchpad.net/manila/+bug/1707066")
|
||||||
|
def test_create_delete_ipv6_access_rule(self, microversion):
|
||||||
|
self._create_delete_access_rule(
|
||||||
|
self.share_id, 'ip', self.access_to['ipv6'].pop(), microversion)
|
||||||
|
|
||||||
|
|
||||||
class NFSShareRWAccessReadWriteTest(ShareAccessReadWriteBase):
|
class NFSShareRWAccessReadWriteTest(ShareAccessReadWriteBase):
|
||||||
protocol = 'nfs'
|
protocol = 'nfs'
|
||||||
|
@@ -386,6 +386,18 @@ class SharesTest(utils.TestCase):
|
|||||||
'action_name': 'allow_access', 'microversion': '2.13'},
|
'action_name': 'allow_access', 'microversion': '2.13'},
|
||||||
{'access_to': 'alice bob', 'access_type': 'cephx',
|
{'access_to': 'alice bob', 'access_type': 'cephx',
|
||||||
'action_name': 'allow_access', 'microversion': '2.13'},
|
'action_name': 'allow_access', 'microversion': '2.13'},
|
||||||
|
{'access_to': 'AD80:0000:0000:0000:ABAA:0000:00C2:0002',
|
||||||
|
'access_type': 'ip', 'action_name': 'allow_access',
|
||||||
|
'microversion': '2.38'},
|
||||||
|
{'access_to': 'AD80::/36',
|
||||||
|
'access_type': 'ip', 'action_name': 'allow_access',
|
||||||
|
'microversion': '2.38'},
|
||||||
|
{'access_to': 'AD80:ABAA::/128',
|
||||||
|
'access_type': 'ip', 'action_name': 'allow_access',
|
||||||
|
'microversion': '2.38'},
|
||||||
|
{'access_to': 'ad80::abaa:0:c2:2',
|
||||||
|
'access_type': 'ip', 'action_name': 'allow_access',
|
||||||
|
'microversion': '2.38'},
|
||||||
)
|
)
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_allow_access_to_share(self, access_to, access_type,
|
def test_allow_access_to_share(self, access_to, access_type,
|
||||||
@@ -436,6 +448,12 @@ class SharesTest(utils.TestCase):
|
|||||||
'microversion': '2.13'},
|
'microversion': '2.13'},
|
||||||
{'access_to': u"bj\u00F6rn", 'access_type': 'cephx',
|
{'access_to': u"bj\u00F6rn", 'access_type': 'cephx',
|
||||||
'microversion': '2.13'},
|
'microversion': '2.13'},
|
||||||
|
{'access_to': "AD80:0000:0000:0000:ABAA:0000:00C2:0002/65",
|
||||||
|
'access_type': 'ip', 'microversion': '2.38'},
|
||||||
|
{'access_to': "AD80:0000:0000:0000:ABAA:0000:00C2:0002*32",
|
||||||
|
'access_type': 'ip', 'microversion': '2.38'},
|
||||||
|
{'access_to': "AD80:0000:0000:0000:ABAA:0000:00C2:0002",
|
||||||
|
'access_type': 'ip', 'microversion': '2.37'},
|
||||||
)
|
)
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_allow_access_to_share_error_invalid_access(self, access_to,
|
def test_allow_access_to_share_error_invalid_access(self, access_to,
|
||||||
|
@@ -15,8 +15,10 @@
|
|||||||
"""Interface for shares extension."""
|
"""Interface for shares extension."""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import ipaddress
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import re
|
import re
|
||||||
|
import six
|
||||||
import string
|
import string
|
||||||
try:
|
try:
|
||||||
from urllib import urlencode # noqa
|
from urllib import urlencode # noqa
|
||||||
@@ -454,32 +456,6 @@ class ShareManager(base.ManagerWithFind):
|
|||||||
'special characters ]{.-_\'`;}[\\')
|
'special characters ]{.-_\'`;}[\\')
|
||||||
raise exceptions.CommandError(exc_str)
|
raise exceptions.CommandError(exc_str)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _validate_ip_range(ip_range):
|
|
||||||
ip_range = ip_range.split('/')
|
|
||||||
exc_str = ('Supported ip format examples:\n'
|
|
||||||
'\t10.0.0.2, 10.0.0.0/24')
|
|
||||||
if len(ip_range) > 2:
|
|
||||||
raise exceptions.CommandError(exc_str)
|
|
||||||
if len(ip_range) == 2:
|
|
||||||
try:
|
|
||||||
prefix = int(ip_range[1])
|
|
||||||
if prefix < 0 or prefix > 32:
|
|
||||||
raise ValueError()
|
|
||||||
except ValueError:
|
|
||||||
msg = 'IP prefix should be in range from 0 to 32.'
|
|
||||||
raise exceptions.CommandError(msg)
|
|
||||||
ip_range = ip_range[0].split('.')
|
|
||||||
if len(ip_range) != 4:
|
|
||||||
raise exceptions.CommandError(exc_str)
|
|
||||||
for item in ip_range:
|
|
||||||
try:
|
|
||||||
if 0 <= int(item) <= 255:
|
|
||||||
continue
|
|
||||||
raise ValueError()
|
|
||||||
except ValueError:
|
|
||||||
raise exceptions.CommandError(exc_str)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _validate_cephx_id(cephx_id):
|
def _validate_cephx_id(cephx_id):
|
||||||
if not cephx_id:
|
if not cephx_id:
|
||||||
@@ -500,13 +476,20 @@ class ShareManager(base.ManagerWithFind):
|
|||||||
raise exceptions.CommandError(
|
raise exceptions.CommandError(
|
||||||
'Ceph IDs may not contain periods.')
|
'Ceph IDs may not contain periods.')
|
||||||
|
|
||||||
def _validate_access(self, access_type, access, valid_access_types=None):
|
def _validate_access(self, access_type, access, valid_access_types=None,
|
||||||
|
enable_ipv6=False):
|
||||||
if not valid_access_types:
|
if not valid_access_types:
|
||||||
valid_access_types = ('ip', 'user', 'cert')
|
valid_access_types = ('ip', 'user', 'cert')
|
||||||
|
|
||||||
if access_type in valid_access_types:
|
if access_type in valid_access_types:
|
||||||
if access_type == 'ip':
|
if access_type == 'ip':
|
||||||
self._validate_ip_range(access)
|
try:
|
||||||
|
if enable_ipv6:
|
||||||
|
ipaddress.ip_network(six.text_type(access))
|
||||||
|
else:
|
||||||
|
ipaddress.IPv4Network(six.text_type(access))
|
||||||
|
except ValueError as error:
|
||||||
|
raise exceptions.CommandError(six.text_type(error))
|
||||||
elif access_type == 'user':
|
elif access_type == 'user':
|
||||||
self._validate_username(access)
|
self._validate_username(access)
|
||||||
elif access_type == 'cert':
|
elif access_type == 'cert':
|
||||||
@@ -553,13 +536,21 @@ class ShareManager(base.ManagerWithFind):
|
|||||||
return self._do_allow(
|
return self._do_allow(
|
||||||
share, access_type, access, access_level, "allow_access")
|
share, access_type, access, access_level, "allow_access")
|
||||||
|
|
||||||
@api_versions.wraps("2.13") # noqa
|
@api_versions.wraps("2.13", "2.37") # noqa
|
||||||
def allow(self, share, access_type, access, access_level):
|
def allow(self, share, access_type, access, access_level):
|
||||||
valid_access_types = ('ip', 'user', 'cert', 'cephx')
|
valid_access_types = ('ip', 'user', 'cert', 'cephx')
|
||||||
self._validate_access(access_type, access, valid_access_types)
|
self._validate_access(access_type, access, valid_access_types)
|
||||||
return self._do_allow(
|
return self._do_allow(
|
||||||
share, access_type, access, access_level, "allow_access")
|
share, access_type, access, access_level, "allow_access")
|
||||||
|
|
||||||
|
@api_versions.wraps("2.38") # noqa
|
||||||
|
def allow(self, share, access_type, access, access_level):
|
||||||
|
valid_access_types = ('ip', 'user', 'cert', 'cephx')
|
||||||
|
self._validate_access(access_type, access, valid_access_types,
|
||||||
|
enable_ipv6=True)
|
||||||
|
return self._do_allow(
|
||||||
|
share, access_type, access, access_level, "allow_access")
|
||||||
|
|
||||||
def _do_deny(self, share, access_id, action_name):
|
def _do_deny(self, share, access_id, action_name):
|
||||||
"""Deny access to a share.
|
"""Deny access to a share.
|
||||||
|
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- IPv6 ACL support has been added in manila. access-allow
|
||||||
|
command now validates and allows access control
|
||||||
|
to IPv6 clients.
|
Reference in New Issue
Block a user