Merge "Add wait condition for heat templates"
This commit is contained in:
commit
e42969b18a
@ -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]
|
||||||
|
@ -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}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user