build.utils   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 67
dl 0
loc 100
rs 10
c 0
b 0
f 0
wmc 9

5 Functions

Rating   Name   Duplication   Size   Complexity  
A emit_event() 0 5 1
A compare_endpoint_trace() 0 6 1
A load_spec() 0 9 1
B validate() 0 51 5
A notify_link_available_tags() 0 3 1
1
"""Utility functions."""
2
import functools
3
from pathlib import Path
4
5
from flask import request
6
from openapi_core import create_spec
7
from openapi_core.contrib.flask import FlaskOpenAPIRequest
8
from openapi_core.validation.request.validators import RequestValidator
9
from openapi_spec_validator import validate_spec
10
from openapi_spec_validator.readers import read_from_filename
11
from werkzeug.exceptions import BadRequest, UnsupportedMediaType
12
13
from kytos.core import log
14
from kytos.core.events import KytosEvent
15
16
17
def emit_event(controller, name, **kwargs):
18
    """Send an event when something happens with an EVC."""
19
    event_name = f"kytos/mef_eline.{name}"
20
    event = KytosEvent(name=event_name, content=kwargs)
21
    controller.buffers.app.put(event)
22
23
24
def notify_link_available_tags(controller, link):
25
    """Notify link available tags."""
26
    emit_event(controller, "link_available_tags", link=link)
27
28
29
def compare_endpoint_trace(endpoint, vlan, trace):
30
    """Compare and endpoint with a trace step."""
31
    return (
32
        endpoint.switch.dpid == trace["dpid"]
33
        and endpoint.port_number == trace["port"]
34
        and vlan == trace["vlan"]
35
    )
36
37
38
def load_spec():
39
    """Validate openapi spec."""
40
    napp_dir = Path(__file__).parent
41
    yml_file = napp_dir / "openapi.yml"
42
    spec_dict, _ = read_from_filename(yml_file)
43
44
    validate_spec(spec_dict)
45
46
    return create_spec(spec_dict)
47
48
49
def validate(spec):
50
    """Decorator to validate a REST endpoint input.
51
52
    Uses the schema defined in the openapi.yml file
53
    to validate.
54
    """
55
56
    def validate_decorator(func):
57
        @functools.wraps(func)
58
        def wrapper_validate(*args, **kwargs):
59
            try:
60
                data = request.get_json()
61
            except BadRequest:
62
                result = "The request body is not a well-formed JSON."
63
                log.debug("create_circuit result %s %s", result, 400)
64
                raise BadRequest(result) from BadRequest
65
            if data is None:
66
                result = "The request body mimetype is not application/json."
67
                log.debug("update result %s %s", result, 415)
68
                raise UnsupportedMediaType(result)
69
70
            validator = RequestValidator(spec)
71
            openapi_request = FlaskOpenAPIRequest(request)
72
            result = validator.validate(openapi_request)
73
            if result.errors:
74
                errors = result.errors[0]
75
                if hasattr(errors, "schema_errors"):
76
                    schema_errors = errors.schema_errors[0]
77
                    error_log = {
78
                        "error_message": schema_errors.message,
79
                        "error_validator": schema_errors.validator,
80
                        "error_validator_value": schema_errors.validator_value,
81
                        "error_path": list(schema_errors.path),
82
                        "error_schema": schema_errors.schema,
83
                        "error_schema_path": list(schema_errors.schema_path),
84
                    }
85
                    log.debug("error response: %s", error_log)
86
                    error_response = f"{schema_errors.message} for field"
87
                    error_response += (
88
                        f" {'/'.join(map(str,schema_errors.path))}."
89
                    )
90
                else:
91
                    error_response = (
92
                        "The request body mimetype is not application/json."
93
                    )
94
                raise BadRequest(error_response) from BadRequest
95
            return func(*args, data=data, **kwargs)
96
97
        return wrapper_validate
98
99
    return validate_decorator
100