Commit e3f502c3 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Merge branch 'feat/299-tid-modify-nbi-to-update-slice-l3vpn' into 'develop'

Resolve "(TID) Modify NBI to Update Slice L3VPN"

See merge request !360
parents 785f2570 bc4d8343
Loading
Loading
Loading
Loading
+59 −3
Original line number Diff line number Diff line
@@ -215,3 +215,59 @@ def process_site(site : Dict, errors : List[Dict]) -> None:
    network_accesses : List[Dict] = site['site-network-accesses']['site-network-access']
    for network_access in network_accesses:
        process_site_network_access(site_id, network_access, site_static_routing, errors)

def update_vpn(site : Dict, errors : List[Dict]) -> None:

    if site['management']['type'] != 'ietf-l3vpn-svc:provider-managed':
        MSG = 'Site Management Type: {:s}'
        raise NotImplementedError(MSG.format(str(site['management']['type'])))

    network_accesses : List[Dict] = site['site-network-accesses']['site-network-access']
    for network_access in network_accesses:
        update_site_network_access(network_access, errors)

def update_site_network_access(
    network_access : Dict, errors : List[Dict]
) -> None:

    if network_access['site-network-access-type'] != 'ietf-l3vpn-svc:multipoint':
        MSG = 'Site Network Access Type: {:s}'
        raise NotImplementedError(MSG.format(str(network_access['site-network-access-type'])))

    service_uuid = network_access['vpn-attachment']['vpn-id']

    service_input_bandwidth  = network_access['service']['svc-input-bandwidth']
    service_output_bandwidth = network_access['service']['svc-output-bandwidth']
    service_bandwidth_bps    = max(service_input_bandwidth, service_output_bandwidth)
    service_bandwidth_gbps   = service_bandwidth_bps / 1.e9

    max_e2e_latency_ms = None
    availability       = None

    exc = update_site_endpoint(
        service_uuid, capacity_gbps=service_bandwidth_gbps,
        e2e_latency_ms=max_e2e_latency_ms, availability=availability,
    )
    if exc is not None: errors.append({'error': str(exc)})

def update_site_endpoint(
    service_uuid : str, capacity_gbps : Optional[float] = None,
    e2e_latency_ms : Optional[float] = None, availability : Optional[float] = None,
    context_uuid : Optional[str] = DEFAULT_CONTEXT_NAME
) -> Optional[Exception]:
    context_client = ContextClient()
    service = get_service_by_uuid(context_client, service_uuid, context_uuid=context_uuid, rw_copy=True)
    if service is None: raise Exception('VPN({:s}) not found in database'.format(str(service_uuid)))

    constraints  = service.service_constraints
    if capacity_gbps  is not None: update_constraint_sla_capacity    (constraints, capacity_gbps)
    if e2e_latency_ms is not None: update_constraint_sla_latency     (constraints, e2e_latency_ms)
    if availability   is not None: update_constraint_sla_availability(constraints, 1, True, availability)

    try:
        service_client = ServiceClient()
        service_client.UpdateService(service)
        return None
    except Exception as e: # pylint: disable=broad-except
        LOGGER.exception('Unhandled exception updating Service')
        return e
+40 −2
Original line number Diff line number Diff line
@@ -20,8 +20,12 @@ from common.proto.context_pb2 import ServiceStatusEnum
from common.tools.context_queries.Service import get_service_by_uuid
from context.client.ContextClient import ContextClient
from service.client.ServiceClient import ServiceClient
from nbi.service._tools.Authentication import HTTP_AUTH
from nbi.service._tools.HttpStatusCodes import HTTP_GATEWAYTIMEOUT, HTTP_NOCONTENT, HTTP_OK, HTTP_SERVERERROR
from typing import Dict, List
from ..tools.Authentication import HTTP_AUTH
from ..tools.HttpStatusCodes import HTTP_GATEWAYTIMEOUT, HTTP_NOCONTENT, HTTP_OK, HTTP_SERVERERROR, HTTP_CREATED
from .Handlers import  update_vpn
from werkzeug.exceptions import UnsupportedMediaType
from .YangValidator import YangValidator

LOGGER = logging.getLogger(__name__)

@@ -76,3 +80,37 @@ class L3VPN_Service(Resource):
            response = jsonify({'error': str(e)})
            response.status_code = HTTP_SERVERERROR
        return response

    def put(self, vpn_id : str):
        #TODO: check vpn_id with request service_id in body
        if not request.is_json: raise UnsupportedMediaType('JSON payload is required')
        request_data: Dict = request.json
        LOGGER.debug('PUT Request: {:s}'.format(str(request_data)))

        errors = list()

        if 'ietf-l3vpn-svc:l3vpn-services' in request_data:
            for l3vpn_svc in request_data['ietf-l3vpn-svc:l3vpn-services']['l3vpn-svc']:
                l3vpn_svc.pop('service-id', None)
                l3vpn_svc_request_data = {'ietf-l3vpn-svc:l3vpn-svc': l3vpn_svc}
                errors.extend(self._update_l3vpn(l3vpn_svc_request_data))
        elif 'ietf-l3vpn-svc:l3vpn-svc' in request_data:
            errors.extend(self._update_l3vpn(request_data))
        else:
            errors.append('Unexpected request format: {:s}'.format(str(request_data)))

        response = jsonify(errors)
        response.status_code = HTTP_CREATED if len(errors) == 0 else HTTP_SERVERERROR
        return response

    def _update_l3vpn(self, request_data: Dict) -> List[Dict]:
        yang_validator = YangValidator('ietf-l3vpn-svc')
        request_data = yang_validator.parse_to_dict(request_data)
        yang_validator.destroy()

        errors = list()

        for site in request_data['l3vpn-svc']['sites']['site']:
            update_vpn(site, errors)

        return errors