
Heat provides tagging fuctionality for stacks, now tagging is possible for stacks generated via murano also. To implement it, added new config parameter `stack_tags` with default value 'murano' and tagged heat stacks created during environment deployment with `stack_tags` parameter's value. Change-Id: Ib3f4027b78616c02cf3bbb210578df23d7e536d3 Implements: blueprint tag-murano-heat-stacks
266 lines
9.5 KiB
Python
266 lines
9.5 KiB
Python
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from heatclient.v1 import stacks
|
|
import mock
|
|
from oslo_config import cfg
|
|
|
|
from murano.dsl import constants
|
|
from murano.dsl import helpers
|
|
from murano.dsl import murano_class
|
|
from murano.dsl import object_store
|
|
from murano.engine import client_manager
|
|
from murano.engine import environment
|
|
from murano.engine.system import heat_stack
|
|
from murano.tests.unit import base
|
|
|
|
MOD_NAME = 'murano.engine.system.heat_stack'
|
|
CONF = cfg.CONF
|
|
|
|
|
|
class TestHeatStack(base.MuranoTestCase):
|
|
def setUp(self):
|
|
super(TestHeatStack, self).setUp()
|
|
self.mock_murano_class = mock.Mock(spec=murano_class.MuranoClass)
|
|
self.mock_murano_class.name = 'io.murano.system.HeatStack'
|
|
self.mock_murano_class.declared_parents = []
|
|
self.heat_client_mock = mock.MagicMock()
|
|
self.heat_client_mock.stacks = mock.MagicMock(spec=stacks.StackManager)
|
|
self.mock_object_store = mock.Mock(spec=object_store.ObjectStore)
|
|
self.environment_mock = mock.Mock(
|
|
spec=environment.Environment)
|
|
client_manager_mock = mock.Mock(spec=client_manager.ClientManager)
|
|
client_manager_mock.get_heat_client.return_value = \
|
|
self.heat_client_mock
|
|
self.environment_mock.clients = client_manager_mock
|
|
CONF.set_override('stack_tags', ['test-murano'], 'heat')
|
|
self.mock_tag = ','.join(CONF.heat.stack_tags)
|
|
|
|
@mock.patch(MOD_NAME + '.HeatStack._wait_state')
|
|
@mock.patch(MOD_NAME + '.HeatStack._get_status')
|
|
def test_push_adds_version(self, status_get, wait_st):
|
|
"""Assert that if heat_template_version is omitted, it's added."""
|
|
|
|
status_get.return_value = 'NOT_FOUND'
|
|
wait_st.return_value = {}
|
|
context = {constants.CTX_ENVIRONMENT: self.environment_mock}
|
|
|
|
with helpers.contextual(context):
|
|
hs = heat_stack.HeatStack(
|
|
'test-stack', 'Generated by TestHeatStack')
|
|
hs._template = {'resources': {'test': 1}}
|
|
hs._files = {}
|
|
hs._hot_environment = ''
|
|
hs._parameters = {}
|
|
hs._applied = False
|
|
hs.push()
|
|
|
|
with helpers.contextual(context):
|
|
hs = heat_stack.HeatStack(
|
|
'test-stack', 'Generated by TestHeatStack')
|
|
hs._template = {'resources': {'test': 1}}
|
|
hs._files = {}
|
|
hs._parameters = {}
|
|
hs._applied = False
|
|
hs.push()
|
|
|
|
expected_template = {
|
|
'heat_template_version': '2013-05-23',
|
|
'description': 'Generated by TestHeatStack',
|
|
'resources': {'test': 1}
|
|
}
|
|
self.heat_client_mock.stacks.create.assert_called_with(
|
|
stack_name='test-stack',
|
|
disable_rollback=True,
|
|
parameters={},
|
|
template=expected_template,
|
|
files={},
|
|
environment='',
|
|
tags=self.mock_tag
|
|
)
|
|
self.assertTrue(hs._applied)
|
|
|
|
@mock.patch(MOD_NAME + '.HeatStack._wait_state')
|
|
@mock.patch(MOD_NAME + '.HeatStack._get_status')
|
|
def test_description_is_optional(self, status_get, wait_st):
|
|
"""Assert that if heat_template_version is omitted, it's added."""
|
|
|
|
status_get.return_value = 'NOT_FOUND'
|
|
wait_st.return_value = {}
|
|
context = {constants.CTX_ENVIRONMENT: self.environment_mock}
|
|
|
|
with helpers.contextual(context):
|
|
hs = heat_stack.HeatStack('test-stack', None)
|
|
hs._template = {'resources': {'test': 1}}
|
|
hs._files = {}
|
|
hs._hot_environment = ''
|
|
hs._parameters = {}
|
|
hs._applied = False
|
|
hs.push()
|
|
|
|
expected_template = {
|
|
'heat_template_version': '2013-05-23',
|
|
'resources': {'test': 1}
|
|
}
|
|
self.heat_client_mock.stacks.create.assert_called_with(
|
|
stack_name='test-stack',
|
|
disable_rollback=True,
|
|
parameters={},
|
|
template=expected_template,
|
|
files={},
|
|
environment='',
|
|
tags=self.mock_tag
|
|
)
|
|
self.assertTrue(hs._applied)
|
|
|
|
@mock.patch(MOD_NAME + '.HeatStack._wait_state')
|
|
@mock.patch(MOD_NAME + '.HeatStack._get_status')
|
|
def test_heat_files_are_sent(self, status_get, wait_st):
|
|
"""Assert that if heat_template_version is omitted, it's added."""
|
|
|
|
status_get.return_value = 'NOT_FOUND'
|
|
wait_st.return_value = {}
|
|
context = {constants.CTX_ENVIRONMENT: self.environment_mock}
|
|
|
|
with helpers.contextual(context):
|
|
hs = heat_stack.HeatStack('test-stack', None)
|
|
hs._description = None
|
|
hs._template = {'resources': {'test': 1}}
|
|
hs._files = {"heatFile": "file"}
|
|
hs._hot_environment = ''
|
|
hs._parameters = {}
|
|
hs._applied = False
|
|
hs.push()
|
|
|
|
expected_template = {
|
|
'heat_template_version': '2013-05-23',
|
|
'resources': {'test': 1}
|
|
}
|
|
self.heat_client_mock.stacks.create.assert_called_with(
|
|
stack_name='test-stack',
|
|
disable_rollback=True,
|
|
parameters={},
|
|
template=expected_template,
|
|
files={"heatFile": "file"},
|
|
environment='',
|
|
tags=self.mock_tag
|
|
)
|
|
self.assertTrue(hs._applied)
|
|
|
|
@mock.patch(MOD_NAME + '.HeatStack._wait_state')
|
|
@mock.patch(MOD_NAME + '.HeatStack._get_status')
|
|
def test_heat_environments_are_sent(self, status_get, wait_st):
|
|
"""Assert that if heat_template_version is omitted, it's added."""
|
|
|
|
status_get.return_value = 'NOT_FOUND'
|
|
wait_st.return_value = {}
|
|
context = {constants.CTX_ENVIRONMENT: self.environment_mock}
|
|
|
|
with helpers.contextual(context):
|
|
hs = heat_stack.HeatStack('test-stack', None)
|
|
hs._description = None
|
|
hs._template = {'resources': {'test': 1}}
|
|
hs._files = {"heatFile": "file"}
|
|
hs._hot_environment = 'environments'
|
|
hs._parameters = {}
|
|
hs._applied = False
|
|
hs.push()
|
|
|
|
expected_template = {
|
|
'heat_template_version': '2013-05-23',
|
|
'resources': {'test': 1}
|
|
}
|
|
self.heat_client_mock.stacks.create.assert_called_with(
|
|
stack_name='test-stack',
|
|
disable_rollback=True,
|
|
parameters={},
|
|
template=expected_template,
|
|
files={"heatFile": "file"},
|
|
environment='environments',
|
|
tags=self.mock_tag
|
|
)
|
|
self.assertTrue(hs._applied)
|
|
|
|
@mock.patch(MOD_NAME + '.HeatStack.current')
|
|
def test_update_wrong_template_version(self, current):
|
|
"""Template version other than expected should cause error."""
|
|
|
|
context = {constants.CTX_ENVIRONMENT: self.environment_mock}
|
|
with helpers.contextual(context):
|
|
hs = heat_stack.HeatStack(
|
|
'test-stack', 'Generated by TestHeatStack')
|
|
hs._template = {'resources': {'test': 1}}
|
|
|
|
invalid_template = {
|
|
'heat_template_version': 'something else'
|
|
}
|
|
|
|
current.return_value = {}
|
|
|
|
e = self.assertRaises(heat_stack.HeatStackError,
|
|
hs.update_template,
|
|
invalid_template)
|
|
err_msg = "Currently only heat_template_version 2013-05-23 "\
|
|
"is supported."
|
|
self.assertEqual(err_msg, str(e))
|
|
|
|
# Check it's ok without a version
|
|
hs.update_template({})
|
|
expected = {'resources': {'test': 1}}
|
|
self.assertEqual(expected, hs._template)
|
|
|
|
# .. or with a good version
|
|
hs.update_template({'heat_template_version': '2013-05-23'})
|
|
expected['heat_template_version'] = '2013-05-23'
|
|
self.assertEqual(expected, hs._template)
|
|
|
|
@mock.patch(MOD_NAME + '.HeatStack._wait_state')
|
|
@mock.patch(MOD_NAME + '.HeatStack._get_status')
|
|
def test_heat_stack_tags_are_sent(self, status_get, wait_st):
|
|
"""Assert that heat_stack `tags` parameter get push & with
|
|
value from config parameter `stack_tags`.
|
|
"""
|
|
|
|
status_get.return_value = 'NOT_FOUND'
|
|
wait_st.return_value = {}
|
|
CONF.set_override('stack_tags', ['test-murano', 'murano-tag'], 'heat')
|
|
context = {constants.CTX_ENVIRONMENT: self.environment_mock}
|
|
|
|
with helpers.contextual(context):
|
|
hs = heat_stack.HeatStack('test-stack', None)
|
|
hs._description = None
|
|
hs._template = {'resources': {'test': 1}}
|
|
hs._files = {}
|
|
hs._hot_environment = ''
|
|
hs._parameters = {}
|
|
hs._applied = False
|
|
hs._tags = ','.join(CONF.heat.stack_tags)
|
|
hs.push()
|
|
|
|
expected_template = {
|
|
'heat_template_version': '2013-05-23',
|
|
'resources': {'test': 1}
|
|
}
|
|
self.heat_client_mock.stacks.create.assert_called_with(
|
|
stack_name='test-stack',
|
|
disable_rollback=True,
|
|
parameters={},
|
|
template=expected_template,
|
|
files={},
|
|
environment='',
|
|
tags=','.join(CONF.heat.stack_tags)
|
|
)
|
|
self.assertTrue(hs._applied)
|