Commit 5234259e authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

QoS Profile component:

- Corrected signature of methods to retrieve existing QoS Profiles and Constraints for a QoS Profile
- Implemented Mock QoSProfile Servicer
parent ea2cafc6
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -47,12 +47,19 @@ message QoSProfile {
  int32 packetErrorLossRate = 16;
}

message QoSProfileList {
  repeated QoSProfile qos_profiles = 1;
}

message ConstraintList {
  repeated context.Constraint constraints = 1;
}

service QoSProfileService {
  rpc CreateQoSProfile            (QoSProfile           ) returns (QoSProfile    ) {}
  rpc UpdateQoSProfile            (QoSProfile           ) returns (QoSProfile    ) {}
  rpc DeleteQoSProfile            (context.QoSProfileId ) returns (context.Empty ) {}
  rpc GetQoSProfile               (context.QoSProfileId ) returns (QoSProfile    ) {}
  rpc GetQoSProfiles                  (context.Empty        ) returns (stream QoSProfile        ) {}
  rpc GetConstraintListFromQoSProfile (QoDConstraintsRequest) returns (stream context.Constraint) {}
  rpc GetQoSProfiles              (context.Empty        ) returns (QoSProfileList) {}
  rpc GetConstraintsFromQoSProfile(QoDConstraintsRequest) returns (ConstraintList) {}
}
+75 −0
Original line number Diff line number Diff line
# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import grpc, logging
from typing import Iterator
from common.proto.context_pb2 import Constraint, Empty, QoSProfileId
from common.proto.qos_profile_pb2 import ConstraintList, QoDConstraintsRequest, QoSProfile, QoSProfileList
from common.proto.qos_profile_pb2_grpc import QoSProfileServiceServicer
from common.tools.grpc.Tools import grpc_message_to_json_string
from common.tools.object_factory.Constraint import json_constraint_qos_profile, json_constraint_schedule
from .InMemoryObjectDatabase import InMemoryObjectDatabase

LOGGER = logging.getLogger(__name__)

class MockServicerImpl_QoSProfile(QoSProfileServiceServicer):
    def __init__(self):
        LOGGER.debug('[__init__] Creating Servicer...')
        self.obj_db = InMemoryObjectDatabase()
        LOGGER.debug('[__init__] Servicer Created')

    def GetQoSProfiles(self, request : Empty, context : grpc.ServicerContext) -> QoSProfileList:
        LOGGER.debug('[GetQoSProfiles] request={:s}'.format(grpc_message_to_json_string(request)))
        reply = QoSProfileList(qos_profiles=self.obj_db.get_entries('qos_profile'))
        LOGGER.debug('[GetQoSProfiles] reply={:s}'.format(grpc_message_to_json_string(reply)))
        return reply

    def GetQoSProfile(self, request : QoSProfileId, context : grpc.ServicerContext) -> QoSProfile:
        LOGGER.debug('[GetQoSProfile] request={:s}'.format(grpc_message_to_json_string(request)))
        reply = self.obj_db.get_entry('qos_profile', request.qos_profile_id.uuid, context)
        LOGGER.debug('[GetQoSProfile] reply={:s}'.format(grpc_message_to_json_string(reply)))
        return reply

    def CreateQoSProfile(self, request : QoSProfile, context : grpc.ServicerContext) -> QoSProfile:
        LOGGER.debug('[CreateQoSProfile] request={:s}'.format(grpc_message_to_json_string(request)))
        reply = self.obj_db.set_entry('qos_profile', request.qos_profile_id.qos_profile_id.uuid, request)
        LOGGER.debug('[CreateQoSProfile] reply={:s}'.format(grpc_message_to_json_string(reply)))
        return reply

    def UpdateQoSProfile(self, request : QoSProfile, context : grpc.ServicerContext) -> QoSProfile:
        LOGGER.debug('[UpdateQoSProfile] request={:s}'.format(grpc_message_to_json_string(request)))
        reply = self.obj_db.set_entry('qos_profile', request.qos_profile_id.qos_profile_id.uuid, request)
        LOGGER.debug('[UpdateQoSProfile] reply={:s}'.format(grpc_message_to_json_string(reply)))
        return reply

    def DeleteQoSProfile(self, request : QoSProfileId, context : grpc.ServicerContext) -> Empty:
        LOGGER.debug('[DeleteQoSProfile] request={:s}'.format(grpc_message_to_json_string(request)))
        self.obj_db.del_entry('qos_profile', request.qos_profile_id.uuid, context)
        reply = Empty()
        LOGGER.debug('[DeleteQoSProfile] reply={:s}'.format(grpc_message_to_json_string(reply)))
        return reply

    def GetConstraintsFromQoSProfile(
        self, request: QoDConstraintsRequest, context: grpc.ServicerContext
    ) -> ConstraintList:
        LOGGER.debug('[GetConstraintsFromQoSProfile] request={:s}'.format(grpc_message_to_json_string(request)))
        qos_profile = self.obj_db.get_entry(
            'qos_profile', request.qos_profile_id.qos_profile_id.uuid, context
        )
        reply = ConstraintList(constraints=[
            Constraint(**json_constraint_qos_profile(qos_profile.qos_profile_id, qos_profile.name)),
            Constraint(**json_constraint_schedule(request.start_timestamp, request.duration / 86400)),
        ])
        LOGGER.debug('[GetConstraintsFromQoSProfile] reply={:s}'.format(grpc_message_to_json_string(reply)))
        return reply
+6 −8
Original line number Diff line number Diff line
@@ -12,13 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Iterator
import grpc, logging
from common.Constants import ServiceNameEnum
from common.Settings import get_service_host, get_service_port_grpc
from common.proto.context_pb2 import Empty, QoSProfileId
from common.proto.qos_profile_pb2 import QoSProfile, QoDConstraintsRequest
from common.proto.context_pb2 import Constraint
from common.proto.qos_profile_pb2 import ConstraintList, QoSProfile, QoDConstraintsRequest, QoSProfileList
from common.proto.qos_profile_pb2_grpc import QoSProfileServiceStub
from common.tools.client.RetryDecorator import retry, delay_exponential
from common.tools.grpc.Tools import grpc_message_to_json_string
@@ -77,15 +75,15 @@ class QoSProfileClient:
        return response

    @RETRY_DECORATOR
    def GetQoSProfiles(self, request: Empty) -> Iterator[QoSProfile]:
    def GetQoSProfiles(self, request: Empty) -> QoSProfileList:
        LOGGER.debug('GetQoSProfiles request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.GetQoSProfiles(request)
        LOGGER.debug('GetQoSProfiles result: {:s}'.format(grpc_message_to_json_string(response)))
        return response

    @RETRY_DECORATOR
    def GetConstraintListFromQoSProfile(self, request: QoDConstraintsRequest) -> Iterator[Constraint]:
        LOGGER.debug('GetConstraintListFromQoSProfile request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.GetConstraintListFromQoSProfile(request)
        LOGGER.debug('GetConstraintListFromQoSProfile result: {:s}'.format(grpc_message_to_json_string(response)))
    def GetConstraintsFromQoSProfile(self, request: QoDConstraintsRequest) -> ConstraintList:
        LOGGER.debug('GetConstraintsFromQoSProfile request: {:s}'.format(grpc_message_to_json_string(request)))
        response = self.stub.GetConstraintsFromQoSProfile(request)
        #LOGGER.debug('GetConstraintsFromQoSProfile result: {:s}'.format(grpc_message_to_json_string(response)))
        return response
+17 −21
Original line number Diff line number Diff line
@@ -13,13 +13,12 @@
# limitations under the License.

import grpc, logging, sqlalchemy
from typing import Iterator

import grpc._channel
from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method
from common.proto.context_pb2 import Constraint, ConstraintActionEnum, Constraint_QoSProfile, Constraint_Schedule, Empty, QoSProfileId
from common.proto.qos_profile_pb2 import QoSProfile, QoDConstraintsRequest
from common.proto.context_pb2 import Constraint, Empty, QoSProfileId
from common.proto.qos_profile_pb2 import ConstraintList, QoSProfile, QoDConstraintsRequest, QoSProfileList
from common.proto.qos_profile_pb2_grpc import QoSProfileServiceServicer
from common.tools.grpc.Tools import grpc_message_to_json_string
from common.tools.object_factory.Constraint import json_constraint_qos_profile, json_constraint_schedule
from .database.QoSProfile import set_qos_profile, delete_qos_profile, get_qos_profile, get_qos_profiles


@@ -71,26 +70,23 @@ class QoSProfileServiceServicerImpl(QoSProfileServiceServicer):
        return qos_profile

    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
    def GetQoSProfiles(self, request: Empty, context: grpc.ServicerContext) -> Iterator[QoSProfile]:
        yield from get_qos_profiles(self.db_engine, request)

    def GetQoSProfiles(self, request: Empty, context: grpc.ServicerContext) -> QoSProfileList:
        return QoSProfileList(qos_profiles=get_qos_profiles(self.db_engine, request))

    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
    def GetConstraintListFromQoSProfile(self, request: QoDConstraintsRequest, context: grpc.ServicerContext) -> Iterator[Constraint]:
    def GetConstraintsFromQoSProfile(
        self, request: QoDConstraintsRequest, context: grpc.ServicerContext
    ) -> ConstraintList:
        LOGGER.debug('[GetConstraintsFromQoSProfile] request={:s}'.format(grpc_message_to_json_string(request)))
        qos_profile = get_qos_profile(self.db_engine, request.qos_profile_id.qos_profile_id.uuid)
        if qos_profile is None:
            context.set_details(f'QoSProfile {request.qos_profile_id.qos_profile_id.uuid} not found')
            context.set_code(grpc.StatusCode.NOT_FOUND)
            yield Constraint()
            return ConstraintList()

        qos_profile_constraint = Constraint_QoSProfile()
        qos_profile_constraint.qos_profile_name = qos_profile.name
        qos_profile_constraint.qos_profile_id.CopyFrom(qos_profile.qos_profile_id)
        constraint_qos = Constraint()
        constraint_qos.action = ConstraintActionEnum.CONSTRAINTACTION_SET
        constraint_qos.qos_profile.CopyFrom(qos_profile_constraint)
        yield constraint_qos
        constraint_schedule = Constraint()
        constraint_schedule.action = ConstraintActionEnum.CONSTRAINTACTION_SET
        constraint_schedule.schedule.CopyFrom(Constraint_Schedule(start_timestamp=request.start_timestamp, duration_days=request.duration/86400))
        yield constraint_schedule
        reply = ConstraintList(constraints=[
            Constraint(**json_constraint_qos_profile(qos_profile.qos_profile_id, qos_profile.name)),
            Constraint(**json_constraint_schedule(request.start_timestamp, request.duration)),
        ])
        LOGGER.debug('[GetConstraintsFromQoSProfile] reply={:s}'.format(grpc_message_to_json_string(reply)))
        return reply
+10 −6
Original line number Diff line number Diff line
@@ -78,15 +78,19 @@ def test_get_constraints(qos_profile_client: QoSProfileClient):
    qos_profile = create_qos_profile_from_json(qos_profile_data)
    qos_profile_created = qos_profile_client.CreateQoSProfile(qos_profile)
    LOGGER.info('qos_profile_data = {:s}'.format(grpc_message_to_json_string(qos_profile_created)))
    constraints = list(qos_profile_client.GetConstraintListFromQoSProfile(QoDConstraintsRequest(
        qos_profile_id=qos_profile.qos_profile_id, start_timestamp=1726063284.25332, duration=86400)
      ))
    constraint_1 = constraints[0]
    constraint_2 = constraints[1]
    assert len(constraints) == 2
    constraints = qos_profile_client.GetConstraintsFromQoSProfile(
        QoDConstraintsRequest(
            qos_profile_id=qos_profile.qos_profile_id, start_timestamp=1726063284.25332, duration=86400
        )
    )
    assert len(constraints.constraints) == 2

    constraint_1 = constraints.constraints[0]
    assert constraint_1.WhichOneof('constraint') == 'qos_profile'
    assert constraint_1.qos_profile.qos_profile_id == qos_profile.qos_profile_id
    assert constraint_1.qos_profile.qos_profile_name == 'QCI_2_voice'

    constraint_2 = constraints.constraints[1]
    assert constraint_2.WhichOneof('constraint') == 'schedule'
    assert constraint_2.schedule.start_timestamp == 1726063284.25332
    assert constraint_2.schedule.duration_days == 1