Skip to content
Snippets Groups Projects
alerts_specification_schema.py 6.06 KiB
Newer Older
#!/usr/bin/python3
"""
// © University of Southampton IT Innovation Centre, 2018
//
// Copyright in this software belongs to University of Southampton
// IT Innovation Centre of Gamma House, Enterprise Road,
// Chilworth Science Park, Southampton, SO16 7NS, UK.
//
// This software may not be used, sold, licensed, transferred, copied
// or reproduced in whole or in part in any manner or form or in or
// on any media by any person other than in accordance with the terms
// of the Licence Agreement supplied with the software, or otherwise
// without the prior written consent of the copyright owners.
//
// This software is distributed WITHOUT ANY WARRANTY, without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE, except where stated in the Licence Agreement supplied with
// the software.
//
//      Created By :            Nikolay Stanchev
//      Created Date :          16-08-2018
//      Created for Project :   FLAME
"""

# Python standard libs
import re
from schema import Schema, And, Or, Optional, SchemaError

# This module defines the schema objects for the TOSCA Alert Specification:
#
#         * flame_clmc_alerts_definitions.yaml must be the only import
#         * metadata section must be present (with key-value pairs for sfc and sfci)
#         * policies section must be present (under the topology_template node)
#         * each policy must be associated with a triggers node (containing at least 1 trigger)
#         * each policy is of type eu.ict-flame.policies.Alert
#         * each trigger must specify event_type, metric, condition, and at least one handler in action/implementation
#         * the condition section must specify threshold, granularity, aggregation_method, comparison_operator

SFEMC = "flame_sfemc"  # describes the keyword used for the SFEMC alert handler


# Influx QL functions defined in the documentation https://docs.influxdata.com/influxdb/v1.6/query_language/functions/
INFLUX_QL_FUNCTIONS = (
    "count", "mean", "median", "mode", "sum", "first", "last", "max", "min", "spread", "stddev"
)

# Kapacitor Tick Script template IDs
TICK_SCRIPT_TEMPLATES = ("threshold", "relative", "deadman")

# Allowed comparison operators and their logical values
COMPARISON_OPERATORS = {"lt": "<", "gt": ">", "lte": "<=", "gte": ">=", "eq": "==", "neq": "!="}

# Regular expression for validating http handlers
URL_REGEX = re.compile(
    r'^https?://'  # http:// or https://
    r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'  # domain, e.g. example.domain.com
    r'localhost|'  # or localhost...
    r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # or IP address (IPv4 format)
    r'(?::\d{2,5})?'  # optional port number
    r'(?:[/?#][^\s]*)?$',  # URL path or query parameters
    re.IGNORECASE)

# Global tags allowed to be used for filtering in the trigger condition
CLMC_INFORMATION_MODEL_GLOBAL_TAGS = {"flame_sfp", "flame_sf", "flame_server", "flame_location"}
# NOTICE that "flame_sfc", "flame_sfci" are not allowed, even though they are part of the CLMC Information Model
# This is because those two tags are automatically added to the InfluxDB queries - the required values are retrieved from the alert spec. metadata
# "flame_sfe" cannot be used as well, because the value of this tag is only known at runtime.

ALERTS_SPECIFICATION_SCHEMA = Schema({
    "tosca_definitions_version": And(str, lambda v: v == "tosca_simple_profile_for_nfv_1_0_0"),
    Optional("description"): str,
    "imports": And([lambda s: s.endswith("flame_clmc_alerts_definitions.yaml")], lambda l: len(l) == 1),
    "metadata": {
        # TODO next release - uncomment
        # "sfc": str,
        # "sfci": str
    },
    "topology_template": {
        "policies": [
            {
                str: {
                    "type": "eu.ict-flame.policies.Alert",
                    "triggers": And({
                        str: {
                            Optional("description"): str,
                            "event_type": And(str, lambda s: s in TICK_SCRIPT_TEMPLATES),
                            "metric": And(str, lambda s: len(s.split('.', 1)) == 2),
                            "condition": {
                                "threshold": Or(int, float),
                                "granularity": And(int, lambda p: p > 0),
                                Optional("aggregation_method"): And(str, lambda s: s in INFLUX_QL_FUNCTIONS),
                                Optional("resource_type"): {
                                    And(str, lambda s: s in CLMC_INFORMATION_MODEL_GLOBAL_TAGS): str
                                },
                                Optional("comparison_operator"): And(str, lambda s: s in COMPARISON_OPERATORS)
                                        Or(SFEMC, And(str, lambda s: URL_REGEX.match(s) is not None))
def validate_clmc_alerts_specification(tosca_yaml_tpl, include_error=False):
    CLMC validation for the TOSCA alerts specification, uses the schema defined in alerts_specification_schema.py
    :param tosca_yaml_tpl: the tosca template to validate (as python dictionary object)
    :param include_error: a flag indicating whether the output of the function should include a caught SchemaError
        (if set to True and no error is thrown, returns None as the error object)
    :return: True/False if the tosca_tpl is valid/invalid along with any error (None if no error) that was thrown during validation (if argument include_error is set to True)
    try:
        ALERTS_SPECIFICATION_SCHEMA.validate(tosca_yaml_tpl)
        valid, err = True, None
    except SchemaError as schema_error:
        valid, err = False, schema_error

    return valid