diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py index edb5095b99f393a040e976c3841d82349a0d9450..d93a8f05927730f8b423b50f3febf43ba0ffc249 100644 --- a/src/context/service/ContextServiceServicerImpl.py +++ b/src/context/service/ContextServiceServicerImpl.py @@ -18,7 +18,6 @@ import grpc, json, logging, sqlalchemy #from sqlalchemy.dialects.postgresql import UUID, insert from typing import Iterator from common.message_broker.MessageBroker import MessageBroker -#from common.orm.backend.Tools import key_to_str from common.proto.context_pb2 import ( Connection, ConnectionEvent, ConnectionId, ConnectionIdList, ConnectionList, Context, ContextEvent, ContextId, ContextIdList, ContextList, @@ -39,6 +38,7 @@ from .database.Context import context_delete, context_get, context_list_ids, con from .database.Device import device_delete, device_get, device_list_ids, device_list_objs, device_set from .database.Link import link_delete, link_get, link_list_ids, link_list_objs, link_set from .database.Service import service_delete, service_get, service_list_ids, service_list_objs, service_set +from .database.Slice import slice_delete, slice_get, slice_list_ids, slice_list_objs, slice_set, slice_unset from .database.Topology import topology_delete, topology_get, topology_list_ids, topology_list_objs, topology_set #from common.tools.grpc.Tools import grpc_message_to_json, grpc_message_to_json_string #from context.service.Database import Database @@ -265,180 +265,38 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # ----- Slice ---------------------------------------------------------------------------------------------------- -# @safe_and_metered_rpc_method(METRICS, LOGGER) -# def ListSliceIds(self, request : ContextId, context : grpc.ServicerContext) -> SliceIdList: -# with self.lock: -# db_context : ContextModel = get_object(self.database, ContextModel, request.context_uuid.uuid) -# db_slices : Set[SliceModel] = get_related_objects(db_context, SliceModel) -# db_slices = sorted(db_slices, key=operator.attrgetter('pk')) -# return SliceIdList(slice_ids=[db_slice.dump_id() for db_slice in db_slices]) + @safe_and_metered_rpc_method(METRICS, LOGGER) + def ListSliceIds(self, request : ContextId, context : grpc.ServicerContext) -> SliceIdList: + return slice_list_ids(self.db_engine, request) -# @safe_and_metered_rpc_method(METRICS, LOGGER) -# def ListSlices(self, request : ContextId, context : grpc.ServicerContext) -> SliceList: -# with self.lock: -# db_context : ContextModel = get_object(self.database, ContextModel, request.context_uuid.uuid) -# db_slices : Set[SliceModel] = get_related_objects(db_context, SliceModel) -# db_slices = sorted(db_slices, key=operator.attrgetter('pk')) -# return SliceList(slices=[db_slice.dump() for db_slice in db_slices]) + @safe_and_metered_rpc_method(METRICS, LOGGER) + def ListSlices(self, request : ContextId, context : grpc.ServicerContext) -> SliceList: + return slice_list_objs(self.db_engine, request) -# @safe_and_metered_rpc_method(METRICS, LOGGER) -# def GetSlice(self, request : SliceId, context : grpc.ServicerContext) -> Slice: -# with self.lock: -# str_key = key_to_str([request.context_id.context_uuid.uuid, request.slice_uuid.uuid]) -# db_slice : SliceModel = get_object(self.database, SliceModel, str_key) -# return Slice(**db_slice.dump( -# include_endpoint_ids=True, include_constraints=True, include_config_rules=True, -# include_service_ids=True, include_subslice_ids=True)) + @safe_and_metered_rpc_method(METRICS, LOGGER) + def GetSlice(self, request : SliceId, context : grpc.ServicerContext) -> Slice: + return slice_get(self.db_engine, request) -# @safe_and_metered_rpc_method(METRICS, LOGGER) -# def SetSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId: -# with self.lock: -# context_uuid = request.slice_id.context_id.context_uuid.uuid -# db_context : ContextModel = get_object(self.database, ContextModel, context_uuid) -# -# for i,endpoint_id in enumerate(request.slice_endpoint_ids): -# endpoint_topology_context_uuid = endpoint_id.topology_id.context_id.context_uuid.uuid -# if len(endpoint_topology_context_uuid) > 0 and context_uuid != endpoint_topology_context_uuid: -# raise InvalidArgumentException( -# 'request.slice_endpoint_ids[{:d}].topology_id.context_id.context_uuid.uuid'.format(i), -# endpoint_topology_context_uuid, -# ['should be == {:s}({:s})'.format( -# 'request.slice_id.context_id.context_uuid.uuid', context_uuid)]) -# -# slice_uuid = request.slice_id.slice_uuid.uuid -# str_slice_key = key_to_str([context_uuid, slice_uuid]) -# -# constraints_result = set_constraints( -# self.database, str_slice_key, 'slice', request.slice_constraints) -# db_constraints = constraints_result[0][0] -# -# running_config_rules = update_config( -# self.database, str_slice_key, 'slice', request.slice_config.config_rules) -# db_running_config = running_config_rules[0][0] -# -# result : Tuple[SliceModel, bool] = update_or_create_object(self.database, SliceModel, str_slice_key, { -# 'context_fk' : db_context, -# 'slice_uuid' : slice_uuid, -# 'slice_constraints_fk': db_constraints, -# 'slice_status' : grpc_to_enum__slice_status(request.slice_status.slice_status), -# 'slice_config_fk' : db_running_config, -# 'slice_owner_uuid' : request.slice_owner.owner_uuid.uuid, -# 'slice_owner_string' : request.slice_owner.owner_string, -# }) -# db_slice, updated = result -# -# for i,endpoint_id in enumerate(request.slice_endpoint_ids): -# endpoint_uuid = endpoint_id.endpoint_uuid.uuid -# endpoint_device_uuid = endpoint_id.device_id.device_uuid.uuid -# endpoint_topology_uuid = endpoint_id.topology_id.topology_uuid.uuid -# endpoint_topology_context_uuid = endpoint_id.topology_id.context_id.context_uuid.uuid -# -# str_endpoint_key = key_to_str([endpoint_device_uuid, endpoint_uuid]) -# if len(endpoint_topology_context_uuid) > 0 and len(endpoint_topology_uuid) > 0: -# str_topology_key = key_to_str([endpoint_topology_context_uuid, endpoint_topology_uuid]) -# str_endpoint_key = key_to_str([str_endpoint_key, str_topology_key], separator=':') -# -# db_endpoint : EndPointModel = get_object(self.database, EndPointModel, str_endpoint_key) -# -# str_slice_endpoint_key = key_to_str([str_slice_key, str_endpoint_key], separator='--') -# result : Tuple[SliceEndPointModel, bool] = get_or_create_object( -# self.database, SliceEndPointModel, str_slice_endpoint_key, { -# 'slice_fk': db_slice, 'endpoint_fk': db_endpoint}) -# #db_slice_endpoint, slice_endpoint_created = result -# -# for i,service_id in enumerate(request.slice_service_ids): -# service_uuid = service_id.service_uuid.uuid -# service_context_uuid = service_id.context_id.context_uuid.uuid -# str_service_key = key_to_str([service_context_uuid, service_uuid]) -# db_service : ServiceModel = get_object(self.database, ServiceModel, str_service_key) -# -# str_slice_service_key = key_to_str([str_slice_key, str_service_key], separator='--') -# result : Tuple[SliceServiceModel, bool] = get_or_create_object( -# self.database, SliceServiceModel, str_slice_service_key, { -# 'slice_fk': db_slice, 'service_fk': db_service}) -# #db_slice_service, slice_service_created = result -# -# for i,subslice_id in enumerate(request.slice_subslice_ids): -# subslice_uuid = subslice_id.slice_uuid.uuid -# subslice_context_uuid = subslice_id.context_id.context_uuid.uuid -# str_subslice_key = key_to_str([subslice_context_uuid, subslice_uuid]) -# db_subslice : SliceModel = get_object(self.database, SliceModel, str_subslice_key) -# -# str_slice_subslice_key = key_to_str([str_slice_key, str_subslice_key], separator='--') -# result : Tuple[SliceSubSliceModel, bool] = get_or_create_object( -# self.database, SliceSubSliceModel, str_slice_subslice_key, { -# 'slice_fk': db_slice, 'sub_slice_fk': db_subslice}) -# #db_slice_subslice, slice_subslice_created = result -# -# event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE -# dict_slice_id = db_slice.dump_id() -# notify_event(self.messagebroker, TOPIC_SLICE, event_type, {'slice_id': dict_slice_id}) -# return SliceId(**dict_slice_id) + @safe_and_metered_rpc_method(METRICS, LOGGER) + def SetSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId: + slice_id,updated = slice_set(self.db_engine, request) + #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE + #notify_event(self.messagebroker, TOPIC_SLICE, event_type, {'slice_id': slice_id}) + return slice_id -# @safe_and_metered_rpc_method(METRICS, LOGGER) -# def UnsetSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId: -# with self.lock: -# context_uuid = request.slice_id.context_id.context_uuid.uuid -# db_context : ContextModel = get_object(self.database, ContextModel, context_uuid) -# -# for i,endpoint_id in enumerate(request.slice_endpoint_ids): -# endpoint_topology_context_uuid = endpoint_id.topology_id.context_id.context_uuid.uuid -# if len(endpoint_topology_context_uuid) > 0 and context_uuid != endpoint_topology_context_uuid: -# raise InvalidArgumentException( -# 'request.slice_endpoint_ids[{:d}].topology_id.context_id.context_uuid.uuid'.format(i), -# endpoint_topology_context_uuid, -# ['should be == {:s}({:s})'.format( -# 'request.slice_id.context_id.context_uuid.uuid', context_uuid)]) -# -# slice_uuid = request.slice_id.slice_uuid.uuid -# str_slice_key = key_to_str([context_uuid, slice_uuid]) -# -# if len(request.slice_constraints) > 0: -# raise NotImplementedError('UnsetSlice: removal of constraints') -# if len(request.slice_config.config_rules) > 0: -# raise NotImplementedError('UnsetSlice: removal of config rules') -# if len(request.slice_endpoint_ids) > 0: -# raise NotImplementedError('UnsetSlice: removal of endpoints') -# -# updated = False -# -# for service_id in request.slice_service_ids: -# service_uuid = service_id.service_uuid.uuid -# service_context_uuid = service_id.context_id.context_uuid.uuid -# str_service_key = key_to_str([service_context_uuid, service_uuid]) -# str_slice_service_key = key_to_str([str_slice_key, str_service_key], separator='--') -# SliceServiceModel(self.database, str_slice_service_key).delete() -# updated = True -# -# for subslice_id in request.slice_subslice_ids: -# subslice_uuid = subslice_id.slice_uuid.uuid -# subslice_context_uuid = subslice_id.context_id.context_uuid.uuid -# str_subslice_key = key_to_str([subslice_context_uuid, subslice_uuid]) -# str_slice_subslice_key = key_to_str([str_slice_key, str_subslice_key], separator='--') -# SliceSubSliceModel(self.database, str_slice_subslice_key).delete() -# updated = True -# -# event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE -# db_slice : SliceModel = get_object(self.database, SliceModel, str_slice_key) -# dict_slice_id = db_slice.dump_id() -# notify_event(self.messagebroker, TOPIC_SLICE, event_type, {'slice_id': dict_slice_id}) -# return SliceId(**dict_slice_id) + @safe_and_metered_rpc_method(METRICS, LOGGER) + def UnsetSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId: + slice_id,updated = slice_unset(self.db_engine, request) + #if updated: + # notify_event(self.messagebroker, TOPIC_SLICE, EventTypeEnum.EVENTTYPE_UPDATE, {'slice_id': slice_id}) + return slice_id -# @safe_and_metered_rpc_method(METRICS, LOGGER) -# def RemoveSlice(self, request : SliceId, context : grpc.ServicerContext) -> Empty: -# with self.lock: -# context_uuid = request.context_id.context_uuid.uuid -# slice_uuid = request.slice_uuid.uuid -# db_slice = SliceModel(self.database, key_to_str([context_uuid, slice_uuid]), auto_load=False) -# found = db_slice.load() -# if not found: return Empty() -# -# dict_slice_id = db_slice.dump_id() -# db_slice.delete() -# -# event_type = EventTypeEnum.EVENTTYPE_REMOVE -# notify_event(self.messagebroker, TOPIC_SLICE, event_type, {'slice_id': dict_slice_id}) -# return Empty() + @safe_and_metered_rpc_method(METRICS, LOGGER) + def RemoveSlice(self, request : SliceId, context : grpc.ServicerContext) -> Empty: + deleted = slice_delete(self.db_engine, request) + #if deleted: + # notify_event(self.messagebroker, TOPIC_SLICE, EventTypeEnum.EVENTTYPE_REMOVE, {'slice_id': request}) + return Empty() @safe_and_metered_rpc_method(METRICS, LOGGER) def GetSliceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[SliceEvent]: diff --git a/src/context/service/_old_code/Config.py b/src/context/service/_old_code/Config.py deleted file mode 100644 index 6f5d1dc0b347dc5db27a2cfae973a4e5bdf7b4cc..0000000000000000000000000000000000000000 --- a/src/context/service/_old_code/Config.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) -# -# 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. - -# Autopopulate the component with fake data for testing purposes? -POPULATE_FAKE_DATA = False diff --git a/src/context/service/_old_code/Populate.py b/src/context/service/_old_code/Populate.py deleted file mode 100644 index ffb739988d163d30e9426da54b990f66015e70a1..0000000000000000000000000000000000000000 --- a/src/context/service/_old_code/Populate.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) -# -# 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 copy -from common.proto.context_pb2 import Connection, Context, Device, Link, Service, Topology -from context.client.ContextClient import ContextClient -from context.tests.Objects import ( - CONNECTION_R1_R3, CONTEXT, TOPOLOGY, DEVICE_R1, DEVICE_R1_ID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R3, DEVICE_R3_ID, - LINK_R1_R2, LINK_R1_R2_ID, LINK_R1_R3, LINK_R1_R3_ID, LINK_R2_R3, LINK_R2_R3_ID, SERVICE_R1_R2, SERVICE_R1_R3, - SERVICE_R2_R3) - -def populate(host=None, port=None): - client = ContextClient(host=host, port=port) - - client.SetContext(Context(**CONTEXT)) - client.SetTopology(Topology(**TOPOLOGY)) - client.SetDevice(Device(**DEVICE_R1)) - client.SetDevice(Device(**DEVICE_R2)) - client.SetDevice(Device(**DEVICE_R3)) - - client.SetLink(Link(**LINK_R1_R2)) - client.SetLink(Link(**LINK_R1_R3)) - client.SetLink(Link(**LINK_R2_R3)) - - TOPOLOGY_WITH_DEVICES_AND_LINKS = copy.deepcopy(TOPOLOGY) - TOPOLOGY_WITH_DEVICES_AND_LINKS['device_ids'].append(DEVICE_R1_ID) - TOPOLOGY_WITH_DEVICES_AND_LINKS['device_ids'].append(DEVICE_R2_ID) - TOPOLOGY_WITH_DEVICES_AND_LINKS['device_ids'].append(DEVICE_R3_ID) - TOPOLOGY_WITH_DEVICES_AND_LINKS['link_ids'].append(LINK_R1_R2_ID) - TOPOLOGY_WITH_DEVICES_AND_LINKS['link_ids'].append(LINK_R1_R3_ID) - TOPOLOGY_WITH_DEVICES_AND_LINKS['link_ids'].append(LINK_R2_R3_ID) - client.SetTopology(Topology(**TOPOLOGY_WITH_DEVICES_AND_LINKS)) - - client.SetService(Service(**SERVICE_R1_R2)) - client.SetService(Service(**SERVICE_R2_R3)) - - client.SetService(Service(**SERVICE_R1_R3)) - client.SetConnection(Connection(**CONNECTION_R1_R3)) diff --git a/src/context/service/_old_code/Resources.py b/src/context/service/_old_code/Resources.py deleted file mode 100644 index 5f03132a34004388596ce1fdfac470f029c093ea..0000000000000000000000000000000000000000 --- a/src/context/service/_old_code/Resources.py +++ /dev/null @@ -1,246 +0,0 @@ -# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) -# -# 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. - -from flask import make_response -from flask.json import jsonify -from flask_restful import Resource -from common.orm.Database import Database -from common.proto.context_pb2 import ConnectionId, ContextId, DeviceId, Empty, LinkId, ServiceId, SliceId, TopologyId -from common.proto.policy_pb2 import PolicyRuleId -from common.tools.grpc.Tools import grpc_message_to_json -from context.service.grpc_server.ContextServiceServicerImpl import ContextServiceServicerImpl - -def format_grpc_to_json(grpc_reply): - return jsonify(grpc_message_to_json(grpc_reply)) - -def grpc_connection_id(connection_uuid): - return ConnectionId(**{ - 'connection_uuid': {'uuid': connection_uuid} - }) - -def grpc_context_id(context_uuid): - return ContextId(**{ - 'context_uuid': {'uuid': context_uuid} - }) - -def grpc_device_id(device_uuid): - return DeviceId(**{ - 'device_uuid': {'uuid': device_uuid} - }) - -def grpc_link_id(link_uuid): - return LinkId(**{ - 'link_uuid': {'uuid': link_uuid} - }) - -def grpc_service_id(context_uuid, service_uuid): - return ServiceId(**{ - 'context_id': {'context_uuid': {'uuid': context_uuid}}, - 'service_uuid': {'uuid': service_uuid} - }) - -def grpc_slice_id(context_uuid, slice_uuid): - return SliceId(**{ - 'context_id': {'context_uuid': {'uuid': context_uuid}}, - 'slice_uuid': {'uuid': slice_uuid} - }) - -def grpc_topology_id(context_uuid, topology_uuid): - return TopologyId(**{ - 'context_id': {'context_uuid': {'uuid': context_uuid}}, - 'topology_uuid': {'uuid': topology_uuid} - }) - -def grpc_policy_rule_id(policy_rule_uuid): - return PolicyRuleId(**{ - 'uuid': {'uuid': policy_rule_uuid} - }) - -class _Resource(Resource): - def __init__(self, database : Database) -> None: - super().__init__() - self.database = database - self.servicer = ContextServiceServicerImpl(self.database, None) - -class ContextIds(_Resource): - def get(self): - return format_grpc_to_json(self.servicer.ListContextIds(Empty(), None)) - -class Contexts(_Resource): - def get(self): - return format_grpc_to_json(self.servicer.ListContexts(Empty(), None)) - -class Context(_Resource): - def get(self, context_uuid : str): - return format_grpc_to_json(self.servicer.GetContext(grpc_context_id(context_uuid), None)) - -class TopologyIds(_Resource): - def get(self, context_uuid : str): - return format_grpc_to_json(self.servicer.ListTopologyIds(grpc_context_id(context_uuid), None)) - -class Topologies(_Resource): - def get(self, context_uuid : str): - return format_grpc_to_json(self.servicer.ListTopologies(grpc_context_id(context_uuid), None)) - -class Topology(_Resource): - def get(self, context_uuid : str, topology_uuid : str): - return format_grpc_to_json(self.servicer.GetTopology(grpc_topology_id(context_uuid, topology_uuid), None)) - -class ServiceIds(_Resource): - def get(self, context_uuid : str): - return format_grpc_to_json(self.servicer.ListServiceIds(grpc_context_id(context_uuid), None)) - -class Services(_Resource): - def get(self, context_uuid : str): - return format_grpc_to_json(self.servicer.ListServices(grpc_context_id(context_uuid), None)) - -class Service(_Resource): - def get(self, context_uuid : str, service_uuid : str): - return format_grpc_to_json(self.servicer.GetService(grpc_service_id(context_uuid, service_uuid), None)) - -class SliceIds(_Resource): - def get(self, context_uuid : str): - return format_grpc_to_json(self.servicer.ListSliceIds(grpc_context_id(context_uuid), None)) - -class Slices(_Resource): - def get(self, context_uuid : str): - return format_grpc_to_json(self.servicer.ListSlices(grpc_context_id(context_uuid), None)) - -class Slice(_Resource): - def get(self, context_uuid : str, slice_uuid : str): - return format_grpc_to_json(self.servicer.GetSlice(grpc_slice_id(context_uuid, slice_uuid), None)) - -class DeviceIds(_Resource): - def get(self): - return format_grpc_to_json(self.servicer.ListDeviceIds(Empty(), None)) - -class Devices(_Resource): - def get(self): - return format_grpc_to_json(self.servicer.ListDevices(Empty(), None)) - -class Device(_Resource): - def get(self, device_uuid : str): - return format_grpc_to_json(self.servicer.GetDevice(grpc_device_id(device_uuid), None)) - -class LinkIds(_Resource): - def get(self): - return format_grpc_to_json(self.servicer.ListLinkIds(Empty(), None)) - -class Links(_Resource): - def get(self): - return format_grpc_to_json(self.servicer.ListLinks(Empty(), None)) - -class Link(_Resource): - def get(self, link_uuid : str): - return format_grpc_to_json(self.servicer.GetLink(grpc_link_id(link_uuid), None)) - -class ConnectionIds(_Resource): - def get(self, context_uuid : str, service_uuid : str): - return format_grpc_to_json(self.servicer.ListConnectionIds(grpc_service_id(context_uuid, service_uuid), None)) - -class Connections(_Resource): - def get(self, context_uuid : str, service_uuid : str): - return format_grpc_to_json(self.servicer.ListConnections(grpc_service_id(context_uuid, service_uuid), None)) - -class Connection(_Resource): - def get(self, connection_uuid : str): - return format_grpc_to_json(self.servicer.GetConnection(grpc_connection_id(connection_uuid), None)) - -class PolicyRuleIds(_Resource): - def get(self): - return format_grpc_to_json(self.servicer.ListPolicyRuleIds(Empty(), None)) - -class PolicyRules(_Resource): - def get(self): - return format_grpc_to_json(self.servicer.ListPolicyRules(Empty(), None)) - -class PolicyRule(_Resource): - def get(self, policy_rule_uuid : str): - return format_grpc_to_json(self.servicer.GetPolicyRule(grpc_policy_rule_id(policy_rule_uuid), None)) - -class DumpText(Resource): - def __init__(self, database : Database) -> None: - super().__init__() - self.database = database - - def get(self): - db_entries = self.database.dump() - num_entries = len(db_entries) - response = ['----- Database Dump [{:3d} entries] -------------------------'.format(num_entries)] - for db_entry in db_entries: - response.append(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - response.append('-----------------------------------------------------------') - headers = {'Content-Type': 'text/plain'} - return make_response('\n'.join(response), 200, headers) - -class DumpHtml(Resource): - def __init__(self, database : Database) -> None: - super().__init__() - self.database = database - - def get(self): - db_entries = self.database.dump() - num_entries = len(db_entries) - response = [] - response.append('<HTML><HEAD><TITLE>Database Dump [{:3d} entries]</TITLE></HEAD><BODY>'.format(num_entries)) - response.append('<H3>Database Dump [{:3d} entries]</H3><HR/>'.format(num_entries)) - response.append('<TABLE border=1>') - response.append('<TR><TH>Type</TH><TH>Key</TH><TH>Value</TH></TR>') - for db_entry in db_entries: - response.append('<TR><TD>{:s}</TD><TD>{:s}</TD><TD>{:s}</TD></TR>'.format(*db_entry)) - response.append('</TABLE></BODY></HTML>') - - headers = {'Content-Type': 'text/html'} - return make_response(''.join(response), 200, headers) - - -# Use 'path' type in Service and Sink because service_uuid and link_uuid might contain char '/' and Flask is unable to -# recognize them in 'string' type. -RESOURCES = [ - # (endpoint_name, resource_class, resource_url) - ('api.context_ids', ContextIds, '/context_ids'), - ('api.contexts', Contexts, '/contexts'), - ('api.context', Context, '/context/<string:context_uuid>'), - - ('api.topology_ids', TopologyIds, '/context/<string:context_uuid>/topology_ids'), - ('api.topologies', Topologies, '/context/<string:context_uuid>/topologies'), - ('api.topology', Topology, '/context/<string:context_uuid>/topology/<string:topology_uuid>'), - - ('api.service_ids', ServiceIds, '/context/<string:context_uuid>/service_ids'), - ('api.services', Services, '/context/<string:context_uuid>/services'), - ('api.service', Service, '/context/<string:context_uuid>/service/<path:service_uuid>'), - - ('api.slice_ids', SliceIds, '/context/<string:context_uuid>/slice_ids'), - ('api.slices', Slices, '/context/<string:context_uuid>/slices'), - ('api.slice', Slice, '/context/<string:context_uuid>/slice/<path:slice_uuid>'), - - ('api.device_ids', DeviceIds, '/device_ids'), - ('api.devices', Devices, '/devices'), - ('api.device', Device, '/device/<string:device_uuid>'), - - ('api.link_ids', LinkIds, '/link_ids'), - ('api.links', Links, '/links'), - ('api.link', Link, '/link/<path:link_uuid>'), - - ('api.connection_ids', ConnectionIds, '/context/<string:context_uuid>/service/<path:service_uuid>/connection_ids'), - ('api.connections', Connections, '/context/<string:context_uuid>/service/<path:service_uuid>/connections'), - ('api.connection', Connection, '/connection/<path:connection_uuid>'), - - ('api.policyrule_ids', PolicyRuleIds, '/policyrule_ids'), - ('api.policyrules', PolicyRules, '/policyrules'), - ('api.policyrule', PolicyRule, '/policyrule/<string:policyrule_uuid>'), - - ('api.dump.text', DumpText, '/dump/text'), - ('api.dump.html', DumpHtml, '/dump/html'), -] diff --git a/src/context/service/_old_code/__init__.py b/src/context/service/_old_code/__init__.py deleted file mode 100644 index 70a33251242c51f49140e596b8208a19dd5245f7..0000000000000000000000000000000000000000 --- a/src/context/service/_old_code/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) -# -# 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. - diff --git a/src/context/service/_old_code/__main__.py b/src/context/service/_old_code/__main__.py deleted file mode 100644 index 69d3f5cbef08d4301891a6ad1cbf2d8a247f7c40..0000000000000000000000000000000000000000 --- a/src/context/service/_old_code/__main__.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) -# -# 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, signal, sys, threading -from prometheus_client import start_http_server -from common.Settings import get_log_level, get_metrics_port, get_setting -from common.orm.Database import Database -from common.orm.Factory import get_database_backend -from common.message_broker.Factory import get_messagebroker_backend -from common.message_broker.MessageBroker import MessageBroker -from context.service.grpc_server.ContextService import ContextService -from .Config import POPULATE_FAKE_DATA -from .Populate import populate -from .Resources import RESOURCES -from .RestServer import RestServer - -terminate = threading.Event() -LOGGER = None - -def signal_handler(signal, frame): # pylint: disable=redefined-outer-name - LOGGER.warning('Terminate signal received') - terminate.set() - -def main(): - global LOGGER # pylint: disable=global-statement - - log_level = get_log_level() - logging.basicConfig(level=log_level, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") - LOGGER = logging.getLogger(__name__) - - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) - - LOGGER.info('Starting...') - - # Start metrics server - metrics_port = get_metrics_port() - start_http_server(metrics_port) - - # Get database instance - database = Database(get_database_backend()) - - # Get message broker instance - messagebroker = MessageBroker(get_messagebroker_backend()) - - # Starting context service - grpc_service = ContextService(database, messagebroker) - grpc_service.start() - - rest_server = RestServer() - for endpoint_name, resource_class, resource_url in RESOURCES: - rest_server.add_resource(resource_class, resource_url, endpoint=endpoint_name, resource_class_args=(database,)) - rest_server.start() - - populate_fake_data = get_setting('POPULATE_FAKE_DATA', default=POPULATE_FAKE_DATA) - if isinstance(populate_fake_data, str): populate_fake_data = (populate_fake_data.upper() in {'T', '1', 'TRUE'}) - if populate_fake_data: - LOGGER.info('Populating fake data...') - populate(host='127.0.0.1', port=grpc_service.bind_port) - LOGGER.info('Fake Data populated') - - # Wait for Ctrl+C or termination signal - while not terminate.wait(timeout=0.1): pass - - LOGGER.info('Terminating...') - grpc_service.stop() - rest_server.shutdown() - rest_server.join() - - LOGGER.info('Bye') - return 0 - -if __name__ == '__main__': - sys.exit(main()) diff --git a/src/context/service/_old_code/_test_restapi.py b/src/context/service/_old_code/_test_restapi.py deleted file mode 100644 index 82a8bca4005eb1ff575293a473c7cebeb5f69a76..0000000000000000000000000000000000000000 --- a/src/context/service/_old_code/_test_restapi.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) -# -# 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 context.service._old_code.Populate import populate -#from context.service.rest_server.RestServer import RestServer -#from context.service.rest_server.Resources import RESOURCES - -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) - -#def do_rest_request(url : str): -# base_url = get_service_baseurl_http(ServiceNameEnum.CONTEXT) -# request_url = 'http://{:s}:{:s}{:s}{:s}'.format(str(LOCAL_HOST), str(HTTP_PORT), str(base_url), url) -# LOGGER.warning('Request: GET {:s}'.format(str(request_url))) -# reply = requests.get(request_url) -# LOGGER.warning('Reply: {:s}'.format(str(reply.text))) -# assert reply.status_code == 200, 'Reply failed with code {}'.format(reply.status_code) -# return reply.json() - diff --git a/src/context/service/_old_code/test_unitary.py b/src/context/service/_old_code/test_unitary.py deleted file mode 100644 index 5a0dcb9c18f4693a40fc3b48ed0297f5902e5d79..0000000000000000000000000000000000000000 --- a/src/context/service/_old_code/test_unitary.py +++ /dev/null @@ -1,1450 +0,0 @@ -# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) -# -# 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. - -# pylint: disable=too-many-lines -import copy, grpc, logging, os, pytest, requests, time, urllib -from typing import Tuple -from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID, ServiceNameEnum -from common.Settings import ( - ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, ENVVAR_SUFIX_SERVICE_PORT_HTTP, get_env_var_name, - get_service_baseurl_http, get_service_port_grpc, get_service_port_http) -from context.service.Database import Database -from common.message_broker.Factory import get_messagebroker_backend, BackendEnum as MessageBrokerBackendEnum -from common.message_broker.MessageBroker import MessageBroker -from common.proto.context_pb2 import ( - Connection, ConnectionEvent, ConnectionId, Context, ContextEvent, ContextId, Device, DeviceEvent, DeviceId, - DeviceOperationalStatusEnum, Empty, EventTypeEnum, Link, LinkEvent, LinkId, Service, ServiceEvent, ServiceId, - ServiceStatusEnum, ServiceTypeEnum, Topology, TopologyEvent, TopologyId) -from common.proto.policy_pb2 import (PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule) -from common.type_checkers.Assertions import ( - validate_connection, validate_connection_ids, validate_connections, validate_context, validate_context_ids, - validate_contexts, validate_device, validate_device_ids, validate_devices, validate_link, validate_link_ids, - validate_links, validate_service, validate_service_ids, validate_services, validate_topologies, validate_topology, - validate_topology_ids) -from context.client.ContextClient import ContextClient -from context.client.EventsCollector import EventsCollector -from context.service.database.tools.Tools import ( - FASTHASHER_DATA_ACCEPTED_FORMAT, FASTHASHER_ITEM_ACCEPTED_FORMAT, fast_hasher) -from context.service.grpc_server.ContextService import ContextService -from context.service._old_code.Populate import populate -from context.service.rest_server.RestServer import RestServer -from context.service.rest_server.Resources import RESOURCES -from requests import Session -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker -from context.service.database.models._Base import Base - -from .Objects import ( - CONNECTION_R1_R3, CONNECTION_R1_R3_ID, CONNECTION_R1_R3_UUID, CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, - DEVICE_R1_UUID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R2_UUID, DEVICE_R3, DEVICE_R3_ID, DEVICE_R3_UUID, LINK_R1_R2, - LINK_R1_R2_ID, LINK_R1_R2_UUID, SERVICE_R1_R2, SERVICE_R1_R2_ID, SERVICE_R1_R2_UUID, SERVICE_R1_R3, - SERVICE_R1_R3_ID, SERVICE_R1_R3_UUID, SERVICE_R2_R3, SERVICE_R2_R3_ID, SERVICE_R2_R3_UUID, TOPOLOGY, TOPOLOGY_ID, - POLICY_RULE, POLICY_RULE_ID, POLICY_RULE_UUID) - -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) - -LOCAL_HOST = '127.0.0.1' -GRPC_PORT = 10000 + int(get_service_port_grpc(ServiceNameEnum.CONTEXT)) # avoid privileged ports -HTTP_PORT = 10000 + int(get_service_port_http(ServiceNameEnum.CONTEXT)) # avoid privileged ports - -os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_HOST )] = str(LOCAL_HOST) -os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(GRPC_PORT) -os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_HTTP)] = str(HTTP_PORT) - -DEFAULT_REDIS_SERVICE_HOST = LOCAL_HOST -DEFAULT_REDIS_SERVICE_PORT = 6379 -DEFAULT_REDIS_DATABASE_ID = 0 - -REDIS_CONFIG = { - 'REDIS_SERVICE_HOST': os.environ.get('REDIS_SERVICE_HOST', DEFAULT_REDIS_SERVICE_HOST), - 'REDIS_SERVICE_PORT': os.environ.get('REDIS_SERVICE_PORT', DEFAULT_REDIS_SERVICE_PORT), - 'REDIS_DATABASE_ID' : os.environ.get('REDIS_DATABASE_ID', DEFAULT_REDIS_DATABASE_ID ), -} - -SCENARIOS = [ - ('all_sqlalchemy', {}, MessageBrokerBackendEnum.INMEMORY, {} ), - ('all_inmemory', DatabaseBackendEnum.INMEMORY, {}, MessageBrokerBackendEnum.INMEMORY, {} ) -# ('all_redis', DatabaseBackendEnum.REDIS, REDIS_CONFIG, MessageBrokerBackendEnum.REDIS, REDIS_CONFIG), -] - -@pytest.fixture(scope='session', ids=[str(scenario[0]) for scenario in SCENARIOS], params=SCENARIOS) -def context_s_mb(request) -> Tuple[Session, MessageBroker]: - name,db_session,mb_backend,mb_settings = request.param - msg = 'Running scenario {:s} db_session={:s}, mb_backend={:s}, mb_settings={:s}...' - LOGGER.info(msg.format(str(name), str(db_session), str(mb_backend.value), str(mb_settings))) - - db_uri = 'cockroachdb://root@10.152.183.111:26257/defaultdb?sslmode=disable' - LOGGER.debug('Connecting to DB: {}'.format(db_uri)) - - try: - engine = create_engine(db_uri) - except Exception as e: - LOGGER.error("Failed to connect to database.") - LOGGER.error(f"{e}") - return 1 - - Base.metadata.create_all(engine) - _session = sessionmaker(bind=engine, expire_on_commit=False) - - _message_broker = MessageBroker(get_messagebroker_backend(backend=mb_backend, **mb_settings)) - yield _session, _message_broker - _message_broker.terminate() - -@pytest.fixture(scope='session') -def context_service_grpc(context_s_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name - _service = ContextService(context_s_mb[0], context_s_mb[1]) - _service.start() - yield _service - _service.stop() -@pytest.fixture(scope='session') -def context_service_rest(context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name - database = context_db_mb[0] - _rest_server = RestServer() - for endpoint_name, resource_class, resource_url in RESOURCES: - _rest_server.add_resource(resource_class, resource_url, endpoint=endpoint_name, resource_class_args=(database,)) - _rest_server.start() - time.sleep(1) # bring time for the server to start - yield _rest_server - _rest_server.shutdown() - _rest_server.join() -@pytest.fixture(scope='session') -def context_client_grpc(context_service_grpc : ContextService): # pylint: disable=redefined-outer-name - _client = ContextClient() - yield _client - _client.close() -""" -def do_rest_request(url : str): - base_url = get_service_baseurl_http(ServiceNameEnum.CONTEXT) - request_url = 'http://{:s}:{:s}{:s}{:s}'.format(str(LOCAL_HOST), str(HTTP_PORT), str(base_url), url) - LOGGER.warning('Request: GET {:s}'.format(str(request_url))) - reply = requests.get(request_url) - LOGGER.warning('Reply: {:s}'.format(str(reply.text))) - assert reply.status_code == 200, 'Reply failed with code {}'.format(reply.status_code) - return reply.json() -""" - -"""# ----- Test gRPC methods ---------------------------------------------------------------------------------------------- -def test_grpc_context( - context_client_grpc : ContextClient, # pylint: disable=redefined-outer-name - context_s_mb : Tuple[Session, MessageBroker]): # pylint: disable=redefined-outer-name - Session = context_s_mb[0] - - database = Database(Session) - - # ----- Clean the database ----------------------------------------------------------------------------------------- - database.clear() - # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- - events_collector = EventsCollector(context_client_grpc) - events_collector.start() - - # ----- Get when the object does not exist ------------------------------------------------------------------------- - with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetContext(ContextId(**CONTEXT_ID)) - assert e.value.code() == grpc.StatusCode.NOT_FOUND - assert e.value.details() == 'Context({:s}) not found'.format(DEFAULT_CONTEXT_UUID) - - # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListContextIds(Empty()) - assert len(response.context_ids) == 0 - - response = context_client_grpc.ListContexts(Empty()) - assert len(response.contexts) == 0 - - # ----- Dump state of database before create the object ------------------------------------------------------------ - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 0 - - # ----- Create the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetContext(Context(**CONTEXT)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - wrong_uuid = 'c97c4185-e1d1-4ea7-b6b9-afbf76cb61f4' - with pytest.raises(grpc.RpcError) as e: - WRONG_TOPOLOGY_ID = copy.deepcopy(TOPOLOGY_ID) - WRONG_TOPOLOGY_ID['context_id']['context_uuid']['uuid'] = wrong_uuid - WRONG_CONTEXT = copy.deepcopy(CONTEXT) - WRONG_CONTEXT['topology_ids'].append(WRONG_TOPOLOGY_ID) - context_client_grpc.SetContext(Context(**WRONG_CONTEXT)) - assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT - msg = 'request.topology_ids[0].context_id.context_uuid.uuid({}) is invalid; '\ - 'should be == request.context_id.context_uuid.uuid({})'.format(wrong_uuid, DEFAULT_CONTEXT_UUID) - assert e.value.details() == msg - - with pytest.raises(grpc.RpcError) as e: - WRONG_SERVICE_ID = copy.deepcopy(SERVICE_R1_R2_ID) - WRONG_SERVICE_ID['context_id']['context_uuid']['uuid'] = wrong_uuid - WRONG_CONTEXT = copy.deepcopy(CONTEXT) - WRONG_CONTEXT['service_ids'].append(WRONG_SERVICE_ID) - context_client_grpc.SetContext(Context(**WRONG_CONTEXT)) - assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT - msg = 'request.service_ids[0].context_id.context_uuid.uuid({}) is invalid; '\ - 'should be == request.context_id.context_uuid.uuid({})'.format(wrong_uuid, DEFAULT_CONTEXT_UUID) - assert e.value.details() == msg - - # ----- Check create event ----------------------------------------------------------------------------------------- - event = events_collector.get_event(block=True) - assert isinstance(event, ContextEvent) - assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # ----- Update the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetContext(Context(**CONTEXT)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Check update event ----------------------------------------------------------------------------------------- - event = events_collector.get_event(block=True) - assert isinstance(event, ContextEvent) - assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Dump state of database after create/update the object ------------------------------------------------------ - db_entries = database.dump_all() - - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 1 - - # ----- Get when the object exists --------------------------------------------------------------------------------- - response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert len(response.topology_ids) == 0 - assert len(response.service_ids) == 0 - - # ----- List when the object exists -------------------------------------------------------------------------------- - response = context_client_grpc.ListContextIds(Empty()) - assert len(response.context_ids) == 1 - assert response.context_ids[0].context_uuid.uuid == DEFAULT_CONTEXT_UUID - - response = context_client_grpc.ListContexts(Empty()) - assert len(response.contexts) == 1 - assert response.contexts[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert len(response.contexts[0].topology_ids) == 0 - assert len(response.contexts[0].service_ids) == 0 - - # ----- Remove the object ------------------------------------------------------------------------------------------ - context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID)) - - # ----- Check remove event ----------------------------------------------------------------------------------------- - # event = events_collector.get_event(block=True) - # assert isinstance(event, ContextEvent) - # assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- - events_collector.stop() - - # ----- Dump state of database after remove the object ------------------------------------------------------------- - db_entries = database.dump_all() - - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 0 - - -def test_grpc_topology( - context_client_grpc: ContextClient, # pylint: disable=redefined-outer-name - context_s_mb: Tuple[Session, MessageBroker]): # pylint: disable=redefined-outer-name - session = context_s_mb[0] - - database = Database(session) - - # ----- Clean the database ----------------------------------------------------------------------------------------- - database.clear() - - # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- - events_collector = EventsCollector(context_client_grpc) - events_collector.start() - - # ----- Prepare dependencies for the test and capture related events ----------------------------------------------- - response = context_client_grpc.SetContext(Context(**CONTEXT)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # event = events_collector.get_event(block=True) - # assert isinstance(event, ContextEvent) - # assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Get when the object does not exist ------------------------------------------------------------------------- - with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID)) - assert e.value.code() == grpc.StatusCode.NOT_FOUND - # assert e.value.details() == 'Topology({:s}/{:s}) not found'.format(DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID) - assert e.value.details() == 'Topology({:s}) not found'.format(DEFAULT_TOPOLOGY_UUID) - # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID)) - assert len(response.topology_ids) == 0 - response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID)) - assert len(response.topologies) == 0 - - # ----- Dump state of database before create the object ------------------------------------------------------------ - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 1 - - # ----- Create the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetTopology(Topology(**TOPOLOGY)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - CONTEXT_WITH_TOPOLOGY = copy.deepcopy(CONTEXT) - CONTEXT_WITH_TOPOLOGY['topology_ids'].append(TOPOLOGY_ID) - response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_TOPOLOGY)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Check create event ----------------------------------------------------------------------------------------- - # events = events_collector.get_events(block=True, count=2) - - # assert isinstance(events[0], TopologyEvent) - # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[0].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # assert events[0].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # assert isinstance(events[1], ContextEvent) - # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - # assert events[1].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Update the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetTopology(Topology(**TOPOLOGY)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # ----- Check update event ----------------------------------------------------------------------------------------- - # event = events_collector.get_event(block=True) - # assert isinstance(event, TopologyEvent) - # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - # assert event.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # assert event.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # ----- Dump state of database after create/update the object ------------------------------------------------------ - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 2 - - # ----- Get when the object exists --------------------------------------------------------------------------------- - response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID)) - assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - assert len(response.device_ids) == 0 - assert len(response.link_ids) == 0 - - # ----- List when the object exists -------------------------------------------------------------------------------- - response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID)) - assert len(response.topology_ids) == 1 - assert response.topology_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_ids[0].topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID)) - assert len(response.topologies) == 1 - assert response.topologies[0].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topologies[0].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - assert len(response.topologies[0].device_ids) == 0 - assert len(response.topologies[0].link_ids) == 0 - - # ----- Remove the object ------------------------------------------------------------------------------------------ - context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID)) - context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID)) - - # ----- Check remove event ----------------------------------------------------------------------------------------- - # events = events_collector.get_events(block=True, count=2) - - # assert isinstance(events[0], TopologyEvent) - # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[0].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # assert events[0].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # assert isinstance(events[1], ContextEvent) - # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[1].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- - # events_collector.stop() - - # ----- Dump state of database after remove the object ------------------------------------------------------------- - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 0 - - -def test_grpc_device( - context_client_grpc: ContextClient, # pylint: disable=redefined-outer-name - context_s_mb: Tuple[Session, MessageBroker]): # pylint: disable=redefined-outer-name - session = context_s_mb[0] - - database = Database(session) - - # ----- Clean the database ----------------------------------------------------------------------------------------- - database.clear() - - # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- - events_collector = EventsCollector(context_client_grpc) - events_collector.start() - - # ----- Prepare dependencies for the test and capture related events ----------------------------------------------- - response = context_client_grpc.SetContext(Context(**CONTEXT)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - response = context_client_grpc.SetTopology(Topology(**TOPOLOGY)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - events = events_collector.get_events(block=True, count=2) - - assert isinstance(events[0], ContextEvent) - assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - assert isinstance(events[1], TopologyEvent) - assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # ----- Get when the object does not exist ------------------------------------------------------------------------- - with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID)) - assert e.value.code() == grpc.StatusCode.NOT_FOUND - assert e.value.details() == 'Device({:s}) not found'.format(DEVICE_R1_UUID) - - # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListDeviceIds(Empty()) - assert len(response.device_ids) == 0 - - response = context_client_grpc.ListDevices(Empty()) - assert len(response.devices) == 0 - - # ----- Dump state of database before create the object ------------------------------------------------------------ - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 2 - - # ----- Create the object ------------------------------------------------------------------------------------------ - with pytest.raises(grpc.RpcError) as e: - WRONG_DEVICE = copy.deepcopy(DEVICE_R1) - WRONG_DEVICE_UUID = '3f03c76d-31fb-47f5-9c1d-bc6b6bfa2d08' - WRONG_DEVICE['device_endpoints'][0]['endpoint_id']['device_id']['device_uuid']['uuid'] = WRONG_DEVICE_UUID - context_client_grpc.SetDevice(Device(**WRONG_DEVICE)) - assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT - msg = 'request.device_endpoints[0].device_id.device_uuid.uuid({}) is invalid; '\ - 'should be == request.device_id.device_uuid.uuid({})'.format(WRONG_DEVICE_UUID, DEVICE_R1_UUID) - assert e.value.details() == msg - response = context_client_grpc.SetDevice(Device(**DEVICE_R1)) - assert response.device_uuid.uuid == DEVICE_R1_UUID - - # ----- Check create event ----------------------------------------------------------------------------------------- - # event = events_collector.get_event(block=True) - # assert isinstance(event, DeviceEvent) - # assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert event.device_id.device_uuid.uuid == DEVICE_R1_UUID - - # ----- Update the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetDevice(Device(**DEVICE_R1)) - assert response.device_uuid.uuid == DEVICE_R1_UUID - - # ----- Check update event ----------------------------------------------------------------------------------------- - # event = events_collector.get_event(block=True) - # assert isinstance(event, DeviceEvent) - # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - # assert event.device_id.device_uuid.uuid == DEVICE_R1_UUID - - # ----- Dump state of database after create/update the object ------------------------------------------------------ - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 47 - - # ----- Get when the object exists --------------------------------------------------------------------------------- - response = context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID)) - assert response.device_id.device_uuid.uuid == DEVICE_R1_UUID - assert response.device_type == 'packet-router' - assert len(response.device_config.config_rules) == 3 - assert response.device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED - assert len(response.device_drivers) == 1 - assert len(response.device_endpoints) == 3 - - # ----- List when the object exists -------------------------------------------------------------------------------- - response = context_client_grpc.ListDeviceIds(Empty()) - assert len(response.device_ids) == 1 - assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID - - response = context_client_grpc.ListDevices(Empty()) - assert len(response.devices) == 1 - assert response.devices[0].device_id.device_uuid.uuid == DEVICE_R1_UUID - assert response.devices[0].device_type == 'packet-router' - assert len(response.devices[0].device_config.config_rules) == 3 - assert response.devices[0].device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED - assert len(response.devices[0].device_drivers) == 1 - assert len(response.devices[0].device_endpoints) == 3 - - # ----- Create object relation ------------------------------------------------------------------------------------- - TOPOLOGY_WITH_DEVICE = copy.deepcopy(TOPOLOGY) - TOPOLOGY_WITH_DEVICE['device_ids'].append(DEVICE_R1_ID) - response = context_client_grpc.SetTopology(Topology(**TOPOLOGY_WITH_DEVICE)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # ----- Check update event ----------------------------------------------------------------------------------------- - # event = events_collector.get_event(block=True) - # assert isinstance(event, TopologyEvent) - # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - # assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # ----- Check relation was created --------------------------------------------------------------------------------- - response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID)) - assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - assert len(response.device_ids) == 1 - assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID - assert len(response.link_ids) == 0 - - # ----- Dump state of database after creating the object relation -------------------------------------------------- - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 47 - - # ----- Remove the object -------------------------------ro----------------------------------------------------------- - context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID)) - context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID)) - context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID)) - - # ----- Check remove event ----------------------------------------------------------------------------------------- - # events = events_collector.get_events(block=True, count=3) - - # assert isinstance(events[0], DeviceEvent) - # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[0].device_id.device_uuid.uuid == DEVICE_R1_UUID - - # assert isinstance(events[1], TopologyEvent) - # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # assert isinstance(events[2], ContextEvent) - # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[2].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- - # events_collector.stop() - - # ----- Dump state of database after remove the object ------------------------------------------------------------- - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 0 - - -def test_grpc_link( - context_client_grpc: ContextClient, # pylint: disable=redefined-outer-name - context_s_mb: Tuple[Session, MessageBroker]): # pylint: disable=redefined-outer-name - session = context_s_mb[0] - - database = Database(session) - - # ----- Clean the database ----------------------------------------------------------------------------------------- - database.clear() - - # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- - events_collector = EventsCollector(context_client_grpc) - events_collector.start() - - # ----- Prepare dependencies for the test and capture related events ----------------------------------------------- - response = context_client_grpc.SetContext(Context(**CONTEXT)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - response = context_client_grpc.SetTopology(Topology(**TOPOLOGY)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - response = context_client_grpc.SetDevice(Device(**DEVICE_R1)) - assert response.device_uuid.uuid == DEVICE_R1_UUID - - response = context_client_grpc.SetDevice(Device(**DEVICE_R2)) - assert response.device_uuid.uuid == DEVICE_R2_UUID - # events = events_collector.get_events(block=True, count=4) - - # assert isinstance(events[0], ContextEvent) - # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # - # assert isinstance(events[1], TopologyEvent) - # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - # - # assert isinstance(events[2], DeviceEvent) - # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[2].device_id.device_uuid.uuid == DEVICE_R1_UUID - # - # assert isinstance(events[3], DeviceEvent) - # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[3].device_id.device_uuid.uuid == DEVICE_R2_UUID - - # ----- Get when the object does not exist ------------------------------------------------------------------------- - with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetLink(LinkId(**LINK_R1_R2_ID)) - assert e.value.code() == grpc.StatusCode.NOT_FOUND - assert e.value.details() == 'Link({:s}) not found'.format(LINK_R1_R2_UUID) - - # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListLinkIds(Empty()) - assert len(response.link_ids) == 0 - - response = context_client_grpc.ListLinks(Empty()) - assert len(response.links) == 0 - - # ----- Dump state of database before create the object ------------------------------------------------------------ - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 80 - - # ----- Create the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetLink(Link(**LINK_R1_R2)) - assert response.link_uuid.uuid == LINK_R1_R2_UUID - - # ----- Check create event ----------------------------------------------------------------------------------------- - # event = events_collector.get_event(block=True) - # assert isinstance(event, LinkEvent) - # assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert event.link_id.link_uuid.uuid == LINK_R1_R2_UUID - - # ----- Update the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetLink(Link(**LINK_R1_R2)) - assert response.link_uuid.uuid == LINK_R1_R2_UUID - # ----- Check update event ----------------------------------------------------------------------------------------- - # event = events_collector.get_event(block=True) - # assert isinstance(event, LinkEvent) - # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - # assert event.link_id.link_uuid.uuid == LINK_R1_R2_UUID - - # ----- Dump state of database after create/update the object ------------------------------------------------------ - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 88 - - # ----- Get when the object exists --------------------------------------------------------------------------------- - response = context_client_grpc.GetLink(LinkId(**LINK_R1_R2_ID)) - assert response.link_id.link_uuid.uuid == LINK_R1_R2_UUID - assert len(response.link_endpoint_ids) == 2 - - # ----- List when the object exists -------------------------------------------------------------------------------- - response = context_client_grpc.ListLinkIds(Empty()) - assert len(response.link_ids) == 1 - assert response.link_ids[0].link_uuid.uuid == LINK_R1_R2_UUID - - response = context_client_grpc.ListLinks(Empty()) - assert len(response.links) == 1 - assert response.links[0].link_id.link_uuid.uuid == LINK_R1_R2_UUID - - assert len(response.links[0].link_endpoint_ids) == 2 - - # ----- Create object relation ------------------------------------------------------------------------------------- - TOPOLOGY_WITH_LINK = copy.deepcopy(TOPOLOGY) - TOPOLOGY_WITH_LINK['link_ids'].append(LINK_R1_R2_ID) - response = context_client_grpc.SetTopology(Topology(**TOPOLOGY_WITH_LINK)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # ----- Check update event ----------------------------------------------------------------------------------------- - # event = events_collector.get_event(block=True) - # assert isinstance(event, TopologyEvent) - # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - # assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - # ----- Check relation was created --------------------------------------------------------------------------------- - response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID)) - assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - assert len(response.device_ids) == 2 - # assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID - # assert response.device_ids[1].device_uuid.uuid == DEVICE_R2_UUID - assert len(response.link_ids) == 1 - assert response.link_ids[0].link_uuid.uuid == LINK_R1_R2_UUID - - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 88 - - # ----- Remove the object ------------------------------------------------------------------------------------------ - context_client_grpc.RemoveLink(LinkId(**LINK_R1_R2_ID)) - context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID)) - context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R2_ID)) - context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID)) - context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID)) - - # ----- Check remove event ----------------------------------------------------------------------------------------- - # events = events_collector.get_events(block=True, count=5) - # - # assert isinstance(events[0], LinkEvent) - # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[0].link_id.link_uuid.uuid == LINK_R1_R2_UUID - # - # assert isinstance(events[1], DeviceEvent) - # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[1].device_id.device_uuid.uuid == DEVICE_R1_UUID - # - # assert isinstance(events[2], DeviceEvent) - # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[2].device_id.device_uuid.uuid == DEVICE_R2_UUID - # - # assert isinstance(events[3], TopologyEvent) - # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[3].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # assert events[3].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - # - # assert isinstance(events[4], ContextEvent) - # assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[4].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- - events_collector.stop() - - # ----- Dump state of database after remove the object ------------------------------------------------------------- - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 0 -""" - -def test_grpc_service( - context_client_grpc : ContextClient, # pylint: disable=redefined-outer-name - context_s_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name - Session = context_s_mb[0] - # ----- Clean the database ----------------------------------------------------------------------------------------- - database = Database(Session) - database.clear() - - # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- - events_collector = EventsCollector(context_client_grpc) - events_collector.start() - - # ----- Prepare dependencies for the test and capture related events ----------------------------------------------- - response = context_client_grpc.SetContext(Context(**CONTEXT)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - response = context_client_grpc.SetTopology(Topology(**TOPOLOGY)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - response = context_client_grpc.SetDevice(Device(**DEVICE_R1)) - assert response.device_uuid.uuid == DEVICE_R1_UUID - - response = context_client_grpc.SetDevice(Device(**DEVICE_R2)) - assert response.device_uuid.uuid == DEVICE_R2_UUID - # events = events_collector.get_events(block=True, count=4) - # - # assert isinstance(events[0], ContextEvent) - # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # - # assert isinstance(events[1], TopologyEvent) - # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - # assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - # - # assert isinstance(events[2], DeviceEvent) - # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[2].device_id.device_uuid.uuid == DEVICE_R1_UUID - # - # assert isinstance(events[3], DeviceEvent) - # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[3].device_id.device_uuid.uuid == DEVICE_R2_UUID - LOGGER.info('----------------') - - # ----- Get when the object does not exist ------------------------------------------------------------------------- - with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetService(ServiceId(**SERVICE_R1_R2_ID)) - assert e.value.code() == grpc.StatusCode.NOT_FOUND - assert e.value.details() == 'Service({:s}) not found'.format(SERVICE_R1_R2_UUID) - LOGGER.info('----------------') - - # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListServiceIds(ContextId(**CONTEXT_ID)) - assert len(response.service_ids) == 0 - LOGGER.info('----------------') - - response = context_client_grpc.ListServices(ContextId(**CONTEXT_ID)) - assert len(response.services) == 0 - LOGGER.info('----------------') - - # ----- Dump state of database before create the object ------------------------------------------------------------ - db_entries = database.dump_all() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(db_entry) - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 80 - - # ----- Create the object ------------------------------------------------------------------------------------------ - with pytest.raises(grpc.RpcError) as e: - WRONG_SERVICE = copy.deepcopy(SERVICE_R1_R2) - WRONG_SERVICE['service_endpoint_ids'][0]\ - ['topology_id']['context_id']['context_uuid']['uuid'] = 'ca1ea172-728f-441d-972c-feeae8c9bffc' - context_client_grpc.SetService(Service(**WRONG_SERVICE)) - assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT - msg = 'request.service_endpoint_ids[0].topology_id.context_id.context_uuid.uuid(ca1ea172-728f-441d-972c-feeae8c9bffc) is invalid; '\ - 'should be == request.service_id.context_id.context_uuid.uuid({:s})'.format(DEFAULT_CONTEXT_UUID) - assert e.value.details() == msg - - response = context_client_grpc.SetService(Service(**SERVICE_R1_R2)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.service_uuid.uuid == SERVICE_R1_R2_UUID - - CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT) - CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R1_R2_ID) - response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Check create event ----------------------------------------------------------------------------------------- - events = events_collector.get_events(block=True, count=2) - - assert isinstance(events[0], ServiceEvent) - assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[0].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[0].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID - - assert isinstance(events[1], ContextEvent) - assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - assert events[1].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Update the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetService(Service(**SERVICE_R1_R2)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.service_uuid.uuid == SERVICE_R1_R2_UUID - - # ----- Check update event ----------------------------------------------------------------------------------------- - event = events_collector.get_event(block=True) - assert isinstance(event, ServiceEvent) - assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - assert event.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert event.service_id.service_uuid.uuid == SERVICE_R1_R2_UUID - - # ----- Dump state of database after create/update the object ------------------------------------------------------ - db_entries = context_database.dump() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 108 - - # ----- Get when the object exists --------------------------------------------------------------------------------- - response = context_client_grpc.GetService(ServiceId(**SERVICE_R1_R2_ID)) - assert response.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.service_id.service_uuid.uuid == SERVICE_R1_R2_UUID - assert response.service_type == ServiceTypeEnum.SERVICETYPE_L3NM - assert len(response.service_endpoint_ids) == 2 - assert len(response.service_constraints) == 2 - assert response.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_PLANNED - assert len(response.service_config.config_rules) == 3 - - # ----- List when the object exists -------------------------------------------------------------------------------- - response = context_client_grpc.ListServiceIds(ContextId(**CONTEXT_ID)) - assert len(response.service_ids) == 1 - assert response.service_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.service_ids[0].service_uuid.uuid == SERVICE_R1_R2_UUID - - response = context_client_grpc.ListServices(ContextId(**CONTEXT_ID)) - assert len(response.services) == 1 - assert response.services[0].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.services[0].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID - assert response.services[0].service_type == ServiceTypeEnum.SERVICETYPE_L3NM - assert len(response.services[0].service_endpoint_ids) == 2 - assert len(response.services[0].service_constraints) == 2 - assert response.services[0].service_status.service_status == ServiceStatusEnum.SERVICESTATUS_PLANNED - assert len(response.services[0].service_config.config_rules) == 3 - - # ----- Remove the object ------------------------------------------------------------------------------------------ - context_client_grpc.RemoveService(ServiceId(**SERVICE_R1_R2_ID)) - context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID)) - context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R2_ID)) - context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID)) - context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID)) - - # ----- Check remove event ----------------------------------------------------------------------------------------- - events = events_collector.get_events(block=True, count=5) - - assert isinstance(events[0], ServiceEvent) - assert events[0].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[0].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID - - assert isinstance(events[1], DeviceEvent) - assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[1].device_id.device_uuid.uuid == DEVICE_R1_UUID - - assert isinstance(events[2], DeviceEvent) - assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[2].device_id.device_uuid.uuid == DEVICE_R2_UUID - - assert isinstance(events[3], TopologyEvent) - assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[3].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[3].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - assert isinstance(events[4], ContextEvent) - assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[4].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- - events_collector.stop() - - # ----- Dump state of database after remove the object ------------------------------------------------------------- - db_entries = context_database.dump() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 0 - - -""" - -def test_grpc_connection( - context_client_grpc : ContextClient, # pylint: disable=redefined-outer-name - context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name - Session = context_s_mb[0] - - database = Database(Session) - - # ----- Clean the database ----------------------------------------------------------------------------------------- - database.clear() - - # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- - events_collector = EventsCollector(context_client_grpc) - events_collector.start() - - # ----- Prepare dependencies for the test and capture related events ----------------------------------------------- - response = context_client_grpc.SetContext(Context(**CONTEXT)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - response = context_client_grpc.SetTopology(Topology(**TOPOLOGY)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - response = context_client_grpc.SetDevice(Device(**DEVICE_R1)) - assert response.device_uuid.uuid == DEVICE_R1_UUID - - response = context_client_grpc.SetDevice(Device(**DEVICE_R2)) - assert response.device_uuid.uuid == DEVICE_R2_UUID - - response = context_client_grpc.SetDevice(Device(**DEVICE_R3)) - assert response.device_uuid.uuid == DEVICE_R3_UUID - - response = context_client_grpc.SetService(Service(**SERVICE_R1_R2)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.service_uuid.uuid == SERVICE_R1_R2_UUID - - CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT) - CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R1_R2_ID) - response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - response = context_client_grpc.SetService(Service(**SERVICE_R2_R3)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.service_uuid.uuid == SERVICE_R2_R3_UUID - - CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT) - CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R2_R3_ID) - response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - response = context_client_grpc.SetService(Service(**SERVICE_R1_R3)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.service_uuid.uuid == SERVICE_R1_R3_UUID - - CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT) - CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R1_R3_ID) - response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - events = events_collector.get_events(block=True, count=11) - - assert isinstance(events[0], ContextEvent) - assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - assert isinstance(events[1], TopologyEvent) - assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - assert isinstance(events[2], DeviceEvent) - assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[2].device_id.device_uuid.uuid == DEVICE_R1_UUID - - assert isinstance(events[3], DeviceEvent) - assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[3].device_id.device_uuid.uuid == DEVICE_R2_UUID - - assert isinstance(events[4], DeviceEvent) - assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[4].device_id.device_uuid.uuid == DEVICE_R3_UUID - - assert isinstance(events[5], ServiceEvent) - assert events[5].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[5].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[5].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID - - assert isinstance(events[6], ContextEvent) - assert events[6].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - assert events[6].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - assert isinstance(events[7], ServiceEvent) - assert events[7].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[7].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[7].service_id.service_uuid.uuid == SERVICE_R2_R3_UUID - - assert isinstance(events[8], ContextEvent) - assert events[8].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - assert events[8].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - assert isinstance(events[9], ServiceEvent) - assert events[9].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert events[9].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[9].service_id.service_uuid.uuid == SERVICE_R1_R3_UUID - - assert isinstance(events[10], ContextEvent) - assert events[10].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - assert events[10].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Get when the object does not exist ------------------------------------------------------------------------- - with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetConnection(ConnectionId(**CONNECTION_R1_R3_ID)) - assert e.value.code() == grpc.StatusCode.NOT_FOUND - assert e.value.details() == 'Connection({:s}) not found'.format(CONNECTION_R1_R3_UUID) - - # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListConnectionIds(ServiceId(**SERVICE_R1_R3_ID)) - assert len(response.connection_ids) == 0 - - response = context_client_grpc.ListConnections(ServiceId(**SERVICE_R1_R3_ID)) - assert len(response.connections) == 0 - - # ----- Dump state of database before create the object ------------------------------------------------------------ - db_entries = context_database.dump() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 187 - - # ----- Create the object ------------------------------------------------------------------------------------------ - with pytest.raises(grpc.RpcError) as e: - WRONG_CONNECTION = copy.deepcopy(CONNECTION_R1_R3) - WRONG_CONNECTION['path_hops_endpoint_ids'][0]\ - ['topology_id']['context_id']['context_uuid']['uuid'] = 'wrong-context-uuid' - context_client_grpc.SetConnection(Connection(**WRONG_CONNECTION)) - assert e.value.code() == grpc.StatusCode.NOT_FOUND - # TODO: should we check that all endpoints belong to same topology? - # TODO: should we check that endpoints form links over the topology? - msg = 'EndPoint({:s}/{:s}:wrong-context-uuid/{:s}) not found'.format( - DEVICE_R1_UUID, WRONG_CONNECTION['path_hops_endpoint_ids'][0]['endpoint_uuid']['uuid'], DEFAULT_TOPOLOGY_UUID) - assert e.value.details() == msg - - response = context_client_grpc.SetConnection(Connection(**CONNECTION_R1_R3)) - assert response.connection_uuid.uuid == CONNECTION_R1_R3_UUID - - # ----- Check create event ----------------------------------------------------------------------------------------- - event = events_collector.get_event(block=True) - assert isinstance(event, ConnectionEvent) - assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE - assert event.connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID - - # ----- Update the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetConnection(Connection(**CONNECTION_R1_R3)) - assert response.connection_uuid.uuid == CONNECTION_R1_R3_UUID - - # ----- Check update event ----------------------------------------------------------------------------------------- - event = events_collector.get_event(block=True) - assert isinstance(event, ConnectionEvent) - assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - assert event.connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID - - # ----- Dump state of database after create/update the object ------------------------------------------------------ - db_entries = context_database.dump() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 203 - - # ----- Get when the object exists --------------------------------------------------------------------------------- - response = context_client_grpc.GetConnection(ConnectionId(**CONNECTION_R1_R3_ID)) - assert response.connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID - assert response.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.service_id.service_uuid.uuid == SERVICE_R1_R3_UUID - assert len(response.path_hops_endpoint_ids) == 6 - assert len(response.sub_service_ids) == 2 - - # ----- List when the object exists -------------------------------------------------------------------------------- - response = context_client_grpc.ListConnectionIds(ServiceId(**SERVICE_R1_R3_ID)) - assert len(response.connection_ids) == 1 - assert response.connection_ids[0].connection_uuid.uuid == CONNECTION_R1_R3_UUID - - response = context_client_grpc.ListConnections(ServiceId(**SERVICE_R1_R3_ID)) - assert len(response.connections) == 1 - assert response.connections[0].connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID - assert len(response.connections[0].path_hops_endpoint_ids) == 6 - assert len(response.connections[0].sub_service_ids) == 2 - - # ----- Remove the object ------------------------------------------------------------------------------------------ - context_client_grpc.RemoveConnection(ConnectionId(**CONNECTION_R1_R3_ID)) - context_client_grpc.RemoveService(ServiceId(**SERVICE_R1_R3_ID)) - context_client_grpc.RemoveService(ServiceId(**SERVICE_R2_R3_ID)) - context_client_grpc.RemoveService(ServiceId(**SERVICE_R1_R2_ID)) - context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID)) - context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R2_ID)) - context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R3_ID)) - context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID)) - context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID)) - - # ----- Check remove event ----------------------------------------------------------------------------------------- - events = events_collector.get_events(block=True, count=9) - - assert isinstance(events[0], ConnectionEvent) - assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[0].connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID - - assert isinstance(events[1], ServiceEvent) - assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[1].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[1].service_id.service_uuid.uuid == SERVICE_R1_R3_UUID - - assert isinstance(events[2], ServiceEvent) - assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[2].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[2].service_id.service_uuid.uuid == SERVICE_R2_R3_UUID - - assert isinstance(events[3], ServiceEvent) - assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[3].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[3].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID - - assert isinstance(events[4], DeviceEvent) - assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[4].device_id.device_uuid.uuid == DEVICE_R1_UUID - - assert isinstance(events[5], DeviceEvent) - assert events[5].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[5].device_id.device_uuid.uuid == DEVICE_R2_UUID - - assert isinstance(events[6], DeviceEvent) - assert events[6].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[6].device_id.device_uuid.uuid == DEVICE_R3_UUID - - assert isinstance(events[7], TopologyEvent) - assert events[7].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[7].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert events[7].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID - - assert isinstance(events[8], ContextEvent) - assert events[8].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - assert events[8].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- - events_collector.stop() - - # ----- Dump state of database after remove the object ------------------------------------------------------------- - db_entries = context_database.dump() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 0 - - -def test_grpc_policy( - context_client_grpc : ContextClient, # pylint: disable=redefined-outer-name - context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name - context_database = context_db_mb[0] - - # ----- Clean the database ----------------------------------------------------------------------------------------- - context_database.clear_all() - - # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- - #events_collector = EventsCollector(context_client_grpc) - #events_collector.start() - - # ----- Get when the object does not exist ------------------------------------------------------------------------- - POLICY_ID = 'no-uuid' - DEFAULT_POLICY_ID = {'uuid': {'uuid': POLICY_ID}} - - with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetPolicyRule(PolicyRuleId(**DEFAULT_POLICY_ID)) - - assert e.value.code() == grpc.StatusCode.NOT_FOUND - assert e.value.details() == 'PolicyRule({:s}) not found'.format(POLICY_ID) - - # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListPolicyRuleIds(Empty()) - assert len(response.policyRuleIdList) == 0 - - response = context_client_grpc.ListPolicyRules(Empty()) - assert len(response.policyRules) == 0 - - # ----- Dump state of database before create the object ------------------------------------------------------------ - db_entries = context_database.dump() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 0 - - # ----- Create the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetPolicyRule(PolicyRule(**POLICY_RULE)) - assert response.uuid.uuid == POLICY_RULE_UUID - - # ----- Check create event ----------------------------------------------------------------------------------------- - # events = events_collector.get_events(block=True, count=1) - # assert isinstance(events[0], PolicyEvent) - # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE - # assert events[0].policy_id.uuid.uuid == POLICY_RULE_UUID - - # ----- Update the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetPolicyRule(PolicyRule(**POLICY_RULE)) - assert response.uuid.uuid == POLICY_RULE_UUID - - # ----- Dump state of database after create/update the object ------------------------------------------------------ - db_entries = context_database.dump() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 2 - - # ----- Get when the object exists --------------------------------------------------------------------------------- - response = context_client_grpc.GetPolicyRule(PolicyRuleId(**POLICY_RULE_ID)) - assert response.device.policyRuleBasic.policyRuleId.uuid.uuid == POLICY_RULE_UUID - - # ----- List when the object exists -------------------------------------------------------------------------------- - response = context_client_grpc.ListPolicyRuleIds(Empty()) - assert len(response.policyRuleIdList) == 1 - assert response.policyRuleIdList[0].uuid.uuid == POLICY_RULE_UUID - - response = context_client_grpc.ListPolicyRules(Empty()) - assert len(response.policyRules) == 1 - - # ----- Remove the object ------------------------------------------------------------------------------------------ - context_client_grpc.RemovePolicyRule(PolicyRuleId(**POLICY_RULE_ID)) - - # ----- Check remove event ----------------------------------------------------------------------------------------- - # events = events_collector.get_events(block=True, count=2) - - # assert isinstance(events[0], PolicyEvent) - # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - # assert events[0].policy_id.uuid.uuid == POLICY_RULE_UUID - - - # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- - # events_collector.stop() - - # ----- Dump state of database after remove the object ------------------------------------------------------------- - db_entries = context_database.dump() - LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries))) - for db_entry in db_entries: - LOGGER.info(' [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover - LOGGER.info('-----------------------------------------------------------') - assert len(db_entries) == 0 - - - -# ----- Test REST API methods ------------------------------------------------------------------------------------------ - -def test_rest_populate_database( - context_db_mb : Tuple[Database, MessageBroker], # pylint: disable=redefined-outer-name - context_service_grpc : ContextService # pylint: disable=redefined-outer-name - ): - database = context_db_mb[0] - database.clear_all() - populate(LOCAL_HOST, GRPC_PORT) - -def test_rest_get_context_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_request('/context_ids') - validate_context_ids(reply) - -def test_rest_get_contexts(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_request('/contexts') - validate_contexts(reply) - -def test_rest_get_context(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - reply = do_rest_request('/context/{:s}'.format(context_uuid)) - validate_context(reply) - -def test_rest_get_topology_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - reply = do_rest_request('/context/{:s}/topology_ids'.format(context_uuid)) - validate_topology_ids(reply) - -def test_rest_get_topologies(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - reply = do_rest_request('/context/{:s}/topologies'.format(context_uuid)) - validate_topologies(reply) - -def test_rest_get_topology(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - topology_uuid = urllib.parse.quote(DEFAULT_TOPOLOGY_UUID) - reply = do_rest_request('/context/{:s}/topology/{:s}'.format(context_uuid, topology_uuid)) - validate_topology(reply, num_devices=3, num_links=3) - -def test_rest_get_service_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - reply = do_rest_request('/context/{:s}/service_ids'.format(context_uuid)) - validate_service_ids(reply) - -def test_rest_get_services(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - reply = do_rest_request('/context/{:s}/services'.format(context_uuid)) - validate_services(reply) - -def test_rest_get_service(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - service_uuid = urllib.parse.quote(SERVICE_R1_R2_UUID, safe='') - reply = do_rest_request('/context/{:s}/service/{:s}'.format(context_uuid, service_uuid)) - validate_service(reply) - -def test_rest_get_slice_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - reply = do_rest_request('/context/{:s}/slice_ids'.format(context_uuid)) - #validate_slice_ids(reply) - -def test_rest_get_slices(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - reply = do_rest_request('/context/{:s}/slices'.format(context_uuid)) - #validate_slices(reply) - -#def test_rest_get_slice(context_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) -# slice_uuid = urllib.parse.quote(SLICE_R1_R2_UUID, safe='') -# reply = do_rest_request('/context/{:s}/slice/{:s}'.format(context_uuid, slice_uuid)) -# #validate_slice(reply) - -def test_rest_get_device_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_request('/device_ids') - validate_device_ids(reply) - -def test_rest_get_devices(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_request('/devices') - validate_devices(reply) - -def test_rest_get_device(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - device_uuid = urllib.parse.quote(DEVICE_R1_UUID, safe='') - reply = do_rest_request('/device/{:s}'.format(device_uuid)) - validate_device(reply) - -def test_rest_get_link_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_request('/link_ids') - validate_link_ids(reply) - -def test_rest_get_links(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_request('/links') - validate_links(reply) - -def test_rest_get_link(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - link_uuid = urllib.parse.quote(LINK_R1_R2_UUID, safe='') - reply = do_rest_request('/link/{:s}'.format(link_uuid)) - validate_link(reply) - -def test_rest_get_connection_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - service_uuid = urllib.parse.quote(SERVICE_R1_R3_UUID, safe='') - reply = do_rest_request('/context/{:s}/service/{:s}/connection_ids'.format(context_uuid, service_uuid)) - validate_connection_ids(reply) - -def test_rest_get_connections(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_UUID) - service_uuid = urllib.parse.quote(SERVICE_R1_R3_UUID, safe='') - reply = do_rest_request('/context/{:s}/service/{:s}/connections'.format(context_uuid, service_uuid)) - validate_connections(reply) - -def test_rest_get_connection(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - connection_uuid = urllib.parse.quote(CONNECTION_R1_R3_UUID, safe='') - reply = do_rest_request('/connection/{:s}'.format(connection_uuid)) - validate_connection(reply) - -def test_rest_get_policyrule_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_request('/policyrule_ids') - #validate_policyrule_ids(reply) - -def test_rest_get_policyrules(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_request('/policyrules') - #validate_policyrules(reply) - -#def test_rest_get_policyrule(context_service_rest : RestServer): # pylint: disable=redefined-outer-name -# policyrule_uuid = urllib.parse.quote(POLICYRULE_UUID, safe='') -# reply = do_rest_request('/policyrule/{:s}'.format(policyrule_uuid)) -# #validate_policyrule(reply) - - -# ----- Test misc. Context internal tools ------------------------------------------------------------------------------ - -def test_tools_fast_string_hasher(): - with pytest.raises(TypeError) as e: - fast_hasher(27) - assert str(e.value) == "data(27) must be " + FASTHASHER_DATA_ACCEPTED_FORMAT + ", found <class 'int'>" - - with pytest.raises(TypeError) as e: - fast_hasher({27}) - assert str(e.value) == "data({27}) must be " + FASTHASHER_DATA_ACCEPTED_FORMAT + ", found <class 'set'>" - - with pytest.raises(TypeError) as e: - fast_hasher({'27'}) - assert str(e.value) == "data({'27'}) must be " + FASTHASHER_DATA_ACCEPTED_FORMAT + ", found <class 'set'>" - - with pytest.raises(TypeError) as e: - fast_hasher([27]) - assert str(e.value) == "data[0](27) must be " + FASTHASHER_ITEM_ACCEPTED_FORMAT + ", found <class 'int'>" - - fast_hasher('hello-world') - fast_hasher('hello-world'.encode('UTF-8')) - fast_hasher(['hello', 'world']) - fast_hasher(('hello', 'world')) - fast_hasher(['hello'.encode('UTF-8'), 'world'.encode('UTF-8')]) - fast_hasher(('hello'.encode('UTF-8'), 'world'.encode('UTF-8'))) -""" \ No newline at end of file diff --git a/src/context/service/database/Context.py b/src/context/service/database/Context.py index 85a06d65ecee7242b642a5a87b08c3215cc7a1cc..e136a4f83c2feff6b8da3d2df7de725b6b5d94cf 100644 --- a/src/context/service/database/Context.py +++ b/src/context/service/database/Context.py @@ -43,8 +43,7 @@ def context_list_objs(db_engine : Engine) -> ContextList: def context_get(db_engine : Engine, request : ContextId) -> Context: context_uuid = context_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: - obj : Optional[ContextModel] = session.query(ContextModel)\ - .filter_by(context_uuid=context_uuid).one_or_none() + obj : Optional[ContextModel] = session.query(ContextModel).filter_by(context_uuid=context_uuid).one_or_none() return None if obj is None else obj.dump() obj = run_transaction(sessionmaker(bind=db_engine), callback) if obj is None: diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py index 7607a2349fd109134f1680161a36c3ccea926262..8899b5a12dbd9e9656d0454e92b17befb87c3453 100644 --- a/src/context/service/database/Device.py +++ b/src/context/service/database/Device.py @@ -16,7 +16,7 @@ from sqlalchemy.dialects.postgresql import insert from sqlalchemy.engine import Engine from sqlalchemy.orm import Session, sessionmaker from sqlalchemy_cockroachdb import run_transaction -from typing import Dict, List, Optional, Set +from typing import Dict, List, Optional, Set, Tuple from common.proto.context_pb2 import Device, DeviceId, DeviceIdList, DeviceList from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentException, NotFoundException from common.tools.object_factory.Device import json_device_id @@ -47,8 +47,7 @@ def device_list_objs(db_engine : Engine) -> DeviceList: def device_get(db_engine : Engine, request : DeviceId) -> Device: device_uuid = device_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: - obj : Optional[DeviceModel] = session.query(DeviceModel)\ - .filter_by(device_uuid=device_uuid).one_or_none() + obj : Optional[DeviceModel] = session.query(DeviceModel).filter_by(device_uuid=device_uuid).one_or_none() return None if obj is None else obj.dump() obj = run_transaction(sessionmaker(bind=db_engine), callback) if obj is None: @@ -58,7 +57,7 @@ def device_get(db_engine : Engine, request : DeviceId) -> Device: ]) return Device(**obj) -def device_set(db_engine : Engine, request : Device) -> bool: +def device_set(db_engine : Engine, request : Device) -> Tuple[DeviceId, bool]: raw_device_uuid = request.device_id.device_uuid.uuid raw_device_name = request.name device_name = raw_device_uuid if len(raw_device_name) == 0 else raw_device_name diff --git a/src/context/service/database/Link.py b/src/context/service/database/Link.py index 9f11cad2376b0d36ba5db5addff43097d1de26c3..7032a213888e6754ebf07dab0cde22ff3fb92a33 100644 --- a/src/context/service/database/Link.py +++ b/src/context/service/database/Link.py @@ -42,8 +42,7 @@ def link_list_objs(db_engine : Engine) -> LinkList: def link_get(db_engine : Engine, request : LinkId) -> Link: link_uuid = link_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: - obj : Optional[LinkModel] = session.query(LinkModel)\ - .filter_by(link_uuid=link_uuid).one_or_none() + obj : Optional[LinkModel] = session.query(LinkModel).filter_by(link_uuid=link_uuid).one_or_none() return None if obj is None else obj.dump() obj = run_transaction(sessionmaker(bind=db_engine), callback) if obj is None: @@ -53,7 +52,7 @@ def link_get(db_engine : Engine, request : LinkId) -> Link: ]) return Link(**obj) -def link_set(db_engine : Engine, request : Link) -> bool: +def link_set(db_engine : Engine, request : Link) -> Tuple[LinkId, bool]: raw_link_uuid = request.link_id.link_uuid.uuid raw_link_name = request.name link_name = raw_link_uuid if len(raw_link_name) == 0 else raw_link_name diff --git a/src/context/service/database/Service.py b/src/context/service/database/Service.py index 7e3d9d044b1991c145528897bc28c09889ae1862..0230bc4d5f6f731fed114716eec4a751cae3fc95 100644 --- a/src/context/service/database/Service.py +++ b/src/context/service/database/Service.py @@ -16,7 +16,7 @@ from sqlalchemy.dialects.postgresql import insert from sqlalchemy.engine import Engine from sqlalchemy.orm import Session, sessionmaker from sqlalchemy_cockroachdb import run_transaction -from typing import Dict, List, Optional +from typing import Dict, List, Optional, Tuple from common.proto.context_pb2 import ContextId, Service, ServiceId, ServiceIdList, ServiceList from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentException, NotFoundException from common.tools.object_factory.Context import json_context_id @@ -50,8 +50,7 @@ def service_list_objs(db_engine : Engine, request : ContextId) -> ServiceList: def service_get(db_engine : Engine, request : ServiceId) -> Service: _,service_uuid = service_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: - obj : Optional[ServiceModel] = session.query(ServiceModel)\ - .filter_by(service_uuid=service_uuid).one_or_none() + obj : Optional[ServiceModel] = session.query(ServiceModel).filter_by(service_uuid=service_uuid).one_or_none() return None if obj is None else obj.dump() obj = run_transaction(sessionmaker(bind=db_engine), callback) if obj is None: @@ -63,7 +62,7 @@ def service_get(db_engine : Engine, request : ServiceId) -> Service: ]) return Service(**obj) -def service_set(db_engine : Engine, request : Service) -> bool: +def service_set(db_engine : Engine, request : Service) -> Tuple[ServiceId, bool]: raw_context_uuid = request.service_id.context_id.context_uuid.uuid raw_service_uuid = request.service_id.service_uuid.uuid raw_service_name = request.name diff --git a/src/context/service/database/Slice.py b/src/context/service/database/Slice.py new file mode 100644 index 0000000000000000000000000000000000000000..318923555e71307aa91258da774ca2a4255d85ff --- /dev/null +++ b/src/context/service/database/Slice.py @@ -0,0 +1,216 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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. + +from sqlalchemy import and_, delete +from sqlalchemy.dialects.postgresql import insert +from sqlalchemy.engine import Engine +from sqlalchemy.orm import Session, sessionmaker +from sqlalchemy_cockroachdb import run_transaction +from typing import Dict, List, Optional, Set, Tuple +from common.proto.context_pb2 import ContextId, Slice, SliceId, SliceIdList, SliceList +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentException, NotFoundException +from common.tools.object_factory.Context import json_context_id +from common.tools.object_factory.Slice import json_slice_id +from context.service.database.ConfigRule import compose_config_rules_data, upsert_config_rules +from context.service.database.Constraint import compose_constraints_data, upsert_constraints +from .models.enums.SliceStatus import grpc_to_enum__slice_status +from .models.RelationModels import SliceEndPointModel, SliceServiceModel #, SliceSubSliceModel +from .models.SliceModel import SliceModel +from .uuids.Context import context_get_uuid +from .uuids.EndPoint import endpoint_get_uuid +from .uuids.Service import service_get_uuid +from .uuids.Slice import slice_get_uuid + +def slice_list_ids(db_engine : Engine, request : ContextId) -> SliceIdList: + context_uuid = context_get_uuid(request, allow_random=False) + def callback(session : Session) -> List[Dict]: + obj_list : List[SliceModel] = session.query(SliceModel).filter_by(context_uuid=context_uuid).all() + #.options(selectinload(ContextModel.slice)).filter_by(context_uuid=context_uuid).one_or_none() + return [obj.dump_id() for obj in obj_list] + return SliceIdList(slice_ids=run_transaction(sessionmaker(bind=db_engine), callback)) + +def slice_list_objs(db_engine : Engine, request : ContextId) -> SliceList: + context_uuid = context_get_uuid(request, allow_random=False) + def callback(session : Session) -> List[Dict]: + obj_list : List[SliceModel] = session.query(SliceModel).filter_by(context_uuid=context_uuid).all() + #.options(selectinload(ContextModel.slice)).filter_by(context_uuid=context_uuid).one_or_none() + return [obj.dump() for obj in obj_list] + return SliceList(slices=run_transaction(sessionmaker(bind=db_engine), callback)) + +def slice_get(db_engine : Engine, request : SliceId) -> Slice: + _,slice_uuid = slice_get_uuid(request, allow_random=False) + def callback(session : Session) -> Optional[Dict]: + obj : Optional[SliceModel] = session.query(SliceModel).filter_by(slice_uuid=slice_uuid).one_or_none() + return None if obj is None else obj.dump() + obj = run_transaction(sessionmaker(bind=db_engine), callback) + if obj is None: + context_uuid = context_get_uuid(request.context_id, allow_random=False) + raw_slice_uuid = '{:s}/{:s}'.format(request.context_id.context_uuid.uuid, request.slice_uuid.uuid) + raise NotFoundException('Slice', raw_slice_uuid, extra_details=[ + 'context_uuid generated was: {:s}'.format(context_uuid), + 'slice_uuid generated was: {:s}'.format(slice_uuid), + ]) + return Slice(**obj) + +def slice_set(db_engine : Engine, request : Slice) -> Tuple[SliceId, bool]: + raw_context_uuid = request.slice_id.context_id.context_uuid.uuid + raw_slice_uuid = request.slice_id.slice_uuid.uuid + raw_slice_name = request.name + slice_name = raw_slice_uuid if len(raw_slice_name) == 0 else raw_slice_name + context_uuid,slice_uuid = slice_get_uuid(request.slice_id, slice_name=slice_name, allow_random=True) + + slice_status = grpc_to_enum__slice_status(request.slice_status.slice_status) + + slice_endpoints_data : List[Dict] = list() + for i,endpoint_id in enumerate(request.slice_endpoint_ids): + endpoint_context_uuid = endpoint_id.topology_id.context_id.context_uuid.uuid + if len(endpoint_context_uuid) == 0: endpoint_context_uuid = context_uuid + if endpoint_context_uuid not in {raw_context_uuid, context_uuid}: + raise InvalidArgumentException( + 'request.slice_endpoint_ids[{:d}].topology_id.context_id.context_uuid.uuid'.format(i), + endpoint_context_uuid, + ['should be == request.slice_id.context_id.context_uuid.uuid({:s})'.format(raw_context_uuid)]) + + _, _, endpoint_uuid = endpoint_get_uuid(endpoint_id, allow_random=False) + slice_endpoints_data.append({ + 'slice_uuid' : slice_uuid, + 'endpoint_uuid': endpoint_uuid, + }) + + slice_services_data : List[Dict] = list() + for i,service_id in enumerate(request.slice_service_ids): + _, service_uuid = service_get_uuid(service_id, allow_random=False) + slice_services_data.append({ + 'slice_uuid' : slice_uuid, + 'service_uuid': service_uuid, + }) + + #slice_subslices_data : List[Dict] = list() + #for i,subslice_id in enumerate(request.slice_subslice_ids): + # _, subslice_uuid = slice_get_uuid(subslice_id, allow_random=False) + # slice_subslices_data.append({ + # 'slice_uuid' : slice_uuid, + # 'subslice_uuid': subslice_uuid, + # }) + + constraints = compose_constraints_data(request.slice_constraints, slice_uuid=slice_uuid) + config_rules = compose_config_rules_data(request.slice_config.config_rules, slice_uuid=slice_uuid) + + slice_data = [{ + 'context_uuid' : context_uuid, + 'slice_uuid' : slice_uuid, + 'slice_name' : slice_name, + 'slice_status' : slice_status, + 'slice_owner_uuid' : request.slice_owner.owner_uuid.uuid, + 'slice_owner_string': request.slice_owner.owner_string, + }] + + def callback(session : Session) -> None: + stmt = insert(SliceModel).values(slice_data) + stmt = stmt.on_conflict_do_update( + index_elements=[SliceModel.slice_uuid], + set_=dict( + slice_name = stmt.excluded.slice_name, + slice_status = stmt.excluded.slice_status, + slice_owner_uuid = stmt.excluded.slice_owner_uuid, + slice_owner_string = stmt.excluded.slice_owner_string, + ) + ) + session.execute(stmt) + + stmt = insert(SliceEndPointModel).values(slice_endpoints_data) + stmt = stmt.on_conflict_do_nothing( + index_elements=[SliceEndPointModel.slice_uuid, SliceEndPointModel.endpoint_uuid] + ) + session.execute(stmt) + + stmt = insert(SliceServiceModel).values(slice_services_data) + stmt = stmt.on_conflict_do_nothing( + index_elements=[SliceServiceModel.slice_uuid, SliceServiceModel.service_uuid] + ) + session.execute(stmt) + + #stmt = insert(SliceSubSliceModel).values(slice_subslices_data) + #stmt = stmt.on_conflict_do_nothing( + # index_elements=[SliceSubSliceModel.slice_uuid, SliceSubSliceModel.subslice_uuid] + #) + #session.execute(stmt) + + upsert_constraints(session, constraints, slice_uuid=slice_uuid) + upsert_config_rules(session, config_rules, slice_uuid=slice_uuid) + + run_transaction(sessionmaker(bind=db_engine), callback) + updated = False # TODO: improve and check if created/updated + return SliceId(**json_slice_id(slice_uuid, json_context_id(context_uuid))),updated + +def slice_unset(db_engine : Engine, request : Slice) -> Tuple[SliceId, bool]: + raw_context_uuid = request.slice_id.context_id.context_uuid.uuid + raw_slice_uuid = request.slice_id.slice_uuid.uuid + raw_slice_name = request.name + slice_name = raw_slice_uuid if len(raw_slice_name) == 0 else raw_slice_name + context_uuid,slice_uuid = slice_get_uuid(request.slice_id, slice_name=slice_name, allow_random=False) + + if len(request.slice_constraints) > 0: raise NotImplementedError('UnsetSlice: removal of constraints') + if len(request.slice_config.config_rules) > 0: raise NotImplementedError('UnsetSlice: removal of config rules') + if len(request.slice_endpoint_ids) > 0: raise NotImplementedError('UnsetSlice: removal of endpoints') + + slice_endpoint_uuids : Set[str] = set() + for i,endpoint_id in enumerate(request.slice_endpoint_ids): + endpoint_context_uuid = endpoint_id.topology_id.context_id.context_uuid.uuid + if len(endpoint_context_uuid) == 0: endpoint_context_uuid = context_uuid + if endpoint_context_uuid not in {raw_context_uuid, context_uuid}: + raise InvalidArgumentException( + 'request.slice_endpoint_ids[{:d}].topology_id.context_id.context_uuid.uuid'.format(i), + endpoint_context_uuid, + ['should be == request.slice_id.context_id.context_uuid.uuid({:s})'.format(raw_context_uuid)]) + slice_endpoint_uuids.add(endpoint_get_uuid(endpoint_id, allow_random=False)[2]) + + slice_service_uuids : Set[str] = { + service_get_uuid(service_id, allow_random=False)[1] + for service_id in request.slice_service_ids + } + + slice_subslice_uuids : Set[str] = { + slice_get_uuid(subslice_id, allow_random=False)[1] + for subslice_id in request.slice_subslice_ids + } + + def callback(session : Session) -> bool: + num_deletes = 0 + num_deletes += session.query(SliceServiceModel)\ + .filter_by(and_( + SliceServiceModel.slice_uuid == slice_uuid, + SliceServiceModel.service_uuid.in_(slice_service_uuids) + )).delete() + #num_deletes += session.query(SliceSubSliceModel)\ + # .filter_by(and_( + # SliceSubSliceModel.slice_uuid == slice_uuid, + # SliceSubSliceModel.subslice_uuid.in_(slice_subslice_uuids) + # )).delete() + num_deletes += session.query(SliceEndPointModel)\ + .filter_by(and_( + SliceEndPointModel.slice_uuid == slice_uuid, + SliceEndPointModel.endpoint_uuid.in_(slice_endpoint_uuids) + )).delete() + return num_deletes > 0 + + updated = run_transaction(sessionmaker(bind=db_engine), callback) + return SliceId(**json_slice_id(slice_uuid, json_context_id(context_uuid))),updated + +def slice_delete(db_engine : Engine, request : SliceId) -> bool: + _,slice_uuid = slice_get_uuid(request, allow_random=False) + def callback(session : Session) -> bool: + num_deleted = session.query(SliceModel).filter_by(slice_uuid=slice_uuid).delete() + return num_deleted > 0 + return run_transaction(sessionmaker(bind=db_engine), callback) diff --git a/src/context/service/database/Topology.py b/src/context/service/database/Topology.py index ae8d0a8bd889a37bea82ff699ce75e521b6faf23..a7272713cd6c7bc91ae729699cb5c2a1c10004ff 100644 --- a/src/context/service/database/Topology.py +++ b/src/context/service/database/Topology.py @@ -17,7 +17,7 @@ from sqlalchemy.dialects.postgresql import insert from sqlalchemy.engine import Engine from sqlalchemy.orm import Session, sessionmaker from sqlalchemy_cockroachdb import run_transaction -from typing import Dict, List, Optional +from typing import Dict, List, Optional, Tuple from common.proto.context_pb2 import ContextId, Topology, TopologyId, TopologyIdList, TopologyList from common.rpc_method_wrapper.ServiceExceptions import NotFoundException from common.tools.object_factory.Context import json_context_id @@ -60,7 +60,7 @@ def topology_get(db_engine : Engine, request : TopologyId) -> Topology: ]) return Topology(**obj) -def topology_set(db_engine : Engine, request : Topology) -> bool: +def topology_set(db_engine : Engine, request : Topology) -> Tuple[TopologyId, bool]: topology_name = request.name if len(topology_name) == 0: topology_name = request.topology_id.topology_uuid.uuid context_uuid,topology_uuid = topology_get_uuid(request.topology_id, topology_name=topology_name, allow_random=True) diff --git a/src/context/service/database/models/ConfigRuleModel.py b/src/context/service/database/models/ConfigRuleModel.py index 11e151ef66e9f06649579fea96ff18bdc1f855d0..0e4b944272caf7fd480d7ad07621a0c5a2aef44f 100644 --- a/src/context/service/database/models/ConfigRuleModel.py +++ b/src/context/service/database/models/ConfigRuleModel.py @@ -30,6 +30,7 @@ class ConfigRuleModel(_Base): configrule_uuid = Column(UUID(as_uuid=False), primary_key=True) device_uuid = Column(ForeignKey('device.device_uuid', ondelete='CASCADE'), nullable=True) service_uuid = Column(ForeignKey('service.service_uuid', ondelete='CASCADE'), nullable=True) + slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE'), nullable=True) position = Column(Integer, nullable=False) kind = Column(Enum(ConfigRuleKindEnum), nullable=False) action = Column(Enum(ORM_ConfigActionEnum), nullable=False) @@ -37,8 +38,9 @@ class ConfigRuleModel(_Base): __table_args__ = ( CheckConstraint(position >= 0, name='check_position_value'), - #UniqueConstraint('device_uuid', 'position', name='unique_per_device'), + #UniqueConstraint('device_uuid', 'position', name='unique_per_device' ), #UniqueConstraint('service_uuid', 'position', name='unique_per_service'), + #UniqueConstraint('slice_uuid', 'position', name='unique_per_slice' ), ) def dump(self) -> Dict: diff --git a/src/context/service/database/models/ConstraintModel.py b/src/context/service/database/models/ConstraintModel.py index 118ae950556d6e7377053aa56c276cfcc653226a..90adb9ce7e0b1e88b2fa639bd8be4119017509a1 100644 --- a/src/context/service/database/models/ConstraintModel.py +++ b/src/context/service/database/models/ConstraintModel.py @@ -30,7 +30,8 @@ class ConstraintModel(_Base): __tablename__ = 'constraint' constraint_uuid = Column(UUID(as_uuid=False), primary_key=True) - service_uuid = Column(ForeignKey('service.service_uuid', ondelete='CASCADE'), nullable=False) + service_uuid = Column(ForeignKey('service.service_uuid', ondelete='CASCADE'), nullable=True) + slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE'), nullable=True) position = Column(Integer, nullable=False) kind = Column(Enum(ConstraintKindEnum), nullable=False) data = Column(String, nullable=False) @@ -38,6 +39,7 @@ class ConstraintModel(_Base): __table_args__ = ( CheckConstraint(position >= 0, name='check_position_value'), #UniqueConstraint('service_uuid', 'position', name='unique_per_service'), + #UniqueConstraint('slice_uuid', 'position', name='unique_per_slice' ), ) def dump(self) -> Dict: diff --git a/src/context/service/database/models/ContextModel.py b/src/context/service/database/models/ContextModel.py index 1a282e8bd4c9ac0e74b1257f035997393a04347c..ffeb101110c9750856a4c1ba0e81331b945ac454 100644 --- a/src/context/service/database/models/ContextModel.py +++ b/src/context/service/database/models/ContextModel.py @@ -26,7 +26,7 @@ class ContextModel(_Base): topologies = relationship('TopologyModel', back_populates='context') services = relationship('ServiceModel', back_populates='context') - #slices = relationship('SliceModel', back_populates='context') + slices = relationship('SliceModel', back_populates='context') def dump_id(self) -> Dict: return {'context_uuid': {'uuid': self.context_uuid}} @@ -37,5 +37,5 @@ class ContextModel(_Base): 'name' : self.context_name, 'topology_ids': [obj.dump_id() for obj in self.topologies], 'service_ids' : [obj.dump_id() for obj in self.services ], - #'slice_ids' : [obj.dump_id() for obj in self.slices ], + 'slice_ids' : [obj.dump_id() for obj in self.slices ], } diff --git a/src/context/service/database/models/RelationModels.py b/src/context/service/database/models/RelationModels.py index a57d85eb3a598b3909600cba9e36d8e07ef9a74f..468b14519d75d6ca990b0adf09f89da2fd7266d1 100644 --- a/src/context/service/database/models/RelationModels.py +++ b/src/context/service/database/models/RelationModels.py @@ -40,20 +40,32 @@ class ServiceEndPointModel(_Base): service = relationship('ServiceModel', back_populates='service_endpoints', lazy='joined') endpoint = relationship('EndPointModel', lazy='joined') # back_populates='service_endpoints' -# class SliceEndPointModel(Model): -# pk = PrimaryKeyField() -# slice_fk = ForeignKeyField(SliceModel) -# endpoint_fk = ForeignKeyField(EndPointModel) +class SliceEndPointModel(_Base): + __tablename__ = 'slice_endpoint' -# class SliceServiceModel(Model): -# pk = PrimaryKeyField() -# slice_fk = ForeignKeyField(SliceModel) -# service_fk = ForeignKeyField(ServiceModel) + slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE' ), primary_key=True) + endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid', ondelete='RESTRICT'), primary_key=True) -# class SliceSubSliceModel(Model): -# pk = PrimaryKeyField() -# slice_fk = ForeignKeyField(SliceModel) -# sub_slice_fk = ForeignKeyField(SliceModel) + slice = relationship('SliceModel', back_populates='slice_endpoints', lazy='joined') + endpoint = relationship('EndPointModel', lazy='joined') # back_populates='slice_endpoints' + +class SliceServiceModel(_Base): + __tablename__ = 'slice_service' + + slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE' ), primary_key=True) + service_uuid = Column(ForeignKey('service.service_uuid', ondelete='RESTRICT'), primary_key=True) + + slice = relationship('SliceModel', back_populates='slice_services', lazy='joined') + service = relationship('ServiceModel', lazy='joined') # back_populates='slice_services' + +#class SliceSubSliceModel(_Base): +# __tablename__ = 'slice_subslice' +# +# slice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE' ), primary_key=True) +# subslice_uuid = Column(ForeignKey('slice.slice_uuid', ondelete='RESTRICT'), primary_key=True) +# +# slice = relationship('SliceModel', foreign_keys=[slice_uuid], lazy='joined') #back_populates='slice_subslices' +# subslice = relationship('SliceModel', foreign_keys=[subslice_uuid], lazy='joined') #back_populates='slice_subslices' class TopologyDeviceModel(_Base): __tablename__ = 'topology_device' diff --git a/src/context/service/database/models/SliceModel.py b/src/context/service/database/models/SliceModel.py index 2b03e61222cd8d36836bdacd921d0f0f359827b0..ef2b64962ecd173409b0211e583190f95aeaaa2a 100644 --- a/src/context/service/database/models/SliceModel.py +++ b/src/context/service/database/models/SliceModel.py @@ -12,111 +12,64 @@ # See the License for the specific language governing permissions and # limitations under the License. -import functools, logging, operator -from enum import Enum -from typing import Dict, List -from common.orm.fields.EnumeratedField import EnumeratedField -from common.orm.fields.ForeignKeyField import ForeignKeyField -from common.orm.fields.PrimaryKeyField import PrimaryKeyField -from common.orm.fields.StringField import StringField -from common.orm.model.Model import Model -from common.orm.HighLevel import get_related_objects -from common.proto.context_pb2 import SliceStatusEnum -from .ConfigRuleModel import ConfigModel -from .ConstraintModel import ConstraintsModel -from .models.ContextModel import ContextModel -from .Tools import grpc_to_enum - -LOGGER = logging.getLogger(__name__) - -class ORM_SliceStatusEnum(Enum): - UNDEFINED = SliceStatusEnum.SLICESTATUS_UNDEFINED - PLANNED = SliceStatusEnum.SLICESTATUS_PLANNED - INIT = SliceStatusEnum.SLICESTATUS_INIT - ACTIVE = SliceStatusEnum.SLICESTATUS_ACTIVE - DEINIT = SliceStatusEnum.SLICESTATUS_DEINIT - -grpc_to_enum__slice_status = functools.partial( - grpc_to_enum, SliceStatusEnum, ORM_SliceStatusEnum) - -class SliceModel(Model): - pk = PrimaryKeyField() - context_fk = ForeignKeyField(ContextModel) - slice_uuid = StringField(required=True, allow_empty=False) - slice_constraints_fk = ForeignKeyField(ConstraintsModel) - slice_status = EnumeratedField(ORM_SliceStatusEnum, required=True) - slice_config_fk = ForeignKeyField(ConfigModel) - slice_owner_uuid = StringField(required=False, allow_empty=True) - slice_owner_string = StringField(required=False, allow_empty=True) - - def delete(self) -> None: - # pylint: disable=import-outside-toplevel - from .RelationModels import SliceEndPointModel, SliceServiceModel, SliceSubSliceModel - - for db_slice_endpoint_pk,_ in self.references(SliceEndPointModel): - SliceEndPointModel(self.database, db_slice_endpoint_pk).delete() - - for db_slice_service_pk,_ in self.references(SliceServiceModel): - SliceServiceModel(self.database, db_slice_service_pk).delete() - - for db_slice_subslice_pk,_ in self.references(SliceSubSliceModel): - SliceSubSliceModel(self.database, db_slice_subslice_pk).delete() - - super().delete() - - ConfigModel(self.database, self.slice_config_fk).delete() - ConstraintsModel(self.database, self.slice_constraints_fk).delete() +import operator +from sqlalchemy import Column, Enum, ForeignKey, String +from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.orm import relationship +from typing import Dict +from .enums.SliceStatus import ORM_SliceStatusEnum +from ._Base import _Base + +class SliceModel(_Base): + __tablename__ = 'slice' + + slice_uuid = Column(UUID(as_uuid=False), primary_key=True) + context_uuid = Column(ForeignKey('context.context_uuid'), nullable=False) + slice_name = Column(String, nullable=True) + slice_status = Column(Enum(ORM_SliceStatusEnum), nullable=False) + slice_owner_uuid = Column(String, nullable=True) + slice_owner_string = Column(String, nullable=True) + + context = relationship('ContextModel', back_populates='slices') + slice_endpoints = relationship('SliceEndPointModel') # lazy='joined', back_populates='slice' + slice_services = relationship('SliceServiceModel') # lazy='joined', back_populates='slice' + #slice_subslices = relationship('SliceSubSliceModel') # lazy='joined', back_populates='slice' + constraints = relationship('ConstraintModel', passive_deletes=True) # lazy='joined', back_populates='slice' + config_rules = relationship('ConfigRuleModel', passive_deletes=True) # lazy='joined', back_populates='slice' def dump_id(self) -> Dict: - context_id = ContextModel(self.database, self.context_fk).dump_id() return { - 'context_id': context_id, + 'context_id': self.context.dump_id(), 'slice_uuid': {'uuid': self.slice_uuid}, } - def dump_endpoint_ids(self) -> List[Dict]: - from .RelationModels import SliceEndPointModel # pylint: disable=import-outside-toplevel - db_endpoints = get_related_objects(self, SliceEndPointModel, 'endpoint_fk') - return [db_endpoint.dump_id() for db_endpoint in sorted(db_endpoints, key=operator.attrgetter('pk'))] - - def dump_constraints(self) -> List[Dict]: - return ConstraintsModel(self.database, self.slice_constraints_fk).dump() - - def dump_config(self) -> Dict: - return ConfigModel(self.database, self.slice_config_fk).dump() - - def dump_service_ids(self) -> List[Dict]: - from .RelationModels import SliceServiceModel # pylint: disable=import-outside-toplevel - db_services = get_related_objects(self, SliceServiceModel, 'service_fk') - return [db_service.dump_id() for db_service in sorted(db_services, key=operator.attrgetter('pk'))] - - def dump_subslice_ids(self) -> List[Dict]: - from .RelationModels import SliceSubSliceModel # pylint: disable=import-outside-toplevel - db_subslices = get_related_objects(self, SliceSubSliceModel, 'sub_slice_fk') - return [ - db_subslice.dump_id() - for db_subslice in sorted(db_subslices, key=operator.attrgetter('pk')) - if db_subslice.pk != self.pk # if I'm subslice of other slice, I will appear as subslice of myself - ] - - def dump( # pylint: disable=arguments-differ - self, include_endpoint_ids=True, include_constraints=True, include_config_rules=True, - include_service_ids=True, include_subslice_ids=True - ) -> Dict: - result = { - 'slice_id': self.dump_id(), - 'slice_status': {'slice_status': self.slice_status.value}, + def dump(self) -> Dict: + return { + 'slice_id' : self.dump_id(), + 'name' : self.slice_name, + 'slice_status' : {'slice_status': self.slice_status.value}, + 'slice_endpoint_ids': [ + slice_endpoint.endpoint.dump_id() + for slice_endpoint in self.slice_endpoints + ], + 'slice_constraints' : [ + constraint.dump() + for constraint in sorted(self.constraints, key=operator.attrgetter('position')) + ], + 'slice_config' : {'config_rules': [ + config_rule.dump() + for config_rule in sorted(self.config_rules, key=operator.attrgetter('position')) + ]}, + 'slice_service_ids': [ + slice_service.service.dump_id() + for slice_service in self.slice_services + ], + 'slice_subslice_ids': [ + #slice_subslice.subslice.dump_id() + #for slice_subslice in self.slice_subslices + ], + 'slice_owner': { + 'owner_uuid': {'uuid': self.slice_owner_uuid}, + 'owner_string': self.slice_owner_string + } } - if include_endpoint_ids: result['slice_endpoint_ids'] = self.dump_endpoint_ids() - if include_constraints: result['slice_constraints'] = self.dump_constraints() - if include_config_rules: result.setdefault('slice_config', {})['config_rules'] = self.dump_config() - if include_service_ids: result['slice_service_ids'] = self.dump_service_ids() - if include_subslice_ids: result['slice_subslice_ids'] = self.dump_subslice_ids() - - if len(self.slice_owner_uuid) > 0: - result.setdefault('slice_owner', {}).setdefault('owner_uuid', {})['uuid'] = self.slice_owner_uuid - - if len(self.slice_owner_string) > 0: - result.setdefault('slice_owner', {})['owner_string'] = self.slice_owner_string - - return result diff --git a/src/context/service/_old_code/RestServer.py b/src/context/service/database/models/enums/SliceStatus.py similarity index 54% rename from src/context/service/_old_code/RestServer.py rename to src/context/service/database/models/enums/SliceStatus.py index 289e92a3c1b74e207a261b133130a551c3c55918..440f5ba2a6f616780f07d491abf6a1689229d36d 100644 --- a/src/context/service/_old_code/RestServer.py +++ b/src/context/service/database/models/enums/SliceStatus.py @@ -12,12 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -from common.Constants import ServiceNameEnum -from common.Settings import get_service_baseurl_http, get_service_port_http -from common.tools.service.GenericRestServer import GenericRestServer +import enum, functools +from common.proto.context_pb2 import SliceStatusEnum +from ._GrpcToEnum import grpc_to_enum -class RestServer(GenericRestServer): - def __init__(self, cls_name: str = __name__) -> None: - bind_port = get_service_port_http(ServiceNameEnum.CONTEXT) - base_url = get_service_baseurl_http(ServiceNameEnum.CONTEXT) - super().__init__(bind_port, base_url, cls_name=cls_name) +class ORM_SliceStatusEnum(enum.Enum): + UNDEFINED = SliceStatusEnum.SLICESTATUS_UNDEFINED + PLANNED = SliceStatusEnum.SLICESTATUS_PLANNED + INIT = SliceStatusEnum.SLICESTATUS_INIT + ACTIVE = SliceStatusEnum.SLICESTATUS_ACTIVE + DEINIT = SliceStatusEnum.SLICESTATUS_DEINIT + +grpc_to_enum__slice_status = functools.partial( + grpc_to_enum, SliceStatusEnum, ORM_SliceStatusEnum) diff --git a/src/context/service/database/uuids/Slice.py b/src/context/service/database/uuids/Slice.py new file mode 100644 index 0000000000000000000000000000000000000000..3b46e582e1b7c93ad81aeaa97a59fd1df8fe5869 --- /dev/null +++ b/src/context/service/database/uuids/Slice.py @@ -0,0 +1,37 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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. + +from typing import Tuple +from common.proto.context_pb2 import SliceId +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentsException +from ._Builder import get_uuid_from_string, get_uuid_random +from .Context import context_get_uuid + +def slice_get_uuid( + slice_id : SliceId, slice_name : str = '', allow_random : bool = False +) -> Tuple[str, str]: + context_uuid = context_get_uuid(slice_id.context_id, allow_random=False) + raw_slice_uuid = slice_id.slice_uuid.uuid + + if len(raw_slice_uuid) > 0: + return context_uuid, get_uuid_from_string(raw_slice_uuid, prefix_for_name=context_uuid) + if len(slice_name) > 0: + return context_uuid, get_uuid_from_string(slice_name, prefix_for_name=context_uuid) + if allow_random: + return context_uuid, get_uuid_random() + + raise InvalidArgumentsException([ + ('slice_id.slice_uuid.uuid', raw_slice_uuid), + ('name', slice_name), + ], extra_details=['At least one is required to produce a Slice UUID']) diff --git a/src/context/tests/Objects.py b/src/context/tests/Objects.py index c350d4f2040f0d85971345c980c502db3072e343..93dd6f2c663601c18b348c35dcb98b9c8e75828b 100644 --- a/src/context/tests/Objects.py +++ b/src/context/tests/Objects.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, List, Tuple +from typing import Dict, List, Optional, Tuple from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME from common.proto.kpi_sample_types_pb2 import KpiSampleType from common.tools.object_factory.ConfigRule import json_config_rule_set @@ -23,6 +23,7 @@ from common.tools.object_factory.Device import json_device_id, json_device_packe from common.tools.object_factory.EndPoint import json_endpoint, json_endpoint_id from common.tools.object_factory.Link import json_link, json_link_id from common.tools.object_factory.Service import json_service_id, json_service_l3nm_planned +from common.tools.object_factory.Slice import json_slice_id, json_slice from common.tools.object_factory.Topology import json_topology, json_topology_id from common.tools.object_factory.PolicyRule import json_policy_rule, json_policy_rule_id @@ -116,6 +117,36 @@ SERVICE_R2_R3_NAME, SERVICE_R2_R3_ID, SERVICE_R2_R3 = compose_service( 'R2-R3', [(DEVICE_R2_ID, '2.3'), (DEVICE_R3_ID, '2.2')], 23.1, 3.4) +# ----- Slice ---------------------------------------------------------------------------------------------------------- +def compose_slice( + name : str, endpoint_ids : List[Tuple[str, str]], latency_ms : float, jitter_us : float, + service_ids : List[Dict] = [], subslice_ids : List[Dict] = [], owner : Optional[Dict] = None +) -> Tuple[str, Dict, Dict]: + slice_id = json_slice_id(name, context_id=CONTEXT_ID) + endpoint_ids = [ + json_endpoint_id(device_id, endpoint_name, topology_id=TOPOLOGY_ID) + for device_id, endpoint_name in endpoint_ids + ] + constraints = [ + json_constraint_custom('latency[ms]', str(latency_ms)), + json_constraint_custom('jitter[us]', str(jitter_us)), + ] + config_rules = [ + json_config_rule_set('svc/rsrc1/value', 'value7'), + json_config_rule_set('svc/rsrc2/value', 'value8'), + json_config_rule_set('svc/rsrc3/value', 'value9'), + ] + slice_ = json_slice( + name, context_id=CONTEXT_ID, endpoint_ids=endpoint_ids, constraints=constraints, config_rules=config_rules, + service_ids=service_ids, subslice_ids=subslice_ids, owner=owner) + return name, slice_id, slice_ + +SLICE_R1_R3_NAME, SLICE_R1_R3_ID, SLICE_R1_R3 = compose_slice( + 'R1-R3', [(DEVICE_R1_ID, '2.3'), (DEVICE_R3_ID, '2.1')], 15.2, 1.2, + service_ids=[SERVICE_R1_R2_ID, SERVICE_R2_R3_ID], + subslice_ids=[], owner=None) + + # ----- Connection ----------------------------------------------------------------------------------------------------- def compose_connection( name : str, service_id : Dict, endpoint_ids : List[Tuple[str, str]], sub_service_ids : List[Dict] = [] diff --git a/src/context/tests/__test_unitary.py b/src/context/tests/__test_unitary.py deleted file mode 100644 index e49fd2752adef62c8816a76c57b5abcf3d739f37..0000000000000000000000000000000000000000 --- a/src/context/tests/__test_unitary.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) -# -# 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 pytest -#from context.client.ContextClient import ContextClient -#from .test_unitary_context import grpc_context -#from ._test_topology import grpc_topology -#from ._test_device import grpc_device -#from ._test_link import grpc_link -#from ._test_service import grpc_service -#from ._test_slice import grpc_slice -#from ._test_connection import grpc_connection -#from ._test_policy import grpc_policy - -#def test_grpc_context(context_client_grpc : ContextClient) -> None: -# grpc_context(context_client_grpc) - -#@pytest.mark.depends(on=['test_grpc_context']) -#def test_grpc_topology(context_client_grpc : ContextClient) -> None: -# grpc_topology(context_client_grpc) - -#@pytest.mark.depends(on=['test_grpc_topology']) -#def test_grpc_device(context_client_grpc : ContextClient) -> None: -# grpc_device(context_client_grpc) - -#@pytest.mark.depends(on=['test_grpc_device']) -#def test_grpc_link(context_client_grpc : ContextClient) -> None: -# grpc_link(context_client_grpc) - -#@pytest.mark.depends(on=['test_grpc_link']) -#def test_grpc_service(context_client_grpc : ContextClient) -> None: -# grpc_service(context_client_grpc) - -#@pytest.mark.depends(on=['test_grpc_service']) -#def test_grpc_slice(context_client_grpc : ContextClient) -> None: -# grpc_slice(context_client_grpc) - -#@pytest.mark.depends(on=['test_grpc_slice']) -#def test_grpc_connection(context_client_grpc : ContextClient) -> None: -# grpc_connection(context_client_grpc) - -#@pytest.mark.depends(on=['test_grpc_connection']) -#def test_grpc_policy(context_client_grpc : ContextClient) -> None: -# grpc_policy(context_client_grpc) diff --git a/src/context/tests/_test_slice.py b/src/context/tests/_test_slice.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/context/tests/conftest.py b/src/context/tests/conftest.py index 8bf4156c57d6c121b33f4f5c0cb0c2adfb55959c..f5ef4efca3ff8336c9c4824cc9d25eaf3d992e2d 100644 --- a/src/context/tests/conftest.py +++ b/src/context/tests/conftest.py @@ -16,7 +16,7 @@ import json, os, pytest, sqlalchemy from _pytest.config import Config from _pytest.terminal import TerminalReporter from prettytable import PrettyTable -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Set, Tuple from common.Constants import ServiceNameEnum from common.Settings import ( ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, ENVVAR_SUFIX_SERVICE_PORT_HTTP, get_env_var_name, @@ -71,7 +71,8 @@ def pytest_terminal_summary( ): yield - method_to_metric_fields : Dict[str, Dict[str, Dict[str, Any]]]= dict() + method_to_metric_fields : Dict[str, Dict[str, Dict[str, Any]]] = dict() + bucket_bounds : Set[str] = set() for raw_metric_name,raw_metric_data in RAW_METRICS.items(): if '_COUNTER_' in raw_metric_name: method_name,metric_name = raw_metric_name.split('_COUNTER_') @@ -81,6 +82,7 @@ def pytest_terminal_summary( raise Exception('Unsupported metric: {:s}'.format(raw_metric_name)) # pragma: no cover metric_data = method_to_metric_fields.setdefault(method_name, dict()).setdefault(metric_name, dict()) for field_name,labels,value,_,_ in raw_metric_data._child_samples(): + if field_name == '_bucket': bucket_bounds.add(labels['le']) if len(labels) > 0: field_name = '{:s}:{:s}'.format(field_name, json.dumps(labels, sort_keys=True)) metric_data[field_name] = value #print('method_to_metric_fields', method_to_metric_fields) @@ -90,10 +92,14 @@ def pytest_terminal_summary( if str_duration == '---': return 0.0 return float(str_duration.replace(' ms', '')) - field_names = ['Method', 'Started', 'Completed', 'Failed', 'avg(Duration)'] - pt_stats = PrettyTable(field_names=field_names, sortby='avg(Duration)', sort_key=sort_stats_key, reversesort=True) + field_names = ['Method', 'TOT', 'OK', 'ERR', 'avg(Dur)'] + bucket_bounds = sorted(bucket_bounds, key=lambda b: float(b)) + bucket_column_names = ['<={:s}'.format(bucket_bound) for bucket_bound in bucket_bounds] + field_names.extend(bucket_column_names) + + pt_stats = PrettyTable(field_names=field_names, sortby='avg(Dur)', sort_key=sort_stats_key, reversesort=True) + for f in field_names: pt_stats.align[f] = 'r' for f in ['Method']: pt_stats.align[f] = 'l' - for f in ['Started', 'Completed', 'Failed', 'avg(Duration)']: pt_stats.align[f] = 'r' for method_name,metrics in method_to_metric_fields.items(): counter_started_value = int(metrics['STARTED']['_total']) @@ -105,10 +111,29 @@ def pytest_terminal_summary( duration_count_value = float(metrics['DURATION']['_count']) duration_sum_value = float(metrics['DURATION']['_sum']) duration_avg_value = duration_sum_value/duration_count_value - pt_stats.add_row([ + + row = [ method_name, str(counter_started_value), str(counter_completed_value), str(counter_failed_value), '{:.3f} ms'.format(1000.0 * duration_avg_value), - ]) + ] + + total_count = 0 + for bucket_bound in bucket_bounds: + labels = json.dumps({"le": bucket_bound}, sort_keys=True) + bucket_name = '_bucket:{:s}'.format(labels) + accumulated_count = int(metrics['DURATION'][bucket_name]) + bucket_count = accumulated_count - total_count + row.append(str(bucket_count) if bucket_count > 0 else '') + total_count = accumulated_count + + pt_stats.add_row(row) + + for bucket_column_name in bucket_column_names: + col_index = pt_stats._field_names.index(bucket_column_name) + num_non_empties = sum([1 for row in pt_stats._rows if len(row[col_index]) > 0]) + if num_non_empties > 0: continue + pt_stats.del_column(bucket_column_name) + print('') print('Performance Results:') print(pt_stats.get_string()) diff --git a/src/context/tests/test_slice.py b/src/context/tests/test_slice.py new file mode 100644 index 0000000000000000000000000000000000000000..9d27523b12567cb949494e0954c691205cb06c96 --- /dev/null +++ b/src/context/tests/test_slice.py @@ -0,0 +1,272 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# 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 copy, grpc, pytest +from common.proto.context_pb2 import ( + Context, ContextId, Device, DeviceId, Link, LinkId, Service, ServiceId, Slice, SliceId, SliceStatusEnum, Topology, + TopologyId) +from context.client.ContextClient import ContextClient +from context.service.database.uuids.Slice import slice_get_uuid +#from context.client.EventsCollector import EventsCollector +from .Objects import ( + CONTEXT, CONTEXT_ID, CONTEXT_NAME, DEVICE_R1, DEVICE_R1_ID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R3, DEVICE_R3_ID, + LINK_R1_R2, LINK_R1_R2_ID, LINK_R1_R3, LINK_R1_R3_ID, LINK_R2_R3, LINK_R2_R3_ID, SERVICE_R1_R2, SERVICE_R1_R2_ID, + SERVICE_R2_R3, SERVICE_R2_R3_ID, SLICE_R1_R3, SLICE_R1_R3_ID, SLICE_R1_R3_NAME, TOPOLOGY, TOPOLOGY_ID) + +@pytest.mark.depends(on=['context/tests/test_service.py::test_service']) +def test_slice(context_client : ContextClient) -> None: + + # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- + #events_collector = EventsCollector( + # context_client, log_events_received=True, + # activate_context_collector = False, activate_topology_collector = False, activate_device_collector = False, + # activate_link_collector = False, activate_service_collector = False, activate_slice_collector = True, + # activate_connection_collector = False) + #events_collector.start() + + # ----- Prepare dependencies for the test and capture related events ----------------------------------------------- + context_client.SetContext(Context(**CONTEXT)) + context_client.SetTopology(Topology(**TOPOLOGY)) + context_client.SetDevice(Device(**DEVICE_R1)) + context_client.SetDevice(Device(**DEVICE_R2)) + context_client.SetDevice(Device(**DEVICE_R3)) + context_client.SetLink(Link(**LINK_R1_R2)) + context_client.SetLink(Link(**LINK_R1_R3)) + context_client.SetLink(Link(**LINK_R2_R3)) + context_client.SetService(Service(**SERVICE_R1_R2)) + context_client.SetService(Service(**SERVICE_R2_R3)) + + #events = events_collector.get_events(block=True, count=10) + #assert isinstance(events[0], ContextEvent) + #assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[0].context_id.context_uuid.uuid == context_uuid + #assert isinstance(events[1], TopologyEvent) + #assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[1].topology_id.context_id.context_uuid.uuid == context_uuid + #assert events[1].topology_id.topology_uuid.uuid == topology_uuid + #assert isinstance(events[2], DeviceEvent) + #assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[2].device_id.device_uuid.uuid == device_r1_uuid + #assert isinstance(events[3], DeviceEvent) + #assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[3].device_id.device_uuid.uuid == device_r2_uuid + #assert isinstance(events[4], DeviceEvent) + #assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[4].device_id.device_uuid.uuid == device_r3_uuid + #assert isinstance(events[5], LinkEvent) + #assert events[5].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[5].link_id.link_uuid.uuid == link_r1_r2_uuid + #assert isinstance(events[6], LinkEvent) + #assert events[6].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[6].link_id.link_uuid.uuid == link_r1_r3_uuid + #assert isinstance(events[7], LinkEvent) + #assert events[7].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[7].link_id.link_uuid.uuid == link_r2_r3_uuid + #assert isinstance(events[8], ServiceEvent) + #assert events[8].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[8].service_id.service_uuid.uuid == service_r1_r2_uuid + #assert isinstance(events[9], ServiceEvent) + #assert events[9].event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert events[9].service_id.service_uuid.uuid == service_r2_r3_uuid + + # ----- Get when the object does not exist ------------------------------------------------------------------------- + slice_id = SliceId(**SLICE_R1_R3_ID) + context_uuid,slice_uuid = slice_get_uuid(slice_id, allow_random=False) + with pytest.raises(grpc.RpcError) as e: + context_client.GetSlice(slice_id) + assert e.value.code() == grpc.StatusCode.NOT_FOUND + MSG = 'Slice({:s}/{:s}) not found; context_uuid generated was: {:s}; slice_uuid generated was: {:s}' + assert e.value.details() == MSG.format(CONTEXT_NAME, SLICE_R1_R3_NAME, context_uuid, slice_uuid) + + # ----- List when the object does not exist ------------------------------------------------------------------------ + response = context_client.GetContext(ContextId(**CONTEXT_ID)) + assert len(response.topology_ids) == 1 + assert len(response.service_ids) == 2 + assert len(response.slice_ids) == 0 + + response = context_client.ListSliceIds(ContextId(**CONTEXT_ID)) + assert len(response.slice_ids) == 0 + + response = context_client.ListSlices(ContextId(**CONTEXT_ID)) + assert len(response.slices) == 0 + + # ----- Create the object ------------------------------------------------------------------------------------------ + with pytest.raises(grpc.RpcError) as e: + WRONG_UUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff' + WRONG_SLICE = copy.deepcopy(SLICE_R1_R3) + WRONG_SLICE['slice_endpoint_ids'][0]['topology_id']['context_id']['context_uuid']['uuid'] = WRONG_UUID + context_client.SetSlice(Slice(**WRONG_SLICE)) + assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT + MSG = 'request.slice_endpoint_ids[0].topology_id.context_id.context_uuid.uuid({}) is invalid; '\ + 'should be == request.slice_id.context_id.context_uuid.uuid({})' + raw_context_uuid = slice_id.context_id.context_uuid.uuid # pylint: disable=no-member + assert e.value.details() == MSG.format(WRONG_UUID, raw_context_uuid) + + response = context_client.SetSlice(Slice(**SLICE_R1_R3)) + assert response.context_id.context_uuid.uuid == context_uuid + assert response.slice_uuid.uuid == slice_uuid + + # ----- Check create event ----------------------------------------------------------------------------------------- + #event = events_collector.get_event(block=True) + #assert isinstance(event, SliceEvent) + #assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert event.slice_id.context_id.context_uuid.uuid == context_uuid + #assert event.slice_id.slice_uuid.uuid == slice_uuid + + # ----- Get when the object exists --------------------------------------------------------------------------------- + response = context_client.GetContext(ContextId(**CONTEXT_ID)) + assert response.context_id.context_uuid.uuid == context_uuid + assert response.name == CONTEXT_NAME + assert len(response.topology_ids) == 1 + assert len(response.service_ids) == 2 + assert len(response.slice_ids) == 1 + assert response.slice_ids[0].context_id.context_uuid.uuid == context_uuid + assert response.slice_ids[0].slice_uuid.uuid == slice_uuid + + response = context_client.GetSlice(SliceId(**SLICE_R1_R3_ID)) + assert response.slice_id.context_id.context_uuid.uuid == context_uuid + assert response.slice_id.slice_uuid.uuid == slice_uuid + assert response.name == SLICE_R1_R3_NAME + assert len(response.slice_endpoint_ids) == 2 + assert len(response.slice_constraints) == 2 + assert response.slice_status.slice_status == SliceStatusEnum.SLICESTATUS_PLANNED + assert len(response.slice_config.config_rules) == 3 + + # ----- List when the object exists -------------------------------------------------------------------------------- + response = context_client.ListSliceIds(ContextId(**CONTEXT_ID)) + assert len(response.slice_ids) == 1 + assert response.slice_ids[0].context_id.context_uuid.uuid == context_uuid + assert response.slice_ids[0].slice_uuid.uuid == slice_uuid + + response = context_client.ListSlices(ContextId(**CONTEXT_ID)) + assert len(response.slices) == 1 + assert response.slices[0].slice_id.context_id.context_uuid.uuid == context_uuid + assert response.slices[0].slice_id.slice_uuid.uuid == slice_uuid + assert response.slices[0].name == SLICE_R1_R3_NAME + assert len(response.slices[0].slice_endpoint_ids) == 2 + assert len(response.slices[0].slice_constraints) == 2 + assert response.slices[0].slice_status.slice_status == SliceStatusEnum.SLICESTATUS_PLANNED + assert len(response.slices[0].slice_config.config_rules) == 3 + + # ----- Update the object ------------------------------------------------------------------------------------------ + new_slice_name = 'new' + SLICE_UPDATED = copy.deepcopy(SLICE_R1_R3) + SLICE_UPDATED['name'] = new_slice_name + SLICE_UPDATED['slice_status']['slice_status'] = SliceStatusEnum.SLICESTATUS_ACTIVE + response = context_client.SetSlice(Slice(**SLICE_UPDATED)) + assert response.context_id.context_uuid.uuid == context_uuid + assert response.slice_uuid.uuid == slice_uuid + + # ----- Check update event ----------------------------------------------------------------------------------------- + #event = events_collector.get_event(block=True) + #assert isinstance(event, SliceEvent) + #assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE + #assert event.slice_id.context_id.context_uuid.uuid == context_uuid + #assert event.slice_id.slice_uuid.uuid == slice_uuid + + # ----- Get when the object is modified ---------------------------------------------------------------------------- + response = context_client.GetSlice(SliceId(**SLICE_R1_R3_ID)) + assert response.slice_id.context_id.context_uuid.uuid == context_uuid + assert response.slice_id.slice_uuid.uuid == slice_uuid + assert response.name == new_slice_name + assert len(response.slice_endpoint_ids) == 2 + assert len(response.slice_constraints) == 2 + assert response.slice_status.slice_status == SliceStatusEnum.SLICESTATUS_ACTIVE + assert len(response.slice_config.config_rules) == 3 + + # ----- List when the object is modified --------------------------------------------------------------------------- + response = context_client.ListSliceIds(ContextId(**CONTEXT_ID)) + assert len(response.slice_ids) == 1 + assert response.slice_ids[0].context_id.context_uuid.uuid == context_uuid + assert response.slice_ids[0].slice_uuid.uuid == slice_uuid + + response = context_client.ListSlices(ContextId(**CONTEXT_ID)) + assert len(response.slices) == 1 + assert response.slices[0].slice_id.context_id.context_uuid.uuid == context_uuid + assert response.slices[0].slice_id.slice_uuid.uuid == slice_uuid + assert response.slices[0].name == new_slice_name + assert len(response.slices[0].slice_endpoint_ids) == 2 + assert len(response.slices[0].slice_constraints) == 2 + assert response.slices[0].slice_status.slice_status == SliceStatusEnum.SLICESTATUS_ACTIVE + assert len(response.slices[0].slice_config.config_rules) == 3 + + # ----- Remove the object ------------------------------------------------------------------------------------------ + context_client.RemoveSlice(SliceId(**SLICE_R1_R3_ID)) + + # ----- Check remove event ----------------------------------------------------------------------------------------- + #event = events_collector.get_event(block=True) + #assert isinstance(event, SliceEvent) + #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert event.slice_id.context_id.context_uuid.uuid == context_uuid + #assert event.slice_id.slice_uuid.uuid == slice_uuid + + # ----- List after deleting the object ----------------------------------------------------------------------------- + response = context_client.GetContext(ContextId(**CONTEXT_ID)) + assert len(response.topology_ids) == 1 + assert len(response.service_ids) == 2 + assert len(response.slice_ids) == 0 + + response = context_client.ListSliceIds(ContextId(**CONTEXT_ID)) + assert len(response.slice_ids) == 0 + + response = context_client.ListSlices(ContextId(**CONTEXT_ID)) + assert len(response.slices) == 0 + + # ----- Clean dependencies used in the test and capture related events --------------------------------------------- + context_client.RemoveService(ServiceId(**SERVICE_R1_R2_ID)) + context_client.RemoveService(ServiceId(**SERVICE_R2_R3_ID)) + context_client.RemoveLink(LinkId(**LINK_R1_R2_ID)) + context_client.RemoveLink(LinkId(**LINK_R1_R3_ID)) + context_client.RemoveLink(LinkId(**LINK_R2_R3_ID)) + context_client.RemoveDevice(DeviceId(**DEVICE_R1_ID)) + context_client.RemoveDevice(DeviceId(**DEVICE_R2_ID)) + context_client.RemoveDevice(DeviceId(**DEVICE_R3_ID)) + context_client.RemoveTopology(TopologyId(**TOPOLOGY_ID)) + context_client.RemoveContext(ContextId(**CONTEXT_ID)) + + #events = events_collector.get_events(block=True, count=10) + #assert isinstance(events[0], ServiceEvent) + #assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[0].service_id.service_uuid.uuid == service_r1_r2_uuid + #assert isinstance(events[1], ServiceEvent) + #assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[1].service_id.service_uuid.uuid == service_r2_r3_uuid + #assert isinstance(events[2], LinkEvent) + #assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[2].link_id.link_uuid.uuid == link_r1_r2_uuid + #assert isinstance(events[3], LinkEvent) + #assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[3].link_id.link_uuid.uuid == link_r1_r3_uuid + #assert isinstance(events[4], LinkEvent) + #assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[4].link_id.link_uuid.uuid == link_r2_r3_uuid + #assert isinstance(events[5], DeviceEvent) + #assert events[5].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[5].device_id.device_uuid.uuid == device_r1_uuid + #assert isinstance(events[6], DeviceEvent) + #assert events[6].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[6].device_id.device_uuid.uuid == device_r2_uuid + #assert isinstance(events[7], DeviceEvent) + #assert events[7].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[7].device_id.device_uuid.uuid == device_r3_uuid + #assert isinstance(events[8], TopologyEvent) + #assert events[8].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[8].topology_id.context_id.context_uuid.uuid == context_uuid + #assert events[8].topology_id.topology_uuid.uuid == topology_uuid + #assert isinstance(events[9], ContextEvent) + #assert events[9].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[9].context_id.context_uuid.uuid == context_uuid + + # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- + #events_collector.stop() diff --git a/test-context.sh b/test-context.sh index 47d81817bd80bd771fa647449a6c49bcfaee9870..a33b1e7dc650600d5cc00f49ff11b52eceb16fa4 100755 --- a/test-context.sh +++ b/test-context.sh @@ -46,7 +46,8 @@ coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose --ma context/tests/test_topology.py \ context/tests/test_device.py \ context/tests/test_link.py \ - context/tests/test_service.py + context/tests/test_service.py \ + context/tests/test_slice.py echo echo "Coverage report:"