Merge "Add wait condition for heat templates"

This commit is contained in:
Jenkins 2015-09-23 00:05:04 +00:00 committed by Gerrit Code Review
commit e42969b18a
3 changed files with 104 additions and 8 deletions

View File

@ -227,6 +227,11 @@ NTP_ENABLED = Config(
'instances' 'instances'
) )
HEAT_WAIT_CONDITION_TIMEOUT = Config(
"Heat Wait Condition timeout", "general", "cluster", priority=1,
config_type="int", default_value=3600, is_optional=True,
description="The number of seconds to wait for the instance to boot")
def list_of_common_configs(): def list_of_common_configs():
return [NTP_ENABLED, NTP_URL] return [NTP_ENABLED, NTP_URL, HEAT_WAIT_CONDITION_TIMEOUT]

View File

@ -19,6 +19,7 @@ from oslo_log import log as logging
import six import six
import yaml import yaml
from sahara.plugins import provisioning as plugin_provisioning
from sahara.utils import general as g from sahara.utils import general as g
from sahara.utils.openstack import base as b from sahara.utils.openstack import base as b
from sahara.utils.openstack import heat as h from sahara.utils.openstack import heat as h
@ -29,6 +30,7 @@ CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
SSH_PORT = 22 SSH_PORT = 22
INSTANCE_RESOURCE_NAME = "inst"
def _get_inst_name(ng): def _get_inst_name(ng):
@ -89,6 +91,14 @@ def _get_volume_name(ng):
} }
def _get_wc_handle_name(inst_name):
return '%s-wc-handle' % inst_name
def _get_wc_waiter_name(inst_name):
return '%s-wc-waiter' % inst_name
class ClusterStack(object): class ClusterStack(object):
def __init__(self, cluster): def __init__(self, cluster):
self.cluster = cluster self.cluster = cluster
@ -204,8 +214,8 @@ class ClusterStack(object):
"resources": self._serialize_instance(ng), "resources": self._serialize_instance(ng),
"outputs": { "outputs": {
"instance": {"value": { "instance": {"value": {
"physical_id": {"get_resource": "inst"}, "physical_id": {"get_resource": INSTANCE_RESOURCE_NAME},
"name": {"get_attr": ["inst", "name"]} "name": {"get_attr": [INSTANCE_RESOURCE_NAME, "name"]}
}}} }}}
}) })
@ -266,6 +276,15 @@ class ClusterStack(object):
return rules return rules
@staticmethod
def _get_wait_condition_timeout(ng):
configs = ng.cluster.cluster_configs
timeout_cfg = plugin_provisioning.HEAT_WAIT_CONDITION_TIMEOUT
cfg_target = timeout_cfg.applicable_target
cfg_name = timeout_cfg.name
return int(configs.get(cfg_target,
{}).get(cfg_name, timeout_cfg.default_value))
def _serialize_instance(self, ng): def _serialize_instance(self, ng):
resources = {} resources = {}
properties = {} properties = {}
@ -297,7 +316,22 @@ class ClusterStack(object):
properties["key_name"] = self.cluster.user_keypair_id properties["key_name"] = self.cluster.user_keypair_id
gen_userdata_func = self.node_groups_extra[ng.id]['gen_userdata_func'] gen_userdata_func = self.node_groups_extra[ng.id]['gen_userdata_func']
userdata = gen_userdata_func(ng, inst_name) key_script = gen_userdata_func(ng, inst_name)
wait_condition_script = (
"wc_notify --data-binary '{\"status\": \"SUCCESS\"}'")
userdata = {
"str_replace": {
"template": "\n".join([key_script, wait_condition_script]),
"params": {
"wc_notify": {
"get_attr": [
_get_wc_handle_name(ng.name),
"curl_cli"
]
}
}
}
}
if ng.availability_zone: if ng.availability_zone:
properties["availability_zone"] = ng.availability_zone properties["availability_zone"] = ng.availability_zone
@ -313,7 +347,7 @@ class ClusterStack(object):
}) })
resources.update({ resources.update({
"inst": { INSTANCE_RESOURCE_NAME: {
"type": "OS::Nova::Server", "type": "OS::Nova::Server",
"properties": properties "properties": properties
} }
@ -322,6 +356,20 @@ class ClusterStack(object):
if ng.volumes_per_node > 0 and ng.volumes_size > 0: if ng.volumes_per_node > 0 and ng.volumes_size > 0:
resources.update(self._serialize_volume(ng)) resources.update(self._serialize_volume(ng))
resources.update(self._serialize_volume(ng))
resources.update({
_get_wc_handle_name(ng.name): {
"type": "OS::Heat::WaitConditionHandle"
},
_get_wc_waiter_name(ng.name): {
"type": "OS::Heat::WaitCondition",
"depends_on": INSTANCE_RESOURCE_NAME,
"properties": {
"timeout": self._get_wait_condition_timeout(ng),
"handle": {"get_resource": _get_wc_handle_name(ng.name)}
}
}
})
return resources return resources
def _serialize_port(self, port_name, fixed_net_id, security_groups): def _serialize_port(self, port_name, fixed_net_id, security_groups):
@ -363,7 +411,7 @@ class ClusterStack(object):
"type": "OS::Nova::FloatingIPAssociation", "type": "OS::Nova::FloatingIPAssociation",
"properties": { "properties": {
"floating_ip": {"get_resource": "floating_ip"}, "floating_ip": {"get_resource": "floating_ip"},
"server_id": {"get_resource": "inst"} "server_id": {"get_resource": INSTANCE_RESOURCE_NAME}
} }
} }
} }
@ -382,7 +430,8 @@ class ClusterStack(object):
"properties": { "properties": {
"volume_index": "%index%", "volume_index": "%index%",
"instance_index": {"get_param": "instance_index"}, "instance_index": {"get_param": "instance_index"},
"instance": {"get_resource": "inst"}} "instance": {"get_resource":
INSTANCE_RESOURCE_NAME}}
} }
} }
} }

View File

@ -21,7 +21,7 @@ from sahara.tests.unit import base
from sahara.tests.unit import testutils as tu from sahara.tests.unit import testutils as tu
class TestClusterTemplate(base.SaharaWithDbTestCase): class BaseTestClusterTemplate(base.SaharaWithDbTestCase):
"""Checks valid structure of Resources section in generated Heat templates. """Checks valid structure of Resources section in generated Heat templates.
1. It checks templates generation with different OpenStack 1. It checks templates generation with different OpenStack
@ -52,6 +52,8 @@ class TestClusterTemplate(base.SaharaWithDbTestCase):
default_image_id='1', image_id=None, default_image_id='1', image_id=None,
anti_affinity=anti_affinity) anti_affinity=anti_affinity)
class TestClusterTemplate(BaseTestClusterTemplate):
def _make_heat_template(self, cluster, ng1, ng2): def _make_heat_template(self, cluster, ng1, ng2):
heat_template = h.ClusterStack(cluster) heat_template = h.ClusterStack(cluster)
heat_template.add_node_group_extra(ng1['id'], 1, heat_template.add_node_group_extra(ng1['id'], 1,
@ -167,6 +169,46 @@ class TestClusterTemplate(base.SaharaWithDbTestCase):
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
class TestClusterTemplateWaitCondition(BaseTestClusterTemplate):
def _make_heat_template(self, cluster, ng1, ng2):
heat_template = h.ClusterStack(cluster)
heat_template.add_node_group_extra(ng1.id, 1,
get_ud_generator('line1\nline2'))
heat_template.add_node_group_extra(ng2.id, 1,
get_ud_generator('line2\nline3'))
return heat_template
def setUp(self):
super(TestClusterTemplateWaitCondition, self).setUp()
_ng1, _ng2 = self._make_node_groups("floating")
_cluster = self._make_cluster("private_net", _ng1, _ng2)
_ng1["cluster"] = _ng2["cluster"] = _cluster
self.ng1 = mock.Mock()
self.ng1.configure_mock(**_ng1)
self.ng2 = mock.Mock()
self.ng2.configure_mock(**_ng2)
self.cluster = mock.Mock()
self.cluster.configure_mock(**_cluster)
self.template = self._make_heat_template(self.cluster,
self.ng1, self.ng2)
def test_use_wait_condition(self):
instance = self.template._serialize_instance(self.ng1)
expected_wc_handle = {
"type": "OS::Heat::WaitConditionHandle"
}
expected_wc_waiter = {
"type": "OS::Heat::WaitCondition",
"depends_on": "inst",
"properties": {
"timeout": 3600,
"handle": {"get_resource": "master-wc-handle"}
}
}
self.assertEqual(expected_wc_handle, instance["master-wc-handle"])
self.assertEqual(expected_wc_waiter, instance["master-wc-waiter"])
def get_ud_generator(s): def get_ud_generator(s):
def generator(*args, **kwargs): def generator(*args, **kwargs):
return s return s