Skip to content
Snippets Groups Projects
Commit 4c479a1b authored by Shayan Hajipour's avatar Shayan Hajipour
Browse files

feat: constraints list retrieval added to QoSProfile component:

- test_crud.py refactored
- test_constraints.py added
- start_timestamp of Constraint_Schedule changed to double from float
parent 90d55e73
No related branches found
No related tags found
2 merge requests!294Release TeraFlowSDN 4.0,!257Resolve "Create QoSProfile component"
...@@ -68,11 +68,11 @@ service ContextService { ...@@ -68,11 +68,11 @@ service ContextService {
rpc GetSliceEvents (Empty ) returns (stream SliceEvent ) {} rpc GetSliceEvents (Empty ) returns (stream SliceEvent ) {}
rpc SelectSlice (SliceFilter ) returns ( SliceList ) {} rpc SelectSlice (SliceFilter ) returns ( SliceList ) {}
rpc CreateQoSProfile (QoSProfile ) returns (QoSProfile ) {} rpc CreateQoSProfile (QoSProfile ) returns ( QoSProfile ) {}
rpc UpdateQoSProfile (QoSProfile ) returns (QoSProfile ) {} rpc UpdateQoSProfile (QoSProfile ) returns ( QoSProfile ) {}
rpc DeleteQoSProfile (QoSProfileId ) returns (Empty ) {} rpc DeleteQoSProfile (QoSProfileId ) returns ( Empty ) {}
rpc GetQoSProfile (QoSProfileId ) returns (QoSProfile ) {} rpc GetQoSProfile (QoSProfileId ) returns ( QoSProfile ) {}
rpc GetQoSProfiles (Empty ) returns (stream QoSProfile) {} rpc GetQoSProfiles (Empty ) returns (stream QoSProfile ) {}
rpc ListConnectionIds (ServiceId ) returns ( ConnectionIdList) {} rpc ListConnectionIds (ServiceId ) returns ( ConnectionIdList) {}
rpc ListConnections (ServiceId ) returns ( ConnectionList ) {} rpc ListConnections (ServiceId ) returns ( ConnectionList ) {}
...@@ -419,6 +419,12 @@ message QoSProfileValueUnitPair { ...@@ -419,6 +419,12 @@ message QoSProfileValueUnitPair {
string unit = 2; string unit = 2;
} }
message QoDConstraintsRequest {
QoSProfileId qos_profile_id = 1;
double start_timestamp = 2;
float duration = 3;
}
message QoSProfile { message QoSProfile {
QoSProfileId qos_profile_id = 1; QoSProfileId qos_profile_id = 1;
string name = 2; string name = 2;
...@@ -571,7 +577,7 @@ message Constraint_Custom { ...@@ -571,7 +577,7 @@ message Constraint_Custom {
} }
message Constraint_Schedule { message Constraint_Schedule {
float start_timestamp = 1; double start_timestamp = 1;
float duration_days = 2; float duration_days = 2;
} }
...@@ -634,6 +640,22 @@ message Constraint_Exclusions { ...@@ -634,6 +640,22 @@ message Constraint_Exclusions {
repeated LinkId link_ids = 4; repeated LinkId link_ids = 4;
} }
message Constraint_QoSProfile {
QoSProfileValueUnitPair target_min_upstream_rate = 1;
QoSProfileValueUnitPair max_upstream_rate = 2;
QoSProfileValueUnitPair max_upstream_burst_rate = 3;
QoSProfileValueUnitPair target_min_downstream_rate = 4;
QoSProfileValueUnitPair max_downstream_rate = 5;
QoSProfileValueUnitPair max_downstream_burst_rate = 6;
QoSProfileValueUnitPair min_duration = 7;
QoSProfileValueUnitPair max_duration = 8;
int32 priority = 9;
QoSProfileValueUnitPair packet_delay_budget = 10;
QoSProfileValueUnitPair jitter = 11;
int32 packet_error_loss_rate = 12;
}
message Constraint { message Constraint {
ConstraintActionEnum action = 1; ConstraintActionEnum action = 1;
oneof constraint { oneof constraint {
...@@ -646,6 +668,7 @@ message Constraint { ...@@ -646,6 +668,7 @@ message Constraint {
Constraint_SLA_Availability sla_availability = 8; Constraint_SLA_Availability sla_availability = 8;
Constraint_SLA_Isolation_level sla_isolation = 9; Constraint_SLA_Isolation_level sla_isolation = 9;
Constraint_Exclusions exclusions = 10; Constraint_Exclusions exclusions = 10;
Constraint_QoSProfile qos_profile = 11;
} }
} }
......
...@@ -18,9 +18,10 @@ package qos_profile; ...@@ -18,9 +18,10 @@ package qos_profile;
import "context.proto"; import "context.proto";
service QoSProfileService { service QoSProfileService {
rpc CreateQoSProfile (context.QoSProfile ) returns (context.QoSProfile ) {} rpc CreateQoSProfile (context.QoSProfile ) returns (context.QoSProfile ) {}
rpc UpdateQoSProfile (context.QoSProfile ) returns (context.QoSProfile ) {} rpc UpdateQoSProfile (context.QoSProfile ) returns (context.QoSProfile ) {}
rpc DeleteQoSProfile (context.QoSProfileId) returns (context.Empty ) {} rpc DeleteQoSProfile (context.QoSProfileId ) returns (context.Empty ) {}
rpc GetQoSProfile (context.QoSProfileId) returns (context.QoSProfile ) {} rpc GetQoSProfile (context.QoSProfileId ) returns (context.QoSProfile ) {}
rpc GetQoSProfiles (context.Empty ) returns (stream context.QoSProfile) {} rpc GetQoSProfiles (context.Empty ) returns (stream context.QoSProfile ) {}
rpc GetConstraintListFromQoSProfile (context.QoDConstraintsRequest) returns (stream context.Constraint ) {}
} }
...@@ -16,7 +16,7 @@ from typing import Iterator ...@@ -16,7 +16,7 @@ from typing import Iterator
import grpc, logging import grpc, logging
from common.Constants import ServiceNameEnum from common.Constants import ServiceNameEnum
from common.Settings import get_service_host, get_service_port_grpc from common.Settings import get_service_host, get_service_port_grpc
from common.proto.context_pb2 import Empty, QoSProfileId, QoSProfile from common.proto.context_pb2 import Empty, QoSProfileId, QoSProfile, QoDConstraintsRequest, Constraint
from common.proto.qos_profile_pb2_grpc import QoSProfileServiceStub from common.proto.qos_profile_pb2_grpc import QoSProfileServiceStub
from common.tools.client.RetryDecorator import retry, delay_exponential from common.tools.client.RetryDecorator import retry, delay_exponential
from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.grpc.Tools import grpc_message_to_json_string
...@@ -80,3 +80,10 @@ class QoSProfileClient: ...@@ -80,3 +80,10 @@ class QoSProfileClient:
response = self.stub.GetQoSProfiles(request) response = self.stub.GetQoSProfiles(request)
LOGGER.debug('GetQoSProfiles result: {:s}'.format(grpc_message_to_json_string(response))) LOGGER.debug('GetQoSProfiles result: {:s}'.format(grpc_message_to_json_string(response)))
return 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)))
return response
\ No newline at end of file
...@@ -17,7 +17,7 @@ from typing import Iterator ...@@ -17,7 +17,7 @@ from typing import Iterator
import grpc._channel import grpc._channel
from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method
from common.proto.context_pb2 import Empty, QoSProfileId, QoSProfile from common.proto.context_pb2 import QoDConstraintsRequest, Constraint, ConstraintActionEnum, Constraint_QoSProfile, Constraint_Schedule, Empty, QoSProfileId, QoSProfile
from common.proto.qos_profile_pb2_grpc import QoSProfileServiceServicer from common.proto.qos_profile_pb2_grpc import QoSProfileServiceServicer
from context.client.ContextClient import ContextClient from context.client.ContextClient import ContextClient
...@@ -87,3 +87,36 @@ class QoSProfileServiceServicerImpl(QoSProfileServiceServicer): ...@@ -87,3 +87,36 @@ class QoSProfileServiceServicerImpl(QoSProfileServiceServicer):
context_client = ContextClient() context_client = ContextClient()
yield from context_client.GetQoSProfiles(request) yield from context_client.GetQoSProfiles(request)
@safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
def GetConstraintListFromQoSProfile(self, request: QoDConstraintsRequest, context: grpc.ServicerContext) -> Iterator[Constraint]:
context_client = ContextClient()
try:
qos_profile = context_client.GetQoSProfile(request.qos_profile_id)
except grpc._channel._InactiveRpcError as exc:
if exc.code() == grpc.StatusCode.NOT_FOUND:
context.set_details(f'QoSProfile {request.qos_profile_id.qos_profile_id.uuid} not found')
context.set_code(grpc.StatusCode.NOT_FOUND)
yield Constraint()
qos_profile_constraint = Constraint_QoSProfile()
qos_profile_constraint.target_min_upstream_rate.CopyFrom(qos_profile.targetMinUpstreamRate)
qos_profile_constraint.max_upstream_rate.CopyFrom(qos_profile.maxUpstreamRate)
qos_profile_constraint.max_upstream_burst_rate.CopyFrom(qos_profile.maxUpstreamBurstRate)
qos_profile_constraint.target_min_downstream_rate.CopyFrom(qos_profile.targetMinDownstreamRate)
qos_profile_constraint.max_downstream_rate.CopyFrom(qos_profile.maxDownstreamRate)
qos_profile_constraint.max_downstream_burst_rate.CopyFrom(qos_profile.maxDownstreamBurstRate)
qos_profile_constraint.min_duration.CopyFrom(qos_profile.minDuration)
qos_profile_constraint.max_duration.CopyFrom(qos_profile.maxDuration)
qos_profile_constraint.priority = qos_profile.priority
qos_profile_constraint.packet_delay_budget.CopyFrom(qos_profile.packetDelayBudget)
qos_profile_constraint.jitter.CopyFrom(qos_profile.jitter)
qos_profile_constraint.packet_error_loss_rate =qos_profile.packetErrorLossRate
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
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
import pytest import pytest
from qos_profile.client.QoSProfileClient import QoSProfileClient from qos_profile.client.QoSProfileClient import QoSProfileClient
from common.proto.context_pb2 import Uuid, QoSProfileValueUnitPair, QoSProfileId, QoSProfile
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def qos_profile_client(): def qos_profile_client():
...@@ -21,3 +22,26 @@ def qos_profile_client(): ...@@ -21,3 +22,26 @@ def qos_profile_client():
yield _client yield _client
_client.close() _client.close()
def create_qos_profile_from_json(qos_profile_data: dict) -> QoSProfile:
def create_QoSProfileValueUnitPair(data) -> QoSProfileValueUnitPair:
return QoSProfileValueUnitPair(value=data['value'], unit=data['unit'])
qos_profile = QoSProfile()
qos_profile.qos_profile_id.CopyFrom(QoSProfileId(qos_profile_id=Uuid(uuid=qos_profile_data['qos_profile_id'])))
qos_profile.name = qos_profile_data['name']
qos_profile.description = qos_profile_data['description']
qos_profile.status = qos_profile_data['status']
qos_profile.targetMinUpstreamRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['targetMinUpstreamRate']))
qos_profile.maxUpstreamRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxUpstreamRate']))
qos_profile.maxUpstreamBurstRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxUpstreamBurstRate']))
qos_profile.targetMinDownstreamRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['targetMinDownstreamRate']))
qos_profile.maxDownstreamRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxDownstreamRate']))
qos_profile.maxDownstreamBurstRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxDownstreamBurstRate']))
qos_profile.minDuration.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['minDuration']))
qos_profile.maxDuration.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxDuration']))
qos_profile.priority = qos_profile_data['priority']
qos_profile.packetDelayBudget.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['packetDelayBudget']))
qos_profile.jitter.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['jitter']))
qos_profile.packetErrorLossRate = qos_profile_data['packetErrorLossRate']
return qos_profile
\ No newline at end of file
# Copyright 2022-2024 ETSI OSG/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 logging
from google.protobuf.json_format import MessageToDict
from common.proto.context_pb2 import QoDConstraintsRequest
from common.tools.grpc.Tools import grpc_message_to_json_string
from qos_profile.client.QoSProfileClient import QoSProfileClient
from .conftest import create_qos_profile_from_json
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)
qos_profile_data = {
"qos_profile_id": "0afc905f-f1f0-4ae2-9925-9df17140b8bf",
"name": "QCI_2_voice",
"description": "QoS profile for game streaming",
"status": "ACTIVE",
"targetMinUpstreamRate": {
"value": 5,
"unit": "bps"
},
"maxUpstreamRate": {
"value": 5,
"unit": "bps"
},
"maxUpstreamBurstRate": {
"value": 5,
"unit": "bps"
},
"targetMinDownstreamRate": {
"value": 5,
"unit": "bps"
},
"maxDownstreamRate": {
"value": 5,
"unit": "bps"
},
"maxDownstreamBurstRate": {
"value": 5,
"unit": "bps"
},
"minDuration": {
"value": 5,
"unit": "Minutes"
},
"maxDuration": {
"value": 6,
"unit": "Minutes"
},
"priority": 5,
"packetDelayBudget": {
"value": 5,
"unit": "Minutes"
},
"jitter": {
"value": 5,
"unit": "Minutes"
},
"packetErrorLossRate": 3
}
target_qos_profile_constraint = {
"action": "CONSTRAINTACTION_SET",
"qos_profile": {
"target_min_upstream_rate": {
"value": 5,
"unit": "bps"
},
"max_upstream_rate": {
"value": 5,
"unit": "bps"
},
"max_upstream_burst_rate": {
"value": 5,
"unit": "bps"
},
"target_min_downstream_rate": {
"value": 5,
"unit": "bps"
},
"max_downstream_rate": {
"value": 5,
"unit": "bps"
},
"max_downstream_burst_rate": {
"value": 5,
"unit": "bps"
},
"min_duration": {
"value": 5,
"unit": "Minutes"
},
"max_duration": {
"value": 6,
"unit": "Minutes"
},
"priority": 5,
"packet_delay_budget": {
"value": 5,
"unit": "Minutes"
},
"jitter": {
"value": 5,
"unit": "Minutes"
},
"packet_error_loss_rate": 3
}
}
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
assert constraint_1.WhichOneof('constraint') == 'qos_profile'
print(MessageToDict(constraint_1, preserving_proto_field_name=True))
assert MessageToDict(constraint_1, preserving_proto_field_name=True) == target_qos_profile_constraint
assert constraint_2.WhichOneof('constraint') == 'schedule'
assert constraint_2.schedule.start_timestamp == 1726063284.25332
assert constraint_2.schedule.duration_days == 1
qos_profile_client.DeleteQoSProfile(qos_profile.qos_profile_id)
\ No newline at end of file
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
from grpc import RpcError, StatusCode from grpc import RpcError, StatusCode
import logging, pytest import logging, pytest
from common.proto.context_pb2 import Empty, Uuid, QoSProfileValueUnitPair, QoSProfileId, QoSProfile from .conftest import create_qos_profile_from_json
from common.proto.context_pb2 import Empty, Uuid, QoSProfileId
from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.grpc.Tools import grpc_message_to_json_string
from qos_profile.client.QoSProfileClient import QoSProfileClient from qos_profile.client.QoSProfileClient import QoSProfileClient
...@@ -71,28 +71,6 @@ qos_profile_data = { ...@@ -71,28 +71,6 @@ qos_profile_data = {
"packetErrorLossRate": 3 "packetErrorLossRate": 3
} }
def create_qos_profile_from_json(qos_profile_data: dict) -> QoSProfile:
def create_QoSProfileValueUnitPair(data) -> QoSProfileValueUnitPair:
return QoSProfileValueUnitPair(value=data['value'], unit=data['unit'])
qos_profile = QoSProfile()
qos_profile.qos_profile_id.CopyFrom(QoSProfileId(qos_profile_id=Uuid(uuid=qos_profile_data['qos_profile_id'])))
qos_profile.name = qos_profile_data['name']
qos_profile.description = qos_profile_data['description']
qos_profile.status = qos_profile_data['status']
qos_profile.targetMinUpstreamRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['targetMinUpstreamRate']))
qos_profile.maxUpstreamRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxUpstreamRate']))
qos_profile.maxUpstreamBurstRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxUpstreamBurstRate']))
qos_profile.targetMinDownstreamRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['targetMinDownstreamRate']))
qos_profile.maxDownstreamRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxDownstreamRate']))
qos_profile.maxDownstreamBurstRate.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxDownstreamBurstRate']))
qos_profile.minDuration.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['minDuration']))
qos_profile.maxDuration.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['maxDuration']))
qos_profile.priority = qos_profile_data['priority']
qos_profile.packetDelayBudget.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['packetDelayBudget']))
qos_profile.jitter.CopyFrom(create_QoSProfileValueUnitPair(qos_profile_data['jitter']))
qos_profile.packetErrorLossRate = qos_profile_data['packetErrorLossRate']
return qos_profile
def test_create_qos_profile(qos_profile_client: QoSProfileClient): def test_create_qos_profile(qos_profile_client: QoSProfileClient):
qos_profile = create_qos_profile_from_json(qos_profile_data) qos_profile = create_qos_profile_from_json(qos_profile_data)
qos_profile_created = qos_profile_client.CreateQoSProfile(qos_profile) qos_profile_created = qos_profile_client.CreateQoSProfile(qos_profile)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment