Passed
Pull Request — master (#226)
by Italo Valcy
03:28
created

build.utils.compare_endpoint_trace()   A

Complexity

Conditions 3

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3.1406

Importance

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