diff --git a/scripts/run_tests_locally-context.sh b/scripts/run_tests_locally-context.sh index 5b6c53aa8a137c3ba3ca75d061a83e0c9810a6b4..8b0c82b3ef1157596c63ce260f2bd2e85a6ca9a1 100755 --- a/scripts/run_tests_locally-context.sh +++ b/scripts/run_tests_locally-context.sh @@ -20,8 +20,6 @@ # If not already set, set the name of the Kubernetes namespace to deploy to. export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"} -#export TFS_K8S_HOSTNAME="tfs-vm" - ######################################################################################################################## # Automated steps start here ######################################################################################################################## @@ -29,24 +27,14 @@ export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"} PROJECTDIR=`pwd` cd $PROJECTDIR/src -#RCFILE=$PROJECTDIR/coverage/.coveragerc - -#kubectl --namespace $TFS_K8S_NAMESPACE expose deployment contextservice --name=redis-tests --port=6379 --type=NodePort -#export REDIS_SERVICE_HOST=$(kubectl --namespace $TFS_K8S_NAMESPACE get service redis-tests -o 'jsonpath={.spec.clusterIP}') -#export REDIS_SERVICE_HOST=$(kubectl get node $TFS_K8S_HOSTNAME -o 'jsonpath={.status.addresses[?(@.type=="InternalIP")].address}') -#export REDIS_SERVICE_PORT=$(kubectl --namespace $TFS_K8S_NAMESPACE get service redis-tests -o 'jsonpath={.spec.ports[?(@.port==6379)].nodePort}') +RCFILE=$PROJECTDIR/coverage/.coveragerc #export CRDB_URI="cockroachdb://tfs:tfs123@127.0.0.1:26257/tfs_test?sslmode=require" export CRDB_URI="cockroachdb://tfs:tfs123@10.1.7.195:26257/tfs_test?sslmode=require" export PYTHONPATH=/home/tfs/tfs-ctrl/src # Run unitary tests and analyze coverage of code at same time -#coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose --maxfail=1 \ -# context/tests/test_unitary.py - -# --log-level=INFO -o log_cli=true --durations=0 -pytest --verbose --maxfail=1 \ +# helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0 +coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose --maxfail=1 \ context/tests/test_unitary.py \ context/tests/test_hasher.py - -#kubectl --namespace $TFS_K8S_NAMESPACE delete service redis-tests diff --git a/src/context/service/ChangeFeedExample.py b/src/context/service/ChangeFeedExample.txt similarity index 99% rename from src/context/service/ChangeFeedExample.py rename to src/context/service/ChangeFeedExample.txt index 2bd46b546f1194ea8a109ee08a9d5c2907f3001d..679a7c716871a92e51252e3422f438a1e3a2d69f 100644 --- a/src/context/service/ChangeFeedExample.py +++ b/src/context/service/ChangeFeedExample.txt @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - @safe_and_metered_rpc_method(METRICS, LOGGER) def GetContextEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ContextEvent]: pass diff --git a/src/context/service/Constants.py b/src/context/service/Constants.py index 25790fe2925cc18003cd3d7df057e9c2923803fb..1eb274cf07d872bdcd6fefb482bf1a6afa7fc487 100644 --- a/src/context/service/Constants.py +++ b/src/context/service/Constants.py @@ -16,14 +16,15 @@ TOPIC_CONNECTION = 'connection' TOPIC_CONTEXT = 'context' TOPIC_DEVICE = 'device' TOPIC_LINK = 'link' -TOPIC_POLICY = 'policy' +#TOPIC_POLICY = 'policy' TOPIC_SERVICE = 'service' TOPIC_SLICE = 'slice' TOPIC_TOPOLOGY = 'topology' TOPICS = { TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, - TOPIC_POLICY, TOPIC_SERVICE, TOPIC_SLICE, TOPIC_TOPOLOGY + #TOPIC_POLICY, + TOPIC_SERVICE, TOPIC_SLICE, TOPIC_TOPOLOGY } CONSUME_TIMEOUT = 0.5 # seconds diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py index 5075d8889fd217623a76955ba0a786a8f5366c01..44409bd0caf59859ebf8f31b4e8c20f7d30942d2 100644 --- a/src/context/service/ContextServiceServicerImpl.py +++ b/src/context/service/ContextServiceServicerImpl.py @@ -13,34 +13,36 @@ # limitations under the License. -import grpc, json, logging, operator, sqlalchemy, threading, time, uuid -from sqlalchemy.orm import Session, contains_eager, selectinload, sessionmaker -from sqlalchemy.dialects.postgresql import UUID, insert -from typing import Dict, Iterator, List, Optional, Set, Tuple, Union - +import grpc, json, logging, sqlalchemy +#from sqlalchemy.orm import Session, contains_eager, selectinload, sessionmaker +#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, Device, DeviceEvent, DeviceId, DeviceIdList, DeviceList, - Empty, EventTypeEnum, + Empty, Link, LinkEvent, LinkId, LinkIdList, LinkList, Service, ServiceEvent, ServiceId, ServiceIdList, ServiceList, Slice, SliceEvent, SliceId, SliceIdList, SliceList, - Topology, TopologyEvent, TopologyId, TopologyIdList, TopologyList, - ConfigActionEnum, Constraint) + Topology, TopologyEvent, TopologyId, TopologyIdList, TopologyList) #from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule from common.proto.context_pb2_grpc import ContextServiceServicer from common.proto.context_policy_pb2_grpc import ContextPolicyServiceServicer -from common.tools.object_factory.Context import json_context_id +#from common.tools.object_factory.Context import json_context_id from common.rpc_method_wrapper.Decorator import create_metrics, safe_and_metered_rpc_method -from common.rpc_method_wrapper.ServiceExceptions import ( - InvalidArgumentException, NotFoundException, OperationFailedException) -from context.service.database.methods.Context import context_delete, context_get, context_list_ids, context_list_objs, context_set -from context.service.database.methods.Device import device_delete, device_get, device_list_ids, device_list_objs, device_set -from context.service.database.methods.Link import link_delete, link_get, link_list_ids, link_list_objs, link_set -from context.service.database.methods.Topology import topology_delete, topology_get, topology_list_ids, topology_list_objs, topology_set +#from common.rpc_method_wrapper.ServiceExceptions import ( +# InvalidArgumentException, NotFoundException, OperationFailedException) +from .database.methods.Context import ( + context_delete, context_get, context_list_ids, context_list_objs, context_set) +from .database.methods.Device import ( + device_delete, device_get, device_list_ids, device_list_objs, device_set) +#from .database.methods.Link import link_delete, link_get, link_list_ids, link_list_objs, link_set +#from .database.methods.Service import service_delete, service_get, service_list_ids, service_list_objs, service_set +from .database.methods.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 #from context.service.database.ConfigModel import ( @@ -64,8 +66,8 @@ from context.service.database.methods.Topology import topology_delete, topology_ #from context.service.database.SliceModel import SliceModel, grpc_to_enum__slice_status #from context.service.database.TopologyModel import TopologyModel from .Constants import ( - CONSUME_TIMEOUT, TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, TOPIC_POLICY, TOPIC_SERVICE, - TOPIC_SLICE, TOPIC_TOPOLOGY) + CONSUME_TIMEOUT, TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, #TOPIC_POLICY, + TOPIC_SERVICE, TOPIC_SLICE, TOPIC_TOPOLOGY) #from .ChangeFeedClient import ChangeFeedClient LOGGER = logging.getLogger(__name__) @@ -110,10 +112,10 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer @safe_and_metered_rpc_method(METRICS, LOGGER) def SetContext(self, request : Context, context : grpc.ServicerContext) -> ContextId: - updated = context_set(self.db_engine, request) + context_id,updated = context_set(self.db_engine, request) #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE - #notify_event(self.messagebroker, TOPIC_CONTEXT, event_type, {'context_id': request.context_id}) - return request.context_id + #notify_event(self.messagebroker, TOPIC_CONTEXT, event_type, {'context_id': context_id}) + return context_id @safe_and_metered_rpc_method(METRICS, LOGGER) def RemoveContext(self, request : ContextId, context : grpc.ServicerContext) -> Empty: @@ -144,10 +146,10 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer @safe_and_metered_rpc_method(METRICS, LOGGER) def SetTopology(self, request : Topology, context : grpc.ServicerContext) -> TopologyId: - updated = topology_set(self.db_engine, request) + topology_id,updated = topology_set(self.db_engine, request) #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE - #notify_event(self.messagebroker, TOPIC_TOPOLOGY, event_type, {'topology_id': request.topology_id}) - return request.topology_id + #notify_event(self.messagebroker, TOPIC_TOPOLOGY, event_type, {'topology_id': topology_id}) + return topology_id @safe_and_metered_rpc_method(METRICS, LOGGER) def RemoveTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Empty: @@ -178,10 +180,10 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer @safe_and_metered_rpc_method(METRICS, LOGGER) def SetDevice(self, request : Device, context : grpc.ServicerContext) -> DeviceId: - updated = device_set(self.db_engine, request) + device_id,updated = device_set(self.db_engine, request) #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE - #notify_event(self.messagebroker, TOPIC_DEVICE, event_type, {'device_id': request.device_id}) - return request.device_id + #notify_event(self.messagebroker, TOPIC_DEVICE, event_type, {'device_id': device_id}) + return device_id @safe_and_metered_rpc_method(METRICS, LOGGER) def RemoveDevice(self, request : DeviceId, context : grpc.ServicerContext) -> Empty: @@ -198,31 +200,31 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # ----- Link ------------------------------------------------------------------------------------------------------- - @safe_and_metered_rpc_method(METRICS, LOGGER) - def ListLinkIds(self, request : Empty, context : grpc.ServicerContext) -> LinkIdList: - return link_list_ids(self.db_engine) +# @safe_and_metered_rpc_method(METRICS, LOGGER) +# def ListLinkIds(self, request : Empty, context : grpc.ServicerContext) -> LinkIdList: +# return link_list_ids(self.db_engine) - @safe_and_metered_rpc_method(METRICS, LOGGER) - def ListLinks(self, request : Empty, context : grpc.ServicerContext) -> LinkList: - return link_list_objs(self.db_engine) +# @safe_and_metered_rpc_method(METRICS, LOGGER) +# def ListLinks(self, request : Empty, context : grpc.ServicerContext) -> LinkList: +# return link_list_objs(self.db_engine) - @safe_and_metered_rpc_method(METRICS, LOGGER) - def GetLink(self, request : LinkId, context : grpc.ServicerContext) -> Link: - return link_get(self.db_engine, request) +# @safe_and_metered_rpc_method(METRICS, LOGGER) +# def GetLink(self, request : LinkId, context : grpc.ServicerContext) -> Link: +# return link_get(self.db_engine, request) - @safe_and_metered_rpc_method(METRICS, LOGGER) - def SetLink(self, request : Link, context : grpc.ServicerContext) -> LinkId: - updated = link_set(self.db_engine, request) - #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE - #notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': request.link_id}) - return request.link_id +# @safe_and_metered_rpc_method(METRICS, LOGGER) +# def SetLink(self, request : Link, context : grpc.ServicerContext) -> LinkId: +# link_id,updated = link_set(self.db_engine, request) +# #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE +# #notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': link_id}) +# return link_id - @safe_and_metered_rpc_method(METRICS, LOGGER) - def RemoveLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty: - deleted = link_delete(self.db_engine, request) - #if deleted: - # notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': dict_link_id}) - return Empty() +# @safe_and_metered_rpc_method(METRICS, LOGGER) +# def RemoveLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty: +# deleted = link_delete(self.db_engine, request) +# #if deleted: +# # notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': dict_link_id}) +# return Empty() @safe_and_metered_rpc_method(METRICS, LOGGER) def GetLinkEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[LinkEvent]: @@ -230,230 +232,33 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer yield LinkEvent(**json.loads(message.content)) -# # ----- Service ---------------------------------------------------------------------------------------------------- -# + # ----- Service ---------------------------------------------------------------------------------------------------- + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def ListServiceIds(self, request : ContextId, context : grpc.ServicerContext) -> ServiceIdList: -# context_uuid = request.context_uuid.uuid -# -# with self.session() as session: -# db_services = session.query(ServiceModel).filter_by(context_uuid=context_uuid).all() -# return ServiceIdList(service_ids=[db_service.dump_id() for db_service in db_services]) -# +# return service_list_ids(self.db_engine, request) + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def ListServices(self, request : ContextId, context : grpc.ServicerContext) -> ServiceList: -# context_uuid = request.context_uuid.uuid -# -# with self.session() as session: -# db_services = session.query(ServiceModel).filter_by(context_uuid=context_uuid).all() -# return ServiceList(services=[db_service.dump() for db_service in db_services]) -# -# -# +# return service_list_objs(self.db_engine, request) + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def GetService(self, request : ServiceId, context : grpc.ServicerContext) -> Service: -# service_uuid = request.service_uuid.uuid -# with self.session() as session: -# result = session.query(ServiceModel).filter_by(service_uuid=service_uuid).one_or_none() -# -# if not result: -# raise NotFoundException(ServiceModel.__name__.replace('Model', ''), service_uuid) -# -# return Service(**result.dump()) -# -# def set_constraint(self, db_constraints: ConstraintsModel, grpc_constraint: Constraint, position: int -# ) -> Tuple[Union_ConstraintModel, bool]: -# with self.session() as session: -# -# grpc_constraint_kind = str(grpc_constraint.WhichOneof('constraint')) -# -# parser = CONSTRAINT_PARSERS.get(grpc_constraint_kind) -# if parser is None: -# raise NotImplementedError('Constraint of kind {:s} is not implemented: {:s}'.format( -# grpc_constraint_kind, grpc_message_to_json_string(grpc_constraint))) -# -# # create specific constraint -# constraint_class, str_constraint_id, constraint_data, constraint_kind = parser(grpc_constraint) -# str_constraint_id = str(uuid.uuid4()) -# LOGGER.info('str_constraint_id: {}'.format(str_constraint_id)) -# # str_constraint_key_hash = fast_hasher(':'.join([constraint_kind.value, str_constraint_id])) -# # str_constraint_key = key_to_str([db_constraints.pk, str_constraint_key_hash], separator=':') -# -# # result : Tuple[Union_ConstraintModel, bool] = update_or_create_object( -# # database, constraint_class, str_constraint_key, constraint_data) -# constraint_data[constraint_class.main_pk_name()] = str_constraint_id -# db_new_constraint = constraint_class(**constraint_data) -# result: Tuple[Union_ConstraintModel, bool] = self.database.create_or_update(db_new_constraint) -# db_specific_constraint, updated = result -# -# # create generic constraint -# # constraint_fk_field_name = 'constraint_uuid'.format(constraint_kind.value) -# constraint_data = { -# 'constraints_uuid': db_constraints.constraints_uuid, 'position': position, 'kind': constraint_kind -# } -# -# db_new_constraint = ConstraintModel(**constraint_data) -# result: Tuple[Union_ConstraintModel, bool] = self.database.create_or_update(db_new_constraint) -# db_constraint, updated = result -# -# return db_constraint, updated -# -# def set_constraints(self, service_uuid: str, constraints_name : str, grpc_constraints -# ) -> List[Tuple[Union[ConstraintsModel, ConstraintModel], bool]]: -# with self.session() as session: -# # str_constraints_key = key_to_str([db_parent_pk, constraints_name], separator=':') -# # result : Tuple[ConstraintsModel, bool] = get_or_create_object(database, ConstraintsModel, str_constraints_key) -# result = session.query(ConstraintsModel).filter_by(constraints_uuid=service_uuid).one_or_none() -# created = None -# if result: -# created = True -# session.query(ConstraintsModel).filter_by(constraints_uuid=service_uuid).one_or_none() -# db_constraints = ConstraintsModel(constraints_uuid=service_uuid) -# session.add(db_constraints) -# -# db_objects = [(db_constraints, created)] -# -# for position,grpc_constraint in enumerate(grpc_constraints): -# result : Tuple[ConstraintModel, bool] = self.set_constraint( -# db_constraints, grpc_constraint, position) -# db_constraint, updated = result -# db_objects.append((db_constraint, updated)) -# -# return db_objects -# +# return service_get(self.db_engine, request) + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def SetService(self, request : Service, context : grpc.ServicerContext) -> ServiceId: -# with self.lock: -# with self.session() as session: -# -# context_uuid = request.service_id.context_id.context_uuid.uuid -# # db_context : ContextModel = get_object(self.database, ContextModel, context_uuid) -# db_context = session.query(ContextModel).filter_by(context_uuid=context_uuid).one_or_none() -# -# for i,endpoint_id in enumerate(request.service_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.service_endpoint_ids[{:d}].topology_id.context_id.context_uuid.uuid'.format(i), -# endpoint_topology_context_uuid, -# ['should be == {:s}({:s})'.format( -# 'request.service_id.context_id.context_uuid.uuid', context_uuid)]) -# -# service_uuid = request.service_id.service_uuid.uuid -# # str_service_key = key_to_str([context_uuid, service_uuid]) -# -# constraints_result = self.set_constraints(service_uuid, 'constraints', request.service_constraints) -# db_constraints = constraints_result[0][0] -# -# config_rules = grpc_config_rules_to_raw(request.service_config.config_rules) -# running_config_result = update_config(self.database, str_service_key, 'running', config_rules) -# db_running_config = running_config_result[0][0] -# -# result : Tuple[ServiceModel, bool] = update_or_create_object(self.database, ServiceModel, str_service_key, { -# 'context_fk' : db_context, -# 'service_uuid' : service_uuid, -# 'service_type' : grpc_to_enum__service_type(request.service_type), -# 'service_constraints_fk': db_constraints, -# 'service_status' : grpc_to_enum__service_status(request.service_status.service_status), -# 'service_config_fk' : db_running_config, -# }) -# db_service, updated = result -# -# for i,endpoint_id in enumerate(request.service_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_service_endpoint_key = key_to_str([service_uuid, str_endpoint_key], separator='--') -# result : Tuple[ServiceEndPointModel, bool] = get_or_create_object( -# self.database, ServiceEndPointModel, str_service_endpoint_key, { -# 'service_fk': db_service, 'endpoint_fk': db_endpoint}) -# #db_service_endpoint, service_endpoint_created = result -# -# event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE -# dict_service_id = db_service.dump_id() -# notify_event(self.messagebroker, TOPIC_SERVICE, event_type, {'service_id': dict_service_id}) -# return ServiceId(**dict_service_id) -# context_uuid = request.service_id.context_id.context_uuid.uuid -# db_context : ContextModel = get_object(self.database, ContextModel, context_uuid) -# -# for i,endpoint_id in enumerate(request.service_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.service_endpoint_ids[{:d}].topology_id.context_id.context_uuid.uuid'.format(i), -# endpoint_topology_context_uuid, -# ['should be == {:s}({:s})'.format( -# 'request.service_id.context_id.context_uuid.uuid', context_uuid)]) -# -# service_uuid = request.service_id.service_uuid.uuid -# str_service_key = key_to_str([context_uuid, service_uuid]) -# -# constraints_result = set_constraints( -# self.database, str_service_key, 'service', request.service_constraints) -# db_constraints = constraints_result[0][0] -# -# running_config_rules = update_config( -# self.database, str_service_key, 'service', request.service_config.config_rules) -# db_running_config = running_config_rules[0][0] -# -# result : Tuple[ServiceModel, bool] = update_or_create_object(self.database, ServiceModel, str_service_key, { -# 'context_fk' : db_context, -# 'service_uuid' : service_uuid, -# 'service_type' : grpc_to_enum__service_type(request.service_type), -# 'service_constraints_fk': db_constraints, -# 'service_status' : grpc_to_enum__service_status(request.service_status.service_status), -# 'service_config_fk' : db_running_config, -# }) -# db_service, updated = result -# -# for i,endpoint_id in enumerate(request.service_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_service_endpoint_key = key_to_str([service_uuid, str_endpoint_key], separator='--') -# result : Tuple[ServiceEndPointModel, bool] = get_or_create_object( -# self.database, ServiceEndPointModel, str_service_endpoint_key, { -# 'service_fk': db_service, 'endpoint_fk': db_endpoint}) -# #db_service_endpoint, service_endpoint_created = result -# -# event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE -# dict_service_id = db_service.dump_id() -# notify_event(self.messagebroker, TOPIC_SERVICE, event_type, {'service_id': dict_service_id}) -# return ServiceId(**dict_service_id) -# +# service_id,updated = service_set(self.db_engine, request) +# #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE +# #notify_event(self.messagebroker, TOPIC_SERVICE, event_type, {'service_id': service_id}) +# return service_id + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def RemoveService(self, request : ServiceId, context : grpc.ServicerContext) -> Empty: -# with self.lock: -# context_uuid = request.context_id.context_uuid.uuid -# service_uuid = request.service_uuid.uuid -# db_service = ServiceModel(self.database, key_to_str([context_uuid, service_uuid]), auto_load=False) -# found = db_service.load() -# if not found: return Empty() -# -# dict_service_id = db_service.dump_id() -# db_service.delete() -# -# event_type = EventTypeEnum.EVENTTYPE_REMOVE -# notify_event(self.messagebroker, TOPIC_SERVICE, event_type, {'service_id': dict_service_id}) -# return Empty() +# deleted = service_delete(self.db_engine, request) +# #if deleted: +# # notify_event(self.messagebroker, TOPIC_SERVICE, EventTypeEnum.EVENTTYPE_REMOVE, {'service_id': request}) +# return Empty() @safe_and_metered_rpc_method(METRICS, LOGGER) def GetServiceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ServiceEvent]: @@ -461,8 +266,8 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer yield ServiceEvent(**json.loads(message.content)) -# # ----- Slice ---------------------------------------------------------------------------------------------------- -# + # ----- Slice ---------------------------------------------------------------------------------------------------- + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def ListSliceIds(self, request : ContextId, context : grpc.ServicerContext) -> SliceIdList: # with self.lock: @@ -470,7 +275,7 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # 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 ListSlices(self, request : ContextId, context : grpc.ServicerContext) -> SliceList: # with self.lock: @@ -478,7 +283,7 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # 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 GetSlice(self, request : SliceId, context : grpc.ServicerContext) -> Slice: # with self.lock: @@ -487,7 +292,7 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # 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 SetSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId: # with self.lock: @@ -572,7 +377,7 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # 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: # with self.lock: @@ -621,7 +426,7 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # 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 RemoveSlice(self, request : SliceId, context : grpc.ServicerContext) -> Empty: # with self.lock: @@ -644,8 +449,8 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer yield SliceEvent(**json.loads(message.content)) -# # ----- Connection ------------------------------------------------------------------------------------------------- -# + # ----- Connection ------------------------------------------------------------------------------------------------- + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def ListConnectionIds(self, request : ServiceId, context : grpc.ServicerContext) -> ConnectionIdList: # with self.session() as session: @@ -658,7 +463,7 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # db_connections : Set[ConnectionModel] = get_related_objects(db_service, ConnectionModel) # db_connections = sorted(db_connections, key=operator.attrgetter('pk')) # return ConnectionIdList(connection_ids=[db_connection.dump_id() for db_connection in db_connections]) -# + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def ListConnections(self, request : ContextId, context : grpc.ServicerContext) -> ServiceList: # with self.lock: @@ -667,13 +472,13 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # db_connections : Set[ConnectionModel] = get_related_objects(db_service, ConnectionModel) # db_connections = sorted(db_connections, key=operator.attrgetter('pk')) # return ConnectionList(connections=[db_connection.dump() for db_connection in db_connections]) -# + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def GetConnection(self, request : ConnectionId, context : grpc.ServicerContext) -> Connection: # with self.lock: # db_connection : ConnectionModel = get_object(self.database, ConnectionModel, request.connection_uuid.uuid) # return Connection(**db_connection.dump(include_path=True, include_sub_service_ids=True)) -# + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def SetConnection(self, request : Connection, context : grpc.ServicerContext) -> ConnectionId: # with self.lock: @@ -712,7 +517,7 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # dict_connection_id = db_connection.dump_id() # notify_event(self.messagebroker, TOPIC_CONNECTION, event_type, {'connection_id': dict_connection_id}) # return ConnectionId(**dict_connection_id) -# + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def RemoveConnection(self, request : ConnectionId, context : grpc.ServicerContext) -> Empty: # with self.lock: @@ -733,29 +538,29 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer yield ConnectionEvent(**json.loads(message.content)) -# # ----- Policy ----------------------------------------------------------------------------------------------------- -# + # ----- Policy ----------------------------------------------------------------------------------------------------- + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def ListPolicyRuleIds(self, request : Empty, context: grpc.ServicerContext) -> PolicyRuleIdList: # with self.lock: # db_policy_rules: List[PolicyRuleModel] = get_all_objects(self.database, PolicyRuleModel) # db_policy_rules = sorted(db_policy_rules, key=operator.attrgetter('pk')) # return PolicyRuleIdList(policyRuleIdList=[db_policy_rule.dump_id() for db_policy_rule in db_policy_rules]) -# + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def ListPolicyRules(self, request : Empty, context: grpc.ServicerContext) -> PolicyRuleList: # with self.lock: # db_policy_rules: List[PolicyRuleModel] = get_all_objects(self.database, PolicyRuleModel) # db_policy_rules = sorted(db_policy_rules, key=operator.attrgetter('pk')) # return PolicyRuleList(policyRules=[db_policy_rule.dump() for db_policy_rule in db_policy_rules]) -# + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def GetPolicyRule(self, request : PolicyRuleId, context: grpc.ServicerContext) -> PolicyRule: # with self.lock: # policy_rule_uuid = request.uuid.uuid # db_policy_rule: PolicyRuleModel = get_object(self.database, PolicyRuleModel, policy_rule_uuid) # return PolicyRule(**db_policy_rule.dump()) -# + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def SetPolicyRule(self, request : PolicyRule, context: grpc.ServicerContext) -> PolicyRuleId: # with self.lock: @@ -764,13 +569,13 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer # policy_rule_uuid = policy_rule_json[policy_rule_type]['policyRuleBasic']['policyRuleId']['uuid']['uuid'] # result: Tuple[PolicyRuleModel, bool] = update_or_create_object( # self.database, PolicyRuleModel, policy_rule_uuid, {'value': json.dumps(policy_rule_json)}) -# db_policy, updated = result # pylint: disable=unused-variable +# db_policy, updated = result # # #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE # dict_policy_id = db_policy.dump_id() # #notify_event(self.messagebroker, TOPIC_POLICY, event_type, {"policy_id": dict_policy_id}) # return PolicyRuleId(**dict_policy_id) -# + # @safe_and_metered_rpc_method(METRICS, LOGGER) # def RemovePolicyRule(self, request : PolicyRuleId, context: grpc.ServicerContext) -> Empty: # with self.lock: diff --git a/src/context/service/Engine.py b/src/context/service/Engine.py index 151f33751b0a04657d01ab4b8369f1dd6cc4b2c5..a1aedc3ae5c0d1ba8ade7222a005ab304e45a842 100644 --- a/src/context/service/Engine.py +++ b/src/context/service/Engine.py @@ -28,13 +28,13 @@ class Engine: try: engine = sqlalchemy.create_engine( crdb_uri, connect_args={'application_name': APP_NAME}, echo=ECHO, future=True) - except: # pylint: disable=bare-except + except: # pylint: disable=bare-except # pragma: no cover LOGGER.exception('Failed to connect to database: {:s}'.format(crdb_uri)) return None try: Engine.create_database(engine) - except: # pylint: disable=bare-except + except: # pylint: disable=bare-except # pragma: no cover LOGGER.exception('Failed to check/create to database: {:s}'.format(engine.url)) return None diff --git a/src/context/service/database/methods/Context.py b/src/context/service/database/methods/Context.py index 8f1c2ee23ef853d450343cf4fdedd320b5a12bac..fc53426e383e9483f525b9044d9af36d992aa186 100644 --- a/src/context/service/database/methods/Context.py +++ b/src/context/service/database/methods/Context.py @@ -12,15 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -import time +import logging 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 Context, ContextId, ContextIdList, ContextList -from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentException, NotFoundException +from common.rpc_method_wrapper.ServiceExceptions import NotFoundException +from common.tools.object_factory.Context import json_context_id from context.service.database.models.ContextModel import ContextModel +from .uuids.Context import context_get_uuid + +LOGGER = logging.getLogger(__name__) def context_list_ids(db_engine : Engine) -> ContextIdList: def callback(session : Session) -> List[Dict]: @@ -37,46 +41,44 @@ def context_list_objs(db_engine : Engine) -> ContextList: return ContextList(contexts=run_transaction(sessionmaker(bind=db_engine), callback)) def context_get(db_engine : Engine, request : ContextId) -> Context: - context_uuid = request.context_uuid.uuid + 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() return None if obj is None else obj.dump() obj = run_transaction(sessionmaker(bind=db_engine), callback) - if obj is None: raise NotFoundException('Context', context_uuid) + if obj is None: + raw_context_uuid = request.context_uuid.uuid + raise NotFoundException('Context', raw_context_uuid, extra_details=[ + 'context_uuid generated was: {:s}'.format(context_uuid) + ]) return Context(**obj) -def context_set(db_engine : Engine, request : Context) -> bool: - context_uuid = request.context_id.context_uuid.uuid +def context_set(db_engine : Engine, request : Context) -> Tuple[ContextId, bool]: context_name = request.name + if len(context_name) == 0: context_name = request.context_id.context_uuid.uuid + context_uuid = context_get_uuid(request.context_id, context_name=context_name, allow_random=True) + + # Ignore request.topology_ids, request.service_ids, and request.slice_ids. They are used + # for retrieving topologies, services and slices added into the context. Explicit addition + # into the context is done automatically qhen creating the topology, service or slice + # specifying the associated context. + + if len(request.topology_ids) > 0: # pragma: no cover + LOGGER.warning('Items in field "topology_ids" ignored. This field is used for retrieval purposes only.') - for i, topology_id in enumerate(request.topology_ids): - topology_context_uuid = topology_id.context_id.context_uuid.uuid - if topology_context_uuid != context_uuid: - raise InvalidArgumentException( - 'request.topology_ids[{:d}].context_id.context_uuid.uuid'.format(i), topology_context_uuid, - ['should be == {:s}({:s})'.format('request.context_id.context_uuid.uuid', context_uuid)]) + if len(request.service_ids) > 0: # pragma: no cover + LOGGER.warning('Items in field "service_ids" ignored. This field is used for retrieval purposes only.') - for i, service_id in enumerate(request.service_ids): - service_context_uuid = service_id.context_id.context_uuid.uuid - if service_context_uuid != context_uuid: - raise InvalidArgumentException( - 'request.service_ids[{:d}].context_id.context_uuid.uuid'.format(i), service_context_uuid, - ['should be == {:s}({:s})'.format('request.context_id.context_uuid.uuid', context_uuid)]) + if len(request.slice_ids) > 0: # pragma: no cover + LOGGER.warning('Items in field "slice_ids" ignored. This field is used for retrieval purposes only.') - for i, slice_id in enumerate(request.slice_ids): - slice_context_uuid = slice_id.context_id.context_uuid.uuid - if slice_context_uuid != context_uuid: - raise InvalidArgumentException( - 'request.slice_ids[{:d}].context_id.context_uuid.uuid'.format(i), slice_context_uuid, - ['should be == {:s}({:s})'.format('request.context_id.context_uuid.uuid', context_uuid)]) + context_data = [{ + 'context_uuid': context_uuid, + 'context_name': context_name, + }] def callback(session : Session) -> None: - context_data = [{ - 'context_uuid': context_uuid, - 'context_name': context_name, - 'created_at' : time.time(), - }] stmt = insert(ContextModel).values(context_data) stmt = stmt.on_conflict_do_update( index_elements=[ContextModel.context_uuid], @@ -85,10 +87,11 @@ def context_set(db_engine : Engine, request : Context) -> bool: session.execute(stmt) run_transaction(sessionmaker(bind=db_engine), callback) - return False # TODO: improve and check if created/updated + updated = False # TODO: improve and check if created/updated + return ContextId(**json_context_id(context_uuid)),updated def context_delete(db_engine : Engine, request : ContextId) -> bool: - context_uuid = request.context_uuid.uuid + context_uuid = context_get_uuid(request, allow_random=False) def callback(session : Session) -> bool: num_deleted = session.query(ContextModel).filter_by(context_uuid=context_uuid).delete() return num_deleted > 0 diff --git a/src/context/service/database/methods/Device.py b/src/context/service/database/methods/Device.py index e7dc3dadb224fafbeb8b459f4ac5a1a70f844874..39ae98de08bf2c120f124aaf79ed443cdaa76a66 100644 --- a/src/context/service/database/methods/Device.py +++ b/src/context/service/database/methods/Device.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -import time from sqlalchemy import delete from sqlalchemy.dialects.postgresql import insert from sqlalchemy.engine import Engine @@ -21,15 +20,18 @@ from sqlalchemy_cockroachdb import run_transaction 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.grpc.Tools import grpc_message_to_json_string -from context.service.database.models.ConfigRuleModel import ConfigRuleKindEnum, ConfigRuleModel +from common.tools.object_factory.Device import json_device_id +#from common.tools.grpc.Tools import grpc_message_to_json_string +#from context.service.database.models.ConfigRuleModel import ConfigRuleKindEnum, ConfigRuleModel from context.service.database.models.DeviceModel import DeviceModel from context.service.database.models.EndPointModel import EndPointModel from context.service.database.models.RelationModels import TopologyDeviceModel -from context.service.database.models.enums.ConfigAction import grpc_to_enum__config_action +#from context.service.database.models.enums.ConfigAction import grpc_to_enum__config_action from context.service.database.models.enums.DeviceDriver import grpc_to_enum__device_driver from context.service.database.models.enums.DeviceOperationalStatus import grpc_to_enum__device_operational_status from context.service.database.models.enums.KpiSampleType import grpc_to_enum__kpi_sample_type +from .uuids.Device import device_get_uuid +from .uuids.EndPoint import endpoint_get_uuid def device_list_ids(db_engine : Engine) -> DeviceIdList: def callback(session : Session) -> List[Dict]: @@ -46,115 +48,121 @@ def device_list_objs(db_engine : Engine) -> DeviceList: return DeviceList(devices=run_transaction(sessionmaker(bind=db_engine), callback)) def device_get(db_engine : Engine, request : DeviceId) -> Device: - device_uuid = request.device_uuid.uuid + 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() return None if obj is None else obj.dump() obj = run_transaction(sessionmaker(bind=db_engine), callback) - if obj is None: raise NotFoundException('Device', device_uuid) + if obj is None: + raw_device_uuid = request.device_uuid.uuid + raise NotFoundException('Device', raw_device_uuid, extra_details=[ + 'device_uuid generated was: {:s}'.format(device_uuid) + ]) return Device(**obj) def device_set(db_engine : Engine, request : Device) -> bool: - device_uuid = request.device_id.device_uuid.uuid - device_name = request.name + raw_device_uuid = request.device_id.device_uuid.uuid + raw_device_name = request.name + device_name = request.device_id.device_uuid.uuid if len(raw_device_name) == 0 else raw_device_name + device_uuid = device_get_uuid(request.device_id, device_name=device_name, allow_random=True) + device_type = request.device_type oper_status = grpc_to_enum__device_operational_status(request.device_operational_status) device_drivers = [grpc_to_enum__device_driver(d) for d in request.device_drivers] - topology_keys : Set[Tuple[str, str]] = set() + topology_uuids : Set[str] = set() related_topologies : List[Dict] = list() endpoints_data : List[Dict] = list() for i, endpoint in enumerate(request.device_endpoints): endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid if len(endpoint_device_uuid) == 0: endpoint_device_uuid = device_uuid - if device_uuid != endpoint_device_uuid: + if endpoint_device_uuid not in {raw_device_uuid, device_uuid}: raise InvalidArgumentException( 'request.device_endpoints[{:d}].device_id.device_uuid.uuid'.format(i), endpoint_device_uuid, - ['should be == {:s}({:s})'.format('request.device_id.device_uuid.uuid', device_uuid)]) + ['should be == request.device_id.device_uuid.uuid({:s})'.format(raw_device_uuid)] + ) - endpoint_context_uuid = endpoint.endpoint_id.topology_id.context_id.context_uuid.uuid - endpoint_topology_uuid = endpoint.endpoint_id.topology_id.topology_uuid.uuid + raw_endpoint_name = endpoint.name + endpoint_topology_uuid, endpoint_device_uuid, endpoint_uuid = endpoint_get_uuid( + endpoint.endpoint_id, endpoint_name=raw_endpoint_name, allow_random=True) kpi_sample_types = [grpc_to_enum__kpi_sample_type(kst) for kst in endpoint.kpi_sample_types] endpoints_data.append({ - 'context_uuid' : endpoint_context_uuid, - 'topology_uuid' : endpoint_topology_uuid, + 'endpoint_uuid' : endpoint_uuid, 'device_uuid' : endpoint_device_uuid, - 'endpoint_uuid' : endpoint.endpoint_id.endpoint_uuid.uuid, + 'topology_uuid' : endpoint_topology_uuid, + 'name' : raw_endpoint_name, 'endpoint_type' : endpoint.endpoint_type, 'kpi_sample_types': kpi_sample_types, }) - if len(endpoint_context_uuid) > 0 and len(endpoint_topology_uuid) > 0: - topology_key = (endpoint_context_uuid, endpoint_topology_uuid) - if topology_key not in topology_keys: - related_topologies.append({ - 'context_uuid': endpoint_context_uuid, - 'topology_uuid': endpoint_topology_uuid, - 'device_uuid': endpoint_device_uuid, - }) - topology_keys.add(topology_key) + if endpoint_topology_uuid not in topology_uuids: + related_topologies.append({ + 'topology_uuid': endpoint_topology_uuid, + 'device_uuid' : endpoint_device_uuid, + }) + topology_uuids.add(endpoint_topology_uuid) - config_rules : List[Dict] = list() - for position,config_rule in enumerate(request.device_config.config_rules): - str_kind = config_rule.WhichOneof('config_rule') - config_rules.append({ - 'device_uuid': device_uuid, - 'kind' : ConfigRuleKindEnum._member_map_.get(str_kind.upper()), # pylint: disable=no-member - 'action' : grpc_to_enum__config_action(config_rule.action), - 'position' : position, - 'data' : grpc_message_to_json_string(getattr(config_rule, str_kind, {})), - }) + #config_rules : List[Dict] = list() + #for position,config_rule in enumerate(request.device_config.config_rules): + # str_kind = config_rule.WhichOneof('config_rule') + # config_rules.append({ + # 'device_uuid': device_uuid, + # 'kind' : ConfigRuleKindEnum._member_map_.get(str_kind.upper()), # pylint: disable=no-member + # 'action' : grpc_to_enum__config_action(config_rule.action), + # 'position' : position, + # 'data' : grpc_message_to_json_string(getattr(config_rule, str_kind, {})), + # }) + + device_data = [{ + 'device_uuid' : device_uuid, + 'device_name' : device_name, + 'device_type' : device_type, + 'device_operational_status': oper_status, + 'device_drivers' : device_drivers, + }] def callback(session : Session) -> None: - obj : Optional[DeviceModel] = session.query(DeviceModel).with_for_update()\ - .filter_by(device_uuid=device_uuid).one_or_none() - is_update = obj is not None - if is_update: - obj.device_name = device_name - obj.device_type = device_type - obj.device_operational_status = oper_status - obj.device_drivers = device_drivers - session.merge(obj) - else: - session.add(DeviceModel( - device_uuid=device_uuid, device_name=device_name, device_type=device_type, - device_operational_status=oper_status, device_drivers=device_drivers, created_at=time.time())) - obj : Optional[DeviceModel] = session.query(DeviceModel)\ - .filter_by(device_uuid=device_uuid).one_or_none() + stmt = insert(DeviceModel).values(device_data) + stmt = stmt.on_conflict_do_update( + index_elements=[DeviceModel.device_uuid], + set_=dict( + device_name = stmt.excluded.device_name, + device_type = stmt.excluded.device_type, + device_operational_status = stmt.excluded.device_operational_status, + device_drivers = stmt.excluded.device_drivers, + ) + ) + session.execute(stmt) stmt = insert(EndPointModel).values(endpoints_data) stmt = stmt.on_conflict_do_update( - index_elements=[ - EndPointModel.context_uuid, EndPointModel.topology_uuid, EndPointModel.device_uuid, - EndPointModel.endpoint_uuid - ], + index_elements=[EndPointModel.endpoint_uuid], set_=dict( - endpoint_type = stmt.excluded.endpoint_type, + name = stmt.excluded.name, + endpoint_type = stmt.excluded.endpoint_type, kpi_sample_types = stmt.excluded.kpi_sample_types, ) ) session.execute(stmt) session.execute(insert(TopologyDeviceModel).values(related_topologies).on_conflict_do_nothing( - index_elements=[ - TopologyDeviceModel.context_uuid, TopologyDeviceModel.topology_uuid, - TopologyDeviceModel.device_uuid - ] + index_elements=[TopologyDeviceModel.topology_uuid, TopologyDeviceModel.device_uuid] )) - session.execute(delete(ConfigRuleModel).where(ConfigRuleModel.device_uuid == device_uuid)) - session.execute(insert(ConfigRuleModel).values(config_rules)) + #session.execute(delete(ConfigRuleModel).where(ConfigRuleModel.device_uuid == device_uuid)) + #session.execute(insert(ConfigRuleModel).values(config_rules)) run_transaction(sessionmaker(bind=db_engine), callback) - return False # TODO: improve and check if created/updated + updated = False # TODO: improve and check if created/updated + return DeviceId(**json_device_id(device_uuid)),updated def device_delete(db_engine : Engine, request : DeviceId) -> bool: - device_uuid = request.device_uuid.uuid + device_uuid = device_get_uuid(request, allow_random=False) def callback(session : Session) -> bool: - session.query(TopologyDeviceModel).filter_by(device_uuid=device_uuid).delete() + #session.query(TopologyDeviceModel).filter_by(device_uuid=device_uuid).delete() num_deleted = session.query(DeviceModel).filter_by(device_uuid=device_uuid).delete() #db_device = session.query(DeviceModel).filter_by(device_uuid=device_uuid).one_or_none() #session.query(ConfigRuleModel).filter_by(config_uuid=db_device.device_config_uuid).delete() diff --git a/src/context/service/database/methods/Service.py b/src/context/service/database/methods/Service.py new file mode 100644 index 0000000000000000000000000000000000000000..9f5e519df2c76d34f0415b3264f7849b92b0b461 --- /dev/null +++ b/src/context/service/database/methods/Service.py @@ -0,0 +1,263 @@ +# 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 time +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 common.proto.context_pb2 import ContextId, Service, ServiceId, ServiceIdList, ServiceList +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentException, NotFoundException +from context.service.database.models.ServiceModel import ServiceModel + +def service_list_ids(db_engine : Engine, request : ContextId) -> ServiceIdList: + context_uuid = request.context_uuid.uuid + def callback(session : Session) -> List[Dict]: + obj_list : List[ServiceModel] = session.query(ServiceModel).filter_by(context_uuid=context_uuid).all() + #.options(selectinload(ContextModel.service)).filter_by(context_uuid=context_uuid).one_or_none() + return [obj.dump_id() for obj in obj_list] + return ServiceIdList(service_ids=run_transaction(sessionmaker(bind=db_engine), callback)) + +def service_list_objs(db_engine : Engine, request : ContextId) -> ServiceList: + context_uuid = request.context_uuid.uuid + def callback(session : Session) -> List[Dict]: + obj_list : List[ServiceModel] = session.query(ServiceModel).filter_by(context_uuid=context_uuid).all() + #.options(selectinload(ContextModel.service)).filter_by(context_uuid=context_uuid).one_or_none() + return [obj.dump() for obj in obj_list] + return ServiceList(services=run_transaction(sessionmaker(bind=db_engine), callback)) + +def service_get(db_engine : Engine, request : ServiceId) -> Service: + context_uuid = request.context_id.context_uuid.uuid + service_uuid = request.service_uuid.uuid + + def callback(session : Session) -> Optional[Dict]: + obj : Optional[ServiceModel] = session.query(ServiceModel)\ + .filter_by(context_uuid=context_uuid, 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: + obj_uuid = '{:s}/{:s}'.format(context_uuid, service_uuid) + raise NotFoundException('Service', obj_uuid) + return Service(**obj) + +def service_set(db_engine : Engine, request : Service) -> bool: + context_uuid = request.service_id.context_id.context_uuid.uuid + service_uuid = request.service_id.service_uuid.uuid + service_name = request.name + + for i,endpoint_id in enumerate(request.service_endpoint_ids): + endpoint_context_uuid = endpoint_id.topology_id.context_id.context_uuid.uuid + if len(endpoint_context_uuid) > 0 and context_uuid != endpoint_context_uuid: + raise InvalidArgumentException( + 'request.service_endpoint_ids[{:d}].topology_id.context_id.context_uuid.uuid'.format(i), + endpoint_context_uuid, + ['should be == {:s}({:s})'.format('request.service_id.context_id.context_uuid.uuid', context_uuid)]) + + + def callback(session : Session) -> None: + service_data = [{ + 'context_uuid' : context_uuid, + 'service_uuid': service_uuid, + 'service_name': service_name, + 'created_at' : time.time(), + }] + stmt = insert(ServiceModel).values(service_data) + stmt = stmt.on_conflict_do_update( + index_elements=[ServiceModel.context_uuid, ServiceModel.service_uuid], + set_=dict(service_name = stmt.excluded.service_name) + ) + session.execute(stmt) + + run_transaction(sessionmaker(bind=db_engine), callback) + return False # TODO: improve and check if created/updated + + +# # db_context : ContextModel = get_object(self.database, ContextModel, context_uuid) +# db_context = session.query(ContextModel).filter_by(context_uuid=context_uuid).one_or_none() +# # str_service_key = key_to_str([context_uuid, service_uuid]) +# constraints_result = self.set_constraints(service_uuid, 'constraints', request.service_constraints) +# db_constraints = constraints_result[0][0] +# +# config_rules = grpc_config_rules_to_raw(request.service_config.config_rules) +# running_config_result = update_config(self.database, str_service_key, 'running', config_rules) +# db_running_config = running_config_result[0][0] +# +# result : Tuple[ServiceModel, bool] = update_or_create_object(self.database, ServiceModel, str_service_key, { +# 'context_fk' : db_context, +# 'service_uuid' : service_uuid, +# 'service_type' : grpc_to_enum__service_type(request.service_type), +# 'service_constraints_fk': db_constraints, +# 'service_status' : grpc_to_enum__service_status(request.service_status.service_status), +# 'service_config_fk' : db_running_config, +# }) +# db_service, updated = result +# +# for i,endpoint_id in enumerate(request.service_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_service_endpoint_key = key_to_str([service_uuid, str_endpoint_key], separator='--') +# result : Tuple[ServiceEndPointModel, bool] = get_or_create_object( +# self.database, ServiceEndPointModel, str_service_endpoint_key, { +# 'service_fk': db_service, 'endpoint_fk': db_endpoint}) +# #db_service_endpoint, service_endpoint_created = result +# +# event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE +# dict_service_id = db_service.dump_id() +# notify_event(self.messagebroker, TOPIC_SERVICE, event_type, {'service_id': dict_service_id}) +# return ServiceId(**dict_service_id) +# context_uuid = request.service_id.context_id.context_uuid.uuid +# db_context : ContextModel = get_object(self.database, ContextModel, context_uuid) +# +# for i,endpoint_id in enumerate(request.service_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.service_endpoint_ids[{:d}].topology_id.context_id.context_uuid.uuid'.format(i), +# endpoint_topology_context_uuid, +# ['should be == {:s}({:s})'.format( +# 'request.service_id.context_id.context_uuid.uuid', context_uuid)]) +# +# service_uuid = request.service_id.service_uuid.uuid +# str_service_key = key_to_str([context_uuid, service_uuid]) +# +# constraints_result = set_constraints( +# self.database, str_service_key, 'service', request.service_constraints) +# db_constraints = constraints_result[0][0] +# +# running_config_rules = update_config( +# self.database, str_service_key, 'service', request.service_config.config_rules) +# db_running_config = running_config_rules[0][0] +# +# result : Tuple[ServiceModel, bool] = update_or_create_object(self.database, ServiceModel, str_service_key, { +# 'context_fk' : db_context, +# 'service_uuid' : service_uuid, +# 'service_type' : grpc_to_enum__service_type(request.service_type), +# 'service_constraints_fk': db_constraints, +# 'service_status' : grpc_to_enum__service_status(request.service_status.service_status), +# 'service_config_fk' : db_running_config, +# }) +# db_service, updated = result +# +# for i,endpoint_id in enumerate(request.service_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_service_endpoint_key = key_to_str([service_uuid, str_endpoint_key], separator='--') +# result : Tuple[ServiceEndPointModel, bool] = get_or_create_object( +# self.database, ServiceEndPointModel, str_service_endpoint_key, { +# 'service_fk': db_service, 'endpoint_fk': db_endpoint}) +# #db_service_endpoint, service_endpoint_created = result +# +# event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE +# dict_service_id = db_service.dump_id() +# notify_event(self.messagebroker, TOPIC_SERVICE, event_type, {'service_id': dict_service_id}) +# return ServiceId(**dict_service_id) + + +# def set_constraint(self, db_constraints: ConstraintsModel, grpc_constraint: Constraint, position: int +# ) -> Tuple[Union_ConstraintModel, bool]: +# with self.session() as session: +# +# grpc_constraint_kind = str(grpc_constraint.WhichOneof('constraint')) +# +# parser = CONSTRAINT_PARSERS.get(grpc_constraint_kind) +# if parser is None: +# raise NotImplementedError('Constraint of kind {:s} is not implemented: {:s}'.format( +# grpc_constraint_kind, grpc_message_to_json_string(grpc_constraint))) +# +# # create specific constraint +# constraint_class, str_constraint_id, constraint_data, constraint_kind = parser(grpc_constraint) +# str_constraint_id = str(uuid.uuid4()) +# LOGGER.info('str_constraint_id: {}'.format(str_constraint_id)) +# # str_constraint_key_hash = fast_hasher(':'.join([constraint_kind.value, str_constraint_id])) +# # str_constraint_key = key_to_str([db_constraints.pk, str_constraint_key_hash], separator=':') +# +# # result : Tuple[Union_ConstraintModel, bool] = update_or_create_object( +# # database, constraint_class, str_constraint_key, constraint_data) +# constraint_data[constraint_class.main_pk_name()] = str_constraint_id +# db_new_constraint = constraint_class(**constraint_data) +# result: Tuple[Union_ConstraintModel, bool] = self.database.create_or_update(db_new_constraint) +# db_specific_constraint, updated = result +# +# # create generic constraint +# # constraint_fk_field_name = 'constraint_uuid'.format(constraint_kind.value) +# constraint_data = { +# 'constraints_uuid': db_constraints.constraints_uuid, 'position': position, 'kind': constraint_kind +# } +# +# db_new_constraint = ConstraintModel(**constraint_data) +# result: Tuple[Union_ConstraintModel, bool] = self.database.create_or_update(db_new_constraint) +# db_constraint, updated = result +# +# return db_constraint, updated +# +# def set_constraints(self, service_uuid: str, constraints_name : str, grpc_constraints +# ) -> List[Tuple[Union[ConstraintsModel, ConstraintModel], bool]]: +# with self.session() as session: +# # str_constraints_key = key_to_str([db_parent_pk, constraints_name], separator=':') +# # result : Tuple[ConstraintsModel, bool] = get_or_create_object(database, ConstraintsModel, str_constraints_key) +# result = session.query(ConstraintsModel).filter_by(constraints_uuid=service_uuid).one_or_none() +# created = None +# if result: +# created = True +# session.query(ConstraintsModel).filter_by(constraints_uuid=service_uuid).one_or_none() +# db_constraints = ConstraintsModel(constraints_uuid=service_uuid) +# session.add(db_constraints) +# +# db_objects = [(db_constraints, created)] +# +# for position,grpc_constraint in enumerate(grpc_constraints): +# result : Tuple[ConstraintModel, bool] = self.set_constraint( +# db_constraints, grpc_constraint, position) +# db_constraint, updated = result +# db_objects.append((db_constraint, updated)) +# +# return db_objects + +def service_delete(db_engine : Engine, request : ServiceId) -> bool: + context_uuid = request.context_id.context_uuid.uuid + service_uuid = request.service_uuid.uuid + def callback(session : Session) -> bool: + num_deleted = session.query(ServiceModel)\ + .filter_by(context_uuid=context_uuid, service_uuid=service_uuid).delete() + return num_deleted > 0 + return run_transaction(sessionmaker(bind=db_engine), callback) + + # def delete(self) -> None: + # from .RelationModels import ServiceEndPointModel + # for db_service_endpoint_pk,_ in self.references(ServiceEndPointModel): + # ServiceEndPointModel(self.database, db_service_endpoint_pk).delete() + # super().delete() + # ConfigModel(self.database, self.service_config_fk).delete() + # ConstraintsModel(self.database, self.service_constraints_fk).delete() diff --git a/src/context/service/database/methods/Topology.py b/src/context/service/database/methods/Topology.py index f9449e0c39050544ae9f5bba6b9f73e6913cde42..1abbc55622c490c5360fda103feb7ff4b22c9833 100644 --- a/src/context/service/database/methods/Topology.py +++ b/src/context/service/database/methods/Topology.py @@ -12,19 +12,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -import time 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 common.proto.context_pb2 import ContextId, Topology, TopologyId, TopologyIdList, TopologyList -from common.rpc_method_wrapper.ServiceExceptions import NotFoundException -from context.service.database.models.RelationModels import TopologyDeviceModel +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentsException, NotFoundException +from common.tools.object_factory.Context import json_context_id +from common.tools.object_factory.Topology import json_topology_id +#from context.service.database.models.RelationModels import TopologyDeviceModel, TopologyLinkModel from context.service.database.models.TopologyModel import TopologyModel +from .uuids.Context import context_get_uuid +from .uuids.Topology import topology_get_uuid def topology_list_ids(db_engine : Engine, request : ContextId) -> TopologyIdList: - context_uuid = request.context_uuid.uuid + context_uuid = context_get_uuid(request, allow_random=False) def callback(session : Session) -> List[Dict]: obj_list : List[TopologyModel] = session.query(TopologyModel).filter_by(context_uuid=context_uuid).all() #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none() @@ -32,7 +35,7 @@ def topology_list_ids(db_engine : Engine, request : ContextId) -> TopologyIdList return TopologyIdList(topology_ids=run_transaction(sessionmaker(bind=db_engine), callback)) def topology_list_objs(db_engine : Engine, request : ContextId) -> TopologyList: - context_uuid = request.context_uuid.uuid + context_uuid = context_get_uuid(request, allow_random=False) def callback(session : Session) -> List[Dict]: obj_list : List[TopologyModel] = session.query(TopologyModel).filter_by(context_uuid=context_uuid).all() #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none() @@ -40,84 +43,74 @@ def topology_list_objs(db_engine : Engine, request : ContextId) -> TopologyList: return TopologyList(topologies=run_transaction(sessionmaker(bind=db_engine), callback)) def topology_get(db_engine : Engine, request : TopologyId) -> Topology: - context_uuid = request.context_id.context_uuid.uuid - topology_uuid = request.topology_uuid.uuid - + _,topology_uuid = topology_get_uuid(request, allow_random=False) def callback(session : Session) -> Optional[Dict]: obj : Optional[TopologyModel] = session.query(TopologyModel)\ - .filter_by(context_uuid=context_uuid, topology_uuid=topology_uuid).one_or_none() + .filter_by(topology_uuid=topology_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: - obj_uuid = '{:s}/{:s}'.format(context_uuid, topology_uuid) - raise NotFoundException('Topology', obj_uuid) + context_uuid = context_get_uuid(request.context_id, allow_random=False) + raw_topology_uuid = '{:s}/{:s}'.format(request.context_id.context_uuid.uuid, request.topology_uuid.uuid) + raise NotFoundException('Topology', raw_topology_uuid, extra_details=[ + 'context_uuid generated was: {:s}'.format(context_uuid), + 'topology_uuid generated was: {:s}'.format(topology_uuid), + ]) return Topology(**obj) def topology_set(db_engine : Engine, request : Topology) -> bool: - context_uuid = request.topology_id.context_id.context_uuid.uuid - topology_uuid = request.topology_id.topology_uuid.uuid 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) + + #device_uuids : Set[str] = set() + #devices_to_add : List[Dict] = list() + #for device_id in request.device_ids: + # device_uuid = device_id.device_uuid.uuid + # if device_uuid in device_uuids: continue + # devices_to_add.append({'topology_uuid': topology_uuid, 'device_uuid': device_uuid}) + # device_uuids.add(device_uuid) - device_uuids : Set[str] = set() - devices_to_add : List[Dict] = list() - for device_id in request.device_ids: - device_uuid = device_id.device_uuid.uuid - if device_uuid in device_uuids: continue - devices_to_add.append({ - 'context_uuid': context_uuid, 'topology_uuid': topology_uuid, 'device_uuid': device_uuid - }) - device_uuids.add(device_uuid) + #link_uuids : Set[str] = set() + #links_to_add : List[Dict] = list() + #for link_id in request.link_ids: + # link_uuid = link_id.link_uuid.uuid + # if link_uuid in link_uuids: continue + # links_to_add.append({'topology_uuid': topology_uuid, 'link_uuid': link_uuid}) + # link_uuids.add(link_uuid) - link_uuids : Set[str] = set() - links_to_add : List[Dict] = list() - for link_id in request.link_ids: - link_uuid = link_id.link_uuid.uuid - if link_uuid in link_uuids: continue - links_to_add.append({ - 'context_uuid': context_uuid, 'topology_uuid': topology_uuid, 'link_uuid': link_uuid - }) - link_uuids.add(link_uuid) + topology_data = [{ + 'context_uuid' : context_uuid, + 'topology_uuid': topology_uuid, + 'topology_name': topology_name, + }] def callback(session : Session) -> None: - topology_data = [{ - 'context_uuid' : context_uuid, - 'topology_uuid': topology_uuid, - 'topology_name': topology_name, - 'created_at' : time.time(), - }] stmt = insert(TopologyModel).values(topology_data) stmt = stmt.on_conflict_do_update( - index_elements=[TopologyModel.context_uuid, TopologyModel.topology_uuid], + index_elements=[TopologyModel.topology_uuid], set_=dict(topology_name = stmt.excluded.topology_name) ) session.execute(stmt) - if len(devices_to_add) > 0: - session.execute(insert(TopologyDeviceModel).values(devices_to_add).on_conflict_do_nothing( - index_elements=[ - TopologyDeviceModel.context_uuid, TopologyDeviceModel.topology_uuid, - TopologyDeviceModel.device_uuid - ] - )) + #if len(devices_to_add) > 0: + # session.execute(insert(TopologyDeviceModel).values(devices_to_add).on_conflict_do_nothing( + # index_elements=[TopologyDeviceModel.topology_uuid, TopologyDeviceModel.device_uuid] + # )) - #if len(link_to_add) > 0: + #if len(links_to_add) > 0: # session.execute(insert(TopologyLinkModel).values(links_to_add).on_conflict_do_nothing( - # index_elements=[ - # TopologyLinkModel.context_uuid, TopologyLinkModel.topology_uuid, - # TopologyLinkModel.link_uuid - # ] + # index_elements=[TopologyLinkModel.topology_uuid, TopologyLinkModel.link_uuid] # )) run_transaction(sessionmaker(bind=db_engine), callback) - return False # TODO: improve and check if created/updated + updated = False # TODO: improve and check if created/updated + return TopologyId(**json_topology_id(topology_uuid, json_context_id(context_uuid))),updated def topology_delete(db_engine : Engine, request : TopologyId) -> bool: - context_uuid = request.context_id.context_uuid.uuid - topology_uuid = request.topology_uuid.uuid - + _,topology_uuid = topology_get_uuid(request, allow_random=False) def callback(session : Session) -> bool: num_deleted = session.query(TopologyModel)\ - .filter_by(context_uuid=context_uuid, topology_uuid=topology_uuid).delete() + .filter_by(topology_uuid=topology_uuid).delete() return num_deleted > 0 - return run_transaction(sessionmaker(bind=db_engine), callback) diff --git a/src/context/service/database/methods/uuids/Context.py b/src/context/service/database/methods/uuids/Context.py new file mode 100644 index 0000000000000000000000000000000000000000..753f80e9c73a3f03e15e23bc51bc85f4f09d6292 --- /dev/null +++ b/src/context/service/database/methods/uuids/Context.py @@ -0,0 +1,33 @@ +# 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 common.proto.context_pb2 import ContextId +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentsException +from ._Builder import get_uuid_from_string, get_uuid_random + +def context_get_uuid( + context_id : ContextId, context_name : str = '', allow_random : bool = False +) -> str: + context_uuid = context_id.context_uuid.uuid + + if len(context_uuid) > 0: + return get_uuid_from_string(context_uuid) + if len(context_name) > 0: + return get_uuid_from_string(context_name) + if allow_random: return get_uuid_random() + + raise InvalidArgumentsException([ + ('context_id.context_uuid.uuid', context_uuid), + ('name', context_name), + ], extra_details=['At least one is required to produce a Context UUID']) diff --git a/src/context/service/database/methods/uuids/Device.py b/src/context/service/database/methods/uuids/Device.py new file mode 100644 index 0000000000000000000000000000000000000000..c1b66759bf69bef8dfb88ced0e5e9630f4fbe4e5 --- /dev/null +++ b/src/context/service/database/methods/uuids/Device.py @@ -0,0 +1,33 @@ +# 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 common.proto.context_pb2 import DeviceId +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentsException +from ._Builder import get_uuid_from_string, get_uuid_random + +def device_get_uuid( + device_id : DeviceId, device_name : str = '', allow_random : bool = False +) -> str: + device_uuid = device_id.device_uuid.uuid + + if len(device_uuid) > 0: + return get_uuid_from_string(device_uuid) + if len(device_name) > 0: + return get_uuid_from_string(device_name) + if allow_random: return get_uuid_random() + + raise InvalidArgumentsException([ + ('device_id.device_uuid.uuid', device_uuid), + ('name', device_name), + ], extra_details=['At least one is required to produce a Device UUID']) diff --git a/src/context/service/database/methods/uuids/EndPoint.py b/src/context/service/database/methods/uuids/EndPoint.py new file mode 100644 index 0000000000000000000000000000000000000000..7afb87184f71499385365490f4ce29733f58f85c --- /dev/null +++ b/src/context/service/database/methods/uuids/EndPoint.py @@ -0,0 +1,41 @@ +# 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 EndPointId +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentsException +from ._Builder import get_uuid_from_string, get_uuid_random +from .Device import device_get_uuid +from .Topology import topology_get_uuid + +def endpoint_get_uuid( + endpoint_id : EndPointId, endpoint_name : str = '', allow_random : bool = False +) -> Tuple[str, str, str]: + device_uuid = device_get_uuid(endpoint_id.device_id, allow_random=False) + _,topology_uuid = topology_get_uuid(endpoint_id.topology_id, allow_random=False) + raw_endpoint_uuid = endpoint_id.endpoint_uuid.uuid + + if len(raw_endpoint_uuid) > 0: + prefix_for_name = '{:s}/{:s}'.format(topology_uuid, device_uuid) + return topology_uuid, device_uuid, get_uuid_from_string(raw_endpoint_uuid, prefix_for_name=prefix_for_name) + if len(endpoint_name) > 0: + prefix_for_name = '{:s}/{:s}'.format(topology_uuid, device_uuid) + return topology_uuid, device_uuid, get_uuid_from_string(endpoint_name, prefix_for_name=prefix_for_name) + if allow_random: + return topology_uuid, device_uuid, get_uuid_random() + + raise InvalidArgumentsException([ + ('endpoint_id.endpoint_uuid.uuid', raw_endpoint_uuid), + ('name', endpoint_name), + ], extra_details=['At least one is required to produce a EndPoint UUID']) diff --git a/src/context/service/database/methods/uuids/Link.py b/src/context/service/database/methods/uuids/Link.py new file mode 100644 index 0000000000000000000000000000000000000000..d1ae4c21fcb780babc6915a05b7e47c0ea2ed771 --- /dev/null +++ b/src/context/service/database/methods/uuids/Link.py @@ -0,0 +1,33 @@ +# 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 common.proto.context_pb2 import LinkId +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentsException +from ._Builder import get_uuid_from_string, get_uuid_random + +def link_get_uuid( + link_id : LinkId, link_name : str = '', allow_random : bool = False +) -> str: + link_uuid = link_id.link_uuid.uuid + + if len(link_uuid) > 0: + return get_uuid_from_string(link_uuid) + if len(link_name) > 0: + return get_uuid_from_string(link_name) + if allow_random: return get_uuid_random() + + raise InvalidArgumentsException([ + ('link_id.link_uuid.uuid', link_uuid), + ('name', link_name), + ], extra_details=['At least one is required to produce a Link UUID']) diff --git a/src/context/service/database/methods/uuids/Topology.py b/src/context/service/database/methods/uuids/Topology.py new file mode 100644 index 0000000000000000000000000000000000000000..c3c9175d808826ca6cfc0b722a97ddabfe5f9151 --- /dev/null +++ b/src/context/service/database/methods/uuids/Topology.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 TopologyId +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 topology_get_uuid( + topology_id : TopologyId, topology_name : str = '', allow_random : bool = False +) -> Tuple[str, str]: + context_uuid = context_get_uuid(topology_id.context_id, allow_random=False) + raw_topology_uuid = topology_id.topology_uuid.uuid + + if len(raw_topology_uuid) > 0: + return context_uuid, get_uuid_from_string(raw_topology_uuid, prefix_for_name=context_uuid) + if len(topology_name) > 0: + return context_uuid, get_uuid_from_string(topology_name, prefix_for_name=context_uuid) + if allow_random: + return context_uuid, get_uuid_random() + + raise InvalidArgumentsException([ + ('topology_id.topology_uuid.uuid', raw_topology_uuid), + ('name', topology_name), + ], extra_details=['At least one is required to produce a Topology UUID']) diff --git a/src/context/service/database/methods/uuids/_Builder.py b/src/context/service/database/methods/uuids/_Builder.py new file mode 100644 index 0000000000000000000000000000000000000000..55384433bdf55023d97ec7153a4e74a9c99b409f --- /dev/null +++ b/src/context/service/database/methods/uuids/_Builder.py @@ -0,0 +1,44 @@ +# 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 Optional, Union +from uuid import UUID, uuid4, uuid5 + +# Generate a UUIDv5-like from the SHA-1 of "TFS" and no namespace to be used as the NAMESPACE for all +# the context UUIDs generated. For efficiency purposes, the UUID is hardcoded; however, it is produced +# using the following code: +# from hashlib import sha1 +# from uuid import UUID +# hash = sha1(bytes('TFS', 'utf-8')).digest() +# NAMESPACE_TFS = UUID(bytes=hash[:16], version=5) +NAMESPACE_TFS = UUID('200e3a1f-2223-534f-a100-758e29c37f40') + +def get_uuid_from_string(str_uuid_or_name : Union[str, UUID], prefix_for_name : Optional[str] = None) -> str: + # if UUID given, assume it is already a valid UUID + if isinstance(str_uuid_or_name, UUID): return str_uuid_or_name + if not isinstance(str_uuid_or_name, str): + MSG = 'Parameter({:s}) cannot be used to produce a UUID' + raise Exception(MSG.format(str(repr(str_uuid_or_name)))) + try: + # try to parse as UUID + return str(UUID(str_uuid_or_name)) + except: # pylint: disable=bare-except + # produce a UUID within TFS namespace from parameter + if prefix_for_name is not None: + str_uuid_or_name = '{:s}/{:s}'.format(prefix_for_name, str_uuid_or_name) + return str(uuid5(NAMESPACE_TFS, str_uuid_or_name)) + +def get_uuid_random() -> str: + # Generate random UUID. No need to use namespace since "namespace + random = random". + return str(uuid4()) diff --git a/src/context/service/database/methods/uuids/__init__.py b/src/context/service/database/methods/uuids/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9953c820575d42fa88351cc8de022d880ba96e6a --- /dev/null +++ b/src/context/service/database/methods/uuids/__init__.py @@ -0,0 +1,13 @@ +# 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/database/models/ConfigRuleModel.py b/src/context/service/database/models/ConfigRuleModel.py index d5a37eed2cfac39ebb4b72906e1e70249e22b365..a229f475d340e94619c9c4efb5fcb6e18a4cc7c1 100644 --- a/src/context/service/database/models/ConfigRuleModel.py +++ b/src/context/service/database/models/ConfigRuleModel.py @@ -13,32 +13,53 @@ # limitations under the License. import enum, json -from sqlalchemy import Column, ForeignKey, INTEGER, CheckConstraint, Enum, String, text +from sqlalchemy import Column, INTEGER, CheckConstraint, Enum, ForeignKeyConstraint, String, UniqueConstraint, text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from typing import Dict from .enums.ConfigAction import ORM_ConfigActionEnum from ._Base import _Base -# enum values should match name of field in ConfigRuleModel +# Enum values should match name of field in ConfigRuleModel class ConfigRuleKindEnum(enum.Enum): CUSTOM = 'custom' ACL = 'acl' class ConfigRuleModel(_Base): __tablename__ = 'config_rule' - device_uuid = Column(UUID(as_uuid=False), ForeignKey('device.device_uuid', ondelete='CASCADE'), primary_key=True) - rule_uuid = Column(UUID(as_uuid=False), primary_key=True, server_default=text('uuid_generate_v4()')) - kind = Column(Enum(ConfigRuleKindEnum)) - action = Column(Enum(ORM_ConfigActionEnum)) - position = Column(INTEGER, nullable=False) - data = Column(String, nullable=False) + + config_rule_uuid = Column(UUID(as_uuid=False), primary_key=True, server_default=text('uuid_generate_v4()')) + device_uuid = Column(UUID(as_uuid=False)) # for device config rules + context_uuid = Column(UUID(as_uuid=False)) # for service/slice config rules + service_uuid = Column(UUID(as_uuid=False)) # for service config rules + #slice_uuid = Column(UUID(as_uuid=False)) # for slice config rules + kind = Column(Enum(ConfigRuleKindEnum)) + action = Column(Enum(ORM_ConfigActionEnum)) + position = Column(INTEGER, nullable=False) + data = Column(String, nullable=False) __table_args__ = ( CheckConstraint(position >= 0, name='check_position_value'), + UniqueConstraint('device_uuid', 'position', name='unique_per_device'), + UniqueConstraint('context_uuid', 'service_uuid', 'position', name='unique_per_service'), + #UniqueConstraint('context_uuid', 'slice_uuid', 'position', name='unique_per_slice'), + ForeignKeyConstraint( + ['device_uuid'], + ['device.device_uuid'], + ondelete='CASCADE'), + ForeignKeyConstraint( + ['context_uuid', 'service_uuid'], + ['service.context_uuid', 'service.service_uuid'], + ondelete='CASCADE'), + #ForeignKeyConstraint( + # ['context_uuid', 'slice_uuid'], + # ['slice.context_uuid', 'slice.slice_uuid'], + # ondelete='CASCADE'), ) device = relationship('DeviceModel', back_populates='config_rules') + service = relationship('ServiceModel', back_populates='config_rules') + #slice = relationship('SliceModel', back_populates='config_rules') def dump(self) -> Dict: return {self.kind.value: json.loads(self.data)} diff --git a/src/context/service/database/models/ContextModel.py b/src/context/service/database/models/ContextModel.py index a5ddeb59686356e211192fc18390df8cc54834bc..84039dea9a5a9c52376b08d8af499b711d509f1b 100644 --- a/src/context/service/database/models/ContextModel.py +++ b/src/context/service/database/models/ContextModel.py @@ -12,28 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict, List -from sqlalchemy import Column, Float, String +from typing import Dict +from sqlalchemy import Column, String from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from ._Base import _Base class ContextModel(_Base): __tablename__ = 'context' + context_uuid = Column(UUID(as_uuid=False), primary_key=True) - context_name = Column(String(), nullable=False) - created_at = Column(Float) + context_name = Column(String, nullable=False) topologies = relationship('TopologyModel', back_populates='context') - #services = relationship('ServiceModel', back_populates='context') - #slices = relationship('SliceModel', back_populates='context') + #services = relationship('ServiceModel', back_populates='context') + #slices = relationship('SliceModel', back_populates='context') def dump_id(self) -> Dict: return {'context_uuid': {'uuid': self.context_uuid}} - def dump_topology_ids(self) -> List[Dict]: - return - def dump(self) -> Dict: return { 'context_id' : self.dump_id(), diff --git a/src/context/service/database/models/DeviceModel.py b/src/context/service/database/models/DeviceModel.py index fb585348216a294f4e92d92fb1d10dac4c9cb57d..33e7804115443b9f5300c77d066b09f3db9972f1 100644 --- a/src/context/service/database/models/DeviceModel.py +++ b/src/context/service/database/models/DeviceModel.py @@ -14,12 +14,12 @@ import operator from typing import Dict -from sqlalchemy import Column, Float, String, Enum +from sqlalchemy import Column, String, Enum from sqlalchemy.dialects.postgresql import UUID, ARRAY from sqlalchemy.orm import relationship -from ._Base import _Base from .enums.DeviceDriver import ORM_DeviceDriverEnum from .enums.DeviceOperationalStatus import ORM_DeviceOperationalStatusEnum +from ._Base import _Base class DeviceModel(_Base): __tablename__ = 'device' @@ -28,10 +28,9 @@ class DeviceModel(_Base): device_type = Column(String, nullable=False) device_operational_status = Column(Enum(ORM_DeviceOperationalStatusEnum)) device_drivers = Column(ARRAY(Enum(ORM_DeviceDriverEnum), dimensions=1)) - created_at = Column(Float) topology_devices = relationship('TopologyDeviceModel', back_populates='device') - config_rules = relationship('ConfigRuleModel', passive_deletes=True, back_populates='device', lazy='joined') + #config_rules = relationship('ConfigRuleModel', passive_deletes=True, back_populates='device', lazy='joined') endpoints = relationship('EndPointModel', passive_deletes=True, back_populates='device', lazy='joined') def dump_id(self) -> Dict: @@ -45,8 +44,11 @@ class DeviceModel(_Base): 'device_operational_status': self.device_operational_status.value, 'device_drivers' : [driver.value for driver in self.device_drivers], 'device_config' : {'config_rules': [ - config_rule.dump() - for config_rule in sorted(self.config_rules, key=operator.attrgetter('position')) + #config_rule.dump() + #for config_rule in sorted(self.config_rules, key=operator.attrgetter('position')) ]}, - 'device_endpoints' : [endpoint.dump() for endpoint in self.endpoints], + 'device_endpoints' : [ + endpoint.dump() + for endpoint in self.endpoints + ], } diff --git a/src/context/service/database/models/EndPointModel.py b/src/context/service/database/models/EndPointModel.py index b7e4c9fe38d59bc6fab02f8cfa7338eb1ce16c41..804b688470ad652b35d976e9aebe3bde3ae8d743 100644 --- a/src/context/service/database/models/EndPointModel.py +++ b/src/context/service/database/models/EndPointModel.py @@ -13,7 +13,7 @@ # limitations under the License. from typing import Dict -from sqlalchemy import Column, String, Enum, ForeignKeyConstraint +from sqlalchemy import Column, Enum, ForeignKey, String from sqlalchemy.dialects.postgresql import ARRAY, UUID from sqlalchemy.orm import relationship from .enums.KpiSampleType import ORM_KpiSampleTypeEnum @@ -21,32 +21,23 @@ from ._Base import _Base class EndPointModel(_Base): __tablename__ = 'endpoint' - context_uuid = Column(UUID(as_uuid=False), primary_key=True) - topology_uuid = Column(UUID(as_uuid=False), primary_key=True) - device_uuid = Column(UUID(as_uuid=False), primary_key=True) - endpoint_uuid = Column(UUID(as_uuid=False), primary_key=True) - endpoint_type = Column(String) - kpi_sample_types = Column(ARRAY(Enum(ORM_KpiSampleTypeEnum), dimensions=1)) - __table_args__ = ( - ForeignKeyConstraint( - ['context_uuid', 'topology_uuid'], - ['topology.context_uuid', 'topology.topology_uuid'], - ondelete='CASCADE'), - ForeignKeyConstraint( - ['device_uuid'], - ['device.device_uuid'], - ondelete='CASCADE'), - ) + endpoint_uuid = Column(UUID(as_uuid=False), primary_key=True) + device_uuid = Column(UUID(as_uuid=False), ForeignKey('device.device_uuid', ondelete='CASCADE')) + topology_uuid = Column(UUID(as_uuid=False), ForeignKey('topology.topology_uuid', ondelete='RESTRICT')) + name = Column(String) + endpoint_type = Column(String) + kpi_sample_types = Column(ARRAY(Enum(ORM_KpiSampleTypeEnum), dimensions=1)) - topology = relationship('TopologyModel', back_populates='endpoints') - device = relationship('DeviceModel', back_populates='endpoints') - link_endpoints = relationship('LinkEndPointModel', back_populates='endpoint') + device = relationship('DeviceModel', back_populates='endpoints') + topology = relationship('TopologyModel') + #link_endpoints = relationship('LinkEndPointModel', back_populates='endpoint' ) + #service_endpoints = relationship('ServiceEndPointModel', back_populates='endpoint' ) def dump_id(self) -> Dict: result = { - 'topology_id': self.topology.dump_id(), - 'device_id': self.device.dump_id(), + 'topology_id' : self.topology.dump_id(), + 'device_id' : self.device.dump_id(), 'endpoint_uuid': {'uuid': self.endpoint_uuid}, } return result @@ -54,34 +45,7 @@ class EndPointModel(_Base): def dump(self) -> Dict: return { 'endpoint_id' : self.dump_id(), + 'name' : self.name, 'endpoint_type' : self.endpoint_type, 'kpi_sample_types': [kst.value for kst in self.kpi_sample_types], } - -# def get_endpoint( -# database : Database, grpc_endpoint_id : EndPointId, -# validate_topology_exists : bool = True, validate_device_in_topology : bool = True -# ) -> Tuple[str, EndPointModel]: -# endpoint_uuid = grpc_endpoint_id.endpoint_uuid.uuid -# endpoint_device_uuid = grpc_endpoint_id.device_id.device_uuid.uuid -# endpoint_topology_uuid = grpc_endpoint_id.topology_id.topology_uuid.uuid -# endpoint_topology_context_uuid = grpc_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: -# # check topology exists -# str_topology_key = key_to_str([endpoint_topology_context_uuid, endpoint_topology_uuid]) -# if validate_topology_exists: -# from .TopologyModel import TopologyModel -# get_object(database, TopologyModel, str_topology_key) -# -# # check device is in topology -# str_topology_device_key = key_to_str([str_topology_key, endpoint_device_uuid], separator='--') -# if validate_device_in_topology: -# from .RelationModels import TopologyDeviceModel -# get_object(database, TopologyDeviceModel, str_topology_device_key) -# -# str_endpoint_key = key_to_str([str_endpoint_key, str_topology_key], separator=':') -# -# db_endpoint : EndPointModel = get_object(database, EndPointModel, str_endpoint_key) -# return str_endpoint_key, db_endpoint diff --git a/src/context/service/database/models/LinkModel.py b/src/context/service/database/models/LinkModel.py index df173f52726f0f9d28fd350c17abed83bea0b876..eec871e7720dc6a7f20ceacb8620f25f5f5c41e0 100644 --- a/src/context/service/database/models/LinkModel.py +++ b/src/context/service/database/models/LinkModel.py @@ -20,6 +20,7 @@ from ._Base import _Base class LinkModel(_Base): __tablename__ = 'link' + link_uuid = Column(UUID(as_uuid=False), primary_key=True) link_name = Column(String, nullable=False) created_at = Column(Float) diff --git a/src/context/service/database/models/RelationModels.py b/src/context/service/database/models/RelationModels.py index 6cc4ff86cf061efd516a2bad59e0ad0e5965c796..38d93bee78cb27b654b11135f0aff3b3f982e0bb 100644 --- a/src/context/service/database/models/RelationModels.py +++ b/src/context/service/database/models/RelationModels.py @@ -12,49 +12,66 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging from sqlalchemy import Column, ForeignKey, ForeignKeyConstraint from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship -from context.service.database.models._Base import _Base - -LOGGER = logging.getLogger(__name__) +from ._Base import _Base # class ConnectionSubServiceModel(Model): # pk = PrimaryKeyField() # connection_fk = ForeignKeyField(ConnectionModel) # sub_service_fk = ForeignKeyField(ServiceModel) - -# link_uuid = Column(UUID(as_uuid=False), ForeignKey("Link.link_uuid")) -# endpoint_uuid = Column(UUID(as_uuid=False), ForeignKey("EndPoint.endpoint_uuid"), primary_key=True) - -class LinkEndPointModel(_Base): - __tablename__ = 'link_endpoint' - link_uuid = Column(UUID(as_uuid=False), primary_key=True) - context_uuid = Column(UUID(as_uuid=False), primary_key=True) - topology_uuid = Column(UUID(as_uuid=False), primary_key=True) - device_uuid = Column(UUID(as_uuid=False), primary_key=True) - endpoint_uuid = Column(UUID(as_uuid=False), primary_key=True) - - link = relationship('LinkModel', back_populates='link_endpoints', lazy='joined') - endpoint = relationship('EndPointModel', back_populates='link_endpoints', lazy='joined') - - __table_args__ = ( - ForeignKeyConstraint( - ['link_uuid'], - ['link.link_uuid'], - ondelete='CASCADE'), - ForeignKeyConstraint( - ['context_uuid', 'topology_uuid', 'device_uuid', 'endpoint_uuid'], - ['endpoint.context_uuid', 'endpoint.topology_uuid', 'endpoint.device_uuid', 'endpoint.endpoint_uuid'], - ondelete='CASCADE'), - ) - -# class ServiceEndPointModel(Model): -# pk = PrimaryKeyField() -# service_fk = ForeignKeyField(ServiceModel) -# endpoint_fk = ForeignKeyField(EndPointModel) +#class LinkEndPointModel(_Base): +# __tablename__ = 'link_endpoint' +# +# link_uuid = Column(UUID(as_uuid=False), primary_key=True) +# context_uuid = Column(UUID(as_uuid=False), primary_key=True) +# topology_uuid = Column(UUID(as_uuid=False), primary_key=True) +# device_uuid = Column(UUID(as_uuid=False), primary_key=True) +# endpoint_uuid = Column(UUID(as_uuid=False), primary_key=True) +# +# link = relationship('LinkModel', back_populates='link_endpoints', lazy='joined') +# endpoint = relationship('EndPointModel', back_populates='link_endpoints', lazy='joined') +# +# __table_args__ = ( +# ForeignKeyConstraint( +# ['link_uuid'], +# ['link.link_uuid'], +# ondelete='CASCADE'), +# ForeignKeyConstraint( +# ['context_uuid', 'topology_uuid', 'device_uuid', 'endpoint_uuid'], +# ['endpoint.context_uuid', 'endpoint.topology_uuid', 'endpoint.device_uuid', 'endpoint.endpoint_uuid'], +# ondelete='CASCADE'), +# ) + +#class ServiceEndPointModel(_Base): +# __tablename__ = 'service_endpoint' +# +# context_uuid = Column(UUID(as_uuid=False), primary_key=True) +# service_uuid = Column(UUID(as_uuid=False), primary_key=True) +# topology_uuid = Column(UUID(as_uuid=False), primary_key=True) +# device_uuid = Column(UUID(as_uuid=False), primary_key=True) +# endpoint_uuid = Column(UUID(as_uuid=False), primary_key=True) +# +# service = relationship('ServiceModel', back_populates='service_endpoints', lazy='joined') +# endpoint = relationship('EndPointModel', back_populates='service_endpoints', lazy='joined') +# writer = relationship( +# "Writer", +# primaryjoin="and_(Writer.id == foreign(Article.writer_id), " +# "Writer.magazine_id == Article.magazine_id)", +# ) +# +# __table_args__ = ( +# ForeignKeyConstraint( +# ['context_uuid', 'service_uuid'], +# ['service.context_uuid', 'service.service_uuid'], +# ondelete='CASCADE'), +# ForeignKeyConstraint( +# ['context_uuid', 'topology_uuid', 'device_uuid', 'endpoint_uuid'], +# ['endpoint.context_uuid', 'endpoint.topology_uuid', 'endpoint.device_uuid', 'endpoint.endpoint_uuid'], +# ondelete='CASCADE'), +# ) # class SliceEndPointModel(Model): # pk = PrimaryKeyField() @@ -64,12 +81,7 @@ class LinkEndPointModel(_Base): # class SliceServiceModel(Model): # pk = PrimaryKeyField() # slice_fk = ForeignKeyField(SliceModel) -# service_fk = ForeignKeyField(ServiceMo# pylint: disable=abstract-method -# __tablename__ = 'LinkEndPoint' -# uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True) -# link_uuid = Column(UUID(as_uuid=False), ForeignKey("Link.link_uuid")) -# endpoint_uuid = Column(UUID(as_uuid=False), ForeignKey("EndPoint.endpoint_uuid")) -#del) +# service_fk = ForeignKeyField(ServiceModel) # class SliceSubSliceModel(Model): # pk = PrimaryKeyField() @@ -78,40 +90,30 @@ class LinkEndPointModel(_Base): class TopologyDeviceModel(_Base): __tablename__ = 'topology_device' - context_uuid = Column(UUID(as_uuid=False), primary_key=True) - topology_uuid = Column(UUID(as_uuid=False), primary_key=True) - device_uuid = Column(UUID(as_uuid=False), primary_key=True) + + topology_uuid = Column(ForeignKey('topology.topology_uuid', ondelete='RESTRICT'), primary_key=True) + device_uuid = Column(ForeignKey('device.device_uuid', ondelete='CASCADE' ), primary_key=True) topology = relationship('TopologyModel', back_populates='topology_devices', lazy='joined') device = relationship('DeviceModel', back_populates='topology_devices', lazy='joined') - __table_args__ = ( - ForeignKeyConstraint( - ['context_uuid', 'topology_uuid'], - ['topology.context_uuid', 'topology.topology_uuid'], - ondelete='CASCADE'), - ForeignKeyConstraint( - ['device_uuid'], - ['device.device_uuid'], - ondelete='CASCADE'), - ) - -class TopologyLinkModel(_Base): - __tablename__ = 'topology_link' - context_uuid = Column(UUID(as_uuid=False), primary_key=True) - topology_uuid = Column(UUID(as_uuid=False), primary_key=True) - link_uuid = Column(UUID(as_uuid=False), primary_key=True) - - topology = relationship('TopologyModel', back_populates='topology_links', lazy='joined') - link = relationship('LinkModel', back_populates='topology_links', lazy='joined') - - __table_args__ = ( - ForeignKeyConstraint( - ['context_uuid', 'topology_uuid'], - ['topology.context_uuid', 'topology.topology_uuid'], - ondelete='CASCADE'), - ForeignKeyConstraint( - ['link_uuid'], - ['link.link_uuid'], - ondelete='CASCADE'), - ) +#class TopologyLinkModel(_Base): +# __tablename__ = 'topology_link' +# +# context_uuid = Column(UUID(as_uuid=False), primary_key=True) +# topology_uuid = Column(UUID(as_uuid=False), primary_key=True) +# link_uuid = Column(UUID(as_uuid=False), primary_key=True) +# +# topology = relationship('TopologyModel', back_populates='topology_links', lazy='joined') +# link = relationship('LinkModel', back_populates='topology_links', lazy='joined') +# +# __table_args__ = ( +# ForeignKeyConstraint( +# ['context_uuid', 'topology_uuid'], +# ['topology.context_uuid', 'topology.topology_uuid'], +# ondelete='CASCADE'), +# ForeignKeyConstraint( +# ['link_uuid'], +# ['link.link_uuid'], +# ondelete='CASCADE'), +# ) diff --git a/src/context/service/database/models/ServiceModel.py b/src/context/service/database/models/ServiceModel.py index c06baca32c785e47fe295699d3cdd2026c0c389b..ea4e895264d3702b174e85c22b35229c6e95687d 100644 --- a/src/context/service/database/models/ServiceModel.py +++ b/src/context/service/database/models/ServiceModel.py @@ -12,100 +12,52 @@ # See the License for the specific language governing permissions and # limitations under the License. -import functools, logging, operator -from sqlalchemy import Column, Enum, ForeignKey -from typing import Dict, List -from common.orm.HighLevel import get_related_objects -from common.proto.context_pb2 import ServiceStatusEnum, ServiceTypeEnum -from .ConfigRuleModel import ConfigModel -from .ConstraintModel import ConstraintsModel -from .models.ContextModel import ContextModel -from .Tools import grpc_to_enum +import operator +from sqlalchemy import Column, Enum, Float, ForeignKey, String +from typing import Dict from sqlalchemy.dialects.postgresql import UUID -from context.service.database.models._Base import Base -import enum -LOGGER = logging.getLogger(__name__) - -class ORM_ServiceTypeEnum(enum.Enum): - UNKNOWN = ServiceTypeEnum.SERVICETYPE_UNKNOWN - L3NM = ServiceTypeEnum.SERVICETYPE_L3NM - L2NM = ServiceTypeEnum.SERVICETYPE_L2NM - TAPI_CONNECTIVITY_SERVICE = ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE - -grpc_to_enum__service_type = functools.partial( - grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum) - -class ORM_ServiceStatusEnum(enum.Enum): - UNDEFINED = ServiceStatusEnum.SERVICESTATUS_UNDEFINED - PLANNED = ServiceStatusEnum.SERVICESTATUS_PLANNED - ACTIVE = ServiceStatusEnum.SERVICESTATUS_ACTIVE - PENDING_REMOVAL = ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL - -grpc_to_enum__service_status = functools.partial( - grpc_to_enum, ServiceStatusEnum, ORM_ServiceStatusEnum) - -class ServiceModel(Base): - __tablename__ = 'Service' - - # pk = PrimaryKeyField() - # context_fk = ForeignKeyField(ContextModel) - context_uuid = Column(UUID(as_uuid=False), ForeignKey("Context.context_uuid")) - # service_uuid = StringField(required=True, allow_empty=False) - service_uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True) - # service_type = EnumeratedField(ORM_ServiceTypeEnum, required=True) - service_type = Column(Enum(ORM_ServiceTypeEnum, create_constraint=False, native_enum=False, allow_empty=False)) - # service_constraints_fk = ForeignKeyField(ConstraintsModel) - service_constraints = Column(UUID(as_uuid=False), ForeignKey("Constraints.constraints_uuid")) - # service_status = EnumeratedField(ORM_ServiceStatusEnum, required=True) - service_status = Column(Enum(ORM_ServiceStatusEnum, create_constraint=False, native_enum=False, allow_empty=False)) - # service_config_fk = ForeignKeyField(ConfigModel) - service_config = Column(UUID(as_uuid=False), ForeignKey("Config.config_uuid")) - - # def delete(self) -> None: - # #pylint: disable=import-outside-toplevel - # from .RelationModels import ServiceEndPointModel - # - # for db_service_endpoint_pk,_ in self.references(ServiceEndPointModel): - # ServiceEndPointModel(self.database, db_service_endpoint_pk).delete() - # - # super().delete() - # - # ConfigModel(self.database, self.service_config_fk).delete() - # ConstraintsModel(self.database, self.service_constraints_fk).delete() - - def main_pk_name(self): - return 'context_uuid' - +from sqlalchemy.orm import relationship +from .enums.ServiceStatus import ORM_ServiceStatusEnum +from .enums.ServiceType import ORM_ServiceTypeEnum +from ._Base import _Base + +class ServiceModel(_Base): + __tablename__ = 'service' + + context_uuid = Column(UUID(as_uuid=False), ForeignKey('context.context_uuid'), primary_key=True) + service_uuid = Column(UUID(as_uuid=False), primary_key=True) + service_name = Column(String, nullable=False) + service_type = Column(Enum(ORM_ServiceTypeEnum)) + service_status = Column(Enum(ORM_ServiceStatusEnum)) + created_at = Column(Float) + + context = relationship('ContextModel', back_populates='services') + service_endpoints = relationship('ServiceEndPointModel', back_populates='service') #, lazy='joined') + #constraints = relationship('ConstraintModel', passive_deletes=True, back_populates='service', lazy='joined') + config_rules = relationship('ConfigRuleModel', passive_deletes=True, back_populates='service', lazy='joined') 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(), 'service_uuid': {'uuid': self.service_uuid}, } - # def dump_endpoint_ids(self, endpoints) -> List[Dict]: - # from .RelationModels import ServiceEndPointModel # pylint: disable=import-outside-toplevel - # db_endpoints = get_related_objects(self, ServiceEndPointModel, '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.service_constraints_fk).dump() - - def dump_config(self) -> Dict: - return ConfigModel(self.database, self.service_config_fk).dump() - - def dump( # pylint: disable=arguments-differ - self, endpoint_ids=True, constraints=True, config_rules=True) -> Dict: - result = { - 'service_id': self.dump_id(), - 'service_type': self.service_type.value, - 'service_status': {'service_status': self.service_status.value}, + def dump(self) -> Dict: + return { + 'service_id' : self.dump_id(), + 'name' : self.service_name, + 'service_type' : self.service_type.value, + 'service_status' : {'service_status': self.service_status.value}, + 'service_endpoint_ids': [ + service_endpoint.endpoint.dump_id() + for service_endpoint in self.service_endpoints + ], + 'service_constraints' : [ + #constraint.dump() + #for constraint in sorted(self.constraints, key=operator.attrgetter('position')) + ], + 'service_config' : {'config_rules': [ + config_rule.dump() + for config_rule in sorted(self.config_rules, key=operator.attrgetter('position')) + ]}, } - if endpoint_ids: - result['service_endpoint_ids'] = self.dump_endpoint_ids() - if constraints: - result['service_constraints'] = self.dump_constraints() - if config_rules: - result.setdefault('service_config', {})['config_rules'] = self.dump_config() - return result diff --git a/src/context/service/database/models/TopologyModel.py b/src/context/service/database/models/TopologyModel.py index 95f7a63502a68e8b92b70a29c7b71cf229f108bf..f7053b603e1f77d786636418cbc944383a37b0c0 100644 --- a/src/context/service/database/models/TopologyModel.py +++ b/src/context/service/database/models/TopologyModel.py @@ -13,23 +13,21 @@ # limitations under the License. from typing import Dict -from sqlalchemy import Column, Float, ForeignKey, String +from sqlalchemy import Column, ForeignKey, String from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from ._Base import _Base class TopologyModel(_Base): __tablename__ = 'topology' - context_uuid = Column(UUID(as_uuid=False), ForeignKey('context.context_uuid'), primary_key=True) - topology_uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True) - topology_name = Column(String(), nullable=False) - created_at = Column(Float) - # Relationships - context = relationship('ContextModel', back_populates='topologies') + topology_uuid = Column(UUID(as_uuid=False), primary_key=True) + context_uuid = Column(UUID(as_uuid=False), ForeignKey('context.context_uuid')) + topology_name = Column(String, nullable=False) + + context = relationship('ContextModel', back_populates='topologies') topology_devices = relationship('TopologyDeviceModel', back_populates='topology') - topology_links = relationship('TopologyLinkModel', back_populates='topology') - endpoints = relationship('EndPointModel', back_populates='topology') + #topology_links = relationship('TopologyLinkModel', back_populates='topology') def dump_id(self) -> Dict: return { @@ -42,5 +40,5 @@ class TopologyModel(_Base): 'topology_id': self.dump_id(), 'name' : self.topology_name, 'device_ids' : [{'device_uuid': {'uuid': td.device_uuid}} for td in self.topology_devices], - 'link_ids' : [{'link_uuid' : {'uuid': td.link_uuid }} for td in self.topology_links ], + #'link_ids' : [{'link_uuid' : {'uuid': td.link_uuid }} for td in self.topology_links ], } diff --git a/src/context/service/database/models/enums/ServiceStatus.py b/src/context/service/database/models/enums/ServiceStatus.py new file mode 100644 index 0000000000000000000000000000000000000000..5afd5da8faf72f8ea1a622010ddd2e78d4f82a16 --- /dev/null +++ b/src/context/service/database/models/enums/ServiceStatus.py @@ -0,0 +1,26 @@ +# 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 enum, functools +from common.proto.context_pb2 import ServiceStatusEnum +from ._GrpcToEnum import grpc_to_enum + +class ORM_ServiceStatusEnum(enum.Enum): + UNDEFINED = ServiceStatusEnum.SERVICESTATUS_UNDEFINED + PLANNED = ServiceStatusEnum.SERVICESTATUS_PLANNED + ACTIVE = ServiceStatusEnum.SERVICESTATUS_ACTIVE + PENDING_REMOVAL = ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL + +grpc_to_enum__service_status = functools.partial( + grpc_to_enum, ServiceStatusEnum, ORM_ServiceStatusEnum) diff --git a/src/context/service/database/models/enums/ServiceType.py b/src/context/service/database/models/enums/ServiceType.py new file mode 100644 index 0000000000000000000000000000000000000000..e36cbc38934463b2d13d46380c6044554a19ed2a --- /dev/null +++ b/src/context/service/database/models/enums/ServiceType.py @@ -0,0 +1,26 @@ +# 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 enum, functools +from common.proto.context_pb2 import ServiceTypeEnum +from ._GrpcToEnum import grpc_to_enum + +class ORM_ServiceTypeEnum(enum.Enum): + UNKNOWN = ServiceTypeEnum.SERVICETYPE_UNKNOWN + L3NM = ServiceTypeEnum.SERVICETYPE_L3NM + L2NM = ServiceTypeEnum.SERVICETYPE_L2NM + TAPI_CONNECTIVITY_SERVICE = ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE + +grpc_to_enum__service_type = functools.partial( + grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum) diff --git a/src/context/tests/Objects.py b/src/context/tests/Objects.py index 3bb0065d3992d6d69f2a1e3c7131245436b4af02..1e50fe3c17070a1260660f8cbbb83bee8a578e47 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 common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID +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 from common.tools.object_factory.Connection import json_connection, json_connection_id @@ -27,13 +27,15 @@ from common.tools.object_factory.PolicyRule import json_policy_rule, json_policy # ----- Context -------------------------------------------------------------------------------------------------------- -CONTEXT_ID = json_context_id(DEFAULT_CONTEXT_UUID) -CONTEXT = json_context(DEFAULT_CONTEXT_UUID) +CONTEXT_NAME = DEFAULT_CONTEXT_NAME +CONTEXT_ID = json_context_id(CONTEXT_NAME) +CONTEXT = json_context(CONTEXT_NAME, name=CONTEXT_NAME) # ----- Topology ------------------------------------------------------------------------------------------------------- -TOPOLOGY_ID = json_topology_id(DEFAULT_TOPOLOGY_UUID, context_id=CONTEXT_ID) -TOPOLOGY = json_topology(DEFAULT_TOPOLOGY_UUID, context_id=CONTEXT_ID) +TOPOLOGY_NAME = DEFAULT_TOPOLOGY_NAME +TOPOLOGY_ID = json_topology_id(TOPOLOGY_NAME, context_id=CONTEXT_ID) +TOPOLOGY = json_topology(TOPOLOGY_NAME, context_id=CONTEXT_ID, name=TOPOLOGY_NAME) # ----- KPI Sample Types ----------------------------------------------------------------------------------------------- @@ -52,8 +54,8 @@ EP3 = '368baf47-0540-4ab4-add8-a19b5167162c' EP100 = '6a923121-36e1-4b5e-8cd6-90aceca9b5cf' -DEVICE_R1_UUID = 'fe83a200-6ded-47b4-b156-3bb3556a10d6' -DEVICE_R1_ID = json_device_id(DEVICE_R1_UUID) +DEVICE_R1_NAME = 'R1' +DEVICE_R1_ID = json_device_id(DEVICE_R1_NAME) DEVICE_R1_EPS = [ json_endpoint(DEVICE_R1_ID, EP2, '10G', topology_id=TOPOLOGY_ID, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES), json_endpoint(DEVICE_R1_ID, EP3, '10G', topology_id=TOPOLOGY_ID, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES), @@ -65,11 +67,11 @@ DEVICE_R1_RULES = [ json_config_rule_set('dev/rsrc3/value', 'value3'), ] DEVICE_R1 = json_device_packetrouter_disabled( - DEVICE_R1_UUID, endpoints=DEVICE_R1_EPS, config_rules=DEVICE_R1_RULES) + DEVICE_R1_NAME, endpoints=DEVICE_R1_EPS, config_rules=DEVICE_R1_RULES) -DEVICE_R2_UUID = '2fd2be23-5b20-414c-b1ea-2f16ae6eb425' -DEVICE_R2_ID = json_device_id(DEVICE_R2_UUID) +DEVICE_R2_NAME = 'R2' +DEVICE_R2_ID = json_device_id(DEVICE_R2_NAME) DEVICE_R2_EPS = [ json_endpoint(DEVICE_R2_ID, EP1, '10G', topology_id=TOPOLOGY_ID, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES), json_endpoint(DEVICE_R2_ID, EP3, '10G', topology_id=TOPOLOGY_ID, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES), @@ -81,11 +83,11 @@ DEVICE_R2_RULES = [ json_config_rule_set('dev/rsrc3/value', 'value6'), ] DEVICE_R2 = json_device_packetrouter_disabled( - DEVICE_R2_UUID, endpoints=DEVICE_R2_EPS, config_rules=DEVICE_R2_RULES) + DEVICE_R2_NAME, endpoints=DEVICE_R2_EPS, config_rules=DEVICE_R2_RULES) -DEVICE_R3_UUID = '3e71a251-2218-42c5-b4b8-de7760c0d9b3' -DEVICE_R3_ID = json_device_id(DEVICE_R3_UUID) +DEVICE_R3_NAME = 'R3' +DEVICE_R3_ID = json_device_id(DEVICE_R3_NAME) DEVICE_R3_EPS = [ json_endpoint(DEVICE_R3_ID, EP2, '10G', topology_id=TOPOLOGY_ID, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES), json_endpoint(DEVICE_R3_ID, EP3, '10G', topology_id=TOPOLOGY_ID, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES), @@ -97,7 +99,7 @@ DEVICE_R3_RULES = [ json_config_rule_set('dev/rsrc3/value', 'value6'), ] DEVICE_R3 = json_device_packetrouter_disabled( - DEVICE_R3_UUID, endpoints=DEVICE_R3_EPS, config_rules=DEVICE_R3_RULES) + DEVICE_R3_NAME, endpoints=DEVICE_R3_EPS, config_rules=DEVICE_R3_RULES) # ----- Link ----------------------------------------------------------------------------------------------------------- diff --git a/src/context/tests/test_unitary.py b/src/context/tests/__test_unitary.py similarity index 64% rename from src/context/tests/test_unitary.py rename to src/context/tests/__test_unitary.py index 6845036bd6daa6ac1c595bca388ef0ff53f98f56..e49fd2752adef62c8816a76c57b5abcf3d739f37 100644 --- a/src/context/tests/test_unitary.py +++ b/src/context/tests/__test_unitary.py @@ -12,31 +12,31 @@ # See the License for the specific language governing permissions and # limitations under the License. -import pytest -from context.client.ContextClient import ContextClient -from ._test_context import grpc_context -from ._test_topology import grpc_topology -from ._test_device import grpc_device -from ._test_link import grpc_link +#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) +#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_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_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_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: diff --git a/src/context/tests/_test_link.py b/src/context/tests/_test_link.py index d493f23d7d64e29ae4fbfc987bd09fb4d54c3aac..963fd72cf2c44c0d2d84b74728466df2595f9ebd 100644 --- a/src/context/tests/_test_link.py +++ b/src/context/tests/_test_link.py @@ -21,7 +21,7 @@ from .Objects import ( CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, DEVICE_R1_UUID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R2_UUID, LINK_R1_R2, LINK_R1_R2_ID, LINK_R1_R2_UUID, TOPOLOGY, TOPOLOGY_ID) -def grpc_link(context_client_grpc: ContextClient) -> None: +def grpc_link(context_client_grpc : ContextClient) -> None: # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- #events_collector = EventsCollector( @@ -78,10 +78,10 @@ def grpc_link(context_client_grpc: ContextClient) -> None: 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 + #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 # ----- Get when the object exists --------------------------------------------------------------------------------- response = context_client_grpc.GetLink(LinkId(**LINK_R1_R2_ID)) @@ -108,10 +108,10 @@ def grpc_link(context_client_grpc: ContextClient) -> None: 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 + #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 # ----- Get when the object is modified ---------------------------------------------------------------------------- response = context_client_grpc.GetLink(LinkId(**LINK_R1_R2_ID)) @@ -138,11 +138,11 @@ def grpc_link(context_client_grpc: ContextClient) -> None: 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 + #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)) @@ -155,35 +155,30 @@ def grpc_link(context_client_grpc: ContextClient) -> None: assert response.link_ids[0].link_uuid.uuid == LINK_R1_R2_UUID # ----- 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)) + 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 + #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() diff --git a/src/context/tests/_test_service.py b/src/context/tests/_test_service.py index 88ece2ba90be93e133ed6699024e399a92045a7b..8bd6570de876cd71b09c55849090f4f84a68e282 100644 --- a/src/context/tests/_test_service.py +++ b/src/context/tests/_test_service.py @@ -13,28 +13,24 @@ # limitations under the License. import copy, grpc, pytest -from typing import Tuple from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID from common.proto.context_pb2 import ( - Context, ContextEvent, ContextId, Device, DeviceEvent, DeviceId, EventTypeEnum, Service, ServiceEvent, ServiceId, - ServiceStatusEnum, ServiceTypeEnum, Topology, TopologyEvent, TopologyId) + Context, ContextId, Device, DeviceId, Service, ServiceId, ServiceStatusEnum, ServiceTypeEnum, Topology, TopologyId) from context.client.ContextClient import ContextClient -from context.client.EventsCollector import EventsCollector +#from context.client.EventsCollector import EventsCollector from .Objects import ( CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, DEVICE_R1_UUID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R2_UUID, SERVICE_R1_R2, SERVICE_R1_R2_ID, SERVICE_R1_R2_UUID, TOPOLOGY, TOPOLOGY_ID) -def grpc_service( - context_client_grpc : ContextClient, # pylint: disable=redefined-outer-name - context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name - Session = context_db_mb[0] - # ----- Clean the database ----------------------------------------------------------------------------------------- - database = Database(Session) - database.clear() +def grpc_service(context_client_grpc : ContextClient) -> None: # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- - events_collector = EventsCollector(context_client_grpc) - events_collector.start() + #events_collector = EventsCollector( + # context_client_grpc, log_events_received=True, + # activate_context_collector = False, activate_topology_collector = False, activate_device_collector = False, + # activate_link_collector = False, activate_service_collector = True, activate_slice_collector = False, + # activate_connection_collector = False) + #events_collector.start() # ----- Prepare dependencies for the test and capture related events ----------------------------------------------- response = context_client_grpc.SetContext(Context(**CONTEXT)) @@ -49,49 +45,39 @@ def grpc_service( 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.GetContext(ContextId(**CONTEXT_ID)) + assert len(response.topology_ids) == 1 + assert len(response.service_ids) == 0 + assert len(response.slice_ids) == 0 + 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: @@ -108,54 +94,77 @@ def grpc_service( 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) + #event = events_collector.get_event(block=True) + #assert isinstance(event, ServiceEvent) + #assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert event.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID + #assert event.service_id.service_uuid.uuid == SERVICE_R1_R2_UUID + + # ----- Get when the object exists --------------------------------------------------------------------------------- + response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID)) + assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID + assert response.name == '' + assert len(response.topology_ids) == 1 + 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 + assert len(response.slice_ids) == 0 + + 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.name == '' + 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 - 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 + # ----- 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 - 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 + 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].name == '' + 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 # ----- Update the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetService(Service(**SERVICE_R1_R2)) + new_service_name = 'svc:r1-r2' + SERVICE_UPDATED = copy.deepcopy(SERVICE_R1_R2) + SERVICE_UPDATED['name'] = new_service_name + response = context_client_grpc.SetService(Service(**SERVICE_UPDATED)) 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 + #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 - # ----- Get when the object exists --------------------------------------------------------------------------------- + # ----- Get when the object is modified ---------------------------------------------------------------------------- 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.name == new_service_name 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 -------------------------------------------------------------------------------- + # ----- List when the object is modified --------------------------------------------------------------------------- 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 @@ -165,6 +174,7 @@ def grpc_service( 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].name == new_service_name 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 @@ -173,42 +183,45 @@ def grpc_service( # ----- 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 + #event = events_collector.get_event(block=True) + #assert isinstance(event, ServiceEvent) + #assert event.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID + #assert event.service_id.service_uuid.uuid == SERVICE_R1_R2_UUID + + # ----- List after deleting the object ----------------------------------------------------------------------------- + response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID)) + assert len(response.topology_ids) == 1 + assert len(response.service_ids) == 0 + assert len(response.slice_ids) == 0 - 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 + response = context_client_grpc.ListServiceIds(ContextId(**CONTEXT_ID)) + assert len(response.service_ids) == 0 - 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 + response = context_client_grpc.ListServices(ContextId(**CONTEXT_ID)) + assert len(response.services) == 0 - 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 + # ----- Clean dependencies used in the test and capture related events --------------------------------------------- + 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)) - 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 + #events = events_collector.get_events(block=True, count=4) + #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], DeviceEvent) + #assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[1].device_id.device_uuid.uuid == DEVICE_R2_UUID + #assert isinstance(events[2], TopologyEvent) + #assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[2].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID + #assert events[2].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID + #assert isinstance(events[3], ContextEvent) + #assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[3].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 + #events_collector.stop() diff --git a/src/context/tests/conftest.py b/src/context/tests/conftest.py index cf56ed9af2798a42191266e58f373422a3374257..872c51ccf5f8ab05e361e32ef9612259b3834c1d 100644 --- a/src/context/tests/conftest.py +++ b/src/context/tests/conftest.py @@ -28,10 +28,6 @@ from context.service.ContextService import ContextService from context.service.Database import Database from context.service.Engine import Engine from context.service.database.models._Base import rebuild_database -#from context.service._old_code.Populate import populate -#from context.service.rest_server.RestServer import RestServer -#from context.service.rest_server.Resources import RESOURCES - LOCAL_HOST = '127.0.0.1' GRPC_PORT = 10000 + int(get_service_port_grpc(ServiceNameEnum.CONTEXT)) # avoid privileged ports @@ -41,29 +37,8 @@ os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_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 = [ -# ('db:cockroach_mb:inmemory', None, {}, None, {}), -# ('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) @pytest.fixture(scope='session') def context_db_mb(request) -> Tuple[sqlalchemy.engine.Engine, MessageBroker]: # pylint: disable=unused-argument - #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_engine = Engine.get_engine() Engine.drop_database(_db_engine) Engine.create_database(_db_engine) @@ -76,7 +51,7 @@ def context_db_mb(request) -> Tuple[sqlalchemy.engine.Engine, MessageBroker]: RAW_METRICS = None @pytest.fixture(scope='session') -def context_service_grpc(context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name +def context_service(context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name global RAW_METRICS # pylint: disable=global-statement _service = ContextService(context_db_mb[0], context_db_mb[1]) RAW_METRICS = _service.context_servicer._get_metrics() @@ -84,22 +59,8 @@ def context_service_grpc(context_db_mb : Tuple[Database, MessageBroker]): # pyli 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,unused-argument -): +def context_client(context_service : ContextService): # pylint: disable=redefined-outer-name,unused-argument _client = ContextClient() yield _client _client.close() @@ -117,7 +78,7 @@ def pytest_terminal_summary( elif '_HISTOGRAM_' in raw_metric_name: method_name,metric_name = raw_metric_name.split('_HISTOGRAM_') else: - raise Exception('Unsupported metric: {:s}'.format(raw_metric_name)) + 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 len(labels) > 0: field_name = '{:s}:{:s}'.format(field_name, json.dumps(labels, sort_keys=True)) diff --git a/src/context/tests/_test_context.py b/src/context/tests/test_context.py similarity index 55% rename from src/context/tests/_test_context.py rename to src/context/tests/test_context.py index ef67d39d79a8fb175ba7da8ca093f39262dd2390..915989eb791ba7965801b162e24b33d626410e18 100644 --- a/src/context/tests/_test_context.py +++ b/src/context/tests/test_context.py @@ -12,96 +12,66 @@ # See the License for the specific language governing permissions and # limitations under the License. -import copy, grpc, pytest, uuid -from common.Constants import DEFAULT_CONTEXT_UUID +import copy, grpc, pytest from common.proto.context_pb2 import Context, ContextId, Empty -from common.tools.object_factory.Context import json_context_id -from common.tools.object_factory.Service import json_service_id -from common.tools.object_factory.Slice import json_slice_id -from common.tools.object_factory.Topology import json_topology_id from context.client.ContextClient import ContextClient +from context.service.database.methods.uuids.Context import context_get_uuid #from context.client.EventsCollector import EventsCollector -from .Objects import CONTEXT, CONTEXT_ID +from .Objects import CONTEXT, CONTEXT_ID, CONTEXT_NAME -def grpc_context(context_client_grpc : ContextClient) -> None: +def test_context(context_client : ContextClient) -> None: # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- #events_collector = EventsCollector( - # context_client_grpc, log_events_received=True, + # context_client, log_events_received=True, # activate_context_collector = True, activate_topology_collector = False, activate_device_collector = False, # activate_link_collector = False, activate_service_collector = False, activate_slice_collector = False, # activate_connection_collector = False) #events_collector.start() # ----- Get when the object does not exist ------------------------------------------------------------------------- + context_id = ContextId(**CONTEXT_ID) + context_uuid = context_get_uuid(context_id, allow_random=False) with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetContext(ContextId(**CONTEXT_ID)) + context_client.GetContext(context_id) assert e.value.code() == grpc.StatusCode.NOT_FOUND - assert e.value.details() == 'Context({:s}) not found'.format(DEFAULT_CONTEXT_UUID) + MSG = 'Context({:s}) not found; context_uuid generated was: {:s}' + assert e.value.details() == MSG.format(CONTEXT_NAME, context_uuid) # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListContextIds(Empty()) + response = context_client.ListContextIds(Empty()) assert len(response.context_ids) == 0 - response = context_client_grpc.ListContexts(Empty()) + response = context_client.ListContexts(Empty()) assert len(response.contexts) == 0 # ----- Create the object ------------------------------------------------------------------------------------------ - response = context_client_grpc.SetContext(Context(**CONTEXT)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID - - wrong_context_uuid = str(uuid.uuid4()) - wrong_context_id = json_context_id(wrong_context_uuid) - with pytest.raises(grpc.RpcError) as e: - WRONG_CONTEXT = copy.deepcopy(CONTEXT) - WRONG_CONTEXT['topology_ids'].append(json_topology_id(str(uuid.uuid4()), context_id=wrong_context_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_context_uuid, DEFAULT_CONTEXT_UUID) - assert e.value.details() == msg - - with pytest.raises(grpc.RpcError) as e: - WRONG_CONTEXT = copy.deepcopy(CONTEXT) - WRONG_CONTEXT['service_ids'].append(json_service_id(str(uuid.uuid4()), context_id=wrong_context_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_context_uuid, DEFAULT_CONTEXT_UUID) - assert e.value.details() == msg - - with pytest.raises(grpc.RpcError) as e: - WRONG_CONTEXT = copy.deepcopy(CONTEXT) - WRONG_CONTEXT['slice_ids'].append(json_slice_id(str(uuid.uuid4()), context_id=wrong_context_id)) - context_client_grpc.SetContext(Context(**WRONG_CONTEXT)) - assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT - msg = 'request.slice_ids[0].context_id.context_uuid.uuid({}) is invalid; '\ - 'should be == request.context_id.context_uuid.uuid({})'.format(wrong_context_uuid, DEFAULT_CONTEXT_UUID) - assert e.value.details() == msg + response = context_client.SetContext(Context(**CONTEXT)) + assert response.context_uuid.uuid == context_uuid # ----- Check create event ----------------------------------------------------------------------------------------- #event = events_collector.get_event(block=True, timeout=10.0) #assert isinstance(event, ContextEvent) #assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE - #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID + #assert event.context_id.context_uuid.uuid == context_uuid # ----- Get when the object exists --------------------------------------------------------------------------------- - response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.name == '' + 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) == 0 assert len(response.service_ids) == 0 assert len(response.slice_ids) == 0 # ----- List when the object exists -------------------------------------------------------------------------------- - response = context_client_grpc.ListContextIds(Empty()) + response = context_client.ListContextIds(Empty()) assert len(response.context_ids) == 1 - assert response.context_ids[0].context_uuid.uuid == DEFAULT_CONTEXT_UUID + assert response.context_ids[0].context_uuid.uuid == context_uuid - response = context_client_grpc.ListContexts(Empty()) + response = context_client.ListContexts(Empty()) assert len(response.contexts) == 1 - assert response.contexts[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.contexts[0].name == '' + assert response.contexts[0].context_id.context_uuid.uuid == context_uuid + assert response.contexts[0].name == CONTEXT_NAME assert len(response.contexts[0].topology_ids) == 0 assert len(response.contexts[0].service_ids) == 0 assert len(response.contexts[0].slice_ids) == 0 @@ -110,50 +80,50 @@ def grpc_context(context_client_grpc : ContextClient) -> None: new_context_name = 'new' CONTEXT_WITH_NAME = copy.deepcopy(CONTEXT) CONTEXT_WITH_NAME['name'] = new_context_name - response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_NAME)) - assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID + response = context_client.SetContext(Context(**CONTEXT_WITH_NAME)) + assert response.context_uuid.uuid == context_uuid # ----- Check update event ----------------------------------------------------------------------------------------- #event = events_collector.get_event(block=True, timeout=10.0) #assert isinstance(event, ContextEvent) #assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE - #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID + #assert event.context_id.context_uuid.uuid == context_uuid # ----- Get when the object is modified ---------------------------------------------------------------------------- - response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID + response = context_client.GetContext(ContextId(**CONTEXT_ID)) + assert response.context_id.context_uuid.uuid == context_uuid assert response.name == new_context_name assert len(response.topology_ids) == 0 assert len(response.service_ids) == 0 assert len(response.slice_ids) == 0 # ----- List when the object is modified --------------------------------------------------------------------------- - response = context_client_grpc.ListContextIds(Empty()) + response = context_client.ListContextIds(Empty()) assert len(response.context_ids) == 1 - assert response.context_ids[0].context_uuid.uuid == DEFAULT_CONTEXT_UUID + assert response.context_ids[0].context_uuid.uuid == context_uuid - response = context_client_grpc.ListContexts(Empty()) + response = context_client.ListContexts(Empty()) assert len(response.contexts) == 1 - assert response.contexts[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID + assert response.contexts[0].context_id.context_uuid.uuid == context_uuid assert response.contexts[0].name == new_context_name assert len(response.contexts[0].topology_ids) == 0 assert len(response.contexts[0].service_ids) == 0 assert len(response.contexts[0].slice_ids) == 0 # ----- Remove the object ------------------------------------------------------------------------------------------ - context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID)) + context_client.RemoveContext(ContextId(**CONTEXT_ID)) # ----- Check remove event ----------------------------------------------------------------------------------------- #event = events_collector.get_event(block=True, timeout=10.0) #assert isinstance(event, ContextEvent) #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID + #assert event.context_id.context_uuid.uuid == context_uuid # ----- List after deleting the object ----------------------------------------------------------------------------- - response = context_client_grpc.ListContextIds(Empty()) + response = context_client.ListContextIds(Empty()) assert len(response.context_ids) == 0 - response = context_client_grpc.ListContexts(Empty()) + response = context_client.ListContexts(Empty()) assert len(response.contexts) == 0 # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- diff --git a/src/context/tests/_test_device.py b/src/context/tests/test_device.py similarity index 56% rename from src/context/tests/_test_device.py rename to src/context/tests/test_device.py index 20760a9612cf57739dda44736e184bccebbc776f..381b5d4fdec4a1d748171b9c85d084b1bf71de21 100644 --- a/src/context/tests/_test_device.py +++ b/src/context/tests/test_device.py @@ -13,122 +13,125 @@ # limitations under the License. import copy, grpc, pytest -from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID from common.proto.context_pb2 import ( Context, ContextId, Device, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Topology, TopologyId) from context.client.ContextClient import ContextClient +from context.service.database.methods.uuids.Device import device_get_uuid #from context.client.EventsCollector import EventsCollector -from .Objects import CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, DEVICE_R1_UUID, TOPOLOGY, TOPOLOGY_ID +from .Objects import CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, DEVICE_R1_NAME, TOPOLOGY, TOPOLOGY_ID -def grpc_device(context_client_grpc : ContextClient) -> None: +@pytest.mark.depends(on=['context/tests/test_topology.py::test_topology']) +def test_device(context_client : ContextClient) -> None: # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- #events_collector = EventsCollector( - # context_client_grpc, log_events_received=True, + # context_client, log_events_received=True, # activate_context_collector = False, activate_topology_collector = False, activate_device_collector = True, # activate_link_collector = False, activate_service_collector = False, activate_slice_collector = False, # activate_connection_collector = False) #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.SetContext(Context(**CONTEXT)) + context_uuid = response.context_uuid.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.SetTopology(Topology(**TOPOLOGY)) + topology_uuid = response.topology_uuid.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 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 == DEFAULT_CONTEXT_UUID - #assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID + #assert events[1].topology_id.context_id.context_uuid.uuid == context_uuid + #assert events[1].topology_id.topology_uuid.uuid == topology_uuid # ----- Get when the object does not exist ------------------------------------------------------------------------- + device_id = DeviceId(**DEVICE_R1_ID) + device_uuid = device_get_uuid(device_id, allow_random=False) with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID)) + context_client.GetDevice(device_id) assert e.value.code() == grpc.StatusCode.NOT_FOUND - assert e.value.details() == 'Device({:s}) not found'.format(DEVICE_R1_UUID) + MSG = 'Device({:s}) not found; device_uuid generated was: {:s}' + assert e.value.details() == MSG.format(DEVICE_R1_NAME, device_uuid) # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListDeviceIds(Empty()) + response = context_client.ListDeviceIds(Empty()) assert len(response.device_ids) == 0 - response = context_client_grpc.ListDevices(Empty()) + response = context_client.ListDevices(Empty()) assert len(response.devices) == 0 # ----- 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_UUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff' WRONG_DEVICE['device_endpoints'][0]['endpoint_id']['device_id']['device_uuid']['uuid'] = WRONG_DEVICE_UUID - context_client_grpc.SetDevice(Device(**WRONG_DEVICE)) + context_client.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 + MSG = 'request.device_endpoints[0].device_id.device_uuid.uuid({}) is invalid; '\ + 'should be == request.device_id.device_uuid.uuid({})' + assert e.value.details() == MSG.format(WRONG_DEVICE_UUID, device_id.device_uuid.uuid) # pylint: disable=no-member - response = context_client_grpc.SetDevice(Device(**DEVICE_R1)) - assert response.device_uuid.uuid == DEVICE_R1_UUID + response = context_client.SetDevice(Device(**DEVICE_R1)) + assert response.device_uuid.uuid == device_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 + #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_uuid # ----- 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.name == '' + response = context_client.GetDevice(DeviceId(**DEVICE_R1_ID)) + assert response.device_id.device_uuid.uuid == device_uuid + assert response.name == DEVICE_R1_NAME assert response.device_type == 'packet-router' - assert len(response.device_config.config_rules) == 3 + #assert len(response.device_config.config_rules) == 3 assert response.device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED assert len(response.device_drivers) == 1 assert DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.device_drivers assert len(response.device_endpoints) == 3 # ----- List when the object exists -------------------------------------------------------------------------------- - response = context_client_grpc.ListDeviceIds(Empty()) + response = context_client.ListDeviceIds(Empty()) assert len(response.device_ids) == 1 - assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID + assert response.device_ids[0].device_uuid.uuid == device_uuid - response = context_client_grpc.ListDevices(Empty()) + response = context_client.ListDevices(Empty()) assert len(response.devices) == 1 - assert response.devices[0].device_id.device_uuid.uuid == DEVICE_R1_UUID - assert response.devices[0].name == '' + assert response.devices[0].device_id.device_uuid.uuid == device_uuid + assert response.devices[0].name == DEVICE_R1_NAME assert response.devices[0].device_type == 'packet-router' - assert len(response.devices[0].device_config.config_rules) == 3 + #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 DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.devices[0].device_drivers assert len(response.devices[0].device_endpoints) == 3 # ----- Update the object ------------------------------------------------------------------------------------------ - new_device_name = 'r1' + new_device_name = 'new' new_device_driver = DeviceDriverEnum.DEVICEDRIVER_UNDEFINED DEVICE_UPDATED = copy.deepcopy(DEVICE_R1) DEVICE_UPDATED['name'] = new_device_name DEVICE_UPDATED['device_operational_status'] = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED DEVICE_UPDATED['device_drivers'].append(new_device_driver) - response = context_client_grpc.SetDevice(Device(**DEVICE_UPDATED)) - assert response.device_uuid.uuid == DEVICE_R1_UUID + response = context_client.SetDevice(Device(**DEVICE_UPDATED)) + assert response.device_uuid.uuid == device_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 + #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_uuid # ----- Get when the object is modified ---------------------------------------------------------------------------- - response = context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID)) - assert response.device_id.device_uuid.uuid == DEVICE_R1_UUID + response = context_client.GetDevice(DeviceId(**DEVICE_R1_ID)) + assert response.device_id.device_uuid.uuid == device_uuid assert response.name == new_device_name assert response.device_type == 'packet-router' - assert len(response.device_config.config_rules) == 3 + #assert len(response.device_config.config_rules) == 3 assert response.device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED assert len(response.device_drivers) == 2 assert DeviceDriverEnum.DEVICEDRIVER_UNDEFINED in response.device_drivers @@ -136,16 +139,16 @@ def grpc_device(context_client_grpc : ContextClient) -> None: assert len(response.device_endpoints) == 3 # ----- List when the object is modified --------------------------------------------------------------------------- - response = context_client_grpc.ListDeviceIds(Empty()) + response = context_client.ListDeviceIds(Empty()) assert len(response.device_ids) == 1 - assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID + assert response.device_ids[0].device_uuid.uuid == device_uuid - response = context_client_grpc.ListDevices(Empty()) + response = context_client.ListDevices(Empty()) assert len(response.devices) == 1 - assert response.devices[0].device_id.device_uuid.uuid == DEVICE_R1_UUID + assert response.devices[0].device_id.device_uuid.uuid == device_uuid assert response.devices[0].name == new_device_name assert response.devices[0].device_type == 'packet-router' - assert len(response.devices[0].device_config.config_rules) == 3 + #assert len(response.devices[0].device_config.config_rules) == 3 assert response.devices[0].device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED assert len(response.devices[0].device_drivers) == 2 assert DeviceDriverEnum.DEVICEDRIVER_UNDEFINED in response.devices[0].device_drivers @@ -153,47 +156,55 @@ def grpc_device(context_client_grpc : ContextClient) -> None: 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 + #TOPOLOGY_WITH_DEVICE = copy.deepcopy(TOPOLOGY) + #TOPOLOGY_WITH_DEVICE['device_ids'].append(DEVICE_R1_ID) + #response = context_client.SetTopology(Topology(**TOPOLOGY_WITH_DEVICE)) + #assert response.context_id.context_uuid.uuid == context_uuid + #assert response.topology_uuid.uuid == 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 + # assert response.context_id.context_uuid.uuid == context_uuid + # assert response.topology_uuid.uuid == 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 + response = context_client.GetTopology(TopologyId(**TOPOLOGY_ID)) + assert response.topology_id.context_id.context_uuid.uuid == context_uuid + assert response.topology_id.topology_uuid.uuid == topology_uuid assert len(response.device_ids) == 1 - assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID + assert response.device_ids[0].device_uuid.uuid == device_uuid assert len(response.link_ids) == 0 # ----- Remove the object ------------------------------------------------------------------------------------------ - context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID)) - context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID)) - context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID)) + #context_client.RemoveDevice(DeviceId(**DEVICE_R1_ID)) # ----- Check remove event ----------------------------------------------------------------------------------------- - # events = events_collector.get_events(block=True, count=3) + #event = events_collector.get_event(block=True) + #assert isinstance(event, DeviceEvent) + #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert event.device_id.device_uuid.uuid == device_uuid - # 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 + # ----- List after deleting the object ----------------------------------------------------------------------------- + #response = context_client.ListDeviceIds(Empty()) + #assert len(response.device_ids) == 0 - # 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 + #response = context_client.ListDevices(Empty()) + #assert len(response.devices) == 0 - # 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 + # ----- Clean dependencies used in the test and capture related events --------------------------------------------- + #context_client.RemoveTopology(TopologyId(**TOPOLOGY_ID)) + #context_client.RemoveContext(ContextId(**CONTEXT_ID)) + + #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 == context_uuid + #assert events[0].topology_id.topology_uuid.uuid == topology_uuid + #assert isinstance(events[1], ContextEvent) + #assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE + #assert events[1].context_id.context_uuid.uuid == context_uuid # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- #events_collector.stop() diff --git a/src/context/tests/_test_topology.py b/src/context/tests/test_topology.py similarity index 57% rename from src/context/tests/_test_topology.py rename to src/context/tests/test_topology.py index 9774d972fc78c0688766ed4b8ad6ff68038a1c89..142887d09031596b7e82e40f424b0100e31199c5 100644 --- a/src/context/tests/_test_topology.py +++ b/src/context/tests/test_topology.py @@ -13,154 +13,162 @@ # limitations under the License. import copy, grpc, pytest -from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID from common.proto.context_pb2 import Context, ContextId, Topology, TopologyId from context.client.ContextClient import ContextClient +from context.service.database.methods.uuids.Topology import topology_get_uuid #from context.client.EventsCollector import EventsCollector -from .Objects import CONTEXT, CONTEXT_ID, TOPOLOGY, TOPOLOGY_ID +from .Objects import CONTEXT, CONTEXT_ID, CONTEXT_NAME, TOPOLOGY, TOPOLOGY_ID, TOPOLOGY_NAME -def grpc_topology(context_client_grpc : ContextClient) -> None: +@pytest.mark.depends(on=['context/tests/test_context.py::test_context']) +def test_topology(context_client : ContextClient) -> None: # ----- Initialize the EventsCollector ----------------------------------------------------------------------------- #events_collector = EventsCollector( - # context_client_grpc, log_events_received=True, + # context_client, log_events_received=True, # activate_context_collector = False, activate_topology_collector = True, activate_device_collector = False, # activate_link_collector = False, activate_service_collector = False, activate_slice_collector = False, # activate_connection_collector = False) #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.SetContext(Context(**CONTEXT)) + context_uuid = response.context_uuid.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 + # assert event.context_id.context_uuid.uuid == context_uuid # ----- Get when the object does not exist ------------------------------------------------------------------------- + topology_id = TopologyId(**TOPOLOGY_ID) + context_uuid,topology_uuid = topology_get_uuid(topology_id, allow_random=False) with pytest.raises(grpc.RpcError) as e: - context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID)) + context_client.GetTopology(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) + MSG = 'Topology({:s}/{:s}) not found; context_uuid generated was: {:s}; topology_uuid generated was: {:s}' + assert e.value.details() == MSG.format(CONTEXT_NAME, TOPOLOGY_NAME, context_uuid, topology_uuid) # ----- List when the object does not exist ------------------------------------------------------------------------ - response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID)) + response = context_client.GetContext(ContextId(**CONTEXT_ID)) assert len(response.topology_ids) == 0 + assert len(response.service_ids) == 0 + assert len(response.slice_ids) == 0 - response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID)) + response = context_client.ListTopologyIds(ContextId(**CONTEXT_ID)) + assert len(response.topology_ids) == 0 + + response = context_client.ListTopologies(ContextId(**CONTEXT_ID)) assert len(response.topologies) == 0 # ----- 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 + response = context_client.SetTopology(Topology(**TOPOLOGY)) + assert response.context_id.context_uuid.uuid == context_uuid + assert response.topology_uuid.uuid == topology_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 + #event = events_collector.get_event(block=True) + #assert isinstance(event, TopologyEvent) + #assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE + #assert event.topology_id.context_id.context_uuid.uuid == context_uuid + #assert event.topology_id.topology_uuid.uuid == topology_uuid # ----- Get when the object exists --------------------------------------------------------------------------------- - response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.name == '' + 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 response.topology_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_ids[0].topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID + assert response.topology_ids[0].context_id.context_uuid.uuid == context_uuid + assert response.topology_ids[0].topology_uuid.uuid == topology_uuid assert len(response.service_ids) == 0 assert len(response.slice_ids) == 0 - 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 response.name == '' + response = context_client.GetTopology(TopologyId(**TOPOLOGY_ID)) + assert response.topology_id.context_id.context_uuid.uuid == context_uuid + assert response.topology_id.topology_uuid.uuid == topology_uuid + assert response.name == TOPOLOGY_NAME 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)) + response = context_client.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 + assert response.topology_ids[0].context_id.context_uuid.uuid == context_uuid + assert response.topology_ids[0].topology_uuid.uuid == topology_uuid - response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID)) + response = context_client.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 response.topologies[0].name == '' + assert response.topologies[0].topology_id.context_id.context_uuid.uuid == context_uuid + assert response.topologies[0].topology_id.topology_uuid.uuid == topology_uuid + assert response.topologies[0].name == TOPOLOGY_NAME assert len(response.topologies[0].device_ids) == 0 assert len(response.topologies[0].link_ids) == 0 # ----- Update the object ------------------------------------------------------------------------------------------ new_topology_name = 'new' - TOPOLOGY_WITH_NAME = copy.deepcopy(TOPOLOGY) - TOPOLOGY_WITH_NAME['name'] = new_topology_name - response = context_client_grpc.SetTopology(Topology(**TOPOLOGY_WITH_NAME)) - assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID + TOPOLOGY_UPDATED = copy.deepcopy(TOPOLOGY) + TOPOLOGY_UPDATED['name'] = new_topology_name + response = context_client.SetTopology(Topology(**TOPOLOGY_UPDATED)) + assert response.context_id.context_uuid.uuid == context_uuid + assert response.topology_uuid.uuid == 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 + #assert event.topology_id.context_id.context_uuid.uuid == context_uuid + #assert event.topology_id.topology_uuid.uuid == topology_uuid # ----- Get when the object is modified ---------------------------------------------------------------------------- - 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 + response = context_client.GetTopology(TopologyId(**TOPOLOGY_ID)) + assert response.topology_id.context_id.context_uuid.uuid == context_uuid + assert response.topology_id.topology_uuid.uuid == topology_uuid assert response.name == new_topology_name assert len(response.device_ids) == 0 assert len(response.link_ids) == 0 # ----- List when the object is modified --------------------------------------------------------------------------- - response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID)) + response = context_client.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 + assert response.topology_ids[0].context_id.context_uuid.uuid == context_uuid + assert response.topology_ids[0].topology_uuid.uuid == topology_uuid - response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID)) + response = context_client.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 response.topologies[0].topology_id.context_id.context_uuid.uuid == context_uuid + assert response.topologies[0].topology_id.topology_uuid.uuid == topology_uuid assert response.topologies[0].name == new_topology_name 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.RemoveTopology(TopologyId(**TOPOLOGY_ID)) # ----- Check remove event ----------------------------------------------------------------------------------------- #event = events_collector.get_event(block=True) #assert isinstance(event, TopologyEvent) #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE - #assert event.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID - #assert event.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID + #assert event.topology_id.context_id.context_uuid.uuid == context_uuid + #assert event.topology_id.topology_uuid.uuid == topology_uuid # ----- List after deleting the object ----------------------------------------------------------------------------- - response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID)) + response = context_client.GetContext(ContextId(**CONTEXT_ID)) + assert len(response.topology_ids) == 0 + assert len(response.service_ids) == 0 + assert len(response.slice_ids) == 0 + + response = context_client.ListTopologyIds(ContextId(**CONTEXT_ID)) assert len(response.topology_ids) == 0 - response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID)) + response = context_client.ListTopologies(ContextId(**CONTEXT_ID)) assert len(response.topologies) == 0 # ----- Clean dependencies used in the test and capture related events --------------------------------------------- - context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID)) + context_client.RemoveContext(ContextId(**CONTEXT_ID)) + #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 + #assert event.context_id.context_uuid.uuid == context_uuid # ----- Stop the EventsCollector ----------------------------------------------------------------------------------- #events_collector.stop() diff --git a/test-context.sh b/test-context.sh new file mode 100755 index 0000000000000000000000000000000000000000..7ad303ca94280b13901980c1cdbcd35583c0041e --- /dev/null +++ b/test-context.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# 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. + +######################################################################################################################## +# Define your deployment settings here +######################################################################################################################## + +# If not already set, set the name of the Kubernetes namespace to deploy to. +export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"} + +######################################################################################################################## +# Automated steps start here +######################################################################################################################## + +PROJECTDIR=`pwd` + +cd $PROJECTDIR/src +RCFILE=$PROJECTDIR/coverage/.coveragerc +COVERAGEFILE=$PROJECTDIR/coverage/.coverage + +# Destroy old coverage file and configure the correct folder on the .coveragerc file +rm -f $COVERAGEFILE +cat $PROJECTDIR/coverage/.coveragerc.template | sed s+~/tfs-ctrl+$PROJECTDIR+g > $RCFILE + +#export CRDB_URI="cockroachdb://tfs:tfs123@127.0.0.1:26257/tfs_test?sslmode=require" +export CRDB_URI="cockroachdb://tfs:tfs123@10.1.7.195:26257/tfs_test?sslmode=require" +export PYTHONPATH=/home/tfs/tfs-ctrl/src + +# Run unitary tests and analyze coverage of code at same time +# helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0 +coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose --maxfail=1 \ + context/tests/test_hasher.py \ + context/tests/test_context.py \ + context/tests/test_topology.py \ + context/tests/test_device.py + +echo +echo "Coverage report:" +echo "----------------" +#coverage report --rcfile=$RCFILE --sort cover --show-missing --skip-covered | grep --color -E -i "^context/.*$|$" +coverage report --rcfile=$RCFILE --sort cover --show-missing --skip-covered --include="context/*"