Reject the cell name include '!', '.' and '@' for Nova API
Nova cells use '!', '.' and '@' for routing the instance in cells. So those special characters can't include in the cell name. This patch adds '@' validation for v2 API, and adds '!', '.' and '@' for v2.1 API. Change-Id: I5cb704a44c2abfb0bfb5b42d4aa8fefe35cc1523 Partial-Bug: #1491511
This commit is contained in:
parent
bc0cc457ba
commit
e5982de3e9
|
@ -187,12 +187,14 @@ class Controller(object):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def _validate_cell_name(self, cell_name):
|
def _validate_cell_name(self, cell_name):
|
||||||
"""Validate cell name is not empty and doesn't contain '!' or '.'."""
|
"""Validate cell name is not empty and doesn't contain '!',
|
||||||
|
'.' or '@'.
|
||||||
|
"""
|
||||||
if not cell_name:
|
if not cell_name:
|
||||||
msg = _("Cell name cannot be empty")
|
msg = _("Cell name cannot be empty")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
if '!' in cell_name or '.' in cell_name:
|
if '!' in cell_name or '.' in cell_name or '@' in cell_name:
|
||||||
msg = _("Cell name cannot contain '!' or '.'")
|
msg = _("Cell name cannot contain '!', '.' or '@'")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
def _validate_cell_type(self, cell_type):
|
def _validate_cell_type(self, cell_type):
|
||||||
|
|
|
@ -21,7 +21,7 @@ create = {
|
||||||
'cell': {
|
'cell': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
'name': parameter_types.name,
|
'name': parameter_types.cell_name,
|
||||||
'type': {
|
'type': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
'enum': ['parent', 'child'],
|
'enum': ['parent', 'child'],
|
||||||
|
@ -61,7 +61,7 @@ update = {
|
||||||
'cell': {
|
'cell': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
'name': parameter_types.name,
|
'name': parameter_types.cell_name,
|
||||||
'type': {
|
'type': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
'enum': ['parent', 'child'],
|
'enum': ['parent', 'child'],
|
||||||
|
|
|
@ -40,6 +40,7 @@ def _get_all_chars():
|
||||||
for i in range(0xFFFF):
|
for i in range(0xFFFF):
|
||||||
yield six.unichr(i)
|
yield six.unichr(i)
|
||||||
|
|
||||||
|
|
||||||
# build a regex that matches all printable characters. This allows
|
# build a regex that matches all printable characters. This allows
|
||||||
# spaces in the middle of the name. Also note that the regexp below
|
# spaces in the middle of the name. Also note that the regexp below
|
||||||
# deliberately allows the empty string. This is so only the constraint
|
# deliberately allows the empty string. This is so only the constraint
|
||||||
|
@ -47,13 +48,25 @@ def _get_all_chars():
|
||||||
# empty string is tested. Otherwise it is not deterministic which
|
# empty string is tested. Otherwise it is not deterministic which
|
||||||
# constraint fails and this causes issues for some unittests when
|
# constraint fails and this causes issues for some unittests when
|
||||||
# PYTHONHASHSEED is set randomly.
|
# PYTHONHASHSEED is set randomly.
|
||||||
_printable = ''.join(c for c in _get_all_chars() if _is_printable(c))
|
def _get_printable(exclude=None):
|
||||||
|
if exclude is None:
|
||||||
|
exclude = []
|
||||||
|
return ''.join(c for c in _get_all_chars()
|
||||||
|
if _is_printable(c) and c not in exclude)
|
||||||
|
|
||||||
|
|
||||||
_printable_ws = ''.join(c for c in _get_all_chars()
|
_printable_ws = ''.join(c for c in _get_all_chars()
|
||||||
if unicodedata.category(c) == "Zs")
|
if unicodedata.category(c) == "Zs")
|
||||||
|
|
||||||
valid_name_regex = '^(?![%s])[%s]*(?<![%s])$' % (
|
valid_name_regex = '^(?![%s])[%s]*(?<![%s])$' % (
|
||||||
re.escape(_printable_ws), re.escape(_printable), re.escape(_printable_ws))
|
re.escape(_printable_ws), re.escape(_get_printable()),
|
||||||
|
re.escape(_printable_ws))
|
||||||
|
|
||||||
|
# cell's name disallow '!', '.' and '@'.
|
||||||
|
valid_cell_name_regex = '^(?![%s])[%s]*(?<![%s])$' % (
|
||||||
|
re.escape(_printable_ws),
|
||||||
|
re.escape(_get_printable(exclude=['!', '.', '@'])),
|
||||||
|
re.escape(_printable_ws))
|
||||||
|
|
||||||
boolean = {
|
boolean = {
|
||||||
'type': ['boolean', 'string'],
|
'type': ['boolean', 'string'],
|
||||||
|
@ -109,6 +122,12 @@ name = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cell_name = {
|
||||||
|
'type': 'string', 'minLength': 1, 'maxLength': 255,
|
||||||
|
'pattern': valid_cell_name_regex,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
tcp_udp_port = {
|
tcp_udp_port = {
|
||||||
'type': ['integer', 'string'], 'pattern': '^[0-9]*$',
|
'type': ['integer', 'string'], 'pattern': '^[0-9]*$',
|
||||||
'minimum': 0, 'maximum': 65535,
|
'minimum': 0, 'maximum': 65535,
|
||||||
|
|
|
@ -286,9 +286,32 @@ class CellsTestV21(BaseCellsTest):
|
||||||
|
|
||||||
req = self._get_request("cells")
|
req = self._get_request("cells")
|
||||||
req.environ['nova.context'] = self.context
|
req.environ['nova.context'] = self.context
|
||||||
res_dict = self.controller.create(req, body=body)
|
self.assertRaises(self.bad_request, self.controller.create,
|
||||||
cell = res_dict['cell']
|
req, body=body)
|
||||||
self.assertEqual(cell['name'], 'moo.cow')
|
|
||||||
|
def test_cell_create_name_with_exclamation_point_raises(self):
|
||||||
|
body = {'cell': {'name': 'moo!cow',
|
||||||
|
'username': 'fred',
|
||||||
|
'password': 'secret',
|
||||||
|
'rpc_host': 'r3.example.org',
|
||||||
|
'type': 'parent'}}
|
||||||
|
|
||||||
|
req = self._get_request("cells")
|
||||||
|
req.environ['nova.context'] = self.context
|
||||||
|
self.assertRaises(self.bad_request, self.controller.create,
|
||||||
|
req, body=body)
|
||||||
|
|
||||||
|
def test_cell_create_name_with_at_raises(self):
|
||||||
|
body = {'cell': {'name': 'moo@cow',
|
||||||
|
'username': 'fred',
|
||||||
|
'password': 'secret',
|
||||||
|
'rpc_host': 'r3.example.org',
|
||||||
|
'type': 'parent'}}
|
||||||
|
|
||||||
|
req = self._get_request("cells")
|
||||||
|
req.environ['nova.context'] = self.context
|
||||||
|
self.assertRaises(self.bad_request, self.controller.create,
|
||||||
|
req, body=body)
|
||||||
|
|
||||||
def test_cell_create_name_with_invalid_type_raises(self):
|
def test_cell_create_name_with_invalid_type_raises(self):
|
||||||
body = {'cell': {'name': 'moocow',
|
body = {'cell': {'name': 'moocow',
|
||||||
|
@ -681,32 +704,11 @@ class CellsTestV2(CellsTestV21):
|
||||||
cell_extension = 'compute_extension:cells'
|
cell_extension = 'compute_extension:cells'
|
||||||
bad_request = exc.HTTPBadRequest
|
bad_request = exc.HTTPBadRequest
|
||||||
|
|
||||||
def test_cell_create_name_with_invalid_character_raises(self):
|
|
||||||
body = {'cell': {'name': 'moo!cow',
|
|
||||||
'username': 'fred',
|
|
||||||
'password': 'secret',
|
|
||||||
'rpc_host': 'r3.example.org',
|
|
||||||
'type': 'parent'}}
|
|
||||||
|
|
||||||
req = self._get_request("cells")
|
|
||||||
req.environ['nova.context'] = self.context
|
|
||||||
self.assertRaises(self.bad_request,
|
|
||||||
self.controller.create, req, body=body)
|
|
||||||
|
|
||||||
def _get_cell_controller(self, ext_mgr):
|
def _get_cell_controller(self, ext_mgr):
|
||||||
return cells_ext_v2.Controller(ext_mgr)
|
return cells_ext_v2.Controller(ext_mgr)
|
||||||
|
|
||||||
def test_cell_create_name_with_dot_raises(self):
|
def test_cell_create_name_with_invalid_character_raises(self):
|
||||||
body = {'cell': {'name': 'moo.cow',
|
pass
|
||||||
'username': 'fred',
|
|
||||||
'password': 'secret',
|
|
||||||
'rpc_host': 'r3.example.org',
|
|
||||||
'type': 'parent'}}
|
|
||||||
|
|
||||||
req = self._get_request("cells")
|
|
||||||
req.environ['nova.context'] = self.context
|
|
||||||
self.assertRaises(exc.HTTPBadRequest,
|
|
||||||
self.controller.create, req, body=body)
|
|
||||||
|
|
||||||
def test_cell_create_rpc_port_with_null(self):
|
def test_cell_create_rpc_port_with_null(self):
|
||||||
body = {'cell': {'name': 'fake',
|
body = {'cell': {'name': 'fake',
|
||||||
|
|
Loading…
Reference in New Issue