summaryrefslogtreecommitdiffstats
path: root/docs/requirements/99-references.rst
blob: 0fd3a36a7e433f0f1c42a42081643945179cfbb1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
.. This work is licensed under a Creative Commons Attribution 4.0 International License.
.. http://creativecommons.org/licenses/by/4.0

References and bibliography
===========================

.. [DOCT] OPNFV, "Doctor" requirements project, [Online]. Available at
          https://wiki.opnfv.org/doctor
.. [PRED] OPNFV, "Data Collection for Failure Prediction" requirements project
          [Online]. Available at https://wiki.opnfv.org/prediction
.. [OPSK] OpenStack, [Online]. Available at https://www.openstack.org/
.. [CEIL] OpenStack Telemetry (Ceilometer), [Online]. Available at
          https://wiki.openstack.org/wiki/Ceilometer
.. [NOVA] OpenStack Nova, [Online]. Available at
          https://wiki.openstack.org/wiki/Nova
.. [NEUT] OpenStack Neutron, [Online]. Available at
          https://wiki.openstack.org/wiki/Neutron
.. [CIND] OpenStack Cinder, [Online]. Available at
          https://wiki.openstack.org/wiki/Cinder
.. [MONA] OpenStack Monasca, [Online], Available at
          https://wiki.openstack.org/wiki/Monasca
.. [OSAG] OpenStack Cloud Administrator Guide, [Online]. Available at
          http://docs.openstack.org/admin-guide-cloud/content/
.. [ZABB] ZABBIX, the Enterprise-class Monitoring Solution for Everyone,
          [Online]. Available at http://www.zabbix.com/
.. [ENFV] ETSI NFV, [Online]. Available at
          http://www.etsi.org/technologies-clusters/technologies/nfv



..
 vim: set tabstop=4 expandtab textwidth=80:
hlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
#                    and others.  All rights reserved.
#
# 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 logging
import time

from heatclient.exc import HTTPNotFound
from snaps.openstack.utils import heat_utils

__author__ = 'spisarski'

logger = logging.getLogger('create_stack')

STACK_COMPLETE_TIMEOUT = 1200
POLL_INTERVAL = 3
STATUS_CREATE_FAILED = 'CREATE_FAILED'
STATUS_CREATE_COMPLETE = 'CREATE_COMPLETE'
STATUS_DELETE_COMPLETE = 'DELETE_COMPLETE'


class OpenStackHeatStack:
    """
    Class responsible for creating an heat stack in OpenStack
    """

    def __init__(self, os_creds, stack_settings):
        """
        Constructor
        :param os_creds: The OpenStack connection credentials
        :param stack_settings: The stack settings
        :return:
        """
        self.__os_creds = os_creds
        self.stack_settings = stack_settings
        self.__stack = None
        self.__heat_cli = None

    def create(self, cleanup=False):
        """
        Creates the heat stack in OpenStack if it does not already exist and
        returns the domain Stack object
        :param cleanup: Denotes whether or not this is being called for cleanup
        :return: The OpenStack Stack object
        """
        self.__heat_cli = heat_utils.heat_client(self.__os_creds)
        self.__stack = heat_utils.get_stack_by_name(self.__heat_cli,
                                                    self.stack_settings.name)
        if self.__stack:
            logger.info('Found stack with name - ' + self.stack_settings.name)
            return self.__stack
        elif not cleanup:
            self.__stack = heat_utils.create_stack(self.__heat_cli,
                                                   self.stack_settings)
            logger.info(
                'Created stack with name - ' + self.stack_settings.name)
            if self.__stack and self.stack_complete(block=True):
                logger.info(
                    'Stack is now active with name - ' +
                    self.stack_settings.name)
                return self.__stack
            else:
                raise StackCreationError(
                    'Stack was not created or activated in the alloted amount '
                    'of time')
        else:
            logger.info('Did not create stack due to cleanup mode')

        return self.__stack

    def clean(self):
        """
        Cleanse environment of all artifacts
        :return: void
        """
        if self.__stack:
            try:
                heat_utils.delete_stack(self.__heat_cli, self.__stack)
            except HTTPNotFound:
                pass

        self.__stack = None

    def get_stack(self):
        """
        Returns the domain Stack object as it was populated when create() was
        called
        :return: the object
        """
        return self.__stack

    def get_outputs(self):
        """
        Returns the list of outputs as contained on the OpenStack Heat Stack
        object
        :return:
        """
        return heat_utils.get_stack_outputs(self.__heat_cli, self.__stack.id)

    def get_status(self):
        """
        Returns the list of outputs as contained on the OpenStack Heat Stack
        object
        :return:
        """
        return heat_utils.get_stack_status(self.__heat_cli, self.__stack.id)

    def stack_complete(self, block=False, timeout=None,
                       poll_interval=POLL_INTERVAL):
        """
        Returns true when the stack status returns the value of
        expected_status_code
        :param block: When true, thread will block until active or timeout
                      value in seconds has been exceeded (False)
        :param timeout: The timeout value
        :param poll_interval: The polling interval in seconds
        :return: T/F
        """
        if not timeout:
            timeout = self.stack_settings.stack_create_timeout
        return self._stack_status_check(STATUS_CREATE_COMPLETE, block, timeout,
                                        poll_interval)

    def _stack_status_check(self, expected_status_code, block, timeout,
                            poll_interval):
        """
        Returns true when the stack status returns the value of
        expected_status_code
        :param expected_status_code: stack status evaluated with this string
                                     value
        :param block: When true, thread will block until active or timeout
                      value in seconds has been exceeded (False)
        :param timeout: The timeout value
        :param poll_interval: The polling interval in seconds
        :return: T/F
        """
        # sleep and wait for stack status change
        if block:
            start = time.time()
        else:
            start = time.time() - timeout

        while timeout > time.time() - start:
            status = self._status(expected_status_code)
            if status:
                logger.debug(
                    'Stack is active with name - ' + self.stack_settings.name)
                return True

            logger.debug('Retry querying stack status in ' + str(
                poll_interval) + ' seconds')
            time.sleep(poll_interval)
            logger.debug('Stack status query timeout in ' + str(
                timeout - (time.time() - start)))

        logger.error(
            'Timeout checking for stack status for ' + expected_status_code)
        return False

    def _status(self, expected_status_code):
        """
        Returns True when active else False
        :param expected_status_code: stack status evaluated with this string
        value
        :return: T/F
        """
        status = self.get_status()
        if not status:
            logger.warning(
                'Cannot stack status for stack with ID - ' + self.__stack.id)
            return False

        if status == STATUS_CREATE_FAILED:
            raise StackCreationError('Stack had an error during deployment')
        logger.debug('Stack status is - ' + status)
        return status == expected_status_code


class StackSettings:
    def __init__(self, **kwargs):
        """
        Constructor
        :param name: the stack's name (required)
        :param template: the heat template in dict() format (required if
                         template_path attribute is None)
        :param template_path: the location of the heat template file (required
                              if template attribute is None)
        :param env_values: k/v pairs of strings for substitution of template
                           default values (optional)
        """

        self.name = kwargs.get('name')
        self.template = kwargs.get('template')
        self.template_path = kwargs.get('template_path')
        self.env_values = kwargs.get('env_values')
        if 'stack_create_timeout' in kwargs:
            self.stack_create_timeout = kwargs['stack_create_timeout']
        else:
            self.stack_create_timeout = STACK_COMPLETE_TIMEOUT

        if not self.name:
            raise StackSettingsError('name is required')

        if not self.template and not self.template_path:
            raise StackSettingsError('A Heat template is required')


class StackSettingsError(Exception):
    """
    Exception to be thrown when an stack settings are incorrect
    """

    def __init__(self, message):
        Exception.__init__(self, message)


class StackCreationError(Exception):
    """
    Exception to be thrown when an stack cannot be created
    """

    def __init__(self, message):
        Exception.__init__(self, message)