Merge "Enforce FlavorExtraSpecs Key format."
This commit is contained in:
commit
b7e9257292
@ -20,11 +20,11 @@ from webob import exc
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api.openstack import xmlutil
|
||||
from nova.compute import flavors
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova.openstack.common.gettextutils import _
|
||||
|
||||
|
||||
authorize = extensions.extension_authorizer('compute', 'flavorextraspecs')
|
||||
|
||||
|
||||
@ -55,6 +55,12 @@ class FlavorExtraSpecsController(object):
|
||||
expl = _('No Request Body')
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
def _check_key_names(self, keys):
|
||||
try:
|
||||
flavors.validate_extra_spec_keys(keys)
|
||||
except exception.InvalidInput as error:
|
||||
raise exc.HTTPBadRequest(explanation=error.format_message())
|
||||
|
||||
@wsgi.serializers(xml=ExtraSpecsTemplate)
|
||||
def index(self, req, flavor_id):
|
||||
"""Returns the list of extra specs for a given flavor."""
|
||||
@ -68,6 +74,7 @@ class FlavorExtraSpecsController(object):
|
||||
authorize(context, action='create')
|
||||
self._check_body(body)
|
||||
specs = body.get('extra_specs')
|
||||
self._check_key_names(specs.keys())
|
||||
try:
|
||||
db.flavor_extra_specs_update_or_create(context,
|
||||
flavor_id,
|
||||
|
@ -17,6 +17,7 @@ import webob
|
||||
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.compute import flavors
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova.openstack.common.db import exception as db_exc
|
||||
@ -41,6 +42,12 @@ class FlavorExtraSpecsController(object):
|
||||
expl = _('No Request Body')
|
||||
raise webob.exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
def _check_key_names(self, keys):
|
||||
try:
|
||||
flavors.validate_extra_spec_keys(keys)
|
||||
except exception.InvalidInput as error:
|
||||
raise webob.exc.HTTPBadRequest(explanation=error.format_message())
|
||||
|
||||
@extensions.expected_errors(())
|
||||
def index(self, req, flavor_id):
|
||||
"""Returns the list of extra specs for a given flavor."""
|
||||
@ -57,6 +64,7 @@ class FlavorExtraSpecsController(object):
|
||||
specs = body.get('extra_specs', {})
|
||||
if not specs or type(specs) is not dict:
|
||||
raise webob.exc.HTTPBadRequest(_('No or bad extra_specs provided'))
|
||||
self._check_key_names(specs.keys())
|
||||
try:
|
||||
db.flavor_extra_specs_update_or_create(context, flavor_id,
|
||||
specs)
|
||||
|
@ -53,6 +53,9 @@ LOG = logging.getLogger(__name__)
|
||||
VALID_ID_REGEX = re.compile("^[\w\.\- ]*$")
|
||||
VALID_NAME_REGEX = re.compile("^[\w\.\- ]*$", re.UNICODE)
|
||||
|
||||
# Validate extra specs key names.
|
||||
VALID_EXTRASPEC_NAME_REGEX = re.compile(r"[\w\.\- :]+$", re.UNICODE)
|
||||
|
||||
|
||||
def _int_or_none(val):
|
||||
if val is not None:
|
||||
@ -307,3 +310,11 @@ def delete_flavor_info(metadata, *prefixes):
|
||||
del metadata[to_key]
|
||||
pci_request.delete_flavor_pci_info(metadata, *prefixes)
|
||||
return metadata
|
||||
|
||||
|
||||
def validate_extra_spec_keys(key_names_list):
|
||||
for key_name in key_names_list:
|
||||
if not VALID_EXTRASPEC_NAME_REGEX.match(key_name):
|
||||
expl = _('Key Names can only contain alphanumeric characters, '
|
||||
'periods, dashes, underscores, colons and spaces.')
|
||||
raise exception.InvalidInput(message=expl)
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import webob
|
||||
|
||||
from nova.api.openstack.compute.contrib import flavorextraspecs
|
||||
@ -151,6 +152,30 @@ class FlavorsExtraSpecsTest(test.TestCase):
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, 1, '')
|
||||
|
||||
@mock.patch('nova.db.flavor_extra_specs_update_or_create')
|
||||
def test_create_invalid_specs_key(self, mock_flavor_extra_specs):
|
||||
invalid_keys = ("key1/", "<key>", "$$akey$", "!akey", "")
|
||||
mock_flavor_extra_specs.side_effects = return_create_flavor_extra_specs
|
||||
|
||||
for key in invalid_keys:
|
||||
body = {"extra_specs": {key: "value1"}}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/flavors/1/os-extra_specs',
|
||||
use_admin_context=True)
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, 1, body)
|
||||
|
||||
@mock.patch('nova.db.flavor_extra_specs_update_or_create')
|
||||
def test_create_valid_specs_key(self, mock_flavor_extra_specs):
|
||||
valid_keys = ("key1", "month.price", "I_am-a Key", "finance:g2")
|
||||
mock_flavor_extra_specs.side_effects = return_create_flavor_extra_specs
|
||||
|
||||
for key in valid_keys:
|
||||
body = {"extra_specs": {key: "value1"}}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/flavors/1/os-extra_specs',
|
||||
use_admin_context=True)
|
||||
res_dict = self.controller.create(req, 1, body)
|
||||
self.assertEqual('value1', res_dict['extra_specs'][key])
|
||||
|
||||
def test_update_item(self):
|
||||
self.stubs.Set(nova.db,
|
||||
'flavor_extra_specs_update_or_create',
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import webob
|
||||
|
||||
from nova.api.openstack.compute.plugins.v3 import flavors_extraspecs
|
||||
@ -176,6 +177,33 @@ class FlavorsExtraSpecsTest(test.TestCase):
|
||||
self.assertRaises(webob.exc.HTTPConflict, self.controller.create,
|
||||
req, 1, body)
|
||||
|
||||
@mock.patch('nova.db.flavor_extra_specs_update_or_create')
|
||||
def test_create_invalid_specs_key(self, mock_flavor_extra_specs):
|
||||
invalid_keys = ("key1/", "<key>", "$$akey$", "!akey", "")
|
||||
mock_flavor_extra_specs.side_effects = return_create_flavor_extra_specs
|
||||
|
||||
for key in invalid_keys:
|
||||
body = {"extra_specs": {key: "value1"}}
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v3/flavors/1/extra-specs',
|
||||
use_admin_context=True)
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||
req, 1, body)
|
||||
|
||||
@mock.patch('nova.db.flavor_extra_specs_update_or_create')
|
||||
def test_create_valid_specs_key(self, mock_flavor_extra_specs):
|
||||
valid_keys = ("key1", "month.price", "I_am-a Key", "finance:g2")
|
||||
mock_flavor_extra_specs.side_effects = return_create_flavor_extra_specs
|
||||
|
||||
for key in valid_keys:
|
||||
body = {"extra_specs": {key: "value1"}}
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v3/flavors/1/extra-specs',
|
||||
use_admin_context=True)
|
||||
res_dict = self.controller.create(req, 1, body)
|
||||
self.assertEqual('value1', res_dict['extra_specs'][key])
|
||||
self.assertEqual(self.controller.create.wsgi_code, 201)
|
||||
|
||||
def test_update_item(self):
|
||||
self.stubs.Set(nova.db,
|
||||
'flavor_extra_specs_update_or_create',
|
||||
|
Loading…
x
Reference in New Issue
Block a user