263 lines
8.7 KiB
Python
263 lines
8.7 KiB
Python
#
|
|
# 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.
|
|
|
|
import copy
|
|
import json
|
|
|
|
from heat.common import exception
|
|
from heat.common import template_format
|
|
from heat.engine import environment
|
|
from heat.engine import stack as parser
|
|
from heat.engine import template
|
|
from heat.tests import common
|
|
from heat.tests import utils
|
|
|
|
|
|
class TestValue(common.HeatTestCase):
|
|
|
|
simple_template = '''
|
|
heat_template_version: '2016-10-14'
|
|
parameters:
|
|
param1:
|
|
type: <the type>
|
|
resources:
|
|
my_value:
|
|
type: OS::Heat::Value
|
|
properties:
|
|
value: {get_param: param1}
|
|
my_value2:
|
|
type: OS::Heat::Value
|
|
properties:
|
|
value: {get_attr: [my_value, value]}
|
|
outputs:
|
|
myout:
|
|
value: {get_attr: [my_value2, value]}
|
|
'''
|
|
|
|
def get_strict_and_loose_templates(self, param_type):
|
|
template_loose = template_format.parse(self.simple_template)
|
|
template_loose['parameters']['param1']['type'] = param_type
|
|
template_strict = copy.deepcopy(template_loose)
|
|
template_strict['resources']['my_value']['properties']['type'] \
|
|
= param_type
|
|
template_strict['resources']['my_value2']['properties']['type'] \
|
|
= param_type
|
|
return (template_strict, template_loose)
|
|
|
|
def parse_stack(self, templ_obj):
|
|
stack_name = 'test_value_stack'
|
|
stack = parser.Stack(utils.dummy_context(), stack_name, templ_obj)
|
|
stack.validate()
|
|
stack.store()
|
|
return stack
|
|
|
|
def create_stack(self, templ, env=None):
|
|
if isinstance(templ, str):
|
|
return self.create_stack(template_format.parse(templ), env=env)
|
|
if isinstance(templ, dict):
|
|
tmpl_obj = template.Template(templ, env=env)
|
|
return self.create_stack(tmpl_obj)
|
|
assert isinstance(templ, template.Template)
|
|
stack = self.parse_stack(templ)
|
|
self.assertIsNone(stack.create())
|
|
return stack
|
|
|
|
|
|
class TestValueSimple(TestValue):
|
|
|
|
scenarios = [
|
|
('boolean', dict(
|
|
param1=True, param_type="boolean")),
|
|
('list', dict(
|
|
param1=['a', 'b', 'Z'], param_type="comma_delimited_list")),
|
|
('map', dict(
|
|
param1={'a': 'Z', 'B': 'y'}, param_type="json")),
|
|
('number-int', dict(
|
|
param1=-11, param_type="number")),
|
|
('number-float', dict(
|
|
param1=100.999, param_type="number")),
|
|
('string', dict(
|
|
param1='Perchance to dream', param_type="string")),
|
|
]
|
|
|
|
def test_value(self):
|
|
ts, tl = self.get_strict_and_loose_templates(self.param_type)
|
|
env = environment.Environment({
|
|
'parameters': {'param1': self.param1}})
|
|
|
|
for templ_dict in [ts, tl]:
|
|
stack = self.create_stack(templ_dict, env)
|
|
self.assertEqual(self.param1, stack['my_value'].FnGetAtt('value'))
|
|
self.assertEqual(self.param1, stack['my_value2'].FnGetAtt('value'))
|
|
stack._update_all_resource_data(False, True)
|
|
self.assertEqual(self.param1, stack.outputs['myout'].get_value())
|
|
|
|
|
|
class TestValueLessSimple(TestValue):
|
|
|
|
template_bad = '''
|
|
heat_template_version: '2016-10-14'
|
|
parameters:
|
|
param1:
|
|
type: json
|
|
resources:
|
|
my_value:
|
|
type: OS::Heat::Value
|
|
properties:
|
|
value: {get_param: param1}
|
|
type: number
|
|
'''
|
|
|
|
template_map = '''
|
|
heat_template_version: '2016-10-14'
|
|
parameters:
|
|
param1:
|
|
type: json
|
|
param2:
|
|
type: json
|
|
resources:
|
|
my_value:
|
|
type: OS::Heat::Value
|
|
properties:
|
|
value: {get_param: param1}
|
|
type: json
|
|
my_value2:
|
|
type: OS::Heat::Value
|
|
properties:
|
|
value: {map_merge: [{get_attr: [my_value, value]}, {get_param: param2}]}
|
|
type: json
|
|
'''
|
|
|
|
template_yaql = '''
|
|
heat_template_version: '2016-10-14'
|
|
parameters:
|
|
param1:
|
|
type: number
|
|
param2:
|
|
type: comma_delimited_list
|
|
resources:
|
|
my_value:
|
|
type: OS::Heat::Value
|
|
properties:
|
|
value: {get_param: param1}
|
|
type: number
|
|
my_value2:
|
|
type: OS::Heat::Value
|
|
properties:
|
|
value:
|
|
yaql:
|
|
expression: $.data.param2.select(int($)).min()
|
|
data:
|
|
param2: {get_param: param2}
|
|
type: number
|
|
my_value3:
|
|
type: OS::Heat::Value
|
|
properties:
|
|
value:
|
|
yaql:
|
|
expression: min($.data.v1,$.data.v2)
|
|
data:
|
|
v1: {get_attr: [my_value, value]}
|
|
v2: {get_attr: [my_value2, value]}
|
|
'''
|
|
|
|
def test_validation_fail(self):
|
|
param1 = {"one": "croissant"}
|
|
env = environment.Environment({
|
|
'parameters': {'param1': json.dumps(param1)}})
|
|
self.assertRaises(exception.StackValidationFailed,
|
|
self.create_stack, self.template_bad, env)
|
|
|
|
def test_map(self):
|
|
param1 = {"one": "skipper", "two": "antennae"}
|
|
param2 = {"one": "monarch", "three": "sky"}
|
|
env = environment.Environment({
|
|
'parameters': {'param1': json.dumps(param1),
|
|
'param2': json.dumps(param2)}})
|
|
stack = self.create_stack(self.template_map, env)
|
|
my_value = stack['my_value']
|
|
self.assertEqual(param1, my_value.FnGetAtt('value'))
|
|
my_value2 = stack['my_value2']
|
|
self.assertEqual({"one": "monarch",
|
|
"two": "antennae",
|
|
"three": "sky"}, my_value2.FnGetAtt('value'))
|
|
|
|
def test_yaql(self):
|
|
param1 = -800
|
|
param2 = [-8, 0, 4, -11, 2]
|
|
env = environment.Environment({
|
|
'parameters': {'param1': param1, 'param2': param2}})
|
|
stack = self.create_stack(self.template_yaql, env)
|
|
my_value = stack['my_value']
|
|
self.assertEqual(param1, my_value.FnGetAtt('value'))
|
|
my_value2 = stack['my_value2']
|
|
self.assertEqual(min(param2), my_value2.FnGetAtt('value'))
|
|
my_value3 = stack['my_value3']
|
|
self.assertEqual(param1, my_value3.FnGetAtt('value'))
|
|
|
|
|
|
class TestValueUpdate(TestValue):
|
|
|
|
scenarios = [
|
|
('boolean-to-number', dict(
|
|
param1=True, param_type1="boolean",
|
|
param2=-100.999, param_type2="number")),
|
|
('number-to-string', dict(
|
|
param1=-77, param_type1="number",
|
|
param2='mellors', param_type2="string")),
|
|
('string-to-map', dict(
|
|
param1='mellors', param_type1="string",
|
|
param2={'3': 'turbo'}, param_type2="json")),
|
|
('map-to-boolean', dict(
|
|
param1={'hey': 'there'}, param_type1="json",
|
|
param2=False, param_type2="boolean")),
|
|
('list-to-boolean', dict(
|
|
param1=['hey', '!'], param_type1="comma_delimited_list",
|
|
param2=True, param_type2="boolean")),
|
|
]
|
|
|
|
def test_value_update(self):
|
|
ts1, tl1 = self.get_strict_and_loose_templates(self.param_type1)
|
|
ts2, tl2 = self.get_strict_and_loose_templates(self.param_type2)
|
|
|
|
env1 = environment.Environment({
|
|
'parameters': {'param1': self.param1}})
|
|
env2 = environment.Environment({
|
|
'parameters': {'param1': self.param2}})
|
|
|
|
updates = [(ts1, ts2), (ts1, tl2), (tl1, ts2), (tl1, tl2)]
|
|
updates_other_way = [(b, a) for a, b in updates]
|
|
updates.extend(updates_other_way)
|
|
for t_initial, t_updated in updates:
|
|
if t_initial == ts1 or t_initial == tl1:
|
|
p1, p2, e1, e2 = self.param1, self.param2, env1, env2
|
|
else:
|
|
# starting with param2, updating to param1
|
|
p2, p1, e2, e1 = self.param1, self.param2, env1, env2
|
|
stack = self.create_stack(copy.deepcopy(t_initial), env=e1)
|
|
self.assertEqual(p1, stack['my_value2'].FnGetAtt('value'))
|
|
res1_id = stack['my_value'].id
|
|
res2_id = stack['my_value2'].id
|
|
res2_uuid = stack['my_value2'].uuid
|
|
|
|
updated_stack = parser.Stack(
|
|
stack.context, 'updated_stack',
|
|
template.Template(copy.deepcopy(t_updated), env=e2))
|
|
updated_stack.validate()
|
|
stack.update(updated_stack)
|
|
self.assertEqual(p2, stack['my_value2'].FnGetAtt('value'))
|
|
# Make sure resources not replaced after update
|
|
self.assertEqual(res1_id, stack['my_value'].id)
|
|
self.assertEqual(res2_id, stack['my_value2'].id)
|
|
self.assertEqual(res2_uuid, stack['my_value2'].uuid)
|