Merge "Make LoadBalancer nested stack template configurable"

This commit is contained in:
Jenkins 2014-01-06 01:23:13 +00:00 committed by Gerrit Code Review
commit b81f794c9e
3 changed files with 54 additions and 9 deletions

View File

@ -116,6 +116,15 @@
#cloud_backend=heat.engine.clients.OpenStackClients #cloud_backend=heat.engine.clients.OpenStackClients
#
# Options defined in heat.engine.resources.loadbalancer
#
# Custom template for the built-in loadbalancer nested stack
# (string value)
#loadbalancer_template=<None>
# #
# Options defined in heat.openstack.common.db.sqlalchemy.session # Options defined in heat.openstack.common.db.sqlalchemy.session
# #

View File

@ -12,7 +12,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import os
from oslo.config import cfg
from heat.common import exception
from heat.common import template_format from heat.common import template_format
from heat.engine import constraints from heat.engine import constraints
from heat.engine import properties from heat.engine import properties
@ -24,7 +28,7 @@ from heat.openstack.common.gettextutils import _
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
lb_template = r''' lb_template_default = r'''
{ {
"AWSTemplateFormatVersion": "2010-09-09", "AWSTemplateFormatVersion": "2010-09-09",
"Description": "Built in HAProxy server", "Description": "Built in HAProxy server",
@ -192,11 +196,15 @@ lb_template = r'''
''' '''
# # Allow user to provide alternative nested stack template to the above
# TODO(asalkeld) the above inline template _could_ be placed in an external loadbalancer_opts = [
# file at the moment this is because we will probably need to implement a cfg.StrOpt('loadbalancer_template',
# LoadBalancer based on keepalived as well (for for ssl support). default=None,
# help='Custom template for the built-in '
'loadbalancer nested stack')]
cfg.CONF.register_opts(loadbalancer_opts)
class LoadBalancer(stack_resource.StackResource): class LoadBalancer(stack_resource.StackResource):
PROPERTIES = ( PROPERTIES = (
@ -414,8 +422,18 @@ class LoadBalancer(stack_resource.StackResource):
return '%s%s%s%s\n' % (gl, frontend, backend, '\n'.join(servers)) return '%s%s%s%s\n' % (gl, frontend, backend, '\n'.join(servers))
def get_parsed_template(self):
if cfg.CONF.loadbalancer_template:
with open(cfg.CONF.loadbalancer_template) as templ_fd:
logger.info(_('Using custom loadbalancer template %s')
% cfg.CONF.loadbalancer_template)
contents = templ_fd.read()
else:
contents = lb_template_default
return template_format.parse(contents)
def handle_create(self): def handle_create(self):
templ = template_format.parse(lb_template) templ = self.get_parsed_template()
if self.properties[self.INSTANCES]: if self.properties[self.INSTANCES]:
md = templ['Resources']['LB_instance']['Metadata'] md = templ['Resources']['LB_instance']['Metadata']
@ -441,7 +459,7 @@ class LoadBalancer(stack_resource.StackResource):
rely on the cfn-hup to reconfigure HAProxy rely on the cfn-hup to reconfigure HAProxy
''' '''
if self.INSTANCES in prop_diff: if self.INSTANCES in prop_diff:
templ = template_format.parse(lb_template) templ = self.get_parsed_template()
cfg = self._haproxy_config(templ, prop_diff[self.INSTANCES]) cfg = self._haproxy_config(templ, prop_diff[self.INSTANCES])
md = self.nested()['LB_instance'].metadata md = self.nested()['LB_instance'].metadata
@ -461,6 +479,11 @@ class LoadBalancer(stack_resource.StackResource):
if res: if res:
return res return res
if cfg.CONF.loadbalancer_template and \
not os.access(cfg.CONF.loadbalancer_template, os.R_OK):
msg = _('Custom LoadBalancer template can not be found')
raise exception.StackValidationFailed(message=msg)
health_chk = self.properties[self.HEALTH_CHECK] health_chk = self.properties[self.HEALTH_CHECK]
if health_chk: if health_chk:
interval = float(health_chk[self.HEALTH_CHECK_INTERVAL]) interval = float(health_chk[self.HEALTH_CHECK_INTERVAL])

View File

@ -179,8 +179,9 @@ class LoadBalancerTest(HeatTestCase):
self.assertEqual('LoadBalancer', rsrc.FnGetRefId()) self.assertEqual('LoadBalancer', rsrc.FnGetRefId())
templ = template_format.parse(lb.lb_template) templ = template_format.parse(lb.lb_template_default)
ha_cfg = rsrc._haproxy_config(templ, rsrc.properties['Instances']) ha_cfg = rsrc._haproxy_config(templ, rsrc.properties['Instances'])
self.assertRegexpMatches(ha_cfg, 'bind \*:80') self.assertRegexpMatches(ha_cfg, 'bind \*:80')
self.assertRegexpMatches(ha_cfg, 'server server1 1\.2\.3\.4:80 ' self.assertRegexpMatches(ha_cfg, 'server server1 1\.2\.3\.4:80 '
'check inter 30s fall 5 rise 3') 'check inter 30s fall 5 rise 3')
@ -228,3 +229,15 @@ class LoadBalancerTest(HeatTestCase):
msg = '%s: %r not found in %r' % (msg, msg = '%s: %r not found in %r' % (msg,
expected_regexp.pattern, text) expected_regexp.pattern, text)
raise self.failureException(msg) raise self.failureException(msg)
def test_loadbalancer_validate_badtemplate(self):
cfg.CONF.set_override('loadbalancer_template', '/a/noexist/x.y')
t = template_format.parse(lb_template)
s = utils.parse_stack(t)
s.store()
rsrc = lb.LoadBalancer('LoadBalancer',
t['Resources']['LoadBalancer'],
s)
self.assertRaises(exception.StackValidationFailed, rsrc.validate)