support nested stack in heat

* add the depth of the nested stack
10 should be enough consider making it
configurable

Change-Id: I9903aa760801170b9d1c2d23fbea79d80e5e959d
This commit is contained in:
Eyal 2017-10-29 16:26:11 +02:00
parent 30e3337a7d
commit bb46cd5232
6 changed files with 88 additions and 22 deletions

1
.gitignore vendored
View File

@ -25,6 +25,7 @@ ChangeLog
cover
etc/vitrage/vitrage.conf
doc/source/_static/
*.db
#Python
*.pyc

View File

@ -25,6 +25,8 @@ fi
sudo cp -rf $DEVSTACK_PATH/vitrage/vitrage_tempest_tests/tests/resources/static_physical/static_physical_configuration.yaml /etc/vitrage/
sudo cp -rf $DEVSTACK_PATH/vitrage/vitrage_tempest_tests/tests/resources/heat/heat_template.yaml /etc/vitrage/
sudo cp -rf $DEVSTACK_PATH/vitrage/vitrage_tempest_tests/tests/resources/heat/heat_nested_template.yaml /etc/vitrage/
sudo cp -rf $DEVSTACK_PATH/vitrage/vitrage_tempest_tests/tests/resources/heat/server.yaml /etc/vitrage/
sudo cp -rf $DEVSTACK_PATH/vitrage/vitrage_tempest_tests/tests/resources/heat/policy.json-tempest /etc/heat/
sudo cp $DEVSTACK_PATH/tempest/etc/logging.conf.sample $DEVSTACK_PATH/tempest/etc/logging.conf

View File

@ -79,9 +79,12 @@ class HeatStackDriver(DriverBase):
# change transformer that if delete we remove the stack from the graph
# and hence all the edges to it
stack_id = event['stack_identity']
if self._is_nested_stack(stack_id):
return
event[DSProps.EVENT_TYPE] = event_type
event = HeatStackDriver._retrieve_stack_resources(
event, event['stack_identity'])
event = HeatStackDriver._retrieve_stack_resources(event, stack_id)
return HeatStackDriver.make_pickleable(
[event],
@ -89,6 +92,10 @@ class HeatStackDriver(DriverBase):
DatasourceAction.UPDATE,
*self.properties_to_filter_out())[0]
@staticmethod
def _is_nested_stack(_id):
return HeatStackDriver.client().stacks.get(_id).to_dict()['parent']
def _filter_resource_types(self):
types = self.conf.datasources.types
tmp_dict = {}
@ -99,8 +106,9 @@ class HeatStackDriver(DriverBase):
HeatStackDriver.RESOURCE_TYPE = tmp_dict
def _make_stacks_list(self, stacks):
return [stack.__dict__ for stack in stacks]
@staticmethod
def _make_stacks_list(stacks):
return [stack.to_dict() for stack in stacks]
def _append_stacks_resources(self, stacks):
return [self._retrieve_stack_resources(stack, stack['id'])
@ -112,9 +120,12 @@ class HeatStackDriver(DriverBase):
@staticmethod
def _retrieve_stack_resources(stack, stack_id):
resources = HeatStackDriver.client().resources.list(stack_id)
stack['resources'] = [resource.__dict__ for resource in resources
if resource.__dict__['resource_type'] in
resources = HeatStackDriver.client().resources.list(stack_id,
# guess 10 is
# enough
nested_depth=10)
stack['resources'] = [resource.to_dict() for resource in resources
if resource.to_dict()['resource_type'] in
HeatStackDriver.RESOURCE_TYPE]
HeatStackDriver._filter_stack_resources(stack)
return stack

View File

@ -14,6 +14,8 @@
import time
from heatclient.common import http
from heatclient.common import template_utils
from oslo_log import log as logging
from vitrage_tempest_tests.tests import utils
@ -29,8 +31,15 @@ class TestHeatStack(BaseTopologyTest):
def setUpClass(cls):
super(TestHeatStack, cls).setUpClass()
@utils.tempest_logger
def test_nested_heat_stack(self):
self._test_heat_stack(nested=True)
@utils.tempest_logger
def test_heat_stack(self):
self._test_heat_stack(nested=False)
def _test_heat_stack(self, nested):
"""heat stack test
This test validate correctness topology graph with heat stack module
@ -38,7 +47,7 @@ class TestHeatStack(BaseTopologyTest):
try:
# Action
self._create_stacks(num_stacks=self.NUM_STACKS)
self._create_stacks(self.NUM_STACKS, nested)
# Calculate expected results
api_graph = self.vitrage_client.topology.get(all_tenants=True)
@ -70,26 +79,33 @@ class TestHeatStack(BaseTopologyTest):
finally:
self._delete_stacks()
def _create_stacks(self, num_stacks):
with open('/etc/vitrage/heat_template.yaml', 'rb') as f:
template_data = f.read()
def _create_stacks(self, num_stacks, nested):
template_file = 'heat_nested_template.yaml'\
if nested else 'heat_template.yaml'
tpl_files, template = template_utils.process_template_path(
'/etc/vitrage/' + template_file,
object_request=http.authenticated_fetcher(self.heat_client))
for i in range(num_stacks):
self.heat_client.stacks.create(stack_name='stack_%s' % i,
template=template_data,
stack_name = 'stack_%s' % i + ('_nested' if nested else '')
self.heat_client.stacks.create(stack_name=stack_name,
template=template,
files=tpl_files,
parameters={})
self._wait_for_status(45,
self._check_num_stacks,
num_stacks=num_stacks,
state='CREATE_COMPLETE')
self._wait_for_status(45,
self._check_num_stacks,
num_stacks=num_stacks,
state='CREATE_COMPLETE')
time.sleep(2)
time.sleep(2)
def _delete_stacks(self):
stacks = self.heat_client.stacks.list()
for stack in stacks:
try:
self.heat_client.stacks.delete(stack.__dict__['id'])
self.heat_client.stacks.delete(stack.to_dict()['id'])
except Exception:
pass
@ -97,12 +113,12 @@ class TestHeatStack(BaseTopologyTest):
self._check_num_stacks,
num_stacks=0)
time.sleep(2)
time.sleep(4)
def _check_num_stacks(self, num_stacks, state=''):
stacks_list = \
[stack.__dict__ for stack in self.heat_client.stacks.list()
if 'FAILED' not in stack.__dict__['stack_status']]
[stack.to_dict() for stack in self.heat_client.stacks.list()
if 'FAILED' not in stack.to_dict()['stack_status']]
if len(stacks_list) != num_stacks:
return False

View File

@ -0,0 +1,12 @@
heat_template_version: 2013-05-23
description: |
The heat template is used to demo
resources:
rg:
type: OS::Heat::ResourceGroup
properties:
count: 1
resource_def:
type: file:///etc/vitrage/server.yaml

View File

@ -0,0 +1,24 @@
heat_template_version: 2013-05-23
description: |
The heat template is used to demo
parameters:
image:
type: string
default: cirros-0.3.5-x86_64-disk
network:
type: string
default: public
flavor:
type: string
default: m1.small
resources:
server_2:
type: OS::Nova::Server
properties:
image: { get_param: image }
flavor: { get_param: flavor }
networks:
- network: { get_param: network }