Simple checks for instance user data.
Check that instance user data wont be truncated, and that it is valid base64 data. This partially resolves bug 1035055. I don't love the hard coded maximum length, but I haven't worked out how to get sqlalchemy to tell me the maximum size of the data type. Change-Id: I045d6b4481563d01cae371cf61a91781cfed6f4b
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
"""Handles all requests relating to compute resources (e.g. guest VMs,
|
||||
networking and storage of VMs, and compute hosts on which they run)."""
|
||||
|
||||
import base64
|
||||
import functools
|
||||
import re
|
||||
import string
|
||||
@@ -58,6 +59,7 @@ LOG = logging.getLogger(__name__)
|
||||
FLAGS = flags.FLAGS
|
||||
flags.DECLARE('consoleauth_topic', 'nova.consoleauth')
|
||||
|
||||
MAX_USERDATA_SIZE = 65535
|
||||
QUOTAS = quota.QUOTAS
|
||||
|
||||
|
||||
@@ -473,6 +475,19 @@ class API(base.Base):
|
||||
'architecture': architecture,
|
||||
'progress': 0}
|
||||
|
||||
if user_data:
|
||||
l = len(user_data)
|
||||
if l > MAX_USERDATA_SIZE:
|
||||
# NOTE(mikal): user_data is stored in a text column, and the
|
||||
# database might silently truncate if its over length.
|
||||
raise exception.InstanceUserDataTooLarge(
|
||||
length=l, maxsize=MAX_USERDATA_SIZE)
|
||||
|
||||
try:
|
||||
base64.decodestring(user_data)
|
||||
except base64.binascii.Error:
|
||||
raise exception.InstanceUserDataMalformed()
|
||||
|
||||
options_from_image = self._inherit_properties_from_image(
|
||||
image, auto_disk_config)
|
||||
|
||||
|
||||
@@ -1155,6 +1155,16 @@ class ConfigDriveUnknownFormat(NovaException):
|
||||
"iso9660 or vfat.")
|
||||
|
||||
|
||||
class InstanceUserDataTooLarge(NovaException):
|
||||
message = _("User data too large. User data must be no larger than "
|
||||
"%(maxsize)s bytes once base64 encoded. Your data is "
|
||||
"%(length)d bytes")
|
||||
|
||||
|
||||
class InstanceUserDataMalformed(NovaException):
|
||||
message = _("User data needs to be valid base 64.")
|
||||
|
||||
|
||||
def get_context_from_function_and_args(function, args, kwargs):
|
||||
"""Find an arg of type RequestContext and return it.
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# under the License.
|
||||
"""Tests for compute service"""
|
||||
|
||||
import base64
|
||||
import copy
|
||||
import datetime
|
||||
import functools
|
||||
@@ -2364,6 +2365,54 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
self.assertEqual(pre_build_len,
|
||||
len(db.instance_get_all(context.get_admin_context())))
|
||||
|
||||
def test_create_with_large_user_data(self):
|
||||
"""Test an instance type with too much user data."""
|
||||
|
||||
inst_type = instance_types.get_default_instance_type()
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['min_ram'] = 2
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
|
||||
self.assertRaises(exception.InstanceUserDataTooLarge,
|
||||
self.compute_api.create, self.context, inst_type, None,
|
||||
user_data=('1' * 65536))
|
||||
|
||||
def test_create_with_malformed_user_data(self):
|
||||
"""Test an instance type with malformed user data."""
|
||||
|
||||
inst_type = instance_types.get_default_instance_type()
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['min_ram'] = 2
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
|
||||
self.assertRaises(exception.InstanceUserDataMalformed,
|
||||
self.compute_api.create, self.context, inst_type, None,
|
||||
user_data='banana')
|
||||
|
||||
def test_create_with_base64_user_data(self):
|
||||
"""Test an instance type with ok much user data."""
|
||||
|
||||
inst_type = instance_types.get_default_instance_type()
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['min_ram'] = 2
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
|
||||
# NOTE(mikal): a string of length 48510 encodes to 65532 characters of
|
||||
# base64
|
||||
(refs, resv_id) = self.compute_api.create(
|
||||
self.context, inst_type, None,
|
||||
user_data=base64.encodestring('1' * 48510))
|
||||
db.instance_destroy(self.context, refs[0]['uuid'])
|
||||
|
||||
def test_default_hostname_generator(self):
|
||||
fake_uuids = [str(utils.gen_uuid()) for x in xrange(4)]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user