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)
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)]