Merge "Added logging when a heat stack fails."
authorSteven Pisarski <s.pisarski@cablelabs.com>
Mon, 6 Nov 2017 15:04:22 +0000 (15:04 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Mon, 6 Nov 2017 15:04:22 +0000 (15:04 +0000)
1  2 
docs/how-to-use/IntegrationTests.rst
snaps/openstack/create_stack.py
snaps/openstack/tests/create_stack_tests.py
snaps/openstack/utils/heat_utils.py

@@@ -362,22 -362,22 +362,22 @@@ create_stack_tests.py - CreateStackSucc
  +---------------------------------------+---------------+-----------------------------------------------------------+
  | Test Name                             |   Heat API    | Description                                               |
  +=======================================+===============+===========================================================+
- | test_create_stack_template_file       | 1             | Ensures that a Heat stack can be created with a file-based|
+ | test_create_stack_template_file       | 1-3           | Ensures that a Heat stack can be created with a file-based|
  |                                       |               | Heat template file                                        |
  +---------------------------------------+---------------+-----------------------------------------------------------+
- | test_create_stack_template_dict       | 1             | Ensures that a Heat stack can be created with a dictionary|
+ | test_create_stack_template_dict       | 1-3           | Ensures that a Heat stack can be created with a dictionary|
  |                                       |               | Heat template                                             |
  +---------------------------------------+---------------+-----------------------------------------------------------+
- | test_create_delete_stack              | 1             | Ensures that a Heat stack can be created and deleted      |
+ | test_create_delete_stack              | 1-3           | Ensures that a Heat stack can be created and deleted      |
  |                                       |               | while having clean() called 2x without an exception       |
  +---------------------------------------+---------------+-----------------------------------------------------------+
- | test_create_same_stack                | 1             | Ensures that a Heat stack with the same name cannot be    |
+ | test_create_same_stack                | 1-3           | Ensures that a Heat stack with the same name cannot be    |
  |                                       |               | created 2x                                                |
  +---------------------------------------+---------------+-----------------------------------------------------------+
- | test_retrieve_network_creators        | 1             | Ensures that an OpenStackHeatStack instance can return an |
+ | test_retrieve_network_creators        | 1-3           | Ensures that an OpenStackHeatStack instance can return an |
  |                                       |               | OpenStackNetwork instance configured as deployed          |
  +---------------------------------------+---------------+-----------------------------------------------------------+
- | test_retrieve_vm_inst_creators        | 1             | Ensures that an OpenStackHeatStack instance can return an |
+ | test_retrieve_vm_inst_creators        | 1-3           | Ensures that an OpenStackHeatStack instance can return an |
  |                                       |               | OpenStackVmInstance instance configured as deployed       |
  +---------------------------------------+---------------+-----------------------------------------------------------+
  
@@@ -387,44 -387,22 +387,44 @@@ create_stack_tests.py - CreateStackVolu
  +---------------------------------------+---------------+-----------------------------------------------------------+
  | Test Name                             |   Heat API    | Description                                               |
  +=======================================+===============+===========================================================+
- | test_retrieve_volume_creator          | 1             | Ensures that an OpenStackHeatStack instance can return a  |
+ | test_retrieve_volume_creator          | 1-3           | Ensures that an OpenStackHeatStack instance can return a  |
  |                                       |               | OpenStackVolume instance that it was responsible for      |
  |                                       |               | deploying                                                 |
  +---------------------------------------+---------------+-----------------------------------------------------------+
- | test_retrieve_volume_type_creator     | 1             | Ensures that an OpenStackHeatStack instance can return a  |
+ | test_retrieve_volume_type_creator     | 1-3           | Ensures that an OpenStackHeatStack instance can return a  |
  |                                       |               | OpenStackVolumeType instance that it was responsible for  |
  |                                       |               | deploying                                                 |
  +---------------------------------------+---------------+-----------------------------------------------------------+
  
 +create_stack_tests.py - CreateStackFloatingIpTests
 +--------------------------------------------------
 +
 ++---------------------------------------+---------------+-----------------------------------------------------------+
 +| Test Name                             |   Heat API    | Description                                               |
 ++=======================================+===============+===========================================================+
 +| test_connect_via_ssh_heat_vm          | 1             | Ensures that an OpenStackHeatStack instance can create a  |
 +|                                       |               | VM with a floating IP that can be accessed via            |
 +|                                       |               | OpenStackVmInstance                                       |
 ++---------------------------------------+---------------+-----------------------------------------------------------+
 +
 +create_stack_tests.py - CreateStackRouterTests
 +----------------------------------------------
 +
 ++---------------------------------------+---------------+-----------------------------------------------------------+
 +| Test Name                             |   Heat API    | Description                                               |
 ++=======================================+===============+===========================================================+
 +| test_retrieve_router_creator          | 1             | Ensures that an OpenStackHeatStack instance can return a  |
 +|                                       |               | OpenStackRouter instance that it was responsible for      |
 +|                                       |               | deploying                                                 |
 ++---------------------------------------+---------------+-----------------------------------------------------------+
 +
  create_stack_tests.py - CreateStackFlavorTests
  ----------------------------------------------
  
  +---------------------------------------+---------------+-----------------------------------------------------------+
  | Test Name                             |   Heat API    | Description                                               |
  +=======================================+===============+===========================================================+
- | test_retrieve_flavor_creator          | 1             | Ensures that an OpenStackHeatStack instance can return a  |
+ | test_retrieve_flavor_creator          | 1-3           | Ensures that an OpenStackHeatStack instance can return a  |
  |                                       |               | OpenStackFlavor instance that it was responsible for      |
  |                                       |               | deploying                                                 |
  +---------------------------------------+---------------+-----------------------------------------------------------+
@@@ -435,7 -413,7 +435,7 @@@ create_stack_tests.py - CreateStackKeyp
  +---------------------------------------+---------------+-----------------------------------------------------------+
  | Test Name                             |   Heat API    | Description                                               |
  +=======================================+===============+===========================================================+
- | test_retrieve_keypair_creator         | 1             | Ensures that an OpenStackHeatStack instance can return a  |
+ | test_retrieve_keypair_creator         | 1-3           | Ensures that an OpenStackHeatStack instance can return a  |
  |                                       |               | OpenStackKeypair instance that it was responsible for     |
  |                                       |               | deploying                                                 |
  +---------------------------------------+---------------+-----------------------------------------------------------+
@@@ -446,7 -424,7 +446,7 @@@ create_stack_tests.py - CreateComplexSt
  +---------------------------------------+---------------+-----------------------------------------------------------+
  | Test Name                             |   Heat API    | Description                                               |
  +=======================================+===============+===========================================================+
- | test_connect_via_ssh_heat_vm          | 1             | Ensures that two OpenStackHeatStack instances can return  |
+ | test_connect_via_ssh_heat_vm          | 1-3           | Ensures that two OpenStackHeatStack instances can return  |
  |                                       |               | OpenStackVmInstance instances one configured with a       |
  |                                       |               | floating IP and keypair and can be access via SSH         |
  +---------------------------------------+---------------+-----------------------------------------------------------+
@@@ -457,13 -435,23 +457,23 @@@ create_stack_tests.py - CreateStackNega
  +----------------------------------------+---------------+-----------------------------------------------------------+
  | Test Name                              |   Heat API    | Description                                               |
  +========================================+===============+===========================================================+
- | test_missing_dependencies              | 1             | Ensures that a Heat template fails to deploy when expected|
+ | test_missing_dependencies              | 1-3           | Ensures that a Heat template fails to deploy when expected|
  |                                        |               | dependencies are missing                                  |
  +----------------------------------------+---------------+-----------------------------------------------------------+
- | test_bad_stack_file                    | 1             | Ensures that a Heat template fails to deploy when the Heat|
+ | test_bad_stack_file                    | 1-3           | Ensures that a Heat template fails to deploy when the Heat|
  |                                        |               | template file does not exist                              |
  +----------------------------------------+---------------+-----------------------------------------------------------+
  
+ create_stack_tests.py - CreateStackFailureTests
+ -----------------------------------------------
+ +----------------------------------------+---------------+-----------------------------------------------------------+
+ | Test Name                              |   Heat API    | Description                                               |
+ +========================================+===============+===========================================================+
+ | test_stack_failure                     | 1-3           | Ensures that a Heat template fails to deploy when expected|
+ |                                        |               | dependencies are missing                                  |
+ +----------------------------------------+---------------+-----------------------------------------------------------+
  create_instance_tests.py - CreateInstanceSimpleTests
  ----------------------------------------------------
  
@@@ -21,7 -21,6 +21,7 @@@ from heatclient.exc import HTTPNotFoun
  from snaps.openstack.create_flavor import OpenStackFlavor
  from snaps.openstack.create_instance import OpenStackVmInstance
  from snaps.openstack.create_keypairs import OpenStackKeypair
 +from snaps.openstack.create_router import OpenStackRouter
  from snaps.openstack.create_volume import OpenStackVolume
  from snaps.openstack.create_volume_type import OpenStackVolumeType
  from snaps.openstack.openstack_creator import OpenStackCloudObject
@@@ -235,28 -234,6 +235,28 @@@ class OpenStackHeatStack(OpenStackCloud
  
          return out
  
 +    def get_router_creators(self):
 +        """
 +        Returns a list of router creator objects as configured by the heat
 +        template
 +        :return: list() of OpenStackRouter objects
 +        """
 +
 +        neutron = neutron_utils.neutron_client(self._os_creds)
 +
 +        out = list()
 +        stack_routers = heat_utils.get_stack_routers(
 +            self.__heat_cli, neutron, self.__stack)
 +
 +        for routers in stack_routers:
 +            settings = settings_utils.create_router_settings(
 +                neutron, routers)
 +            creator = OpenStackRouter(self._os_creds, settings)
 +            out.append(creator)
 +            creator.initialize()
 +
 +        return out
 +
      def get_vm_inst_creators(self, heat_keypair_option=None):
          """
          Returns a list of VM Instance creator objects as configured by the heat
              return False
  
          if fail_status and status == fail_status:
+             resources = heat_utils.get_resources(self.__heat_cli, self.__stack)
+             logger.error('Stack %s failed', self.__stack.name)
+             for resource in resources:
+                 if resource.status != STATUS_CREATE_COMPLETE:
+                     logger.error(
+                         'Resource: [%s] status: [%s] reason: [%s]',
+                         resource.name, resource.status, resource.status_reason)
+                 else:
+                     logger.debug(
+                         'Resource: [%s] status: [%s] reason: [%s]',
+                         resource.name, resource.status, resource.status_reason)
              raise StackError('Stack had an error')
          logger.debug('Stack status is - ' + status)
          return status == expected_status_code
  # 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 os
  import time
  
  import pkg_resources
  from heatclient.exc import HTTPBadRequest
  from snaps import file_utils
  from snaps.openstack.create_flavor import OpenStackFlavor, FlavorSettings
- from snaps.openstack.create_image import OpenStackImage
+ from snaps.openstack.create_image import OpenStackImage, ImageSettings
  
  try:
      from urllib.request import URLError
@@@ -31,7 -32,7 +32,7 @@@ import uui
  
  from snaps.openstack import create_stack
  from snaps.openstack.create_stack import (
-     StackSettings, StackSettingsError, StackCreationError)
+     StackSettings, StackSettingsError, StackCreationError, StackError)
  from snaps.openstack.tests import openstack_tests, create_instance_tests
  from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
  from snaps.openstack.utils import heat_utils, neutron_utils, nova_utils
@@@ -123,14 -124,11 +124,11 @@@ class StackSettingsUnitTests(unittest.T
  
  class CreateStackSuccessTests(OSIntegrationTestCase):
      """
-     Tests for the CreateStack class defined in create_stack.py
+     Tests for the OpenStackHeatStack class defined in create_stack.py
      """
  
      def setUp(self):
-         """
-         Instantiates the CreateStack object that is responsible for downloading
-         and creating an OS stack file within OpenStack
-         """
          super(self.__class__, self).__start__()
  
          self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
  
  class CreateStackFloatingIpTests(OSIntegrationTestCase):
      """
-     Tests for the CreateStack class defined in create_stack.py
+     Tests to ensure that floating IPs can be accessed via an
+     OpenStackVmInstance object obtained from the OpenStackHeatStack instance
      """
  
      def setUp(self):
-         """
-         Instantiates the CreateStack object that is responsible for downloading
-         and creating an OS stack file within OpenStack
-         """
          super(self.__class__, self).__start__()
  
          self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
                  self.assertEqual(0, len(vm_settings.floating_ip_settings))
  
  
 +class CreateStackRouterTests(OSIntegrationTestCase):
 +    """
 +    Tests for the CreateStack class defined in create_stack.py where the
 +    target is a Network, Subnet, and Router
 +    """
 +
 +    def setUp(self):
 +        """
 +        Instantiates the CreateStack object that is responsible for downloading
 +        and creating an OS stack file within OpenStack
 +        """
 +        super(self.__class__, self).__start__()
 +
 +        self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
 +
 +        self.heat_creds = self.admin_os_creds
 +        self.heat_creds.project_name = self.admin_os_creds.project_name
 +
 +        self.heat_cli = heat_utils.heat_client(self.heat_creds)
 +        self.neutron = neutron_utils.neutron_client(self.os_creds)
 +        self.stack_creator = None
 +
 +        self.net_name = self.guid + '-net'
 +        self.subnet_name = self.guid + '-subnet'
 +        self.router_name = self.guid + '-router'
 +
 +        self.env_values = {
 +            'net_name': self.net_name,
 +            'subnet_name': self.subnet_name,
 +            'router_name': self.router_name,
 +            'external_net_name': self.ext_net_name}
 +
 +        self.heat_tmplt_path = pkg_resources.resource_filename(
 +            'snaps.openstack.tests.heat', 'router_heat_template.yaml')
 +
 +        stack_settings = StackSettings(
 +            name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
 +            template_path=self.heat_tmplt_path,
 +            env_values=self.env_values)
 +        self.stack_creator = create_stack.OpenStackHeatStack(
 +            self.heat_creds, stack_settings)
 +        self.created_stack = self.stack_creator.create()
 +        self.assertIsNotNone(self.created_stack)
 +
 +    def tearDown(self):
 +        """
 +        Cleans the stack and downloaded stack file
 +        """
 +        if self.stack_creator:
 +            try:
 +                self.stack_creator.clean()
 +            except:
 +                pass
 +
 +        super(self.__class__, self).__clean__()
 +
 +    def test_retrieve_router_creator(self):
 +        """
 +        Tests the creation of an OpenStack stack from Heat template file and
 +        the retrieval of an OpenStackRouter creator/state machine instance
 +        """
 +        router_creators = self.stack_creator.get_router_creators()
 +        self.assertEqual(1, len(router_creators))
 +
 +        creator = router_creators[0]
 +        self.assertEqual(self.router_name, creator.router_settings.name)
 +
 +        router = creator.get_router()
 +
 +        ext_net = neutron_utils.get_network(
 +            self.neutron, network_name=self.ext_net_name)
 +        self.assertEqual(ext_net.id, router.external_network_id)
 +
 +
  class CreateStackVolumeTests(OSIntegrationTestCase):
      """
-     Tests for the CreateStack class as they pertain to volumes
+     Tests to ensure that floating IPs can be accessed via an
+     OpenStackVolume object obtained from the OpenStackHeatStack instance
      """
  
      def setUp(self):
-         """
-         Instantiates the CreateStack object that is responsible for downloading
-         and creating an OS stack file within OpenStack
-         """
          super(self.__class__, self).__start__()
  
          self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
  
  class CreateStackFlavorTests(OSIntegrationTestCase):
      """
-     Tests for the CreateStack class defined in create_stack.py
+     Tests to ensure that floating IPs can be accessed via an
+     OpenStackFlavor object obtained from the OpenStackHeatStack instance
      """
  
      def setUp(self):
-         """
-         Instantiates the CreateStack object that is responsible for downloading
-         and creating an OS stack file within OpenStack
-         """
          super(self.__class__, self).__start__()
  
          self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
  
  class CreateStackKeypairTests(OSIntegrationTestCase):
      """
-     Tests for the CreateStack class as they pertain to keypairs
+     Tests to ensure that floating IPs can be accessed via an
+     OpenStackKeypair object obtained from the OpenStackHeatStack instance
      """
  
      def setUp(self):
-         """
-         Instantiates the CreateStack object that is responsible for downloading
-         and creating an OS stack file within OpenStack
-         """
          super(self.__class__, self).__start__()
  
          self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
  
  class CreateStackNegativeTests(OSIntegrationTestCase):
      """
-     Negative test cases for the CreateStack class
+     Negative test cases for the OpenStackHeatStack class with poor
+     configuration
      """
  
      def setUp(self):
          super(self.__class__, self).__start__()
  
          self.heat_creds = self.admin_os_creds
                                                               stack_settings)
          with self.assertRaises(IOError):
              self.stack_creator.create()
+ class CreateStackFailureTests(OSIntegrationTestCase):
+     """
+     Tests for the OpenStackHeatStack class defined in create_stack.py for
+     when failures occur. Failures are being triggered by allocating 1 million
+     CPUs.
+     """
+     def setUp(self):
+         super(self.__class__, self).__start__()
+         self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
+         self.heat_creds = self.admin_os_creds
+         self.heat_creds.project_name = self.admin_os_creds.project_name
+         self.heat_cli = heat_utils.heat_client(self.heat_creds)
+         self.stack_creator = None
+         self.tmp_file = file_utils.save_string_to_file(
+             ' ', str(uuid.uuid4()) + '-bad-image')
+         self.image_creator = OpenStackImage(
+             self.heat_creds, ImageSettings(
+                 name=self.guid + 'image', image_file=self.tmp_file.name,
+                 image_user='foo', img_format='qcow2'))
+         self.image_creator.create()
+         # Create Flavor
+         self.flavor_creator = OpenStackFlavor(
+             self.admin_os_creds,
+             FlavorSettings(name=self.guid + '-flavor-name', ram=256, disk=10,
+                            vcpus=1000000))
+         self.flavor_creator.create()
+         self.network_name = self.guid + '-net'
+         self.subnet_name = self.guid + '-subnet'
+         self.vm_inst_name = self.guid + '-inst'
+         self.env_values = {
+             'image_name': self.image_creator.image_settings.name,
+             'flavor_name': self.flavor_creator.flavor_settings.name,
+             'net_name': self.network_name,
+             'subnet_name': self.subnet_name,
+             'inst_name': self.vm_inst_name}
+         self.heat_tmplt_path = pkg_resources.resource_filename(
+             'snaps.openstack.tests.heat', 'test_heat_template.yaml')
+     def tearDown(self):
+         """
+         Cleans the stack and downloaded stack file
+         """
+         if self.stack_creator:
+             try:
+                 self.stack_creator.clean()
+             except:
+                 pass
+         if self.image_creator:
+             try:
+                 self.image_creator.clean()
+             except:
+                 pass
+         if self.flavor_creator:
+             try:
+                 self.flavor_creator.clean()
+             except:
+                 pass
+         if self.tmp_file:
+             try:
+                 os.remove(self.tmp_file.name)
+             except:
+                 pass
+         super(self.__class__, self).__clean__()
+     def test_stack_failure(self):
+         """
+         Tests the creation of an OpenStack stack from Heat template file that
+         should always fail due to too many CPU cores
+         """
+         # Create Stack
+         # Set the default stack settings, then set any custom parameters sent
+         # from the app
+         stack_settings = StackSettings(
+             name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
+             template_path=self.heat_tmplt_path,
+             env_values=self.env_values)
+         self.stack_creator = create_stack.OpenStackHeatStack(self.heat_creds,
+                                                              stack_settings)
+         with self.assertRaises(StackError):
+             try:
+                 self.stack_creator.create()
+             except StackError:
+                 resources = heat_utils.get_resources(
+                     self.heat_cli, self.stack_creator.get_stack())
+                 found = False
+                 for resource in resources:
+                     if resource.status == create_stack.STATUS_CREATE_COMPLETE:
+                         found = True
+                 self.assertTrue(found)
+                 raise
@@@ -23,8 -23,8 +23,8 @@@ from oslo_serialization import jsonutil
  from snaps import file_utils
  from snaps.domain.stack import Stack, Resource, Output
  
- from snaps.openstack.utils import keystone_utils, neutron_utils, nova_utils, \
-     cinder_utils
+ from snaps.openstack.utils import (
+     keystone_utils, neutron_utils, nova_utils, cinder_utils)
  
  __author__ = 'spisarski'
  
@@@ -155,10 -155,13 +155,13 @@@ def get_resources(heat_cli, stack, res_
          out = list()
          for os_resource in os_resources:
              if ((res_type and os_resource.resource_type == res_type)
-                     or not res_type):
+                 or not res_type):
                  out.append(Resource(
+                     name=os_resource.resource_name,
                      resource_type=os_resource.resource_type,
-                     resource_id=os_resource.physical_resource_id))
+                     resource_id=os_resource.physical_resource_id,
+                     status=os_resource.resource_status,
+                     status_reason=os_resource.resource_status_reason))
          return out
  
  
@@@ -204,25 -207,6 +207,25 @@@ def get_stack_networks(heat_cli, neutro
      return out
  
  
 +def get_stack_routers(heat_cli, neutron, stack):
 +    """
 +    Returns a list of Network domain objects deployed by this stack
 +    :param heat_cli: the OpenStack heat client object
 +    :param neutron: the OpenStack neutron client object
 +    :param stack: the SNAPS-OO Stack domain object
 +    :return: a list of Network objects
 +    """
 +
 +    out = list()
 +    resources = get_resources(heat_cli, stack, 'OS::Neutron::Router')
 +    for resource in resources:
 +        router = neutron_utils.get_router_by_id(neutron, resource.id)
 +        if router:
 +            out.append(router)
 +
 +    return out
 +
 +
  def get_stack_servers(heat_cli, nova, stack):
      """
      Returns a list of VMInst domain objects associated with a Stack