]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Limit maximum size of all templates
authorClint Byrum <clint@fewbar.com>
Wed, 21 Aug 2013 20:24:17 +0000 (13:24 -0700)
committerClint Byrum <clint@fewbar.com>
Thu, 22 Aug 2013 15:26:13 +0000 (08:26 -0700)
Templates of an extremely large size can eat up tons of CPU time,
memory and storage. By refusing to parse any template over a certain
size, we can prevent users from abusing the service.

Fixes bug #1214234

Change-Id: I2f731c8e2fc9e1f497199e310de81fa48c9582af

etc/heat/heat.conf.sample
heat/common/config.py
heat/common/exception.py
heat/common/template_format.py
heat/tests/test_template_format.py

index 8a31cd2074b863d67b088fd53a807b723966e5d8..3f6e29ea81aeb1830dddc17fce138c4cc3f41b55 100644 (file)
@@ -70,6 +70,9 @@
 # Keystone role for heat template-defined users (string value)
 #heat_stack_user_role=heat_stack_user
 
+# Maximum raw byte size of any template. (integer value)
+#max_template_size=524288
+
 
 #
 # Options defined in heat.common.crypt
index 8feeacb30d1e6a2be0a6b74285a5307f696545e9..6f584fc6687eeb235216c42356a3b2d50ac9d486 100644 (file)
@@ -81,7 +81,10 @@ service_opts = [
                help='Instance connection to cfn/cw API validate certs if ssl'),
     cfg.StrOpt('heat_stack_user_role',
                default="heat_stack_user",
-               help='Keystone role for heat template-defined users')]
+               help='Keystone role for heat template-defined users'),
+    cfg.IntOpt('max_template_size',
+               default=524288,
+               help='Maximum raw byte size of any template.')]
 
 db_opts = [
     cfg.StrOpt('sql_connection',
index fe3c78b42b5ea313dfbf05af7478d92022e9afdf..9645a05d39b600f35b25c4ef9adedac6e55479a3 100644 (file)
@@ -297,3 +297,7 @@ class HTTPExceptionDisguise(Exception):
     def __init__(self, exception):
         self.exc = exception
         self.tb = sys.exc_info()[2]
+
+
+class TemplateTooBig(OpenstackException):
+    message = _('Template exceeds maximum allowed size.')
index d6bd8e814e8847307a8464d7c520de0b7609182c..a4064edf355f1fd85cfa5544b7f60e02cf139193 100644 (file)
@@ -17,6 +17,12 @@ import re
 import yaml
 import json
 
+from oslo.config import cfg
+
+from heat.common import exception
+
+cfg.CONF.import_opt('max_template_size', 'heat.common.config')
+
 HEAT_VERSIONS = (u'2012-12-12',)
 CFN_VERSIONS = (u'2010-09-09',)
 
@@ -43,6 +49,8 @@ def parse(tmpl_str, add_template_sections=True):
     This includes determination of whether the string is using the
     JSON or YAML format.
     '''
+    if len(tmpl_str) > cfg.CONF.max_template_size:
+        raise exception.TemplateTooBig()
     if tmpl_str.startswith('{'):
         tpl = json.loads(tmpl_str)
     else:
index 83843a1fd2c66954be5675a773c8f4c1bd3403aa..da98752f4127009e0fc574d53bbc82e0645028ad 100644 (file)
 
 from testtools import skipIf
 import os
+import yaml
 
 from heat.engine import clients
+from heat.common import config
+from heat.common import exception
 from heat.common import template_format
 from heat.tests.common import HeatTestCase
 from heat.tests import utils
@@ -89,6 +92,15 @@ Outputs: {}
         tpl2 = template_format.parse(yaml2)
         self.assertEqual(tpl1, tpl2)
 
+    def test_long_yaml(self):
+        template = {'HeatTemplateVersion': '2012-12-12'}
+        template['Resources'] = ['a'] * (config.cfg.CONF.max_template_size / 3)
+        limit = config.cfg.CONF.max_template_size
+        long_yaml = yaml.safe_dump(template)
+        self.assertTrue(len(long_yaml) > limit)
+        self.assertRaises(exception.TemplateTooBig, template_format.parse,
+                          long_yaml)
+
 
 class YamlEnvironmentTest(HeatTestCase):