Commit 5d538c47 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

NBI - Camara QoD:

- Corrected path of connector
- Corrected unitary test
parent 3ed137dd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ unit_test nbi:
    - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_ietf_network.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_network.xml"
    - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_ietf_l3vpn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_l3vpn.xml"
    - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_etsi_bwm.py --junitxml=/opt/results/${IMAGE_NAME}_report_etsi_bwm.xml"
    - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_camara_qod.py --junitxml=/opt/results/${IMAGE_NAME}_report_camara_qod.xml"
    - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing"
  coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
  after_script:
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ from common.Settings import (
    wait_for_environment_variables
)
from .NbiApplication import NbiApplication
from .camara_qod import register_camara_qod
from .etsi_bwm import register_etsi_bwm_api
from .health_probes import register_health_probes
from .ietf_acl import register_ietf_acl
@@ -96,6 +97,7 @@ register_ietf_acl (nbi_app)
register_qkd_app         (nbi_app)
#register_topology_updates(nbi_app) # does not work; check if eventlet-grpc side effects
register_vntm_recommend  (nbi_app)
register_camara_qod      (nbi_app)
LOGGER.info('All connectors registered')

nbi_app.dump_configuration()
+9 −8
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ from typing import Dict
from uuid import uuid4
from flask.json import jsonify
from flask_restful import Resource, request
from common.proto.context_pb2 import  QoSProfileId, Uuid,Empty
from common.proto.context_pb2 import Empty, QoSProfileId, Uuid
from common.Constants import DEFAULT_CONTEXT_NAME
from context.client.ContextClient import ContextClient
from qos_profile.client.QoSProfileClient import QoSProfileClient
@@ -89,13 +89,12 @@ class ProfileDetail(_Resource):
            if exc.code() == grpc.StatusCode.NOT_FOUND:
                LOGGER.warning(f"QoSProfile not found: {qos_profile_id}")
                return {"error": f"QoSProfile {qos_profile_id} not found"}, 404
            LOGGER.error(f"gRPC error while fetching QoSProfile: {exc}")
            LOGGER.exception("gRPC error while fetching QoSProfile")
            return {"error": "Internal Server Error"}, 500
        except:
            LOGGER.exception(f"Error while fetching QoSProfile")
            LOGGER.exception("Error while fetching QoSProfile")
            return {"error": "Internal Server Error"}, 500

    
    def put(self, qos_profile_id):
        try:
            request_data = request.get_json() # get the json to do the update
@@ -105,13 +104,13 @@ class ProfileDetail(_Resource):
            qos_profile_updated = self.qos_profile_client.UpdateQoSProfile(qos_profile) # update the profile in the grpc server
            return grpc_message_to_qos_table_data(qos_profile_updated), 200
        except KeyError as e:
            LOGGER.error(f"Missing required key: {e}")
            LOGGER.exception("Missing required key")
            return {"error": f"Missing required key: {str(e)}"}, 400
        except grpc._channel._InactiveRpcError as exc:
            if exc.code() == grpc.StatusCode.NOT_FOUND:
                LOGGER.warning(f"QoSProfile not found for update: {qos_profile_id}")
                return {"error": f"QoSProfile {qos_profile_id} not found"}, 404
            LOGGER.error(f"gRPC error while updating QoSProfile: {exc}")
            LOGGER.exception("gRPC error while updating QoSProfile")
            return {"error": "Internal Server Error"}, 500
        except:
            LOGGER.exception(f"Error in PUT /profiles/{qos_profile_id}")
@@ -134,6 +133,7 @@ class ProfileDetail(_Resource):
            return {"error": "Internal Server Error"}, 500

### SESSION ##########################################################

class QodInfo(_Resource):
    def post(self):
        if not request.is_json:
@@ -164,6 +164,7 @@ class QodInfo(_Resource):
            return jsonify({'error': 'Internal Server Error', 'message': 'An unexpected error occurred'}), 500
        return response
        #didnt work return jsonify(response)

    def get(self):
        service_list = self.client.ListServices(grpc_context_id(DEFAULT_CONTEXT_NAME)) #return context id as json
        qod_info = [service_2_qod(service) for service in service_list.services] #iterating over service list 
@@ -180,6 +181,7 @@ class QodInfoID(_Resource):
            if exc.code()==grpc.StatusCode.NOT_FOUND:
                LOGGER.warning(f"Qod Session not found: {sessionId}")
                return {"error": f"Qod Session {sessionId} not found"}, 404

    def put(self, sessionId: str):
        try:
            request_data: Dict = request.get_json()
@@ -212,8 +214,7 @@ class QodInfoID(_Resource):
        except:
            LOGGER.exception(f"Error in PUT /sessions/{sessionId}")
            return {"error": "Internal Server Error"}, 500

    def delete(self, sessionId: str):
        self.service_client.DeleteService(grpc_service_id(DEFAULT_CONTEXT_NAME, sessionId))
        return{"Session Deleted"}

+14 −12
Original line number Diff line number Diff line
@@ -14,30 +14,32 @@

import json, logging, re, time
from flask.json import jsonify
from netaddr import IPAddress, IPNetwork
from uuid import uuid4
from common.proto.context_pb2 import (
    ContextId, Empty, EndPointId, ServiceId, ServiceStatusEnum, ServiceTypeEnum,
    Service,ConfigRule, ConfigRule_Custom,
    ConfigActionEnum)
    ConfigActionEnum, ConfigRule, ConfigRule_Custom, ContextId, Empty, EndPointId,
    QoSProfileId, Service, ServiceId, ServiceStatusEnum, ServiceTypeEnum, Uuid
)
from common.proto.qos_profile_pb2 import (
    QoSProfileValueUnitPair, QoSProfile,QoDConstraintsRequest
)
from common.tools.grpc.ConfigRules import update_config_rule_custom
from common.tools.grpc.Tools import grpc_message_to_json
from common.tools.object_factory.Context import json_context_id
from common.tools.object_factory.Service import json_service_id
from uuid import uuid4
from nbi.service.rest_server.nbi_plugins.ietf_network.bindings.networks import network
from qos_profile.client.QoSProfileClient import QoSProfileClient
from context.client.ContextClient import ContextClient
from common.proto.context_pb2 import QoSProfileId, Uuid,Empty,ServiceId
from common.proto.context_pb2 import Uuid, QoSProfileId
from common.proto.qos_profile_pb2 import QoSProfileValueUnitPair, QoSProfile,QoDConstraintsRequest
import logging
from netaddr import IPAddress, IPNetwork
from qos_profile.client.QoSProfileClient import QoSProfileClient


LOGGER = logging.getLogger(__name__)

ENDPOINT_SETTINGS_KEY = '/device[{:s}]/endpoint[{:s}]/vlan[{:d}]/settings'
DEVICE_SETTINGS_KEY = '/device[{:s}]/settings'
RE_CONFIG_RULE_IF_SUBIF = re.compile(r'^\/interface\[([^\]]+)\]\/subinterface\[([^\]]+)\]$')
MEC_CONSIDERED_FIELDS = ['device', 'applicationServer', 'qosProfile', 'sessionId', 'duration', 'startedAt', 'expiresAt', 'qosStatus']
MEC_CONSIDERED_FIELDS = [
    'device', 'applicationServer', 'qosProfile', 'sessionId', 'duration',
    'startedAt', 'expiresAt', 'qosStatus'
]

def __init__(self) -> None:
        super().__init__()
+22 −13
Original line number Diff line number Diff line
@@ -12,20 +12,29 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from nbi.service.rest_server.RestServer import RestServer
from nbi.service.NbiApplication import NbiApplication
from .Resources import ProfileList, ProfileDetail, QodInfo, QodInfoID

URL_PREFIX = '/camara/qod/v0'

# Use 'path' type since some identifiers might contain char '/' and Flask is unable to recognize them in 'string' type.
RESOURCES = [
    # (endpoint_name, resource_class, resource_url)
    ('camara.qod_session_info',    QodInfo,       '/sessions'),
    ('camara.qod_info_session_id', QodInfoID,     '/sessions/<sessionId>'),
    ('camara.qod.profile_list',    ProfileList,   '/profiles'),
    ('camara.qod.profile_detail',  ProfileDetail, '/profiles/<string:qos_profile_id>'),
]

def register_camara_qod(rest_server : RestServer):
    for endpoint_name, resource_class, resource_url in RESOURCES:
        rest_server.add_resource(resource_class, URL_PREFIX + resource_url, endpoint=endpoint_name)
def register_camara_qod(nbi_app : NbiApplication):
    nbi_app.add_rest_api_resource(
        QodInfo,
        URL_PREFIX + '/sessions',
        endpoint='camara.qod_session_info'
    )
    nbi_app.add_rest_api_resource(
        QodInfoID,
        URL_PREFIX + '/bw_allocations',
        endpoint='/sessions/<sessionId>'
    )
    nbi_app.add_rest_api_resource(
        ProfileList,
        URL_PREFIX + '/bw_allocations',
        endpoint='/profiles'
    )
    nbi_app.add_rest_api_resource(
        ProfileDetail,
        URL_PREFIX + '/bw_allocations',
        endpoint='/profiles/<string:qos_profile_id>'
    )
Loading