Lookup nodes and networks in the nested stacks

Each custom resource, defined in the "resource_registry:" key
in the heat environment file, creates a separated stack that
handles the resources defined in this custom resources file.
To get the nested stacks: openstack stack list --nested

To find all the OS::Nova::Server and OS::Neutron::Subnet,
need to inspect all the nested stack, check that the stacks
are childs from the current stack, and collect all the resources
from them.

Change-Id: I28f9dd16070104b8f0715987408b8c2c2f7d810e
diff --git a/tcp_tests/managers/envmanager_heat.py b/tcp_tests/managers/envmanager_heat.py
index c5cee17..7432bd5 100644
--- a/tcp_tests/managers/envmanager_heat.py
+++ b/tcp_tests/managers/envmanager_heat.py
@@ -137,13 +137,39 @@
             self.__init_heatclient()
             return self.__heatclient.resources
 
+    def __get_stack_parent(self, stack_id, stacks):
+        """Find the parent ID of the specified stack_id in the 'stacks' list"""
+        for stack in stacks:
+            if stack_id == stack.id:
+                if stack.parent:
+                    return self.__get_stack_parent(stack.parent, stacks)
+                else:
+                    return stack.id
+        raise Exception("stack with ID {} not found!".format(stack_id))
+
+    @property
+    def __nested_resources(self):
+        resources = []
+        stacks = [s for s in self.__stacks.list(show_nested=True)]
+        current_stack_id = self._current_stack.id
+        for stack in stacks:
+            parent_stack_id = self.__get_stack_parent(stack.id, stacks)
+            if parent_stack_id == current_stack_id:
+                # Add resources to list
+                LOG.info("Get resources from stack {0}"
+                         .format(stack.stack_name))
+                resources.extend([
+                    res for res in self.__resources.list(stack.id)
+                ])
+        LOG.info("Found {0} resources".format(len(resources)))
+        return resources
+
     def _get_resources_by_type(self, resource_type):
         res = []
-        for item in self.__resources.list(
-                self.__config.hardware.heat_stack_name):
+        for item in self.__nested_resources:
             if item.resource_type == resource_type:
                 resource = self.__resources.get(
-                    self.__config.hardware.heat_stack_name,
+                    item.stack_name,
                     item.resource_name)
                 res.append(resource)
         return res
@@ -199,7 +225,7 @@
                                   .format(addr_type,
                                           heat_node.attributes['name'],
                                           network))
-                if fixed is None or floating is None:
+                if fixed is None and floating is None:
                     LOG.error("Unable to determine the correct IP address "
                               "in node '{0}' for network '{1}'"
                               .format(heat_node.attributes['name'], network))
@@ -213,6 +239,10 @@
                             # addresses[role] = floating
                             # Use fixed addresses for SSH access
                             addresses[role] = fixed
+            if 'metadata' not in heat_node.attributes or \
+                    'roles' not in heat_node.attributes['metadata']:
+                raise Exception("Node {} doesn't have metadata:roles:[...,...]"
+                                .format(heat_node.attributes['name']))
 
             nodes.append({
                 'name': heat_node.attributes['name'],
@@ -283,8 +313,7 @@
 
     def _get_resources_with_wrong_status(self):
         res = []
-        for item in self.__resources.list(
-                self.__config.hardware.heat_stack_name):
+        for item in self.__nested_resources:
             if item.resource_status in BAD_STACK_STATUSES:
                 res.append({
                     'resource_name': item.resource_name,