summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Still <mikal@stillhq.com>2012-08-11 20:51:27 +1000
committerMichael Still <mikal@stillhq.com>2012-08-14 09:56:58 +1000
commit4d350dc82ecfe1d272bfbd43445a78c69a32fc90 (patch)
treeec33ab174447f7861522410b4e486fc35588dd64
parent4d9cca956c7df53e0ca47e88b01ea34e541d1a3e (diff)
downloadnova-4d350dc82ecfe1d272bfbd43445a78c69a32fc90.tar.gz
nova-4d350dc82ecfe1d272bfbd43445a78c69a32fc90.tar.xz
nova-4d350dc82ecfe1d272bfbd43445a78c69a32fc90.zip
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
-rw-r--r--nova/compute/api.py15
-rw-r--r--nova/exception.py10
-rw-r--r--nova/tests/compute/test_compute.py49
3 files changed, 74 insertions, 0 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index cd3ffdf56..971540de1 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -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)
diff --git a/nova/exception.py b/nova/exception.py
index 315147764..de8982488 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -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.
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index a625397ea..10cc325e5 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -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)]