aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick/tests/unit/orchestrator/test_heat.py
diff options
context:
space:
mode:
authorRodolfo Alonso Hernandez <rodolfo.alonso.hernandez@intel.com>2017-12-04 16:24:13 +0000
committerRodolfo Alonso Hernandez <rodolfo.alonso.hernandez@intel.com>2018-02-09 15:44:32 +0000
commit35d2f095fa3948293e8f74e41b3fec39a05e7034 (patch)
treefa83d601b16c080a4e18643de48f295a01d710fc /yardstick/tests/unit/orchestrator/test_heat.py
parent36f0563490a4ee8f5b30eb7fe51a62d3b55c5b32 (diff)
Replace "python-heatclient" with "shade" client
Replaced "python-heatclient" with "shade" client. The "python-heatclient" library is removed from requirements file. "shade" client version 1.22.2 is the required one for OpenStack Pike release. shade is the recommended client to interact with OpenStack clouds [1] [1] https://github.com/openstack-infra/shade JIRA: YARDSTICK-880 Change-Id: Ibbdfc42a543d2d9ed4cf70d78de3de8cbecd0076 Signed-off-by: Rodolfo Alonso Hernandez <rodolfo.alonso.hernandez@intel.com>
Diffstat (limited to 'yardstick/tests/unit/orchestrator/test_heat.py')
-rw-r--r--yardstick/tests/unit/orchestrator/test_heat.py572
1 files changed, 172 insertions, 400 deletions
diff --git a/yardstick/tests/unit/orchestrator/test_heat.py b/yardstick/tests/unit/orchestrator/test_heat.py
index faf70cdbc..9164197b8 100644
--- a/yardstick/tests/unit/orchestrator/test_heat.py
+++ b/yardstick/tests/unit/orchestrator/test_heat.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
##############################################################################
# Copyright (c) 2017 Intel Corporation
#
@@ -9,62 +7,87 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-# Unittest for yardstick.benchmark.orchestrator.heat
-from contextlib import contextmanager
-from itertools import count
-from tempfile import NamedTemporaryFile
-import time
-import uuid
+import tempfile
import mock
+from oslo_serialization import jsonutils
+from oslo_utils import uuidutils
+import shade
import unittest
from yardstick.benchmark.contexts import node
+from yardstick.common import exceptions
from yardstick.orchestrator import heat
-TARGET_MODULE = 'yardstick.orchestrator.heat'
-
-
-def mock_patch_target_module(inner_import):
- return mock.patch('.'.join([TARGET_MODULE, inner_import]))
-
-
-@contextmanager
-def timer():
- start = time.time()
- data = {'start': start}
- try:
- yield data
- finally:
- data['end'] = end = time.time()
- data['delta'] = end - start
-
-
-def index_value_iter(index, index_value, base_value=None):
- for current_index in count():
- if current_index == index:
- yield index_value
- else:
- yield base_value
-
+class FakeStack(object):
-def get_error_message(error):
- try:
- # py2
- return error.message
- except AttributeError:
- # py3
- return next((arg for arg in error.args if isinstance(arg, str)), None)
+ def __init__(self, outputs=None, status=None, id=None):
+ self.outputs = outputs
+ self.status = status
+ self.id = id
-class HeatContextTestCase(unittest.TestCase):
+class HeatStackTestCase(unittest.TestCase):
- def test_get_short_key_uuid(self):
- u = uuid.uuid4()
- k = heat.get_short_key_uuid(u)
- self.assertEqual(heat.HEAT_KEY_UUID_LENGTH, len(k))
- self.assertIn(k, str(u))
+ def setUp(self):
+ self.stack_name = 'STACK NAME'
+ with mock.patch.object(shade, 'openstack_cloud'):
+ self.heatstack = heat.HeatStack(self.stack_name)
+ self._mock_stack_create = mock.patch.object(self.heatstack._cloud,
+ 'create_stack')
+ self.mock_stack_create = self._mock_stack_create.start()
+ self._mock_stack_delete = mock.patch.object(self.heatstack._cloud,
+ 'delete_stack')
+ self.mock_stack_delete = self._mock_stack_delete.start()
+
+ self.addCleanup(self._cleanup)
+
+ def _cleanup(self):
+ self._mock_stack_create.stop()
+ self._mock_stack_delete.stop()
+ heat._DEPLOYED_STACKS = {}
+
+ def test_create(self):
+ template = {'tkey': 'tval'}
+ heat_parameters = {'pkey': 'pval'}
+ outputs = [{'output_key': 'okey', 'output_value': 'oval'}]
+ id = uuidutils.generate_uuid()
+ self.mock_stack_create.return_value = FakeStack(
+ outputs=outputs, status=mock.Mock(), id=id)
+ mock_tfile = mock.Mock()
+ with mock.patch.object(tempfile._TemporaryFileWrapper, '__enter__',
+ return_value=mock_tfile):
+ self.heatstack.create(template, heat_parameters, True, 100)
+ mock_tfile.write.assert_called_once_with(jsonutils.dumps(template))
+ mock_tfile.close.assert_called_once()
+
+ self.mock_stack_create.assert_called_once_with(
+ self.stack_name, template_file=mock_tfile.name, wait=True,
+ timeout=100, pkey='pval')
+ self.assertEqual({'okey': 'oval'}, self.heatstack.outputs)
+ self.assertEqual(heat._DEPLOYED_STACKS[id], self.heatstack._stack)
+
+ def test_stacks_exist(self):
+ self.assertEqual(0, self.heatstack.stacks_exist())
+ heat._DEPLOYED_STACKS['id'] = 'stack'
+ self.assertEqual(1, self.heatstack.stacks_exist())
+
+ def test_delete_not_uuid(self):
+ self.assertIsNone(self.heatstack.delete())
+
+ def test_delete_existing_uuid(self):
+ id = uuidutils.generate_uuid()
+ self.heatstack._stack = FakeStack(
+ outputs=mock.Mock(), status=mock.Mock(), id=id)
+ heat._DEPLOYED_STACKS[id] = self.heatstack._stack
+ delete_return = mock.Mock()
+ self.mock_stack_delete.return_value = delete_return
+
+ ret = self.heatstack.delete(wait=True)
+ self.assertEqual(delete_return, ret)
+ self.assertFalse(heat._DEPLOYED_STACKS)
+ self.mock_stack_delete.assert_called_once_with(id, wait=True)
class HeatTemplateTestCase(unittest.TestCase):
@@ -75,63 +98,53 @@ class HeatTemplateTestCase(unittest.TestCase):
def test_add_tenant_network(self):
self.template.add_network('some-network')
- self.assertEqual(
- self.template.resources['some-network']['type'],
- 'OS::Neutron::Net')
+ self.assertEqual('OS::Neutron::Net',
+ self.template.resources['some-network']['type'])
def test_add_provider_network(self):
self.template.add_network('some-network', 'physnet2', 'sriov')
- self.assertEqual(
- self.template.resources['some-network']['type'],
- 'OS::Neutron::ProviderNet')
- self.assertEqual(
- self.template.resources['some-network']['properties']['physical_network'],
- 'physnet2')
+ self.assertEqual(self.template.resources['some-network']['type'],
+ 'OS::Neutron::ProviderNet')
+ self.assertEqual(self.template.resources['some-network'][
+ 'properties']['physical_network'], 'physnet2')
def test_add_subnet(self):
netattrs = {'cidr': '10.0.0.0/24',
- 'provider': None, 'external_network': 'ext_net'}
- self.template.add_subnet(
- 'some-subnet', "some-network", netattrs['cidr'])
+ 'provider': None,
+ 'external_network': 'ext_net'}
+ self.template.add_subnet('some-subnet', "some-network",
+ netattrs['cidr'])
- self.assertEqual(
- self.template.resources['some-subnet']['type'],
- 'OS::Neutron::Subnet')
- self.assertEqual(
- self.template.resources['some-subnet']['properties']['cidr'],
- '10.0.0.0/24')
+ self.assertEqual(self.template.resources['some-subnet']['type'],
+ 'OS::Neutron::Subnet')
+ self.assertEqual(self.template.resources['some-subnet']['properties'][
+ 'cidr'], '10.0.0.0/24')
def test_add_router(self):
self.template.add_router('some-router', 'ext-net', 'some-subnet')
- self.assertEqual(
- self.template.resources['some-router']['type'],
- 'OS::Neutron::Router')
- self.assertIn(
- 'some-subnet',
- self.template.resources['some-router']['depends_on'])
+ self.assertEqual(self.template.resources['some-router']['type'],
+ 'OS::Neutron::Router')
+ self.assertIn('some-subnet',
+ self.template.resources['some-router']['depends_on'])
def test_add_router_interface(self):
- self.template.add_router_interface(
- 'some-router-if', 'some-router', 'some-subnet')
+ self.template.add_router_interface('some-router-if', 'some-router',
+ 'some-subnet')
- self.assertEqual(
- self.template.resources['some-router-if']['type'],
- 'OS::Neutron::RouterInterface')
- self.assertIn(
- 'some-subnet',
- self.template.resources['some-router-if']['depends_on'])
+ self.assertEqual(self.template.resources['some-router-if']['type'],
+ 'OS::Neutron::RouterInterface')
+ self.assertIn('some-subnet',
+ self.template.resources['some-router-if']['depends_on'])
def test_add_servergroup(self):
self.template.add_servergroup('some-server-group', 'anti-affinity')
- self.assertEqual(
- self.template.resources['some-server-group']['type'],
- 'OS::Nova::ServerGroup')
- self.assertEqual(
- self.template.resources['some-server-group']['properties']['policies'],
- ['anti-affinity'])
+ self.assertEqual(self.template.resources['some-server-group']['type'],
+ 'OS::Nova::ServerGroup')
+ self.assertEqual(self.template.resources['some-server-group'][
+ 'properties']['policies'], ['anti-affinity'])
def test__add_resources_to_template_raw(self):
test_context = node.NodeContext()
@@ -142,16 +155,13 @@ class HeatTemplateTestCase(unittest.TestCase):
test_context.keypair_name = "foo-key"
test_context.secgroup_name = "foo-secgroup"
test_context.key_uuid = "2f2e4997-0a8e-4eb7-9fa4-f3f8fbbc393b"
- heat_object = heat.HeatObject()
- heat_stack = heat.HeatStack("tmpStack")
- self.assertTrue(heat_stack.stacks_exist())
-
- test_context.tmpfile = NamedTemporaryFile(delete=True, mode='w+t')
+ test_context.tmpfile = tempfile.NamedTemporaryFile(
+ delete=True, mode='w+t')
test_context.tmpfile.write("heat_template_version: 2015-04-30")
test_context.tmpfile.flush()
test_context.tmpfile.seek(0)
- heat_template = heat.HeatTemplate(heat_object)
+ heat_template = heat.HeatTemplate('template name')
heat_template.resources = {}
heat_template.add_network("network1")
@@ -163,324 +173,86 @@ class HeatTemplateTestCase(unittest.TestCase):
heat_template.add_router("router1", "gw1", "subnet1")
heat_template.add_router_interface("router_if1", "router1", "subnet1")
heat_template.add_port("port1", "network1", "subnet1", "normal")
- heat_template.add_port(
- "port2",
- "network2",
- "subnet2",
- "normal",
- sec_group_id="sec_group1",
- provider="not-sriov")
- heat_template.add_port(
- "port3",
- "network2",
- "subnet2",
- "normal",
- sec_group_id="sec_group1",
- provider="sriov")
- heat_template.add_floating_ip(
- "floating_ip1", "network1", "port1", "router_if1")
- heat_template.add_floating_ip(
- "floating_ip2", "network2", "port2", "router_if2", "foo-secgroup")
- heat_template.add_floating_ip_association(
- "floating_ip1_association", "floating_ip1", "port1")
+ heat_template.add_port("port2", "network2", "subnet2", "normal",
+ sec_group_id="sec_group1", provider="not-sriov")
+ heat_template.add_port("port3", "network2", "subnet2", "normal",
+ sec_group_id="sec_group1", provider="sriov")
+ heat_template.add_floating_ip("floating_ip1", "network1", "port1",
+ "router_if1")
+ heat_template.add_floating_ip("floating_ip2", "network2", "port2",
+ "router_if2", "foo-secgroup")
+ heat_template.add_floating_ip_association("floating_ip1_association",
+ "floating_ip1", "port1")
heat_template.add_servergroup("server_grp2", "affinity")
heat_template.add_servergroup("server_grp3", "anti-affinity")
heat_template.add_security_group("security_group")
+ heat_template.add_server(name="server1", image="image1",
+ flavor="flavor1", flavors=[])
+ heat_template.add_server_group(name="servergroup",
+ policies=["policy1", "policy2"])
+ heat_template.add_server_group(name="servergroup",
+ policies="policy1")
heat_template.add_server(
- name="server1", image="image1", flavor="flavor1", flavors=[])
- heat_template.add_server_group(
- name="servergroup", policies=["policy1", "policy2"])
- heat_template.add_server_group(name="servergroup", policies="policy1")
- heat_template.add_server(
- name="server2",
- image="image1",
- flavor="flavor1",
- flavors=[],
- ports=[
- "port1",
- "port2"],
- networks=[
- "network1",
- "network2"],
- scheduler_hints="hints1",
- user="user1",
- key_name="foo-key",
- user_data="user",
- metadata={
- "cat": 1,
- "doc": 2},
- additional_properties={
- "prop1": 1,
- "prop2": 2})
+ name="server2", image="image1", flavor="flavor1", flavors=[],
+ ports=["port1", "port2"], networks=["network1", "network2"],
+ scheduler_hints="hints1", user="user1", key_name="foo-key",
+ user_data="user", metadata={"cat": 1, "doc": 2},
+ additional_properties={"prop1": 1, "prop2": 2})
heat_template.add_server(
- name="server2",
- image="image1",
- flavor="flavor1",
- flavors=[
- "flavor1",
- "flavor2"],
- ports=[
- "port1",
- "port2"],
- networks=[
- "network1",
- "network2"],
- scheduler_hints="hints1",
- user="user1",
- key_name="foo-key",
- user_data="user",
- metadata={
- "cat": 1,
- "doc": 2},
- additional_properties={
- "prop1": 1,
- "prop2": 2})
+ name="server2", image="image1", flavor="flavor1",
+ flavors=["flavor1", "flavor2"], ports=["port1", "port2"],
+ networks=["network1", "network2"], scheduler_hints="hints1",
+ user="user1", key_name="foo-key", user_data="user",
+ metadata={"cat": 1, "doc": 2},
+ additional_properties={"prop1": 1, "prop2": 2})
heat_template.add_server(
- name="server2",
- image="image1",
- flavor="flavor1",
- flavors=[
- "flavor3",
- "flavor4"],
- ports=[
- "port1",
- "port2"],
- networks=[
- "network1",
- "network2"],
- scheduler_hints="hints1",
- user="user1",
- key_name="foo-key",
- user_data="user",
- metadata={
- "cat": 1,
- "doc": 2},
- additional_properties={
- "prop1": 1,
- "prop2": 2})
- heat_template.add_flavor(
- name="flavor1",
- vcpus=1,
- ram=2048,
- disk=1,
- extra_specs={
- "cat": 1,
- "dog": 2})
+ name="server2", image="image1", flavor="flavor1",
+ flavors=["flavor3", "flavor4"], ports=["port1", "port2"],
+ networks=["network1", "network2"], scheduler_hints="hints1",
+ user="user1", key_name="foo-key", user_data="user",
+ metadata={"cat": 1, "doc": 2},
+ additional_properties={"prop1": 1, "prop2": 2})
+ heat_template.add_flavor(name="flavor1", vcpus=1, ram=2048, disk=1,
+ extra_specs={"cat": 1, "dog": 2})
heat_template.add_flavor(name=None, vcpus=1, ram=2048)
heat_template.add_server(
- name="server1",
- image="image1",
- flavor="flavor1",
- flavors=[],
- ports=[
- "port1",
- "port2"],
- networks=[
- "network1",
- "network2"],
- scheduler_hints="hints1",
- user="user1",
- key_name="foo-key",
- user_data="user",
- metadata={
- "cat": 1,
- "doc": 2},
- additional_properties={
- "prop1": 1,
- "prop2": 2})
+ name="server1", image="image1", flavor="flavor1", flavors=[],
+ ports=["port1", "port2"], networks=["network1", "network2"],
+ scheduler_hints="hints1", user="user1", key_name="foo-key",
+ user_data="user", metadata={"cat": 1, "doc": 2},
+ additional_properties={"prop1": 1, "prop2": 2})
heat_template.add_network("network1")
heat_template.add_flavor("test")
- self.assertEqual(
- heat_template.resources['test']['type'], 'OS::Nova::Flavor')
-
- @mock_patch_target_module('op_utils')
- @mock_patch_target_module('heatclient')
- def test_create_negative(self, mock_heat_client_class, mock_op_utils):
- self.template.HEAT_WAIT_LOOP_INTERVAL = 0
- mock_heat_client = mock_heat_client_class() # get the constructed mock
-
- # populate attributes of the constructed mock
- mock_heat_client.stacks.get().stack_status_reason = 'the reason'
-
- expected_status_calls = 0
- expected_constructor_calls = 1 # above, to get the instance
- expected_create_calls = 0
- expected_op_utils_usage = 0
-
- with mock.patch.object(self.template, 'status', return_value=None) as mock_status:
- # block with timeout hit
- timeout = 0
- with self.assertRaises(RuntimeError) as raised, timer():
- self.template.create(block=True, timeout=timeout)
-
- # ensure op_utils was used
- expected_op_utils_usage += 1
- self.assertEqual(
- mock_op_utils.get_session.call_count, expected_op_utils_usage)
- self.assertEqual(
- mock_op_utils.get_endpoint.call_count, expected_op_utils_usage)
- self.assertEqual(
- mock_op_utils.get_heat_api_version.call_count,
- expected_op_utils_usage)
-
- # ensure the constructor and instance were used
- self.assertEqual(mock_heat_client_class.call_count,
- expected_constructor_calls)
- self.assertEqual(
- mock_heat_client.stacks.create.call_count,
- expected_create_calls)
-
- # ensure that the status was used
- self.assertGreater(mock_status.call_count, expected_status_calls)
- expected_status_calls = mock_status.call_count # synchronize the value
-
- # ensure the expected exception was raised
- error_message = get_error_message(raised.exception)
- self.assertIn('timeout', error_message)
- self.assertNotIn('the reason', error_message)
-
- # block with create failed
- timeout = 10
- mock_status.side_effect = iter([None, None, u'CREATE_FAILED'])
- with self.assertRaises(RuntimeError) as raised, timer():
- self.template.create(block=True, timeout=timeout)
-
- # ensure the existing heat_client was used and op_utils was used
- # again
- self.assertEqual(
- mock_op_utils.get_session.call_count, expected_op_utils_usage)
- self.assertEqual(
- mock_op_utils.get_endpoint.call_count, expected_op_utils_usage)
- self.assertEqual(
- mock_op_utils.get_heat_api_version.call_count,
- expected_op_utils_usage)
-
- # ensure the constructor was not used but the instance was used
- self.assertEqual(mock_heat_client_class.call_count,
- expected_constructor_calls)
- self.assertEqual(
- mock_heat_client.stacks.create.call_count,
- expected_create_calls)
-
- # ensure that the status was used three times
- expected_status_calls += 3
- self.assertEqual(mock_status.call_count, expected_status_calls)
-
- # NOTE(elfoley): This needs to be split into multiple tests.
- # The lines where the template is reset should serve as a guide for where
- # to split.
- @mock_patch_target_module('op_utils')
- @mock_patch_target_module('heatclient')
- def test_create(self, mock_heat_client_class, mock_op_utils):
- self.template.HEAT_WAIT_LOOP_INTERVAL = 0.2
- mock_heat_client = mock_heat_client_class()
-
- # populate attributes of the constructed mock
- mock_heat_client.stacks.get().outputs = [
- {'output_key': 'key1', 'output_value': 'value1'},
- {'output_key': 'key2', 'output_value': 'value2'},
- {'output_key': 'key3', 'output_value': 'value3'},
- ]
- expected_outputs = { # pylint: disable=unused-variable
- 'key1': 'value1',
- 'key2': 'value2',
- 'key3': 'value3',
- }
-
- expected_status_calls = 0
- expected_constructor_calls = 1 # above, to get the instance
- expected_create_calls = 0
- expected_op_utils_usage = 0
-
- with mock.patch.object(self.template, 'status') as mock_status:
- self.template.name = 'no block test'
- mock_status.return_value = None
-
- # no block
- self.assertIsInstance(self.template.create(
- block=False, timeout=2), heat.HeatStack)
-
- # ensure op_utils was used
- expected_op_utils_usage += 1
- self.assertEqual(
- mock_op_utils.get_session.call_count, expected_op_utils_usage)
- self.assertEqual(
- mock_op_utils.get_endpoint.call_count, expected_op_utils_usage)
- self.assertEqual(
- mock_op_utils.get_heat_api_version.call_count,
- expected_op_utils_usage)
-
- # ensure the constructor and instance were used
- self.assertEqual(mock_heat_client_class.call_count,
- expected_constructor_calls)
- self.assertEqual(
- mock_heat_client.stacks.create.call_count,
- expected_create_calls)
-
- # ensure that the status was not used
- self.assertEqual(mock_status.call_count, expected_status_calls)
-
- # ensure no outputs because this requires blocking
- self.assertEqual(self.template.outputs, {})
-
- # block with immediate complete
- self.template.name = 'block, immediate complete test'
-
- mock_status.return_value = self.template.HEAT_CREATE_COMPLETE_STATUS
- self.assertIsInstance(self.template.create(
- block=True, timeout=2), heat.HeatStack)
-
- # ensure existing instance was re-used and op_utils was not used
- self.assertEqual(mock_heat_client_class.call_count,
- expected_constructor_calls)
- self.assertEqual(
- mock_heat_client.stacks.create.call_count,
- expected_create_calls)
-
- # ensure status was checked once
- expected_status_calls += 1
- self.assertEqual(mock_status.call_count, expected_status_calls)
-
- # reset template outputs
- self.template.outputs = None
-
- # block with delayed complete
- self.template.name = 'block, delayed complete test'
-
- success_index = 2
- mock_status.side_effect = index_value_iter(
- success_index, self.template.HEAT_CREATE_COMPLETE_STATUS)
- self.assertIsInstance(self.template.create(
- block=True, timeout=2), heat.HeatStack)
-
- # ensure existing instance was re-used and op_utils was not used
- self.assertEqual(mock_heat_client_class.call_count,
- expected_constructor_calls)
- self.assertEqual(
- mock_heat_client.stacks.create.call_count,
- expected_create_calls)
-
- # ensure status was checked three more times
- expected_status_calls += 1 + success_index
- self.assertEqual(mock_status.call_count, expected_status_calls)
-
-
-class HeatStackTestCase(unittest.TestCase):
-
- def test_delete_calls__delete_multiple_times(self):
- stack = heat.HeatStack('test')
- stack.uuid = 1
- with mock.patch.object(stack, "_delete") as delete_mock:
- stack.delete()
- # call once and then call again if uuid is not none
- self.assertGreater(delete_mock.call_count, 1)
-
- def test_delete_all_calls_delete(self):
- # we must patch the object before we create an instance
- # so we can override delete() in all the instances
- with mock.patch.object(heat.HeatStack, "delete") as delete_mock:
- stack = heat.HeatStack('test')
- stack.uuid = 1
- stack.delete_all()
- self.assertGreater(delete_mock.call_count, 0)
+ self.assertEqual(heat_template.resources['test']['type'],
+ 'OS::Nova::Flavor')
+
+ def test_create_not_block(self):
+ heat_stack = mock.Mock()
+ with mock.patch.object(heat, 'HeatStack', return_value=heat_stack):
+ ret = self.template.create(block=False)
+ heat_stack.create.assert_called_once_with(
+ self.template._template, self.template.heat_parameters, False,
+ 3600)
+ self.assertEqual(heat_stack, ret)
+
+ def test_create_block(self):
+ heat_stack = mock.Mock()
+ heat_stack.status = self.template.HEAT_STATUS_COMPLETE
+ with mock.patch.object(heat, 'HeatStack', return_value=heat_stack):
+ ret = self.template.create(block=False)
+ heat_stack.create.assert_called_once_with(
+ self.template._template, self.template.heat_parameters, False,
+ 3600)
+ self.assertEqual(heat_stack, ret)
+
+
+ def test_create_block_status_no_complete(self):
+ heat_stack = mock.Mock()
+ heat_stack.status = 'other status'
+ with mock.patch.object(heat, 'HeatStack', return_value=heat_stack):
+ self.assertRaises(exceptions.HeatTemplateError,
+ self.template.create, block=True)
+ heat_stack.create.assert_called_once_with(
+ self.template._template, self.template.heat_parameters, True,
+ 3600)