diff --git a/src/common/message_broker/Factory.py b/src/common/message_broker/Factory.py index 34e030b0e2bd878e75cee8af7ea1b56bc095eb23..a2ea36435c717835bf4b7c89c2522878e67074c9 100644 --- a/src/common/message_broker/Factory.py +++ b/src/common/message_broker/Factory.py @@ -3,13 +3,13 @@ from typing import Optional, Union from .backend._Backend import _Backend from .backend.BackendEnum import BackendEnum from .backend.inmemory.InMemoryBackend import InMemoryBackend -# from .backend.redis.RedisBackend import RedisBackend +from .backend.redis.RedisBackend import RedisBackend LOGGER = logging.getLogger(__name__) BACKENDS = { BackendEnum.INMEMORY.value: InMemoryBackend, - # BackendEnum.REDIS.value: RedisBackend, + BackendEnum.REDIS.value: RedisBackend, #BackendEnum.KAFKA.value: KafkaBackend, #BackendEnum.RABBITMQ.value: RabbitMQBackend, #BackendEnum.ZEROMQ.value: ZeroMQBackend, diff --git a/src/common/orm/Factory.py b/src/common/orm/Factory.py index df1df56eec900ea8d6dffce5c1dd1132e0e88eee..6ef0e11ccdd7b2f0f9e3fde62903fef522cb9f7a 100644 --- a/src/common/orm/Factory.py +++ b/src/common/orm/Factory.py @@ -3,13 +3,13 @@ from typing import Optional, Union from .backend._Backend import _Backend from .backend.BackendEnum import BackendEnum from .backend.inmemory.InMemoryBackend import InMemoryBackend -# from .backend.redis.RedisBackend import RedisBackend +from .backend.redis.RedisBackend import RedisBackend LOGGER = logging.getLogger(__name__) BACKENDS = { BackendEnum.INMEMORY.value: InMemoryBackend, - # BackendEnum.REDIS.value: RedisBackend, + BackendEnum.REDIS.value: RedisBackend, #BackendEnum.MONGODB.value: MongoDBBackend, #BackendEnum.RETHINKDB.value: RethinkDBBackend, #BackendEnum.ETCD.value: EtcdBackend, diff --git a/src/context/proto/context_pb2.py b/src/context/proto/context_pb2.py index 658c58897615b33a435c7004d05b0a291abf95b7..8b4848bc33bfb0eba76590c8a3a627b2db84ca9f 100644 --- a/src/context/proto/context_pb2.py +++ b/src/context/proto/context_pb2.py @@ -12,7 +12,6 @@ from google.protobuf import symbol_database as _symbol_database _sym_db = _symbol_database.Default() -from . import kpi_sample_types_pb2 as kpi__sample__types__pb2 DESCRIPTOR = _descriptor.FileDescriptor( @@ -21,9 +20,8 @@ DESCRIPTOR = _descriptor.FileDescriptor( syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\rcontext.proto\x12\x07\x63ontext\x1a\x16kpi_sample_types.proto\"\x07\n\x05\x45mpty\"\x14\n\x04Uuid\x12\x0c\n\x04uuid\x18\x01 \x01(\t\"F\n\x05\x45vent\x12\x11\n\ttimestamp\x18\x01 \x01(\x01\x12*\n\nevent_type\x18\x02 \x01(\x0e\x32\x16.context.EventTypeEnum\"0\n\tContextId\x12#\n\x0c\x63ontext_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\xb6\x01\n\x07\x43ontext\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12)\n\x0ctopology_ids\x18\x02 \x03(\x0b\x32\x13.context.TopologyId\x12\'\n\x0bservice_ids\x18\x03 \x03(\x0b\x32\x12.context.ServiceId\x12/\n\ncontroller\x18\x04 \x01(\x0b\x32\x1b.context.TeraFlowController\"8\n\rContextIdList\x12\'\n\x0b\x63ontext_ids\x18\x01 \x03(\x0b\x32\x12.context.ContextId\"1\n\x0b\x43ontextList\x12\"\n\x08\x63ontexts\x18\x01 \x03(\x0b\x32\x10.context.Context\"U\n\x0c\x43ontextEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12&\n\ncontext_id\x18\x02 \x01(\x0b\x32\x12.context.ContextId\"Z\n\nTopologyId\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12$\n\rtopology_uuid\x18\x02 \x01(\x0b\x32\r.context.Uuid\"~\n\x08Topology\x12(\n\x0btopology_id\x18\x01 \x01(\x0b\x32\x13.context.TopologyId\x12%\n\ndevice_ids\x18\x02 \x03(\x0b\x32\x11.context.DeviceId\x12!\n\x08link_ids\x18\x03 \x03(\x0b\x32\x0f.context.LinkId\";\n\x0eTopologyIdList\x12)\n\x0ctopology_ids\x18\x01 \x03(\x0b\x32\x13.context.TopologyId\"5\n\x0cTopologyList\x12%\n\ntopologies\x18\x01 \x03(\x0b\x32\x11.context.Topology\"X\n\rTopologyEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12(\n\x0btopology_id\x18\x02 \x01(\x0b\x32\x13.context.TopologyId\".\n\x08\x44\x65viceId\x12\"\n\x0b\x64\x65vice_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\x9a\x02\n\x06\x44\x65vice\x12$\n\tdevice_id\x18\x01 \x01(\x0b\x32\x11.context.DeviceId\x12\x13\n\x0b\x64\x65vice_type\x18\x02 \x01(\t\x12,\n\rdevice_config\x18\x03 \x01(\x0b\x32\x15.context.DeviceConfig\x12G\n\x19\x64\x65vice_operational_status\x18\x04 \x01(\x0e\x32$.context.DeviceOperationalStatusEnum\x12\x31\n\x0e\x64\x65vice_drivers\x18\x05 \x03(\x0e\x32\x19.context.DeviceDriverEnum\x12+\n\x10\x64\x65vice_endpoints\x18\x06 \x03(\x0b\x32\x11.context.EndPoint\"9\n\x0c\x44\x65viceConfig\x12)\n\x0c\x63onfig_rules\x18\x01 \x03(\x0b\x32\x13.context.ConfigRule\"5\n\x0c\x44\x65viceIdList\x12%\n\ndevice_ids\x18\x01 \x03(\x0b\x32\x11.context.DeviceId\".\n\nDeviceList\x12 \n\x07\x64\x65vices\x18\x01 \x03(\x0b\x32\x0f.context.Device\"R\n\x0b\x44\x65viceEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12$\n\tdevice_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\"*\n\x06LinkId\x12 \n\tlink_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"X\n\x04Link\x12 \n\x07link_id\x18\x01 \x01(\x0b\x32\x0f.context.LinkId\x12.\n\x11link_endpoint_ids\x18\x02 \x03(\x0b\x32\x13.context.EndPointId\"/\n\nLinkIdList\x12!\n\x08link_ids\x18\x01 \x03(\x0b\x32\x0f.context.LinkId\"(\n\x08LinkList\x12\x1c\n\x05links\x18\x01 \x03(\x0b\x32\r.context.Link\"L\n\tLinkEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12 \n\x07link_id\x18\x02 \x01(\x0b\x32\x0f.context.LinkId\"X\n\tServiceId\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12#\n\x0cservice_uuid\x18\x02 \x01(\x0b\x32\r.context.Uuid\"\xa6\x02\n\x07Service\x12&\n\nservice_id\x18\x01 \x01(\x0b\x32\x12.context.ServiceId\x12.\n\x0cservice_type\x18\x02 \x01(\x0e\x32\x18.context.ServiceTypeEnum\x12\x31\n\x14service_endpoint_ids\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\x12\x30\n\x13service_constraints\x18\x04 \x03(\x0b\x32\x13.context.Constraint\x12.\n\x0eservice_status\x18\x05 \x01(\x0b\x32\x16.context.ServiceStatus\x12.\n\x0eservice_config\x18\x06 \x01(\x0b\x32\x16.context.ServiceConfig\"C\n\rServiceStatus\x12\x32\n\x0eservice_status\x18\x01 \x01(\x0e\x32\x1a.context.ServiceStatusEnum\":\n\rServiceConfig\x12)\n\x0c\x63onfig_rules\x18\x01 \x03(\x0b\x32\x13.context.ConfigRule\"8\n\rServiceIdList\x12\'\n\x0bservice_ids\x18\x01 \x03(\x0b\x32\x12.context.ServiceId\"1\n\x0bServiceList\x12\"\n\x08services\x18\x01 \x03(\x0b\x32\x10.context.Service\"U\n\x0cServiceEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12&\n\nservice_id\x18\x02 \x01(\x0b\x32\x12.context.ServiceId\"\x82\x01\n\nEndPointId\x12(\n\x0btopology_id\x18\x01 \x01(\x0b\x32\x13.context.TopologyId\x12$\n\tdevice_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\x12$\n\rendpoint_uuid\x18\x03 \x01(\x0b\x32\r.context.Uuid\"K\n\x08\x45ndPoint\x12(\n\x0b\x65ndpoint_id\x18\x01 \x01(\x0b\x32\x13.context.EndPointId\x12\x15\n\rendpoint_type\x18\x02 \x01(\t\"\x9f\x01\n\nConfigRule\x12)\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x19.context.ConfigActionEnum\x12\x14\n\x0cresource_key\x18\x02 \x01(\t\x12\x16\n\x0eresource_value\x18\x03 \x01(\t\x12\x38\n\x0fkpi_sample_type\x18\x04 \x01(\x0e\x32\x1f.kpi_sample_types.KpiSampleType\"?\n\nConstraint\x12\x17\n\x0f\x63onstraint_type\x18\x01 \x01(\t\x12\x18\n\x10\x63onstraint_value\x18\x02 \x01(\t\"6\n\x0c\x43onnectionId\x12&\n\x0f\x63onnection_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\x8d\x01\n\nConnection\x12,\n\rconnection_id\x18\x01 \x01(\x0b\x32\x15.context.ConnectionId\x12.\n\x12related_service_id\x18\x02 \x01(\x0b\x32\x12.context.ServiceId\x12!\n\x04path\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\"A\n\x10\x43onnectionIdList\x12-\n\x0e\x63onnection_ids\x18\x01 \x03(\x0b\x32\x15.context.ConnectionId\":\n\x0e\x43onnectionList\x12(\n\x0b\x63onnections\x18\x01 \x03(\x0b\x32\x13.context.Connection\"^\n\x12TeraFlowController\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x12\n\nip_address\x18\x02 \x01(\t\x12\x0c\n\x04port\x18\x03 \x01(\r\"U\n\x14\x41uthenticationResult\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x15\n\rauthenticated\x18\x02 \x01(\x08*j\n\rEventTypeEnum\x12\x17\n\x13\x45VENTTYPE_UNDEFINED\x10\x00\x12\x14\n\x10\x45VENTTYPE_CREATE\x10\x01\x12\x14\n\x10\x45VENTTYPE_UPDATE\x10\x02\x12\x14\n\x10\x45VENTTYPE_REMOVE\x10\x03*\xc5\x01\n\x10\x44\x65viceDriverEnum\x12\x1a\n\x16\x44\x45VICEDRIVER_UNDEFINED\x10\x00\x12\x1b\n\x17\x44\x45VICEDRIVER_OPENCONFIG\x10\x01\x12\x1e\n\x1a\x44\x45VICEDRIVER_TRANSPORT_API\x10\x02\x12\x13\n\x0f\x44\x45VICEDRIVER_P4\x10\x03\x12&\n\"DEVICEDRIVER_IETF_NETWORK_TOPOLOGY\x10\x04\x12\x1b\n\x17\x44\x45VICEDRIVER_ONF_TR_352\x10\x05*\x8f\x01\n\x1b\x44\x65viceOperationalStatusEnum\x12%\n!DEVICEOPERATIONALSTATUS_UNDEFINED\x10\x00\x12$\n DEVICEOPERATIONALSTATUS_DISABLED\x10\x01\x12#\n\x1f\x44\x45VICEOPERATIONALSTATUS_ENABLED\x10\x02*\x81\x01\n\x0fServiceTypeEnum\x12\x17\n\x13SERVICETYPE_UNKNOWN\x10\x00\x12\x14\n\x10SERVICETYPE_L3NM\x10\x01\x12\x14\n\x10SERVICETYPE_L2NM\x10\x02\x12)\n%SERVICETYPE_TAPI_CONNECTIVITY_SERVICE\x10\x03*\x88\x01\n\x11ServiceStatusEnum\x12\x1b\n\x17SERVICESTATUS_UNDEFINED\x10\x00\x12\x19\n\x15SERVICESTATUS_PLANNED\x10\x01\x12\x18\n\x14SERVICESTATUS_ACTIVE\x10\x02\x12!\n\x1dSERVICESTATUS_PENDING_REMOVAL\x10\x03*]\n\x10\x43onfigActionEnum\x12\x1a\n\x16\x43ONFIGACTION_UNDEFINED\x10\x00\x12\x14\n\x10\x43ONFIGACTION_SET\x10\x01\x12\x17\n\x13\x43ONFIGACTION_DELETE\x10\x02\x32\xa5\r\n\x0e\x43ontextService\x12:\n\x0eListContextIds\x12\x0e.context.Empty\x1a\x16.context.ContextIdList\"\x00\x12\x36\n\x0cListContexts\x12\x0e.context.Empty\x1a\x14.context.ContextList\"\x00\x12\x34\n\nGetContext\x12\x12.context.ContextId\x1a\x10.context.Context\"\x00\x12\x34\n\nSetContext\x12\x10.context.Context\x1a\x12.context.ContextId\"\x00\x12\x35\n\rRemoveContext\x12\x12.context.ContextId\x1a\x0e.context.Empty\"\x00\x12=\n\x10GetContextEvents\x12\x0e.context.Empty\x1a\x15.context.ContextEvent\"\x00\x30\x01\x12@\n\x0fListTopologyIds\x12\x12.context.ContextId\x1a\x17.context.TopologyIdList\"\x00\x12=\n\x0eListTopologies\x12\x12.context.ContextId\x1a\x15.context.TopologyList\"\x00\x12\x37\n\x0bGetTopology\x12\x13.context.TopologyId\x1a\x11.context.Topology\"\x00\x12\x37\n\x0bSetTopology\x12\x11.context.Topology\x1a\x13.context.TopologyId\"\x00\x12\x37\n\x0eRemoveTopology\x12\x13.context.TopologyId\x1a\x0e.context.Empty\"\x00\x12?\n\x11GetTopologyEvents\x12\x0e.context.Empty\x1a\x16.context.TopologyEvent\"\x00\x30\x01\x12\x38\n\rListDeviceIds\x12\x0e.context.Empty\x1a\x15.context.DeviceIdList\"\x00\x12\x34\n\x0bListDevices\x12\x0e.context.Empty\x1a\x13.context.DeviceList\"\x00\x12\x31\n\tGetDevice\x12\x11.context.DeviceId\x1a\x0f.context.Device\"\x00\x12\x31\n\tSetDevice\x12\x0f.context.Device\x1a\x11.context.DeviceId\"\x00\x12\x33\n\x0cRemoveDevice\x12\x11.context.DeviceId\x1a\x0e.context.Empty\"\x00\x12;\n\x0fGetDeviceEvents\x12\x0e.context.Empty\x1a\x14.context.DeviceEvent\"\x00\x30\x01\x12\x34\n\x0bListLinkIds\x12\x0e.context.Empty\x1a\x13.context.LinkIdList\"\x00\x12\x30\n\tListLinks\x12\x0e.context.Empty\x1a\x11.context.LinkList\"\x00\x12+\n\x07GetLink\x12\x0f.context.LinkId\x1a\r.context.Link\"\x00\x12+\n\x07SetLink\x12\r.context.Link\x1a\x0f.context.LinkId\"\x00\x12/\n\nRemoveLink\x12\x0f.context.LinkId\x1a\x0e.context.Empty\"\x00\x12\x37\n\rGetLinkEvents\x12\x0e.context.Empty\x1a\x12.context.LinkEvent\"\x00\x30\x01\x12>\n\x0eListServiceIds\x12\x12.context.ContextId\x1a\x16.context.ServiceIdList\"\x00\x12:\n\x0cListServices\x12\x12.context.ContextId\x1a\x14.context.ServiceList\"\x00\x12\x34\n\nGetService\x12\x12.context.ServiceId\x1a\x10.context.Service\"\x00\x12\x34\n\nSetService\x12\x10.context.Service\x1a\x12.context.ServiceId\"\x00\x12\x35\n\rRemoveService\x12\x12.context.ServiceId\x1a\x0e.context.Empty\"\x00\x12=\n\x10GetServiceEvents\x12\x0e.context.Empty\x1a\x15.context.ServiceEvent\"\x00\x30\x01\x62\x06proto3' - , - dependencies=[kpi__sample__types__pb2.DESCRIPTOR,]) + serialized_pb=b'\n\rcontext.proto\x12\x07\x63ontext\"\x07\n\x05\x45mpty\"\x14\n\x04Uuid\x12\x0c\n\x04uuid\x18\x01 \x01(\t\"F\n\x05\x45vent\x12\x11\n\ttimestamp\x18\x01 \x01(\x01\x12*\n\nevent_type\x18\x02 \x01(\x0e\x32\x16.context.EventTypeEnum\"0\n\tContextId\x12#\n\x0c\x63ontext_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\xb6\x01\n\x07\x43ontext\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12)\n\x0ctopology_ids\x18\x02 \x03(\x0b\x32\x13.context.TopologyId\x12\'\n\x0bservice_ids\x18\x03 \x03(\x0b\x32\x12.context.ServiceId\x12/\n\ncontroller\x18\x04 \x01(\x0b\x32\x1b.context.TeraFlowController\"8\n\rContextIdList\x12\'\n\x0b\x63ontext_ids\x18\x01 \x03(\x0b\x32\x12.context.ContextId\"1\n\x0b\x43ontextList\x12\"\n\x08\x63ontexts\x18\x01 \x03(\x0b\x32\x10.context.Context\"U\n\x0c\x43ontextEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12&\n\ncontext_id\x18\x02 \x01(\x0b\x32\x12.context.ContextId\"Z\n\nTopologyId\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12$\n\rtopology_uuid\x18\x02 \x01(\x0b\x32\r.context.Uuid\"~\n\x08Topology\x12(\n\x0btopology_id\x18\x01 \x01(\x0b\x32\x13.context.TopologyId\x12%\n\ndevice_ids\x18\x02 \x03(\x0b\x32\x11.context.DeviceId\x12!\n\x08link_ids\x18\x03 \x03(\x0b\x32\x0f.context.LinkId\";\n\x0eTopologyIdList\x12)\n\x0ctopology_ids\x18\x01 \x03(\x0b\x32\x13.context.TopologyId\"5\n\x0cTopologyList\x12%\n\ntopologies\x18\x01 \x03(\x0b\x32\x11.context.Topology\"X\n\rTopologyEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12(\n\x0btopology_id\x18\x02 \x01(\x0b\x32\x13.context.TopologyId\".\n\x08\x44\x65viceId\x12\"\n\x0b\x64\x65vice_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\x9a\x02\n\x06\x44\x65vice\x12$\n\tdevice_id\x18\x01 \x01(\x0b\x32\x11.context.DeviceId\x12\x13\n\x0b\x64\x65vice_type\x18\x02 \x01(\t\x12,\n\rdevice_config\x18\x03 \x01(\x0b\x32\x15.context.DeviceConfig\x12G\n\x19\x64\x65vice_operational_status\x18\x04 \x01(\x0e\x32$.context.DeviceOperationalStatusEnum\x12\x31\n\x0e\x64\x65vice_drivers\x18\x05 \x03(\x0e\x32\x19.context.DeviceDriverEnum\x12+\n\x10\x64\x65vice_endpoints\x18\x06 \x03(\x0b\x32\x11.context.EndPoint\"9\n\x0c\x44\x65viceConfig\x12)\n\x0c\x63onfig_rules\x18\x01 \x03(\x0b\x32\x13.context.ConfigRule\"5\n\x0c\x44\x65viceIdList\x12%\n\ndevice_ids\x18\x01 \x03(\x0b\x32\x11.context.DeviceId\".\n\nDeviceList\x12 \n\x07\x64\x65vices\x18\x01 \x03(\x0b\x32\x0f.context.Device\"R\n\x0b\x44\x65viceEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12$\n\tdevice_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\"*\n\x06LinkId\x12 \n\tlink_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"X\n\x04Link\x12 \n\x07link_id\x18\x01 \x01(\x0b\x32\x0f.context.LinkId\x12.\n\x11link_endpoint_ids\x18\x02 \x03(\x0b\x32\x13.context.EndPointId\"/\n\nLinkIdList\x12!\n\x08link_ids\x18\x01 \x03(\x0b\x32\x0f.context.LinkId\"(\n\x08LinkList\x12\x1c\n\x05links\x18\x01 \x03(\x0b\x32\r.context.Link\"L\n\tLinkEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12 \n\x07link_id\x18\x02 \x01(\x0b\x32\x0f.context.LinkId\"X\n\tServiceId\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12#\n\x0cservice_uuid\x18\x02 \x01(\x0b\x32\r.context.Uuid\"\xa6\x02\n\x07Service\x12&\n\nservice_id\x18\x01 \x01(\x0b\x32\x12.context.ServiceId\x12.\n\x0cservice_type\x18\x02 \x01(\x0e\x32\x18.context.ServiceTypeEnum\x12\x31\n\x14service_endpoint_ids\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\x12\x30\n\x13service_constraints\x18\x04 \x03(\x0b\x32\x13.context.Constraint\x12.\n\x0eservice_status\x18\x05 \x01(\x0b\x32\x16.context.ServiceStatus\x12.\n\x0eservice_config\x18\x06 \x01(\x0b\x32\x16.context.ServiceConfig\"C\n\rServiceStatus\x12\x32\n\x0eservice_status\x18\x01 \x01(\x0e\x32\x1a.context.ServiceStatusEnum\":\n\rServiceConfig\x12)\n\x0c\x63onfig_rules\x18\x01 \x03(\x0b\x32\x13.context.ConfigRule\"8\n\rServiceIdList\x12\'\n\x0bservice_ids\x18\x01 \x03(\x0b\x32\x12.context.ServiceId\"1\n\x0bServiceList\x12\"\n\x08services\x18\x01 \x03(\x0b\x32\x10.context.Service\"U\n\x0cServiceEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12&\n\nservice_id\x18\x02 \x01(\x0b\x32\x12.context.ServiceId\"\x82\x01\n\nEndPointId\x12(\n\x0btopology_id\x18\x01 \x01(\x0b\x32\x13.context.TopologyId\x12$\n\tdevice_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\x12$\n\rendpoint_uuid\x18\x03 \x01(\x0b\x32\r.context.Uuid\"K\n\x08\x45ndPoint\x12(\n\x0b\x65ndpoint_id\x18\x01 \x01(\x0b\x32\x13.context.EndPointId\x12\x15\n\rendpoint_type\x18\x02 \x01(\t\"e\n\nConfigRule\x12)\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x19.context.ConfigActionEnum\x12\x14\n\x0cresource_key\x18\x02 \x01(\t\x12\x16\n\x0eresource_value\x18\x03 \x01(\t\"?\n\nConstraint\x12\x17\n\x0f\x63onstraint_type\x18\x01 \x01(\t\x12\x18\n\x10\x63onstraint_value\x18\x02 \x01(\t\"6\n\x0c\x43onnectionId\x12&\n\x0f\x63onnection_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\x8d\x01\n\nConnection\x12,\n\rconnection_id\x18\x01 \x01(\x0b\x32\x15.context.ConnectionId\x12.\n\x12related_service_id\x18\x02 \x01(\x0b\x32\x12.context.ServiceId\x12!\n\x04path\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\"A\n\x10\x43onnectionIdList\x12-\n\x0e\x63onnection_ids\x18\x01 \x03(\x0b\x32\x15.context.ConnectionId\":\n\x0e\x43onnectionList\x12(\n\x0b\x63onnections\x18\x01 \x03(\x0b\x32\x13.context.Connection\"^\n\x12TeraFlowController\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x12\n\nip_address\x18\x02 \x01(\t\x12\x0c\n\x04port\x18\x03 \x01(\r\"U\n\x14\x41uthenticationResult\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x15\n\rauthenticated\x18\x02 \x01(\x08*j\n\rEventTypeEnum\x12\x17\n\x13\x45VENTTYPE_UNDEFINED\x10\x00\x12\x14\n\x10\x45VENTTYPE_CREATE\x10\x01\x12\x14\n\x10\x45VENTTYPE_UPDATE\x10\x02\x12\x14\n\x10\x45VENTTYPE_REMOVE\x10\x03*\xc5\x01\n\x10\x44\x65viceDriverEnum\x12\x1a\n\x16\x44\x45VICEDRIVER_UNDEFINED\x10\x00\x12\x1b\n\x17\x44\x45VICEDRIVER_OPENCONFIG\x10\x01\x12\x1e\n\x1a\x44\x45VICEDRIVER_TRANSPORT_API\x10\x02\x12\x13\n\x0f\x44\x45VICEDRIVER_P4\x10\x03\x12&\n\"DEVICEDRIVER_IETF_NETWORK_TOPOLOGY\x10\x04\x12\x1b\n\x17\x44\x45VICEDRIVER_ONF_TR_352\x10\x05*\x8f\x01\n\x1b\x44\x65viceOperationalStatusEnum\x12%\n!DEVICEOPERATIONALSTATUS_UNDEFINED\x10\x00\x12$\n DEVICEOPERATIONALSTATUS_DISABLED\x10\x01\x12#\n\x1f\x44\x45VICEOPERATIONALSTATUS_ENABLED\x10\x02*\x81\x01\n\x0fServiceTypeEnum\x12\x17\n\x13SERVICETYPE_UNKNOWN\x10\x00\x12\x14\n\x10SERVICETYPE_L3NM\x10\x01\x12\x14\n\x10SERVICETYPE_L2NM\x10\x02\x12)\n%SERVICETYPE_TAPI_CONNECTIVITY_SERVICE\x10\x03*\x88\x01\n\x11ServiceStatusEnum\x12\x1b\n\x17SERVICESTATUS_UNDEFINED\x10\x00\x12\x19\n\x15SERVICESTATUS_PLANNED\x10\x01\x12\x18\n\x14SERVICESTATUS_ACTIVE\x10\x02\x12!\n\x1dSERVICESTATUS_PENDING_REMOVAL\x10\x03*]\n\x10\x43onfigActionEnum\x12\x1a\n\x16\x43ONFIGACTION_UNDEFINED\x10\x00\x12\x14\n\x10\x43ONFIGACTION_SET\x10\x01\x12\x17\n\x13\x43ONFIGACTION_DELETE\x10\x02\x32\xa5\r\n\x0e\x43ontextService\x12:\n\x0eListContextIds\x12\x0e.context.Empty\x1a\x16.context.ContextIdList\"\x00\x12\x36\n\x0cListContexts\x12\x0e.context.Empty\x1a\x14.context.ContextList\"\x00\x12\x34\n\nGetContext\x12\x12.context.ContextId\x1a\x10.context.Context\"\x00\x12\x34\n\nSetContext\x12\x10.context.Context\x1a\x12.context.ContextId\"\x00\x12\x35\n\rRemoveContext\x12\x12.context.ContextId\x1a\x0e.context.Empty\"\x00\x12=\n\x10GetContextEvents\x12\x0e.context.Empty\x1a\x15.context.ContextEvent\"\x00\x30\x01\x12@\n\x0fListTopologyIds\x12\x12.context.ContextId\x1a\x17.context.TopologyIdList\"\x00\x12=\n\x0eListTopologies\x12\x12.context.ContextId\x1a\x15.context.TopologyList\"\x00\x12\x37\n\x0bGetTopology\x12\x13.context.TopologyId\x1a\x11.context.Topology\"\x00\x12\x37\n\x0bSetTopology\x12\x11.context.Topology\x1a\x13.context.TopologyId\"\x00\x12\x37\n\x0eRemoveTopology\x12\x13.context.TopologyId\x1a\x0e.context.Empty\"\x00\x12?\n\x11GetTopologyEvents\x12\x0e.context.Empty\x1a\x16.context.TopologyEvent\"\x00\x30\x01\x12\x38\n\rListDeviceIds\x12\x0e.context.Empty\x1a\x15.context.DeviceIdList\"\x00\x12\x34\n\x0bListDevices\x12\x0e.context.Empty\x1a\x13.context.DeviceList\"\x00\x12\x31\n\tGetDevice\x12\x11.context.DeviceId\x1a\x0f.context.Device\"\x00\x12\x31\n\tSetDevice\x12\x0f.context.Device\x1a\x11.context.DeviceId\"\x00\x12\x33\n\x0cRemoveDevice\x12\x11.context.DeviceId\x1a\x0e.context.Empty\"\x00\x12;\n\x0fGetDeviceEvents\x12\x0e.context.Empty\x1a\x14.context.DeviceEvent\"\x00\x30\x01\x12\x34\n\x0bListLinkIds\x12\x0e.context.Empty\x1a\x13.context.LinkIdList\"\x00\x12\x30\n\tListLinks\x12\x0e.context.Empty\x1a\x11.context.LinkList\"\x00\x12+\n\x07GetLink\x12\x0f.context.LinkId\x1a\r.context.Link\"\x00\x12+\n\x07SetLink\x12\r.context.Link\x1a\x0f.context.LinkId\"\x00\x12/\n\nRemoveLink\x12\x0f.context.LinkId\x1a\x0e.context.Empty\"\x00\x12\x37\n\rGetLinkEvents\x12\x0e.context.Empty\x1a\x12.context.LinkEvent\"\x00\x30\x01\x12>\n\x0eListServiceIds\x12\x12.context.ContextId\x1a\x16.context.ServiceIdList\"\x00\x12:\n\x0cListServices\x12\x12.context.ContextId\x1a\x14.context.ServiceList\"\x00\x12\x34\n\nGetService\x12\x12.context.ServiceId\x1a\x10.context.Service\"\x00\x12\x34\n\nSetService\x12\x10.context.Service\x1a\x12.context.ServiceId\"\x00\x12\x35\n\rRemoveService\x12\x12.context.ServiceId\x1a\x0e.context.Empty\"\x00\x12=\n\x10GetServiceEvents\x12\x0e.context.Empty\x1a\x15.context.ServiceEvent\"\x00\x30\x01\x62\x06proto3' +) _EVENTTYPEENUM = _descriptor.EnumDescriptor( name='EventTypeEnum', @@ -55,8 +53,8 @@ _EVENTTYPEENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=3551, - serialized_end=3657, + serialized_start=3468, + serialized_end=3574, ) _sym_db.RegisterEnumDescriptor(_EVENTTYPEENUM) @@ -101,8 +99,8 @@ _DEVICEDRIVERENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=3660, - serialized_end=3857, + serialized_start=3577, + serialized_end=3774, ) _sym_db.RegisterEnumDescriptor(_DEVICEDRIVERENUM) @@ -132,8 +130,8 @@ _DEVICEOPERATIONALSTATUSENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=3860, - serialized_end=4003, + serialized_start=3777, + serialized_end=3920, ) _sym_db.RegisterEnumDescriptor(_DEVICEOPERATIONALSTATUSENUM) @@ -168,8 +166,8 @@ _SERVICETYPEENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=4006, - serialized_end=4135, + serialized_start=3923, + serialized_end=4052, ) _sym_db.RegisterEnumDescriptor(_SERVICETYPEENUM) @@ -204,8 +202,8 @@ _SERVICESTATUSENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=4138, - serialized_end=4274, + serialized_start=4055, + serialized_end=4191, ) _sym_db.RegisterEnumDescriptor(_SERVICESTATUSENUM) @@ -235,8 +233,8 @@ _CONFIGACTIONENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=4276, - serialized_end=4369, + serialized_start=4193, + serialized_end=4286, ) _sym_db.RegisterEnumDescriptor(_CONFIGACTIONENUM) @@ -288,8 +286,8 @@ _EMPTY = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=50, - serialized_end=57, + serialized_start=26, + serialized_end=33, ) @@ -320,8 +318,8 @@ _UUID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=59, - serialized_end=79, + serialized_start=35, + serialized_end=55, ) @@ -359,8 +357,8 @@ _EVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=81, - serialized_end=151, + serialized_start=57, + serialized_end=127, ) @@ -391,8 +389,8 @@ _CONTEXTID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=153, - serialized_end=201, + serialized_start=129, + serialized_end=177, ) @@ -444,8 +442,8 @@ _CONTEXT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=204, - serialized_end=386, + serialized_start=180, + serialized_end=362, ) @@ -476,8 +474,8 @@ _CONTEXTIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=388, - serialized_end=444, + serialized_start=364, + serialized_end=420, ) @@ -508,8 +506,8 @@ _CONTEXTLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=446, - serialized_end=495, + serialized_start=422, + serialized_end=471, ) @@ -547,8 +545,8 @@ _CONTEXTEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=497, - serialized_end=582, + serialized_start=473, + serialized_end=558, ) @@ -586,8 +584,8 @@ _TOPOLOGYID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=584, - serialized_end=674, + serialized_start=560, + serialized_end=650, ) @@ -632,8 +630,8 @@ _TOPOLOGY = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=676, - serialized_end=802, + serialized_start=652, + serialized_end=778, ) @@ -664,8 +662,8 @@ _TOPOLOGYIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=804, - serialized_end=863, + serialized_start=780, + serialized_end=839, ) @@ -696,8 +694,8 @@ _TOPOLOGYLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=865, - serialized_end=918, + serialized_start=841, + serialized_end=894, ) @@ -735,8 +733,8 @@ _TOPOLOGYEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=920, - serialized_end=1008, + serialized_start=896, + serialized_end=984, ) @@ -767,8 +765,8 @@ _DEVICEID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1010, - serialized_end=1056, + serialized_start=986, + serialized_end=1032, ) @@ -834,8 +832,8 @@ _DEVICE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1059, - serialized_end=1341, + serialized_start=1035, + serialized_end=1317, ) @@ -866,8 +864,8 @@ _DEVICECONFIG = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1343, - serialized_end=1400, + serialized_start=1319, + serialized_end=1376, ) @@ -898,8 +896,8 @@ _DEVICEIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1402, - serialized_end=1455, + serialized_start=1378, + serialized_end=1431, ) @@ -930,8 +928,8 @@ _DEVICELIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1457, - serialized_end=1503, + serialized_start=1433, + serialized_end=1479, ) @@ -969,8 +967,8 @@ _DEVICEEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1505, - serialized_end=1587, + serialized_start=1481, + serialized_end=1563, ) @@ -1001,8 +999,8 @@ _LINKID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1589, - serialized_end=1631, + serialized_start=1565, + serialized_end=1607, ) @@ -1040,8 +1038,8 @@ _LINK = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1633, - serialized_end=1721, + serialized_start=1609, + serialized_end=1697, ) @@ -1072,8 +1070,8 @@ _LINKIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1723, - serialized_end=1770, + serialized_start=1699, + serialized_end=1746, ) @@ -1104,8 +1102,8 @@ _LINKLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1772, - serialized_end=1812, + serialized_start=1748, + serialized_end=1788, ) @@ -1143,8 +1141,8 @@ _LINKEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1814, - serialized_end=1890, + serialized_start=1790, + serialized_end=1866, ) @@ -1182,8 +1180,8 @@ _SERVICEID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1892, - serialized_end=1980, + serialized_start=1868, + serialized_end=1956, ) @@ -1249,8 +1247,8 @@ _SERVICE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1983, - serialized_end=2277, + serialized_start=1959, + serialized_end=2253, ) @@ -1281,8 +1279,8 @@ _SERVICESTATUS = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2279, - serialized_end=2346, + serialized_start=2255, + serialized_end=2322, ) @@ -1313,8 +1311,8 @@ _SERVICECONFIG = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2348, - serialized_end=2406, + serialized_start=2324, + serialized_end=2382, ) @@ -1345,8 +1343,8 @@ _SERVICEIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2408, - serialized_end=2464, + serialized_start=2384, + serialized_end=2440, ) @@ -1377,8 +1375,8 @@ _SERVICELIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2466, - serialized_end=2515, + serialized_start=2442, + serialized_end=2491, ) @@ -1416,8 +1414,8 @@ _SERVICEEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2517, - serialized_end=2602, + serialized_start=2493, + serialized_end=2578, ) @@ -1462,8 +1460,8 @@ _ENDPOINTID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2605, - serialized_end=2735, + serialized_start=2581, + serialized_end=2711, ) @@ -1501,8 +1499,8 @@ _ENDPOINT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2737, - serialized_end=2812, + serialized_start=2713, + serialized_end=2788, ) @@ -1535,13 +1533,6 @@ _CONFIGRULE = _descriptor.Descriptor( message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='kpi_sample_type', full_name='context.ConfigRule.kpi_sample_type', index=3, - number=4, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -1554,8 +1545,8 @@ _CONFIGRULE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2815, - serialized_end=2974, + serialized_start=2790, + serialized_end=2891, ) @@ -1593,8 +1584,8 @@ _CONSTRAINT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2976, - serialized_end=3039, + serialized_start=2893, + serialized_end=2956, ) @@ -1625,8 +1616,8 @@ _CONNECTIONID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3041, - serialized_end=3095, + serialized_start=2958, + serialized_end=3012, ) @@ -1671,8 +1662,8 @@ _CONNECTION = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3098, - serialized_end=3239, + serialized_start=3015, + serialized_end=3156, ) @@ -1703,8 +1694,8 @@ _CONNECTIONIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3241, - serialized_end=3306, + serialized_start=3158, + serialized_end=3223, ) @@ -1735,8 +1726,8 @@ _CONNECTIONLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3308, - serialized_end=3366, + serialized_start=3225, + serialized_end=3283, ) @@ -1781,8 +1772,8 @@ _TERAFLOWCONTROLLER = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3368, - serialized_end=3462, + serialized_start=3285, + serialized_end=3379, ) @@ -1820,8 +1811,8 @@ _AUTHENTICATIONRESULT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3464, - serialized_end=3549, + serialized_start=3381, + serialized_end=3466, ) _EVENT.fields_by_name['event_type'].enum_type = _EVENTTYPEENUM @@ -1880,7 +1871,6 @@ _ENDPOINTID.fields_by_name['device_id'].message_type = _DEVICEID _ENDPOINTID.fields_by_name['endpoint_uuid'].message_type = _UUID _ENDPOINT.fields_by_name['endpoint_id'].message_type = _ENDPOINTID _CONFIGRULE.fields_by_name['action'].enum_type = _CONFIGACTIONENUM -_CONFIGRULE.fields_by_name['kpi_sample_type'].enum_type = kpi__sample__types__pb2._KPISAMPLETYPE _CONNECTIONID.fields_by_name['connection_uuid'].message_type = _UUID _CONNECTION.fields_by_name['connection_id'].message_type = _CONNECTIONID _CONNECTION.fields_by_name['related_service_id'].message_type = _SERVICEID @@ -2234,8 +2224,8 @@ _CONTEXTSERVICE = _descriptor.ServiceDescriptor( index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=4372, - serialized_end=6073, + serialized_start=4289, + serialized_end=5990, methods=[ _descriptor.MethodDescriptor( name='ListContextIds', diff --git a/src/context/proto/context_pb2_grpc.py b/src/context/proto/context_pb2_grpc.py index 63a7edb530ab138e7f2d6c2ba2d6075db52e2fee..c344c8b539324140fddc411324959368da3c1b7b 100644 --- a/src/context/proto/context_pb2_grpc.py +++ b/src/context/proto/context_pb2_grpc.py @@ -6,7 +6,9 @@ from . import context_pb2 as context__pb2 class ContextServiceStub(object): - """Missing associated documentation comment in .proto file.""" + """import "kpi_sample_types.proto"; + + """ def __init__(self, channel): """Constructor. @@ -167,7 +169,9 @@ class ContextServiceStub(object): class ContextServiceServicer(object): - """Missing associated documentation comment in .proto file.""" + """import "kpi_sample_types.proto"; + + """ def ListContextIds(self, request, context): """Missing associated documentation comment in .proto file.""" @@ -510,7 +514,9 @@ def add_ContextServiceServicer_to_server(servicer, server): # This class is part of an EXPERIMENTAL API. class ContextService(object): - """Missing associated documentation comment in .proto file.""" + """import "kpi_sample_types.proto"; + + """ @staticmethod def ListContextIds(request, diff --git a/src/context/proto/kpi_sample_types_pb2.py b/src/context/proto/kpi_sample_types_pb2.py index 31fbaa216bca629a4de4272091c490982c1aa166..ad22554ec352d0aeae644fdce00c0f28996ed73b 100644 --- a/src/context/proto/kpi_sample_types_pb2.py +++ b/src/context/proto/kpi_sample_types_pb2.py @@ -2,7 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: kpi_sample_types.proto """Generated protocol buffer code.""" -from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -16,62 +15,15 @@ _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='kpi_sample_types.proto', - package='kpi_sample_types', + package='', syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x16kpi_sample_types.proto\x12\x10kpi_sample_types*x\n\rKpiSampleType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x17\n\x13PACKETS_TRANSMITTED\x10\x65\x12\x14\n\x10PACKETS_RECEIVED\x10\x66\x12\x16\n\x11\x42YTES_TRANSMITTED\x10\xc9\x01\x12\x13\n\x0e\x42YTES_RECEIVED\x10\xca\x01\x62\x06proto3' + serialized_pb=b'\n\x16kpi_sample_types.protob\x06proto3' ) -_KPISAMPLETYPE = _descriptor.EnumDescriptor( - name='KpiSampleType', - full_name='kpi_sample_types.KpiSampleType', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='UNKNOWN', index=0, number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='PACKETS_TRANSMITTED', index=1, number=101, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='PACKETS_RECEIVED', index=2, number=102, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='BYTES_TRANSMITTED', index=3, number=201, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='BYTES_RECEIVED', index=4, number=202, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - serialized_start=44, - serialized_end=164, -) -_sym_db.RegisterEnumDescriptor(_KPISAMPLETYPE) - -KpiSampleType = enum_type_wrapper.EnumTypeWrapper(_KPISAMPLETYPE) -UNKNOWN = 0 -PACKETS_TRANSMITTED = 101 -PACKETS_RECEIVED = 102 -BYTES_TRANSMITTED = 201 -BYTES_RECEIVED = 202 -DESCRIPTOR.enum_types_by_name['KpiSampleType'] = _KPISAMPLETYPE _sym_db.RegisterFileDescriptor(DESCRIPTOR) diff --git a/src/context/service/database/ConfigModel.py b/src/context/service/database/ConfigModel.py index 0fe3484896a39545c4dd49042707dc1ee09fc868..d97cdb7dfe6594a59be10427ed52341346c19a97 100644 --- a/src/context/service/database/ConfigModel.py +++ b/src/context/service/database/ConfigModel.py @@ -1,8 +1,8 @@ import functools, logging, operator from enum import Enum -from typing import Dict, List, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union from common.orm.Database import Database -from common.orm.HighLevel import get_or_create_object, update_or_create_object +from common.orm.HighLevel import get_object, get_or_create_object, update_or_create_object from common.orm.backend.Tools import key_to_str from common.orm.fields.EnumeratedField import EnumeratedField from common.orm.fields.ForeignKeyField import ForeignKeyField @@ -11,7 +11,7 @@ from common.orm.fields.PrimaryKeyField import PrimaryKeyField from common.orm.fields.StringField import StringField from common.orm.model.Model import Model from context.proto.context_pb2 import ConfigActionEnum -from context.service.database.Tools import fast_hasher, grpc_to_enum, remove_dict_key +from .Tools import fast_hasher, grpc_to_enum, remove_dict_key LOGGER = logging.getLogger(__name__) @@ -50,35 +50,62 @@ class ConfigRuleModel(Model): # pylint: disable=abstract-method return result def set_config_rule( - database : Database, db_config : ConfigModel, grpc_config_rule, position : int + database : Database, db_config : ConfigModel, position : int, resource_key : str, resource_value : str ) -> Tuple[ConfigRuleModel, bool]: - str_rule_key_hash = fast_hasher(grpc_config_rule.resource_key) + str_rule_key_hash = fast_hasher(resource_key) str_config_rule_key = key_to_str([db_config.pk, str_rule_key_hash], separator=':') - result : Tuple[ConfigRuleModel, bool] = update_or_create_object(database, ConfigRuleModel, str_config_rule_key, { - 'config_fk': db_config, - 'position' : position, - 'action' : grpc_to_enum__config_action(grpc_config_rule.action), - 'key' : grpc_config_rule.resource_key, - 'value' : grpc_config_rule.resource_value, - }) + 'config_fk': db_config, 'position': position, 'action': ORM_ConfigActionEnum.SET, + 'key': resource_key, 'value': resource_value}) db_config_rule, updated = result return db_config_rule, updated -def set_config( - database : Database, db_parent_pk : str, config_name : str, grpc_config_rules +def delete_config_rule( + database : Database, db_config : ConfigModel, resource_key : str + ) -> None: + + str_rule_key_hash = fast_hasher(resource_key) + str_config_rule_key = key_to_str([db_config.pk, str_rule_key_hash], separator=':') + db_config_rule : Optional[ConfigRuleModel] = get_object( + database, ConfigRuleModel, str_config_rule_key, raise_if_not_found=False) + if db_config_rule is None: return + db_config_rule.delete() + +def delete_all_config_rules( + database : Database, db_config : ConfigModel + ) -> None: + + db_config_rule_pks = db_config.references(ConfigRuleModel) + for pk,_ in db_config_rule_pks: ConfigRuleModel(database, pk).delete() + +def grpc_config_rules_to_raw(grpc_config_rules) -> List[Tuple[ORM_ConfigActionEnum, str, str]]: + def translate(grpc_config_rule): + action = grpc_to_enum__config_action(grpc_config_rule.action) + return action, grpc_config_rule.resource_key, grpc_config_rule.resource_value + return [translate(grpc_config_rule) for grpc_config_rule in grpc_config_rules] + +def update_config( + database : Database, db_parent_pk : str, config_name : str, + raw_config_rules : List[Tuple[ORM_ConfigActionEnum, str, str]] ) -> List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]]: str_config_key = key_to_str([db_parent_pk, config_name], separator=':') result : Tuple[ConfigModel, bool] = get_or_create_object(database, ConfigModel, str_config_key) db_config, created = result - db_objects = [(db_config, created)] + db_objects : List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]] = [(db_config, created)] - for position,grpc_config_rule in enumerate(grpc_config_rules): - result : Tuple[ConfigRuleModel, bool] = set_config_rule(database, db_config, grpc_config_rule, position) - db_config_rule, updated = result - db_objects.append((db_config_rule, updated)) + for position,(action, resource_key, resource_value) in enumerate(raw_config_rules): + if action == ORM_ConfigActionEnum.SET: + result : Tuple[ConfigRuleModel, bool] = set_config_rule( + database, db_config, position, resource_key, resource_value) + db_config_rule, updated = result + db_objects.append((db_config_rule, updated)) + elif action == ORM_ConfigActionEnum.DELETE: + delete_config_rule(database, db_config, resource_key) + else: + msg = 'Unsupported action({:s}) for resource_key({:s})/resource_value({:s})' + raise AttributeError(msg.format(str(ConfigActionEnum.Name(action)), str(resource_key), str(resource_value))) return db_objects diff --git a/src/context/service/database/EndPointModel.py b/src/context/service/database/EndPointModel.py index b7c220a00b2a85b2c3f4c11a2eceb3aa66aadc5a..38b87d6f37c4e99dd3790f4d8802acd03873f77d 100644 --- a/src/context/service/database/EndPointModel.py +++ b/src/context/service/database/EndPointModel.py @@ -4,8 +4,8 @@ from common.orm.fields.ForeignKeyField import ForeignKeyField from common.orm.fields.PrimaryKeyField import PrimaryKeyField from common.orm.fields.StringField import StringField from common.orm.model.Model import Model -from context.service.database.DeviceModel import DeviceModel -from context.service.database.TopologyModel import TopologyModel +from .DeviceModel import DeviceModel +from .TopologyModel import TopologyModel LOGGER = logging.getLogger(__name__) diff --git a/src/context/service/grpc_server/ContextServiceServicerImpl.py b/src/context/service/grpc_server/ContextServiceServicerImpl.py index d8f7b648b4b919cc61330f236195c444f550ede1..e76c399cd4e17578a01ac7bf88cb0fc3f7017b8e 100644 --- a/src/context/service/grpc_server/ContextServiceServicerImpl.py +++ b/src/context/service/grpc_server/ContextServiceServicerImpl.py @@ -12,7 +12,7 @@ from context.proto.context_pb2 import ( DeviceList, Empty, EventTypeEnum, Link, LinkEvent, LinkId, LinkIdList, LinkList, Service, ServiceEvent, ServiceId, ServiceIdList, ServiceList, Topology, TopologyEvent, TopologyId, TopologyIdList, TopologyList) from context.proto.context_pb2_grpc import ContextServiceServicer -from context.service.database.ConfigModel import ConfigModel, ConfigRuleModel, set_config +from context.service.database.ConfigModel import ConfigModel, ConfigRuleModel, grpc_config_rules_to_raw, update_config from context.service.database.ConstraintModel import ConstraintModel, ConstraintsModel, set_constraints from context.service.database.ContextModel import ContextModel from context.service.database.DeviceModel import ( @@ -236,7 +236,8 @@ class ContextServiceServicerImpl(ContextServiceServicer): '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)]) - running_config_result = set_config(self.database, device_uuid, 'running', request.device_config.config_rules) + config_rules = grpc_config_rules_to_raw(request.device_config.config_rules) + running_config_result = update_config(self.database, device_uuid, 'running', config_rules) db_running_config = running_config_result[0][0] result : Tuple[DeviceModel, bool] = update_or_create_object(self.database, DeviceModel, device_uuid, { @@ -452,8 +453,8 @@ class ContextServiceServicerImpl(ContextServiceServicer): self.database, str_service_key, 'constraints', request.service_constraints) db_constraints = constraints_result[0][0] - running_config_result = set_config( - self.database, str_service_key, 'running', request.service_config.config_rules) + 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, { diff --git a/src/context/tests/example_objects.py b/src/context/tests/example_objects.py index 226119f9d29213a6f1857a476b37b32c9941a813..81339c04e1fe77667bd41179f3fa0813c5fc69df 100644 --- a/src/context/tests/example_objects.py +++ b/src/context/tests/example_objects.py @@ -2,13 +2,12 @@ from copy import deepcopy from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID from context.proto.context_pb2 import ( ConfigActionEnum, DeviceDriverEnum, DeviceOperationalStatusEnum, ServiceStatusEnum, ServiceTypeEnum) -from context.proto.kpi_sample_types_pb2 import KpiSampleType # Some example objects to be used by the tests # Helper methods -def config_rule(action, resource_key, resource_value, kpi_sample_type): - return {'action': action, 'resource_key': resource_key, 'resource_value': resource_value, 'kpi_sample_type': kpi_sample_type} +def config_rule(action, resource_key, resource_value): + return {'action': action, 'resource_key': resource_key, 'resource_value': resource_value} def endpoint_id(topology_id, device_id, endpoint_uuid): return {'topology_id': deepcopy(topology_id), 'device_id': deepcopy(device_id), @@ -41,10 +40,9 @@ DEVICE1 = { 'device_id': deepcopy(DEVICE1_ID), 'device_type': 'packet-router', 'device_config': {'config_rules': [ - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value1', KpiSampleType.PACKETS_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value2', KpiSampleType.PACKETS_RECEIVED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value3', KpiSampleType.BYTES_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc4/value', 'value4', KpiSampleType.BYTES_RECEIVED), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value1'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value2'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value3'), ]}, 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED, 'device_drivers': [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_P4], @@ -61,9 +59,9 @@ DEVICE2 = { 'device_id': deepcopy(DEVICE2_ID), 'device_type': 'packet-router', 'device_config': {'config_rules': [ - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value4', KpiSampleType.PACKETS_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value5', KpiSampleType.PACKETS_RECEIVED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value6', KpiSampleType.BYTES_TRANSMITTED), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value4'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value5'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value6'), ]}, 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED, 'device_drivers': [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_P4], @@ -80,9 +78,9 @@ DEVICE3 = { 'device_id': deepcopy(DEVICE3_ID), 'device_type': 'packet-router', 'device_config': {'config_rules': [ - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value4', KpiSampleType.PACKETS_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value5', KpiSampleType.PACKETS_RECEIVED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value6', KpiSampleType.BYTES_TRANSMITTED), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value4'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value5'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value6'), ]}, 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED, 'device_drivers': [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_P4], @@ -141,9 +139,9 @@ SERVICE_DEV1_DEV2 = { ], 'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_ACTIVE}, 'service_config': {'config_rules': [ - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7', KpiSampleType.PACKETS_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8', KpiSampleType.PACKETS_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9', KpiSampleType.PACKETS_TRANSMITTED), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9'), ]}, } @@ -165,9 +163,9 @@ SERVICE_DEV1_DEV3 = { ], 'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_ACTIVE}, 'service_config': {'config_rules': [ - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7', KpiSampleType.PACKETS_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8', KpiSampleType.PACKETS_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9', KpiSampleType.PACKETS_TRANSMITTED), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9'), ]}, } @@ -189,8 +187,8 @@ SERVICE_DEV2_DEV3 = { ], 'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_ACTIVE}, 'service_config': {'config_rules': [ - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7', KpiSampleType.PACKETS_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8', KpiSampleType.PACKETS_TRANSMITTED), - config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9', KpiSampleType.PACKETS_TRANSMITTED), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8'), + config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9'), ]}, } diff --git a/src/device/.gitlab-ci.yml b/src/device/.gitlab-ci.yml index fca94bf712606f590c13c3e90f8fc686b9238471..e6ee81e379f8eeeca6c715bff5dfc6f2cf1c3d23 100644 --- a/src/device/.gitlab-ci.yml +++ b/src/device/.gitlab-ci.yml @@ -35,7 +35,7 @@ unit_test device: - sleep 5 - docker ps -a - docker logs $IMAGE_NAME - - docker exec -i $IMAGE_NAME bash -c "pytest --log-level=DEBUG --verbose $IMAGE_NAME/tests/test_unitary_service.py $IMAGE_NAME/tests/test_unitary_driverapi.py" + - docker exec -i $IMAGE_NAME bash -c "pytest --log-level=DEBUG --verbose $IMAGE_NAME/tests/test_unitary_driverapi.py $IMAGE_NAME/tests/test_unitary.py" after_script: - docker stop $IMAGE_NAME - docker rm $IMAGE_NAME diff --git a/src/device/Config.py b/src/device/Config.py index 6787413a881b4d84ed6b4ecb5e041901399a4ae6..753f4b57b2767552317882e72622c613f40e3ea2 100644 --- a/src/device/Config.py +++ b/src/device/Config.py @@ -10,3 +10,9 @@ GRPC_GRACE_PERIOD = 60 # Prometheus settings METRICS_PORT = 9192 + +# Dependency micro-service connection settings +CONTEXT_SERVICE_HOST = '127.0.0.1' +CONTEXT_SERVICE_PORT = 1010 +MONITORING_SERVICE_HOST = '127.0.0.1' +MONITORING_SERVICE_PORT = 7070 diff --git a/src/device/Dockerfile b/src/device/Dockerfile index 52eb5c82cce99ebc488ae586fd29375dba709a09..70e3c8dcbbc6b78a53b468e51034ffb8e69f8e53 100644 --- a/src/device/Dockerfile +++ b/src/device/Dockerfile @@ -29,7 +29,9 @@ RUN python3 -m pip install -r device/requirements.in # Add files into working directory COPY common/. common +COPY context/. context COPY device/. device +COPY monitoring/. monitoring # Start device service ENTRYPOINT ["python", "-m", "device.service"] diff --git a/src/device/client/DeviceClient.py b/src/device/client/DeviceClient.py index d9cd16f77b607ac0817c16448d65c7f563201646..3841bf8cb4892dcc191d536061aea2bb1bd9d06d 100644 --- a/src/device/client/DeviceClient.py +++ b/src/device/client/DeviceClient.py @@ -1,7 +1,7 @@ import grpc, logging from common.tools.client.RetryDecorator import retry, delay_exponential -from device.proto.context_pb2 import Device, DeviceId, Empty -from device.proto.device_pb2 import MonitoringSettings +from device.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty +#from device.proto.device_pb2 import MonitoringSettings from device.proto.device_pb2_grpc import DeviceServiceStub LOGGER = logging.getLogger(__name__) @@ -22,7 +22,7 @@ class DeviceClient: self.stub = DeviceServiceStub(self.channel) def close(self): - if(self.channel is not None): self.channel.close() + if self.channel is not None: self.channel.close() self.channel = None self.stub = None @@ -48,8 +48,15 @@ class DeviceClient: return response @retry(exceptions=set(), max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect') - def MonitorDeviceKpi(self, request: MonitoringSettings) -> Empty: - LOGGER.debug('MonitorDeviceKpi request: {:s}'.format(str(request))) - response = self.stub.MonitorDeviceKpi(request) - LOGGER.debug('MonitorDeviceKpi result: {:s}'.format(str(response))) + def GetInitialConfig(self, request : DeviceId) -> DeviceConfig: + LOGGER.debug('GetInitialConfig request: {:s}'.format(str(request))) + response = self.stub.GetInitialConfig(request) + LOGGER.debug('GetInitialConfig result: {:s}'.format(str(response))) return response + + #@retry(exceptions=set(), max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect') + #def MonitorDeviceKpi(self, request : MonitoringSettings) -> Empty: + # LOGGER.debug('MonitorDeviceKpi request: {:s}'.format(str(request))) + # response = self.stub.MonitorDeviceKpi(request) + # LOGGER.debug('MonitorDeviceKpi result: {:s}'.format(str(response))) + # return response diff --git a/src/device/genproto.sh b/src/device/genproto.sh index c5f9ec20f289ff2005641ac2489db1469fcbcaaf..31632fb894f3ede9582063d81b1911fe2551d96d 100755 --- a/src/device/genproto.sh +++ b/src/device/genproto.sh @@ -26,10 +26,14 @@ touch proto/__init__.py python -m grpc_tools.protoc -I../../proto --python_out=proto --grpc_python_out=proto context.proto python -m grpc_tools.protoc -I../../proto --python_out=proto --grpc_python_out=proto device.proto python -m grpc_tools.protoc -I../../proto --python_out=proto --grpc_python_out=proto kpi_sample_types.proto +python -m grpc_tools.protoc -I../../proto --python_out=proto --grpc_python_out=proto monitoring.proto rm proto/context_pb2_grpc.py rm proto/kpi_sample_types_pb2_grpc.py +rm proto/monitoring_pb2_grpc.py sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' proto/context_pb2.py sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' proto/device_pb2.py sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' proto/device_pb2_grpc.py +sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' proto/kpi_sample_types_pb2.py +sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' proto/monitoring_pb2.py diff --git a/src/device/proto/context_pb2.py b/src/device/proto/context_pb2.py index 658c58897615b33a435c7004d05b0a291abf95b7..8b4848bc33bfb0eba76590c8a3a627b2db84ca9f 100644 --- a/src/device/proto/context_pb2.py +++ b/src/device/proto/context_pb2.py @@ -12,7 +12,6 @@ from google.protobuf import symbol_database as _symbol_database _sym_db = _symbol_database.Default() -from . import kpi_sample_types_pb2 as kpi__sample__types__pb2 DESCRIPTOR = _descriptor.FileDescriptor( @@ -21,9 +20,8 @@ DESCRIPTOR = _descriptor.FileDescriptor( syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\rcontext.proto\x12\x07\x63ontext\x1a\x16kpi_sample_types.proto\"\x07\n\x05\x45mpty\"\x14\n\x04Uuid\x12\x0c\n\x04uuid\x18\x01 \x01(\t\"F\n\x05\x45vent\x12\x11\n\ttimestamp\x18\x01 \x01(\x01\x12*\n\nevent_type\x18\x02 \x01(\x0e\x32\x16.context.EventTypeEnum\"0\n\tContextId\x12#\n\x0c\x63ontext_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\xb6\x01\n\x07\x43ontext\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12)\n\x0ctopology_ids\x18\x02 \x03(\x0b\x32\x13.context.TopologyId\x12\'\n\x0bservice_ids\x18\x03 \x03(\x0b\x32\x12.context.ServiceId\x12/\n\ncontroller\x18\x04 \x01(\x0b\x32\x1b.context.TeraFlowController\"8\n\rContextIdList\x12\'\n\x0b\x63ontext_ids\x18\x01 \x03(\x0b\x32\x12.context.ContextId\"1\n\x0b\x43ontextList\x12\"\n\x08\x63ontexts\x18\x01 \x03(\x0b\x32\x10.context.Context\"U\n\x0c\x43ontextEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12&\n\ncontext_id\x18\x02 \x01(\x0b\x32\x12.context.ContextId\"Z\n\nTopologyId\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12$\n\rtopology_uuid\x18\x02 \x01(\x0b\x32\r.context.Uuid\"~\n\x08Topology\x12(\n\x0btopology_id\x18\x01 \x01(\x0b\x32\x13.context.TopologyId\x12%\n\ndevice_ids\x18\x02 \x03(\x0b\x32\x11.context.DeviceId\x12!\n\x08link_ids\x18\x03 \x03(\x0b\x32\x0f.context.LinkId\";\n\x0eTopologyIdList\x12)\n\x0ctopology_ids\x18\x01 \x03(\x0b\x32\x13.context.TopologyId\"5\n\x0cTopologyList\x12%\n\ntopologies\x18\x01 \x03(\x0b\x32\x11.context.Topology\"X\n\rTopologyEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12(\n\x0btopology_id\x18\x02 \x01(\x0b\x32\x13.context.TopologyId\".\n\x08\x44\x65viceId\x12\"\n\x0b\x64\x65vice_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\x9a\x02\n\x06\x44\x65vice\x12$\n\tdevice_id\x18\x01 \x01(\x0b\x32\x11.context.DeviceId\x12\x13\n\x0b\x64\x65vice_type\x18\x02 \x01(\t\x12,\n\rdevice_config\x18\x03 \x01(\x0b\x32\x15.context.DeviceConfig\x12G\n\x19\x64\x65vice_operational_status\x18\x04 \x01(\x0e\x32$.context.DeviceOperationalStatusEnum\x12\x31\n\x0e\x64\x65vice_drivers\x18\x05 \x03(\x0e\x32\x19.context.DeviceDriverEnum\x12+\n\x10\x64\x65vice_endpoints\x18\x06 \x03(\x0b\x32\x11.context.EndPoint\"9\n\x0c\x44\x65viceConfig\x12)\n\x0c\x63onfig_rules\x18\x01 \x03(\x0b\x32\x13.context.ConfigRule\"5\n\x0c\x44\x65viceIdList\x12%\n\ndevice_ids\x18\x01 \x03(\x0b\x32\x11.context.DeviceId\".\n\nDeviceList\x12 \n\x07\x64\x65vices\x18\x01 \x03(\x0b\x32\x0f.context.Device\"R\n\x0b\x44\x65viceEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12$\n\tdevice_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\"*\n\x06LinkId\x12 \n\tlink_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"X\n\x04Link\x12 \n\x07link_id\x18\x01 \x01(\x0b\x32\x0f.context.LinkId\x12.\n\x11link_endpoint_ids\x18\x02 \x03(\x0b\x32\x13.context.EndPointId\"/\n\nLinkIdList\x12!\n\x08link_ids\x18\x01 \x03(\x0b\x32\x0f.context.LinkId\"(\n\x08LinkList\x12\x1c\n\x05links\x18\x01 \x03(\x0b\x32\r.context.Link\"L\n\tLinkEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12 \n\x07link_id\x18\x02 \x01(\x0b\x32\x0f.context.LinkId\"X\n\tServiceId\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12#\n\x0cservice_uuid\x18\x02 \x01(\x0b\x32\r.context.Uuid\"\xa6\x02\n\x07Service\x12&\n\nservice_id\x18\x01 \x01(\x0b\x32\x12.context.ServiceId\x12.\n\x0cservice_type\x18\x02 \x01(\x0e\x32\x18.context.ServiceTypeEnum\x12\x31\n\x14service_endpoint_ids\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\x12\x30\n\x13service_constraints\x18\x04 \x03(\x0b\x32\x13.context.Constraint\x12.\n\x0eservice_status\x18\x05 \x01(\x0b\x32\x16.context.ServiceStatus\x12.\n\x0eservice_config\x18\x06 \x01(\x0b\x32\x16.context.ServiceConfig\"C\n\rServiceStatus\x12\x32\n\x0eservice_status\x18\x01 \x01(\x0e\x32\x1a.context.ServiceStatusEnum\":\n\rServiceConfig\x12)\n\x0c\x63onfig_rules\x18\x01 \x03(\x0b\x32\x13.context.ConfigRule\"8\n\rServiceIdList\x12\'\n\x0bservice_ids\x18\x01 \x03(\x0b\x32\x12.context.ServiceId\"1\n\x0bServiceList\x12\"\n\x08services\x18\x01 \x03(\x0b\x32\x10.context.Service\"U\n\x0cServiceEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12&\n\nservice_id\x18\x02 \x01(\x0b\x32\x12.context.ServiceId\"\x82\x01\n\nEndPointId\x12(\n\x0btopology_id\x18\x01 \x01(\x0b\x32\x13.context.TopologyId\x12$\n\tdevice_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\x12$\n\rendpoint_uuid\x18\x03 \x01(\x0b\x32\r.context.Uuid\"K\n\x08\x45ndPoint\x12(\n\x0b\x65ndpoint_id\x18\x01 \x01(\x0b\x32\x13.context.EndPointId\x12\x15\n\rendpoint_type\x18\x02 \x01(\t\"\x9f\x01\n\nConfigRule\x12)\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x19.context.ConfigActionEnum\x12\x14\n\x0cresource_key\x18\x02 \x01(\t\x12\x16\n\x0eresource_value\x18\x03 \x01(\t\x12\x38\n\x0fkpi_sample_type\x18\x04 \x01(\x0e\x32\x1f.kpi_sample_types.KpiSampleType\"?\n\nConstraint\x12\x17\n\x0f\x63onstraint_type\x18\x01 \x01(\t\x12\x18\n\x10\x63onstraint_value\x18\x02 \x01(\t\"6\n\x0c\x43onnectionId\x12&\n\x0f\x63onnection_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\x8d\x01\n\nConnection\x12,\n\rconnection_id\x18\x01 \x01(\x0b\x32\x15.context.ConnectionId\x12.\n\x12related_service_id\x18\x02 \x01(\x0b\x32\x12.context.ServiceId\x12!\n\x04path\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\"A\n\x10\x43onnectionIdList\x12-\n\x0e\x63onnection_ids\x18\x01 \x03(\x0b\x32\x15.context.ConnectionId\":\n\x0e\x43onnectionList\x12(\n\x0b\x63onnections\x18\x01 \x03(\x0b\x32\x13.context.Connection\"^\n\x12TeraFlowController\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x12\n\nip_address\x18\x02 \x01(\t\x12\x0c\n\x04port\x18\x03 \x01(\r\"U\n\x14\x41uthenticationResult\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x15\n\rauthenticated\x18\x02 \x01(\x08*j\n\rEventTypeEnum\x12\x17\n\x13\x45VENTTYPE_UNDEFINED\x10\x00\x12\x14\n\x10\x45VENTTYPE_CREATE\x10\x01\x12\x14\n\x10\x45VENTTYPE_UPDATE\x10\x02\x12\x14\n\x10\x45VENTTYPE_REMOVE\x10\x03*\xc5\x01\n\x10\x44\x65viceDriverEnum\x12\x1a\n\x16\x44\x45VICEDRIVER_UNDEFINED\x10\x00\x12\x1b\n\x17\x44\x45VICEDRIVER_OPENCONFIG\x10\x01\x12\x1e\n\x1a\x44\x45VICEDRIVER_TRANSPORT_API\x10\x02\x12\x13\n\x0f\x44\x45VICEDRIVER_P4\x10\x03\x12&\n\"DEVICEDRIVER_IETF_NETWORK_TOPOLOGY\x10\x04\x12\x1b\n\x17\x44\x45VICEDRIVER_ONF_TR_352\x10\x05*\x8f\x01\n\x1b\x44\x65viceOperationalStatusEnum\x12%\n!DEVICEOPERATIONALSTATUS_UNDEFINED\x10\x00\x12$\n DEVICEOPERATIONALSTATUS_DISABLED\x10\x01\x12#\n\x1f\x44\x45VICEOPERATIONALSTATUS_ENABLED\x10\x02*\x81\x01\n\x0fServiceTypeEnum\x12\x17\n\x13SERVICETYPE_UNKNOWN\x10\x00\x12\x14\n\x10SERVICETYPE_L3NM\x10\x01\x12\x14\n\x10SERVICETYPE_L2NM\x10\x02\x12)\n%SERVICETYPE_TAPI_CONNECTIVITY_SERVICE\x10\x03*\x88\x01\n\x11ServiceStatusEnum\x12\x1b\n\x17SERVICESTATUS_UNDEFINED\x10\x00\x12\x19\n\x15SERVICESTATUS_PLANNED\x10\x01\x12\x18\n\x14SERVICESTATUS_ACTIVE\x10\x02\x12!\n\x1dSERVICESTATUS_PENDING_REMOVAL\x10\x03*]\n\x10\x43onfigActionEnum\x12\x1a\n\x16\x43ONFIGACTION_UNDEFINED\x10\x00\x12\x14\n\x10\x43ONFIGACTION_SET\x10\x01\x12\x17\n\x13\x43ONFIGACTION_DELETE\x10\x02\x32\xa5\r\n\x0e\x43ontextService\x12:\n\x0eListContextIds\x12\x0e.context.Empty\x1a\x16.context.ContextIdList\"\x00\x12\x36\n\x0cListContexts\x12\x0e.context.Empty\x1a\x14.context.ContextList\"\x00\x12\x34\n\nGetContext\x12\x12.context.ContextId\x1a\x10.context.Context\"\x00\x12\x34\n\nSetContext\x12\x10.context.Context\x1a\x12.context.ContextId\"\x00\x12\x35\n\rRemoveContext\x12\x12.context.ContextId\x1a\x0e.context.Empty\"\x00\x12=\n\x10GetContextEvents\x12\x0e.context.Empty\x1a\x15.context.ContextEvent\"\x00\x30\x01\x12@\n\x0fListTopologyIds\x12\x12.context.ContextId\x1a\x17.context.TopologyIdList\"\x00\x12=\n\x0eListTopologies\x12\x12.context.ContextId\x1a\x15.context.TopologyList\"\x00\x12\x37\n\x0bGetTopology\x12\x13.context.TopologyId\x1a\x11.context.Topology\"\x00\x12\x37\n\x0bSetTopology\x12\x11.context.Topology\x1a\x13.context.TopologyId\"\x00\x12\x37\n\x0eRemoveTopology\x12\x13.context.TopologyId\x1a\x0e.context.Empty\"\x00\x12?\n\x11GetTopologyEvents\x12\x0e.context.Empty\x1a\x16.context.TopologyEvent\"\x00\x30\x01\x12\x38\n\rListDeviceIds\x12\x0e.context.Empty\x1a\x15.context.DeviceIdList\"\x00\x12\x34\n\x0bListDevices\x12\x0e.context.Empty\x1a\x13.context.DeviceList\"\x00\x12\x31\n\tGetDevice\x12\x11.context.DeviceId\x1a\x0f.context.Device\"\x00\x12\x31\n\tSetDevice\x12\x0f.context.Device\x1a\x11.context.DeviceId\"\x00\x12\x33\n\x0cRemoveDevice\x12\x11.context.DeviceId\x1a\x0e.context.Empty\"\x00\x12;\n\x0fGetDeviceEvents\x12\x0e.context.Empty\x1a\x14.context.DeviceEvent\"\x00\x30\x01\x12\x34\n\x0bListLinkIds\x12\x0e.context.Empty\x1a\x13.context.LinkIdList\"\x00\x12\x30\n\tListLinks\x12\x0e.context.Empty\x1a\x11.context.LinkList\"\x00\x12+\n\x07GetLink\x12\x0f.context.LinkId\x1a\r.context.Link\"\x00\x12+\n\x07SetLink\x12\r.context.Link\x1a\x0f.context.LinkId\"\x00\x12/\n\nRemoveLink\x12\x0f.context.LinkId\x1a\x0e.context.Empty\"\x00\x12\x37\n\rGetLinkEvents\x12\x0e.context.Empty\x1a\x12.context.LinkEvent\"\x00\x30\x01\x12>\n\x0eListServiceIds\x12\x12.context.ContextId\x1a\x16.context.ServiceIdList\"\x00\x12:\n\x0cListServices\x12\x12.context.ContextId\x1a\x14.context.ServiceList\"\x00\x12\x34\n\nGetService\x12\x12.context.ServiceId\x1a\x10.context.Service\"\x00\x12\x34\n\nSetService\x12\x10.context.Service\x1a\x12.context.ServiceId\"\x00\x12\x35\n\rRemoveService\x12\x12.context.ServiceId\x1a\x0e.context.Empty\"\x00\x12=\n\x10GetServiceEvents\x12\x0e.context.Empty\x1a\x15.context.ServiceEvent\"\x00\x30\x01\x62\x06proto3' - , - dependencies=[kpi__sample__types__pb2.DESCRIPTOR,]) + serialized_pb=b'\n\rcontext.proto\x12\x07\x63ontext\"\x07\n\x05\x45mpty\"\x14\n\x04Uuid\x12\x0c\n\x04uuid\x18\x01 \x01(\t\"F\n\x05\x45vent\x12\x11\n\ttimestamp\x18\x01 \x01(\x01\x12*\n\nevent_type\x18\x02 \x01(\x0e\x32\x16.context.EventTypeEnum\"0\n\tContextId\x12#\n\x0c\x63ontext_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\xb6\x01\n\x07\x43ontext\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12)\n\x0ctopology_ids\x18\x02 \x03(\x0b\x32\x13.context.TopologyId\x12\'\n\x0bservice_ids\x18\x03 \x03(\x0b\x32\x12.context.ServiceId\x12/\n\ncontroller\x18\x04 \x01(\x0b\x32\x1b.context.TeraFlowController\"8\n\rContextIdList\x12\'\n\x0b\x63ontext_ids\x18\x01 \x03(\x0b\x32\x12.context.ContextId\"1\n\x0b\x43ontextList\x12\"\n\x08\x63ontexts\x18\x01 \x03(\x0b\x32\x10.context.Context\"U\n\x0c\x43ontextEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12&\n\ncontext_id\x18\x02 \x01(\x0b\x32\x12.context.ContextId\"Z\n\nTopologyId\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12$\n\rtopology_uuid\x18\x02 \x01(\x0b\x32\r.context.Uuid\"~\n\x08Topology\x12(\n\x0btopology_id\x18\x01 \x01(\x0b\x32\x13.context.TopologyId\x12%\n\ndevice_ids\x18\x02 \x03(\x0b\x32\x11.context.DeviceId\x12!\n\x08link_ids\x18\x03 \x03(\x0b\x32\x0f.context.LinkId\";\n\x0eTopologyIdList\x12)\n\x0ctopology_ids\x18\x01 \x03(\x0b\x32\x13.context.TopologyId\"5\n\x0cTopologyList\x12%\n\ntopologies\x18\x01 \x03(\x0b\x32\x11.context.Topology\"X\n\rTopologyEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12(\n\x0btopology_id\x18\x02 \x01(\x0b\x32\x13.context.TopologyId\".\n\x08\x44\x65viceId\x12\"\n\x0b\x64\x65vice_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\x9a\x02\n\x06\x44\x65vice\x12$\n\tdevice_id\x18\x01 \x01(\x0b\x32\x11.context.DeviceId\x12\x13\n\x0b\x64\x65vice_type\x18\x02 \x01(\t\x12,\n\rdevice_config\x18\x03 \x01(\x0b\x32\x15.context.DeviceConfig\x12G\n\x19\x64\x65vice_operational_status\x18\x04 \x01(\x0e\x32$.context.DeviceOperationalStatusEnum\x12\x31\n\x0e\x64\x65vice_drivers\x18\x05 \x03(\x0e\x32\x19.context.DeviceDriverEnum\x12+\n\x10\x64\x65vice_endpoints\x18\x06 \x03(\x0b\x32\x11.context.EndPoint\"9\n\x0c\x44\x65viceConfig\x12)\n\x0c\x63onfig_rules\x18\x01 \x03(\x0b\x32\x13.context.ConfigRule\"5\n\x0c\x44\x65viceIdList\x12%\n\ndevice_ids\x18\x01 \x03(\x0b\x32\x11.context.DeviceId\".\n\nDeviceList\x12 \n\x07\x64\x65vices\x18\x01 \x03(\x0b\x32\x0f.context.Device\"R\n\x0b\x44\x65viceEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12$\n\tdevice_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\"*\n\x06LinkId\x12 \n\tlink_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"X\n\x04Link\x12 \n\x07link_id\x18\x01 \x01(\x0b\x32\x0f.context.LinkId\x12.\n\x11link_endpoint_ids\x18\x02 \x03(\x0b\x32\x13.context.EndPointId\"/\n\nLinkIdList\x12!\n\x08link_ids\x18\x01 \x03(\x0b\x32\x0f.context.LinkId\"(\n\x08LinkList\x12\x1c\n\x05links\x18\x01 \x03(\x0b\x32\r.context.Link\"L\n\tLinkEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12 \n\x07link_id\x18\x02 \x01(\x0b\x32\x0f.context.LinkId\"X\n\tServiceId\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12#\n\x0cservice_uuid\x18\x02 \x01(\x0b\x32\r.context.Uuid\"\xa6\x02\n\x07Service\x12&\n\nservice_id\x18\x01 \x01(\x0b\x32\x12.context.ServiceId\x12.\n\x0cservice_type\x18\x02 \x01(\x0e\x32\x18.context.ServiceTypeEnum\x12\x31\n\x14service_endpoint_ids\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\x12\x30\n\x13service_constraints\x18\x04 \x03(\x0b\x32\x13.context.Constraint\x12.\n\x0eservice_status\x18\x05 \x01(\x0b\x32\x16.context.ServiceStatus\x12.\n\x0eservice_config\x18\x06 \x01(\x0b\x32\x16.context.ServiceConfig\"C\n\rServiceStatus\x12\x32\n\x0eservice_status\x18\x01 \x01(\x0e\x32\x1a.context.ServiceStatusEnum\":\n\rServiceConfig\x12)\n\x0c\x63onfig_rules\x18\x01 \x03(\x0b\x32\x13.context.ConfigRule\"8\n\rServiceIdList\x12\'\n\x0bservice_ids\x18\x01 \x03(\x0b\x32\x12.context.ServiceId\"1\n\x0bServiceList\x12\"\n\x08services\x18\x01 \x03(\x0b\x32\x10.context.Service\"U\n\x0cServiceEvent\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.context.Event\x12&\n\nservice_id\x18\x02 \x01(\x0b\x32\x12.context.ServiceId\"\x82\x01\n\nEndPointId\x12(\n\x0btopology_id\x18\x01 \x01(\x0b\x32\x13.context.TopologyId\x12$\n\tdevice_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\x12$\n\rendpoint_uuid\x18\x03 \x01(\x0b\x32\r.context.Uuid\"K\n\x08\x45ndPoint\x12(\n\x0b\x65ndpoint_id\x18\x01 \x01(\x0b\x32\x13.context.EndPointId\x12\x15\n\rendpoint_type\x18\x02 \x01(\t\"e\n\nConfigRule\x12)\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x19.context.ConfigActionEnum\x12\x14\n\x0cresource_key\x18\x02 \x01(\t\x12\x16\n\x0eresource_value\x18\x03 \x01(\t\"?\n\nConstraint\x12\x17\n\x0f\x63onstraint_type\x18\x01 \x01(\t\x12\x18\n\x10\x63onstraint_value\x18\x02 \x01(\t\"6\n\x0c\x43onnectionId\x12&\n\x0f\x63onnection_uuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\x8d\x01\n\nConnection\x12,\n\rconnection_id\x18\x01 \x01(\x0b\x32\x15.context.ConnectionId\x12.\n\x12related_service_id\x18\x02 \x01(\x0b\x32\x12.context.ServiceId\x12!\n\x04path\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\"A\n\x10\x43onnectionIdList\x12-\n\x0e\x63onnection_ids\x18\x01 \x03(\x0b\x32\x15.context.ConnectionId\":\n\x0e\x43onnectionList\x12(\n\x0b\x63onnections\x18\x01 \x03(\x0b\x32\x13.context.Connection\"^\n\x12TeraFlowController\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x12\n\nip_address\x18\x02 \x01(\t\x12\x0c\n\x04port\x18\x03 \x01(\r\"U\n\x14\x41uthenticationResult\x12&\n\ncontext_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x15\n\rauthenticated\x18\x02 \x01(\x08*j\n\rEventTypeEnum\x12\x17\n\x13\x45VENTTYPE_UNDEFINED\x10\x00\x12\x14\n\x10\x45VENTTYPE_CREATE\x10\x01\x12\x14\n\x10\x45VENTTYPE_UPDATE\x10\x02\x12\x14\n\x10\x45VENTTYPE_REMOVE\x10\x03*\xc5\x01\n\x10\x44\x65viceDriverEnum\x12\x1a\n\x16\x44\x45VICEDRIVER_UNDEFINED\x10\x00\x12\x1b\n\x17\x44\x45VICEDRIVER_OPENCONFIG\x10\x01\x12\x1e\n\x1a\x44\x45VICEDRIVER_TRANSPORT_API\x10\x02\x12\x13\n\x0f\x44\x45VICEDRIVER_P4\x10\x03\x12&\n\"DEVICEDRIVER_IETF_NETWORK_TOPOLOGY\x10\x04\x12\x1b\n\x17\x44\x45VICEDRIVER_ONF_TR_352\x10\x05*\x8f\x01\n\x1b\x44\x65viceOperationalStatusEnum\x12%\n!DEVICEOPERATIONALSTATUS_UNDEFINED\x10\x00\x12$\n DEVICEOPERATIONALSTATUS_DISABLED\x10\x01\x12#\n\x1f\x44\x45VICEOPERATIONALSTATUS_ENABLED\x10\x02*\x81\x01\n\x0fServiceTypeEnum\x12\x17\n\x13SERVICETYPE_UNKNOWN\x10\x00\x12\x14\n\x10SERVICETYPE_L3NM\x10\x01\x12\x14\n\x10SERVICETYPE_L2NM\x10\x02\x12)\n%SERVICETYPE_TAPI_CONNECTIVITY_SERVICE\x10\x03*\x88\x01\n\x11ServiceStatusEnum\x12\x1b\n\x17SERVICESTATUS_UNDEFINED\x10\x00\x12\x19\n\x15SERVICESTATUS_PLANNED\x10\x01\x12\x18\n\x14SERVICESTATUS_ACTIVE\x10\x02\x12!\n\x1dSERVICESTATUS_PENDING_REMOVAL\x10\x03*]\n\x10\x43onfigActionEnum\x12\x1a\n\x16\x43ONFIGACTION_UNDEFINED\x10\x00\x12\x14\n\x10\x43ONFIGACTION_SET\x10\x01\x12\x17\n\x13\x43ONFIGACTION_DELETE\x10\x02\x32\xa5\r\n\x0e\x43ontextService\x12:\n\x0eListContextIds\x12\x0e.context.Empty\x1a\x16.context.ContextIdList\"\x00\x12\x36\n\x0cListContexts\x12\x0e.context.Empty\x1a\x14.context.ContextList\"\x00\x12\x34\n\nGetContext\x12\x12.context.ContextId\x1a\x10.context.Context\"\x00\x12\x34\n\nSetContext\x12\x10.context.Context\x1a\x12.context.ContextId\"\x00\x12\x35\n\rRemoveContext\x12\x12.context.ContextId\x1a\x0e.context.Empty\"\x00\x12=\n\x10GetContextEvents\x12\x0e.context.Empty\x1a\x15.context.ContextEvent\"\x00\x30\x01\x12@\n\x0fListTopologyIds\x12\x12.context.ContextId\x1a\x17.context.TopologyIdList\"\x00\x12=\n\x0eListTopologies\x12\x12.context.ContextId\x1a\x15.context.TopologyList\"\x00\x12\x37\n\x0bGetTopology\x12\x13.context.TopologyId\x1a\x11.context.Topology\"\x00\x12\x37\n\x0bSetTopology\x12\x11.context.Topology\x1a\x13.context.TopologyId\"\x00\x12\x37\n\x0eRemoveTopology\x12\x13.context.TopologyId\x1a\x0e.context.Empty\"\x00\x12?\n\x11GetTopologyEvents\x12\x0e.context.Empty\x1a\x16.context.TopologyEvent\"\x00\x30\x01\x12\x38\n\rListDeviceIds\x12\x0e.context.Empty\x1a\x15.context.DeviceIdList\"\x00\x12\x34\n\x0bListDevices\x12\x0e.context.Empty\x1a\x13.context.DeviceList\"\x00\x12\x31\n\tGetDevice\x12\x11.context.DeviceId\x1a\x0f.context.Device\"\x00\x12\x31\n\tSetDevice\x12\x0f.context.Device\x1a\x11.context.DeviceId\"\x00\x12\x33\n\x0cRemoveDevice\x12\x11.context.DeviceId\x1a\x0e.context.Empty\"\x00\x12;\n\x0fGetDeviceEvents\x12\x0e.context.Empty\x1a\x14.context.DeviceEvent\"\x00\x30\x01\x12\x34\n\x0bListLinkIds\x12\x0e.context.Empty\x1a\x13.context.LinkIdList\"\x00\x12\x30\n\tListLinks\x12\x0e.context.Empty\x1a\x11.context.LinkList\"\x00\x12+\n\x07GetLink\x12\x0f.context.LinkId\x1a\r.context.Link\"\x00\x12+\n\x07SetLink\x12\r.context.Link\x1a\x0f.context.LinkId\"\x00\x12/\n\nRemoveLink\x12\x0f.context.LinkId\x1a\x0e.context.Empty\"\x00\x12\x37\n\rGetLinkEvents\x12\x0e.context.Empty\x1a\x12.context.LinkEvent\"\x00\x30\x01\x12>\n\x0eListServiceIds\x12\x12.context.ContextId\x1a\x16.context.ServiceIdList\"\x00\x12:\n\x0cListServices\x12\x12.context.ContextId\x1a\x14.context.ServiceList\"\x00\x12\x34\n\nGetService\x12\x12.context.ServiceId\x1a\x10.context.Service\"\x00\x12\x34\n\nSetService\x12\x10.context.Service\x1a\x12.context.ServiceId\"\x00\x12\x35\n\rRemoveService\x12\x12.context.ServiceId\x1a\x0e.context.Empty\"\x00\x12=\n\x10GetServiceEvents\x12\x0e.context.Empty\x1a\x15.context.ServiceEvent\"\x00\x30\x01\x62\x06proto3' +) _EVENTTYPEENUM = _descriptor.EnumDescriptor( name='EventTypeEnum', @@ -55,8 +53,8 @@ _EVENTTYPEENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=3551, - serialized_end=3657, + serialized_start=3468, + serialized_end=3574, ) _sym_db.RegisterEnumDescriptor(_EVENTTYPEENUM) @@ -101,8 +99,8 @@ _DEVICEDRIVERENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=3660, - serialized_end=3857, + serialized_start=3577, + serialized_end=3774, ) _sym_db.RegisterEnumDescriptor(_DEVICEDRIVERENUM) @@ -132,8 +130,8 @@ _DEVICEOPERATIONALSTATUSENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=3860, - serialized_end=4003, + serialized_start=3777, + serialized_end=3920, ) _sym_db.RegisterEnumDescriptor(_DEVICEOPERATIONALSTATUSENUM) @@ -168,8 +166,8 @@ _SERVICETYPEENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=4006, - serialized_end=4135, + serialized_start=3923, + serialized_end=4052, ) _sym_db.RegisterEnumDescriptor(_SERVICETYPEENUM) @@ -204,8 +202,8 @@ _SERVICESTATUSENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=4138, - serialized_end=4274, + serialized_start=4055, + serialized_end=4191, ) _sym_db.RegisterEnumDescriptor(_SERVICESTATUSENUM) @@ -235,8 +233,8 @@ _CONFIGACTIONENUM = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=4276, - serialized_end=4369, + serialized_start=4193, + serialized_end=4286, ) _sym_db.RegisterEnumDescriptor(_CONFIGACTIONENUM) @@ -288,8 +286,8 @@ _EMPTY = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=50, - serialized_end=57, + serialized_start=26, + serialized_end=33, ) @@ -320,8 +318,8 @@ _UUID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=59, - serialized_end=79, + serialized_start=35, + serialized_end=55, ) @@ -359,8 +357,8 @@ _EVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=81, - serialized_end=151, + serialized_start=57, + serialized_end=127, ) @@ -391,8 +389,8 @@ _CONTEXTID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=153, - serialized_end=201, + serialized_start=129, + serialized_end=177, ) @@ -444,8 +442,8 @@ _CONTEXT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=204, - serialized_end=386, + serialized_start=180, + serialized_end=362, ) @@ -476,8 +474,8 @@ _CONTEXTIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=388, - serialized_end=444, + serialized_start=364, + serialized_end=420, ) @@ -508,8 +506,8 @@ _CONTEXTLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=446, - serialized_end=495, + serialized_start=422, + serialized_end=471, ) @@ -547,8 +545,8 @@ _CONTEXTEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=497, - serialized_end=582, + serialized_start=473, + serialized_end=558, ) @@ -586,8 +584,8 @@ _TOPOLOGYID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=584, - serialized_end=674, + serialized_start=560, + serialized_end=650, ) @@ -632,8 +630,8 @@ _TOPOLOGY = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=676, - serialized_end=802, + serialized_start=652, + serialized_end=778, ) @@ -664,8 +662,8 @@ _TOPOLOGYIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=804, - serialized_end=863, + serialized_start=780, + serialized_end=839, ) @@ -696,8 +694,8 @@ _TOPOLOGYLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=865, - serialized_end=918, + serialized_start=841, + serialized_end=894, ) @@ -735,8 +733,8 @@ _TOPOLOGYEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=920, - serialized_end=1008, + serialized_start=896, + serialized_end=984, ) @@ -767,8 +765,8 @@ _DEVICEID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1010, - serialized_end=1056, + serialized_start=986, + serialized_end=1032, ) @@ -834,8 +832,8 @@ _DEVICE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1059, - serialized_end=1341, + serialized_start=1035, + serialized_end=1317, ) @@ -866,8 +864,8 @@ _DEVICECONFIG = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1343, - serialized_end=1400, + serialized_start=1319, + serialized_end=1376, ) @@ -898,8 +896,8 @@ _DEVICEIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1402, - serialized_end=1455, + serialized_start=1378, + serialized_end=1431, ) @@ -930,8 +928,8 @@ _DEVICELIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1457, - serialized_end=1503, + serialized_start=1433, + serialized_end=1479, ) @@ -969,8 +967,8 @@ _DEVICEEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1505, - serialized_end=1587, + serialized_start=1481, + serialized_end=1563, ) @@ -1001,8 +999,8 @@ _LINKID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1589, - serialized_end=1631, + serialized_start=1565, + serialized_end=1607, ) @@ -1040,8 +1038,8 @@ _LINK = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1633, - serialized_end=1721, + serialized_start=1609, + serialized_end=1697, ) @@ -1072,8 +1070,8 @@ _LINKIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1723, - serialized_end=1770, + serialized_start=1699, + serialized_end=1746, ) @@ -1104,8 +1102,8 @@ _LINKLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1772, - serialized_end=1812, + serialized_start=1748, + serialized_end=1788, ) @@ -1143,8 +1141,8 @@ _LINKEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1814, - serialized_end=1890, + serialized_start=1790, + serialized_end=1866, ) @@ -1182,8 +1180,8 @@ _SERVICEID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1892, - serialized_end=1980, + serialized_start=1868, + serialized_end=1956, ) @@ -1249,8 +1247,8 @@ _SERVICE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1983, - serialized_end=2277, + serialized_start=1959, + serialized_end=2253, ) @@ -1281,8 +1279,8 @@ _SERVICESTATUS = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2279, - serialized_end=2346, + serialized_start=2255, + serialized_end=2322, ) @@ -1313,8 +1311,8 @@ _SERVICECONFIG = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2348, - serialized_end=2406, + serialized_start=2324, + serialized_end=2382, ) @@ -1345,8 +1343,8 @@ _SERVICEIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2408, - serialized_end=2464, + serialized_start=2384, + serialized_end=2440, ) @@ -1377,8 +1375,8 @@ _SERVICELIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2466, - serialized_end=2515, + serialized_start=2442, + serialized_end=2491, ) @@ -1416,8 +1414,8 @@ _SERVICEEVENT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2517, - serialized_end=2602, + serialized_start=2493, + serialized_end=2578, ) @@ -1462,8 +1460,8 @@ _ENDPOINTID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2605, - serialized_end=2735, + serialized_start=2581, + serialized_end=2711, ) @@ -1501,8 +1499,8 @@ _ENDPOINT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2737, - serialized_end=2812, + serialized_start=2713, + serialized_end=2788, ) @@ -1535,13 +1533,6 @@ _CONFIGRULE = _descriptor.Descriptor( message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='kpi_sample_type', full_name='context.ConfigRule.kpi_sample_type', index=3, - number=4, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -1554,8 +1545,8 @@ _CONFIGRULE = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2815, - serialized_end=2974, + serialized_start=2790, + serialized_end=2891, ) @@ -1593,8 +1584,8 @@ _CONSTRAINT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=2976, - serialized_end=3039, + serialized_start=2893, + serialized_end=2956, ) @@ -1625,8 +1616,8 @@ _CONNECTIONID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3041, - serialized_end=3095, + serialized_start=2958, + serialized_end=3012, ) @@ -1671,8 +1662,8 @@ _CONNECTION = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3098, - serialized_end=3239, + serialized_start=3015, + serialized_end=3156, ) @@ -1703,8 +1694,8 @@ _CONNECTIONIDLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3241, - serialized_end=3306, + serialized_start=3158, + serialized_end=3223, ) @@ -1735,8 +1726,8 @@ _CONNECTIONLIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3308, - serialized_end=3366, + serialized_start=3225, + serialized_end=3283, ) @@ -1781,8 +1772,8 @@ _TERAFLOWCONTROLLER = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3368, - serialized_end=3462, + serialized_start=3285, + serialized_end=3379, ) @@ -1820,8 +1811,8 @@ _AUTHENTICATIONRESULT = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=3464, - serialized_end=3549, + serialized_start=3381, + serialized_end=3466, ) _EVENT.fields_by_name['event_type'].enum_type = _EVENTTYPEENUM @@ -1880,7 +1871,6 @@ _ENDPOINTID.fields_by_name['device_id'].message_type = _DEVICEID _ENDPOINTID.fields_by_name['endpoint_uuid'].message_type = _UUID _ENDPOINT.fields_by_name['endpoint_id'].message_type = _ENDPOINTID _CONFIGRULE.fields_by_name['action'].enum_type = _CONFIGACTIONENUM -_CONFIGRULE.fields_by_name['kpi_sample_type'].enum_type = kpi__sample__types__pb2._KPISAMPLETYPE _CONNECTIONID.fields_by_name['connection_uuid'].message_type = _UUID _CONNECTION.fields_by_name['connection_id'].message_type = _CONNECTIONID _CONNECTION.fields_by_name['related_service_id'].message_type = _SERVICEID @@ -2234,8 +2224,8 @@ _CONTEXTSERVICE = _descriptor.ServiceDescriptor( index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=4372, - serialized_end=6073, + serialized_start=4289, + serialized_end=5990, methods=[ _descriptor.MethodDescriptor( name='ListContextIds', diff --git a/src/device/proto/device_pb2.py b/src/device/proto/device_pb2.py index 4d4dbb82567256dd79595884f0ed9c2f13498d31..e351738e6ac1ea9dadf4310897a979ab38db669b 100644 --- a/src/device/proto/device_pb2.py +++ b/src/device/proto/device_pb2.py @@ -12,7 +12,6 @@ _sym_db = _symbol_database.Default() from . import context_pb2 as context__pb2 -from . import monitoring_pb2 as monitoring__pb2 DESCRIPTOR = _descriptor.FileDescriptor( @@ -21,77 +20,14 @@ DESCRIPTOR = _descriptor.FileDescriptor( syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x0c\x64\x65vice.proto\x12\x06\x64\x65vice\x1a\rcontext.proto\x1a\x10monitoring.proto\"\xa4\x01\n\x12MonitoringSettings\x12!\n\x06kpi_id\x18\x01 \x01(\x0b\x32\x11.monitoring.KpiId\x12\x31\n\x0ekpi_descriptor\x18\x02 \x01(\x0b\x32\x19.monitoring.KpiDescriptor\x12\x1b\n\x13sampling_duration_s\x18\x03 \x01(\x02\x12\x1b\n\x13sampling_interval_s\x18\x04 \x01(\x02\x32\xb2\x02\n\rDeviceService\x12\x31\n\tAddDevice\x12\x0f.context.Device\x1a\x11.context.DeviceId\"\x00\x12\x37\n\x0f\x43onfigureDevice\x12\x0f.context.Device\x1a\x11.context.DeviceId\"\x00\x12\x33\n\x0c\x44\x65leteDevice\x12\x11.context.DeviceId\x1a\x0e.context.Empty\"\x00\x12>\n\x10GetInitialConfig\x12\x11.context.DeviceId\x1a\x15.context.DeviceConfig\"\x00\x12@\n\x10MonitorDeviceKpi\x12\x1a.device.MonitoringSettings\x1a\x0e.context.Empty\"\x00\x62\x06proto3' + serialized_pb=b'\n\x0c\x64\x65vice.proto\x12\x06\x64\x65vice\x1a\rcontext.proto2\xf0\x01\n\rDeviceService\x12\x31\n\tAddDevice\x12\x0f.context.Device\x1a\x11.context.DeviceId\"\x00\x12\x37\n\x0f\x43onfigureDevice\x12\x0f.context.Device\x1a\x11.context.DeviceId\"\x00\x12\x33\n\x0c\x44\x65leteDevice\x12\x11.context.DeviceId\x1a\x0e.context.Empty\"\x00\x12>\n\x10GetInitialConfig\x12\x11.context.DeviceId\x1a\x15.context.DeviceConfig\"\x00\x62\x06proto3' , - dependencies=[context__pb2.DESCRIPTOR,monitoring__pb2.DESCRIPTOR,]) + dependencies=[context__pb2.DESCRIPTOR,]) - -_MONITORINGSETTINGS = _descriptor.Descriptor( - name='MonitoringSettings', - full_name='device.MonitoringSettings', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='kpi_id', full_name='device.MonitoringSettings.kpi_id', index=0, - number=1, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='kpi_descriptor', full_name='device.MonitoringSettings.kpi_descriptor', index=1, - number=2, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='sampling_duration_s', full_name='device.MonitoringSettings.sampling_duration_s', index=2, - number=3, type=2, cpp_type=6, label=1, - has_default_value=False, default_value=float(0), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='sampling_interval_s', full_name='device.MonitoringSettings.sampling_interval_s', index=3, - number=4, type=2, cpp_type=6, label=1, - has_default_value=False, default_value=float(0), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=58, - serialized_end=222, -) - -_MONITORINGSETTINGS.fields_by_name['kpi_id'].message_type = monitoring__pb2._KPIID -_MONITORINGSETTINGS.fields_by_name['kpi_descriptor'].message_type = monitoring__pb2._KPIDESCRIPTOR -DESCRIPTOR.message_types_by_name['MonitoringSettings'] = _MONITORINGSETTINGS _sym_db.RegisterFileDescriptor(DESCRIPTOR) -MonitoringSettings = _reflection.GeneratedProtocolMessageType('MonitoringSettings', (_message.Message,), { - 'DESCRIPTOR' : _MONITORINGSETTINGS, - '__module__' : 'device_pb2' - # @@protoc_insertion_point(class_scope:device.MonitoringSettings) - }) -_sym_db.RegisterMessage(MonitoringSettings) - _DEVICESERVICE = _descriptor.ServiceDescriptor( @@ -101,8 +37,8 @@ _DEVICESERVICE = _descriptor.ServiceDescriptor( index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=225, - serialized_end=531, + serialized_start=40, + serialized_end=280, methods=[ _descriptor.MethodDescriptor( name='AddDevice', @@ -144,16 +80,6 @@ _DEVICESERVICE = _descriptor.ServiceDescriptor( serialized_options=None, create_key=_descriptor._internal_create_key, ), - _descriptor.MethodDescriptor( - name='MonitorDeviceKpi', - full_name='device.DeviceService.MonitorDeviceKpi', - index=4, - containing_service=None, - input_type=_MONITORINGSETTINGS, - output_type=context__pb2._EMPTY, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), ]) _sym_db.RegisterServiceDescriptor(_DEVICESERVICE) diff --git a/src/device/proto/device_pb2_grpc.py b/src/device/proto/device_pb2_grpc.py index 2b9bfc47da3b33b632ff46a8454496a499305a6c..453aa2fcbc9296cf25298c2041433dfbb06b8e28 100644 --- a/src/device/proto/device_pb2_grpc.py +++ b/src/device/proto/device_pb2_grpc.py @@ -3,7 +3,6 @@ import grpc from . import context_pb2 as context__pb2 -from . import device_pb2 as device__pb2 class DeviceServiceStub(object): @@ -35,11 +34,6 @@ class DeviceServiceStub(object): request_serializer=context__pb2.DeviceId.SerializeToString, response_deserializer=context__pb2.DeviceConfig.FromString, ) - self.MonitorDeviceKpi = channel.unary_unary( - '/device.DeviceService/MonitorDeviceKpi', - request_serializer=device__pb2.MonitoringSettings.SerializeToString, - response_deserializer=context__pb2.Empty.FromString, - ) class DeviceServiceServicer(object): @@ -69,12 +63,6 @@ class DeviceServiceServicer(object): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') - def MonitorDeviceKpi(self, request, context): - """Missing associated documentation comment in .proto file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - def add_DeviceServiceServicer_to_server(servicer, server): rpc_method_handlers = { @@ -98,11 +86,6 @@ def add_DeviceServiceServicer_to_server(servicer, server): request_deserializer=context__pb2.DeviceId.FromString, response_serializer=context__pb2.DeviceConfig.SerializeToString, ), - 'MonitorDeviceKpi': grpc.unary_unary_rpc_method_handler( - servicer.MonitorDeviceKpi, - request_deserializer=device__pb2.MonitoringSettings.FromString, - response_serializer=context__pb2.Empty.SerializeToString, - ), } generic_handler = grpc.method_handlers_generic_handler( 'device.DeviceService', rpc_method_handlers) @@ -180,20 +163,3 @@ class DeviceService(object): context__pb2.DeviceConfig.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def MonitorDeviceKpi(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/device.DeviceService/MonitorDeviceKpi', - device__pb2.MonitoringSettings.SerializeToString, - context__pb2.Empty.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/src/device/proto/kpi_sample_types_pb2.py b/src/device/proto/kpi_sample_types_pb2.py index 31fbaa216bca629a4de4272091c490982c1aa166..ad22554ec352d0aeae644fdce00c0f28996ed73b 100644 --- a/src/device/proto/kpi_sample_types_pb2.py +++ b/src/device/proto/kpi_sample_types_pb2.py @@ -2,7 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: kpi_sample_types.proto """Generated protocol buffer code.""" -from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -16,62 +15,15 @@ _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor.FileDescriptor( name='kpi_sample_types.proto', - package='kpi_sample_types', + package='', syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x16kpi_sample_types.proto\x12\x10kpi_sample_types*x\n\rKpiSampleType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x17\n\x13PACKETS_TRANSMITTED\x10\x65\x12\x14\n\x10PACKETS_RECEIVED\x10\x66\x12\x16\n\x11\x42YTES_TRANSMITTED\x10\xc9\x01\x12\x13\n\x0e\x42YTES_RECEIVED\x10\xca\x01\x62\x06proto3' + serialized_pb=b'\n\x16kpi_sample_types.protob\x06proto3' ) -_KPISAMPLETYPE = _descriptor.EnumDescriptor( - name='KpiSampleType', - full_name='kpi_sample_types.KpiSampleType', - filename=None, - file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, - values=[ - _descriptor.EnumValueDescriptor( - name='UNKNOWN', index=0, number=0, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='PACKETS_TRANSMITTED', index=1, number=101, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='PACKETS_RECEIVED', index=2, number=102, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='BYTES_TRANSMITTED', index=3, number=201, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='BYTES_RECEIVED', index=4, number=202, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), - ], - containing_type=None, - serialized_options=None, - serialized_start=44, - serialized_end=164, -) -_sym_db.RegisterEnumDescriptor(_KPISAMPLETYPE) - -KpiSampleType = enum_type_wrapper.EnumTypeWrapper(_KPISAMPLETYPE) -UNKNOWN = 0 -PACKETS_TRANSMITTED = 101 -PACKETS_RECEIVED = 102 -BYTES_TRANSMITTED = 201 -BYTES_RECEIVED = 202 -DESCRIPTOR.enum_types_by_name['KpiSampleType'] = _KPISAMPLETYPE _sym_db.RegisterFileDescriptor(DESCRIPTOR) diff --git a/src/device/proto/monitoring_pb2.py b/src/device/proto/monitoring_pb2.py index b313ebb68f0da37a540898e8c362fd204a799076..7368609d2145f94cc3b746836a5297333151c738 100644 --- a/src/device/proto/monitoring_pb2.py +++ b/src/device/proto/monitoring_pb2.py @@ -2,6 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: monitoring.proto """Generated protocol buffer code.""" +from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -12,7 +13,6 @@ _sym_db = _symbol_database.Default() from . import context_pb2 as context__pb2 -from . import kpi_sample_types_pb2 as kpi__sample__types__pb2 DESCRIPTOR = _descriptor.FileDescriptor( @@ -21,56 +21,180 @@ DESCRIPTOR = _descriptor.FileDescriptor( syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x10monitoring.proto\x12\nmonitoring\x1a\rcontext.proto\x1a\x16kpi_sample_types.proto\"\xda\x01\n\rKpiDescriptor\x12\x17\n\x0fkpi_description\x18\x01 \x01(\t\x12\x38\n\x0fkpi_sample_type\x18\x02 \x01(\x0e\x32\x1f.kpi_sample_types.KpiSampleType\x12$\n\tdevice_id\x18\x03 \x01(\x0b\x32\x11.context.DeviceId\x12(\n\x0b\x65ndpoint_id\x18\x04 \x01(\x0b\x32\x13.context.EndPointId\x12&\n\nservice_id\x18\x05 \x01(\x0b\x32\x12.context.ServiceId\"p\n\x11MonitorKpiRequest\x12!\n\x06kpi_id\x18\x01 \x01(\x0b\x32\x11.monitoring.KpiId\x12\x1b\n\x13sampling_duration_s\x18\x02 \x01(\x02\x12\x1b\n\x13sampling_interval_s\x18\x03 \x01(\x02\"&\n\x05KpiId\x12\x1d\n\x06kpi_id\x18\x01 \x01(\x0b\x32\r.context.Uuid\"d\n\x03Kpi\x12!\n\x06kpi_id\x18\x01 \x01(\x0b\x32\x11.monitoring.KpiId\x12\x11\n\ttimestamp\x18\x02 \x01(\t\x12\'\n\tkpi_value\x18\x04 \x01(\x0b\x32\x14.monitoring.KpiValue\"a\n\x08KpiValue\x12\x10\n\x06intVal\x18\x01 \x01(\rH\x00\x12\x12\n\x08\x66loatVal\x18\x02 \x01(\x02H\x00\x12\x13\n\tstringVal\x18\x03 \x01(\tH\x00\x12\x11\n\x07\x62oolVal\x18\x04 \x01(\x08H\x00\x42\x07\n\x05value\",\n\x07KpiList\x12!\n\x08kpi_list\x18\x01 \x03(\x0b\x32\x0f.monitoring.Kpi2\xf3\x02\n\x11MonitoringService\x12;\n\tCreateKpi\x12\x19.monitoring.KpiDescriptor\x1a\x11.monitoring.KpiId\"\x00\x12\x42\n\x10GetKpiDescriptor\x12\x11.monitoring.KpiId\x1a\x19.monitoring.KpiDescriptor\"\x00\x12/\n\nIncludeKpi\x12\x0f.monitoring.Kpi\x1a\x0e.context.Empty\"\x00\x12=\n\nMonitorKpi\x12\x1d.monitoring.MonitorKpiRequest\x1a\x0e.context.Empty\"\x00\x12\x36\n\x0cGetStreamKpi\x12\x11.monitoring.KpiId\x1a\x0f.monitoring.Kpi\"\x00\x30\x01\x12\x35\n\rGetInstantKpi\x12\x11.monitoring.KpiId\x1a\x0f.monitoring.Kpi\"\x00\x62\x06proto3' + serialized_pb=b'\n\x10monitoring.proto\x12\nmonitoring\x1a\rcontext.proto\"\x84\x01\n\x10\x43reateKpiRequest\x12\x16\n\x0ekpiDescription\x18\x01 \x01(\t\x12$\n\tdevice_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\x12\x32\n\x0fkpi_sample_type\x18\x03 \x01(\x0e\x32\x19.monitoring.KpiSampleType\"h\n\x11MonitorKpiRequest\x12!\n\x06kpi_id\x18\x01 \x01(\x0b\x32\x11.monitoring.KpiId\x12\x18\n\x10\x63onnexion_time_s\x18\x02 \x01(\r\x12\x16\n\x0esample_rate_ms\x18\x03 \x01(\r\"i\n\x17MonitorDeviceKpiRequest\x12\x1c\n\x03kpi\x18\x01 \x01(\x0b\x32\x0f.monitoring.Kpi\x12\x18\n\x10\x63onnexion_time_s\x18\x02 \x01(\r\x12\x16\n\x0esample_rate_ms\x18\x03 \x01(\r\"s\n\x11IncludeKpiRequest\x12!\n\x06kpi_id\x18\x01 \x01(\x0b\x32\x11.monitoring.KpiId\x12\x12\n\ntime_stamp\x18\x02 \x01(\t\x12\'\n\tkpi_value\x18\x03 \x01(\x0b\x32\x14.monitoring.KpiValue\"&\n\x05KpiId\x12\x1d\n\x06kpi_id\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\xd6\x01\n\x03Kpi\x12!\n\x06kpi_id\x18\x01 \x01(\x0b\x32\x11.monitoring.KpiId\x12\x11\n\ttimestamp\x18\x02 \x01(\t\x12\x16\n\x0ekpiDescription\x18\x03 \x01(\t\x12\'\n\tkpi_value\x18\x04 \x01(\x0b\x32\x14.monitoring.KpiValue\x12\x32\n\x0fkpi_sample_type\x18\x05 \x01(\x0e\x32\x19.monitoring.KpiSampleType\x12$\n\tdevice_id\x18\x06 \x01(\x0b\x32\x11.context.DeviceId\"a\n\x08KpiValue\x12\x10\n\x06intVal\x18\x01 \x01(\rH\x00\x12\x12\n\x08\x66loatVal\x18\x02 \x01(\x02H\x00\x12\x13\n\tstringVal\x18\x03 \x01(\tH\x00\x12\x11\n\x07\x62oolVal\x18\x04 \x01(\x08H\x00\x42\x07\n\x05value\"+\n\x07KpiList\x12 \n\x07kpiList\x18\x01 \x03(\x0b\x32\x0f.monitoring.Kpi*x\n\rKpiSampleType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x17\n\x13PACKETS_TRANSMITTED\x10\x65\x12\x14\n\x10PACKETS_RECEIVED\x10\x66\x12\x16\n\x11\x42YTES_TRANSMITTED\x10\xc9\x01\x12\x13\n\x0e\x42YTES_RECEIVED\x10\xca\x01\x32\x8b\x03\n\x11MonitoringService\x12>\n\tCreateKpi\x12\x1c.monitoring.CreateKpiRequest\x1a\x11.monitoring.KpiId\"\x00\x12=\n\nIncludeKpi\x12\x1d.monitoring.IncludeKpiRequest\x1a\x0e.context.Empty\"\x00\x12=\n\nMonitorKpi\x12\x1d.monitoring.MonitorKpiRequest\x1a\x0e.context.Empty\"\x00\x12I\n\x10MonitorDeviceKpi\x12#.monitoring.MonitorDeviceKpiRequest\x1a\x0e.context.Empty\"\x00\x12\x36\n\x0cGetStreamKpi\x12\x11.monitoring.KpiId\x1a\x0f.monitoring.Kpi\"\x00\x30\x01\x12\x35\n\rGetInstantKpi\x12\x11.monitoring.KpiId\x1a\x0f.monitoring.Kpi\"\x00\x62\x06proto3' , - dependencies=[context__pb2.DESCRIPTOR,kpi__sample__types__pb2.DESCRIPTOR,]) + dependencies=[context__pb2.DESCRIPTOR,]) +_KPISAMPLETYPE = _descriptor.EnumDescriptor( + name='KpiSampleType', + full_name='monitoring.KpiSampleType', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='UNKNOWN', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='PACKETS_TRANSMITTED', index=1, number=101, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='PACKETS_RECEIVED', index=2, number=102, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='BYTES_TRANSMITTED', index=3, number=201, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='BYTES_RECEIVED', index=4, number=202, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=913, + serialized_end=1033, +) +_sym_db.RegisterEnumDescriptor(_KPISAMPLETYPE) + +KpiSampleType = enum_type_wrapper.EnumTypeWrapper(_KPISAMPLETYPE) +UNKNOWN = 0 +PACKETS_TRANSMITTED = 101 +PACKETS_RECEIVED = 102 +BYTES_TRANSMITTED = 201 +BYTES_RECEIVED = 202 -_KPIDESCRIPTOR = _descriptor.Descriptor( - name='KpiDescriptor', - full_name='monitoring.KpiDescriptor', +_CREATEKPIREQUEST = _descriptor.Descriptor( + name='CreateKpiRequest', + full_name='monitoring.CreateKpiRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( - name='kpi_description', full_name='monitoring.KpiDescriptor.kpi_description', index=0, + name='kpiDescription', full_name='monitoring.CreateKpiRequest.kpiDescription', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='kpi_sample_type', full_name='monitoring.KpiDescriptor.kpi_sample_type', index=1, - number=2, type=14, cpp_type=8, label=1, + name='device_id', full_name='monitoring.CreateKpiRequest.device_id', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='kpi_sample_type', full_name='monitoring.CreateKpiRequest.kpi_sample_type', index=2, + number=3, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=48, + serialized_end=180, +) + + +_MONITORKPIREQUEST = _descriptor.Descriptor( + name='MonitorKpiRequest', + full_name='monitoring.MonitorKpiRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ _descriptor.FieldDescriptor( - name='device_id', full_name='monitoring.KpiDescriptor.device_id', index=2, - number=3, type=11, cpp_type=10, label=1, + name='kpi_id', full_name='monitoring.MonitorKpiRequest.kpi_id', index=0, + number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='endpoint_id', full_name='monitoring.KpiDescriptor.endpoint_id', index=3, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, + name='connexion_time_s', full_name='monitoring.MonitorKpiRequest.connexion_time_s', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='service_id', full_name='monitoring.KpiDescriptor.service_id', index=4, - number=5, type=11, cpp_type=10, label=1, + name='sample_rate_ms', full_name='monitoring.MonitorKpiRequest.sample_rate_ms', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=182, + serialized_end=286, +) + + +_MONITORDEVICEKPIREQUEST = _descriptor.Descriptor( + name='MonitorDeviceKpiRequest', + full_name='monitoring.MonitorDeviceKpiRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='kpi', full_name='monitoring.MonitorDeviceKpiRequest.kpi', index=0, + number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='connexion_time_s', full_name='monitoring.MonitorDeviceKpiRequest.connexion_time_s', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='sample_rate_ms', full_name='monitoring.MonitorDeviceKpiRequest.sample_rate_ms', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -83,37 +207,37 @@ _KPIDESCRIPTOR = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=72, - serialized_end=290, + serialized_start=288, + serialized_end=393, ) -_MONITORKPIREQUEST = _descriptor.Descriptor( - name='MonitorKpiRequest', - full_name='monitoring.MonitorKpiRequest', +_INCLUDEKPIREQUEST = _descriptor.Descriptor( + name='IncludeKpiRequest', + full_name='monitoring.IncludeKpiRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( - name='kpi_id', full_name='monitoring.MonitorKpiRequest.kpi_id', index=0, + name='kpi_id', full_name='monitoring.IncludeKpiRequest.kpi_id', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='sampling_duration_s', full_name='monitoring.MonitorKpiRequest.sampling_duration_s', index=1, - number=2, type=2, cpp_type=6, label=1, - has_default_value=False, default_value=float(0), + name='time_stamp', full_name='monitoring.IncludeKpiRequest.time_stamp', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='sampling_interval_s', full_name='monitoring.MonitorKpiRequest.sampling_interval_s', index=2, - number=3, type=2, cpp_type=6, label=1, - has_default_value=False, default_value=float(0), + name='kpi_value', full_name='monitoring.IncludeKpiRequest.kpi_value', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), @@ -129,8 +253,8 @@ _MONITORKPIREQUEST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=292, - serialized_end=404, + serialized_start=395, + serialized_end=510, ) @@ -161,8 +285,8 @@ _KPIID = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=406, - serialized_end=444, + serialized_start=512, + serialized_end=550, ) @@ -189,12 +313,33 @@ _KPI = _descriptor.Descriptor( is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='kpi_value', full_name='monitoring.Kpi.kpi_value', index=2, + name='kpiDescription', full_name='monitoring.Kpi.kpiDescription', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='kpi_value', full_name='monitoring.Kpi.kpi_value', index=3, number=4, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='kpi_sample_type', full_name='monitoring.Kpi.kpi_sample_type', index=4, + number=5, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='device_id', full_name='monitoring.Kpi.device_id', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -207,8 +352,8 @@ _KPI = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=446, - serialized_end=546, + serialized_start=553, + serialized_end=767, ) @@ -265,8 +410,8 @@ _KPIVALUE = _descriptor.Descriptor( create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=548, - serialized_end=645, + serialized_start=769, + serialized_end=866, ) @@ -279,7 +424,7 @@ _KPILIST = _descriptor.Descriptor( create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( - name='kpi_list', full_name='monitoring.KpiList.kpi_list', index=0, + name='kpiList', full_name='monitoring.KpiList.kpiList', index=0, number=1, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, @@ -297,18 +442,21 @@ _KPILIST = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=647, - serialized_end=691, + serialized_start=868, + serialized_end=911, ) -_KPIDESCRIPTOR.fields_by_name['kpi_sample_type'].enum_type = kpi__sample__types__pb2._KPISAMPLETYPE -_KPIDESCRIPTOR.fields_by_name['device_id'].message_type = context__pb2._DEVICEID -_KPIDESCRIPTOR.fields_by_name['endpoint_id'].message_type = context__pb2._ENDPOINTID -_KPIDESCRIPTOR.fields_by_name['service_id'].message_type = context__pb2._SERVICEID +_CREATEKPIREQUEST.fields_by_name['device_id'].message_type = context__pb2._DEVICEID +_CREATEKPIREQUEST.fields_by_name['kpi_sample_type'].enum_type = _KPISAMPLETYPE _MONITORKPIREQUEST.fields_by_name['kpi_id'].message_type = _KPIID +_MONITORDEVICEKPIREQUEST.fields_by_name['kpi'].message_type = _KPI +_INCLUDEKPIREQUEST.fields_by_name['kpi_id'].message_type = _KPIID +_INCLUDEKPIREQUEST.fields_by_name['kpi_value'].message_type = _KPIVALUE _KPIID.fields_by_name['kpi_id'].message_type = context__pb2._UUID _KPI.fields_by_name['kpi_id'].message_type = _KPIID _KPI.fields_by_name['kpi_value'].message_type = _KPIVALUE +_KPI.fields_by_name['kpi_sample_type'].enum_type = _KPISAMPLETYPE +_KPI.fields_by_name['device_id'].message_type = context__pb2._DEVICEID _KPIVALUE.oneofs_by_name['value'].fields.append( _KPIVALUE.fields_by_name['intVal']) _KPIVALUE.fields_by_name['intVal'].containing_oneof = _KPIVALUE.oneofs_by_name['value'] @@ -321,21 +469,24 @@ _KPIVALUE.fields_by_name['stringVal'].containing_oneof = _KPIVALUE.oneofs_by_nam _KPIVALUE.oneofs_by_name['value'].fields.append( _KPIVALUE.fields_by_name['boolVal']) _KPIVALUE.fields_by_name['boolVal'].containing_oneof = _KPIVALUE.oneofs_by_name['value'] -_KPILIST.fields_by_name['kpi_list'].message_type = _KPI -DESCRIPTOR.message_types_by_name['KpiDescriptor'] = _KPIDESCRIPTOR +_KPILIST.fields_by_name['kpiList'].message_type = _KPI +DESCRIPTOR.message_types_by_name['CreateKpiRequest'] = _CREATEKPIREQUEST DESCRIPTOR.message_types_by_name['MonitorKpiRequest'] = _MONITORKPIREQUEST +DESCRIPTOR.message_types_by_name['MonitorDeviceKpiRequest'] = _MONITORDEVICEKPIREQUEST +DESCRIPTOR.message_types_by_name['IncludeKpiRequest'] = _INCLUDEKPIREQUEST DESCRIPTOR.message_types_by_name['KpiId'] = _KPIID DESCRIPTOR.message_types_by_name['Kpi'] = _KPI DESCRIPTOR.message_types_by_name['KpiValue'] = _KPIVALUE DESCRIPTOR.message_types_by_name['KpiList'] = _KPILIST +DESCRIPTOR.enum_types_by_name['KpiSampleType'] = _KPISAMPLETYPE _sym_db.RegisterFileDescriptor(DESCRIPTOR) -KpiDescriptor = _reflection.GeneratedProtocolMessageType('KpiDescriptor', (_message.Message,), { - 'DESCRIPTOR' : _KPIDESCRIPTOR, +CreateKpiRequest = _reflection.GeneratedProtocolMessageType('CreateKpiRequest', (_message.Message,), { + 'DESCRIPTOR' : _CREATEKPIREQUEST, '__module__' : 'monitoring_pb2' - # @@protoc_insertion_point(class_scope:monitoring.KpiDescriptor) + # @@protoc_insertion_point(class_scope:monitoring.CreateKpiRequest) }) -_sym_db.RegisterMessage(KpiDescriptor) +_sym_db.RegisterMessage(CreateKpiRequest) MonitorKpiRequest = _reflection.GeneratedProtocolMessageType('MonitorKpiRequest', (_message.Message,), { 'DESCRIPTOR' : _MONITORKPIREQUEST, @@ -344,6 +495,20 @@ MonitorKpiRequest = _reflection.GeneratedProtocolMessageType('MonitorKpiRequest' }) _sym_db.RegisterMessage(MonitorKpiRequest) +MonitorDeviceKpiRequest = _reflection.GeneratedProtocolMessageType('MonitorDeviceKpiRequest', (_message.Message,), { + 'DESCRIPTOR' : _MONITORDEVICEKPIREQUEST, + '__module__' : 'monitoring_pb2' + # @@protoc_insertion_point(class_scope:monitoring.MonitorDeviceKpiRequest) + }) +_sym_db.RegisterMessage(MonitorDeviceKpiRequest) + +IncludeKpiRequest = _reflection.GeneratedProtocolMessageType('IncludeKpiRequest', (_message.Message,), { + 'DESCRIPTOR' : _INCLUDEKPIREQUEST, + '__module__' : 'monitoring_pb2' + # @@protoc_insertion_point(class_scope:monitoring.IncludeKpiRequest) + }) +_sym_db.RegisterMessage(IncludeKpiRequest) + KpiId = _reflection.GeneratedProtocolMessageType('KpiId', (_message.Message,), { 'DESCRIPTOR' : _KPIID, '__module__' : 'monitoring_pb2' @@ -381,45 +546,45 @@ _MONITORINGSERVICE = _descriptor.ServiceDescriptor( index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=694, - serialized_end=1065, + serialized_start=1036, + serialized_end=1431, methods=[ _descriptor.MethodDescriptor( name='CreateKpi', full_name='monitoring.MonitoringService.CreateKpi', index=0, containing_service=None, - input_type=_KPIDESCRIPTOR, + input_type=_CREATEKPIREQUEST, output_type=_KPIID, serialized_options=None, create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( - name='GetKpiDescriptor', - full_name='monitoring.MonitoringService.GetKpiDescriptor', + name='IncludeKpi', + full_name='monitoring.MonitoringService.IncludeKpi', index=1, containing_service=None, - input_type=_KPIID, - output_type=_KPIDESCRIPTOR, + input_type=_INCLUDEKPIREQUEST, + output_type=context__pb2._EMPTY, serialized_options=None, create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( - name='IncludeKpi', - full_name='monitoring.MonitoringService.IncludeKpi', + name='MonitorKpi', + full_name='monitoring.MonitoringService.MonitorKpi', index=2, containing_service=None, - input_type=_KPI, + input_type=_MONITORKPIREQUEST, output_type=context__pb2._EMPTY, serialized_options=None, create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( - name='MonitorKpi', - full_name='monitoring.MonitoringService.MonitorKpi', + name='MonitorDeviceKpi', + full_name='monitoring.MonitoringService.MonitorDeviceKpi', index=3, containing_service=None, - input_type=_MONITORKPIREQUEST, + input_type=_MONITORDEVICEKPIREQUEST, output_type=context__pb2._EMPTY, serialized_options=None, create_key=_descriptor._internal_create_key, diff --git a/src/device/requirements.in b/src/device/requirements.in index 5a05d7efa6ef6964717635123756da0aead4ceff..5c38e92914207bf101ebc00b2cef453a3a85f82a 100644 --- a/src/device/requirements.in +++ b/src/device/requirements.in @@ -3,8 +3,12 @@ apscheduler fastcache grpcio-health-checking grpcio +Jinja2 +netconf-client #1.7.3 prometheus-client pytest pytest-benchmark +python-json-logger pytz redis +xmltodict diff --git a/src/device/service/DeviceService.py b/src/device/service/DeviceService.py index 29fdc97ce1ba5c8d7266ecdac340dce3e3670425..ae0d5c8396157d5398751587f5e7d808b0d8f484 100644 --- a/src/device/service/DeviceService.py +++ b/src/device/service/DeviceService.py @@ -1,20 +1,28 @@ -import grpc -import logging +import grpc, logging from concurrent import futures from grpc_health.v1.health import HealthServicer, OVERALL_HEALTH from grpc_health.v1.health_pb2 import HealthCheckResponse from grpc_health.v1.health_pb2_grpc import add_HealthServicer_to_server -from device.proto.device_pb2_grpc import add_DeviceServiceServicer_to_server -from device.service.DeviceServiceServicerImpl import DeviceServiceServicerImpl +from context.client.ContextClient import ContextClient from device.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD +from device.proto.device_pb2_grpc import add_DeviceServiceServicer_to_server +from .DeviceServiceServicerImpl import DeviceServiceServicerImpl +#from .MonitoringLoops import MonitoringLoops +from .driver_api.DriverInstanceCache import DriverInstanceCache BIND_ADDRESS = '0.0.0.0' LOGGER = logging.getLogger(__name__) class DeviceService: - def __init__(self, database, address=BIND_ADDRESS, port=GRPC_SERVICE_PORT, max_workers=GRPC_MAX_WORKERS, - grace_period=GRPC_GRACE_PERIOD): - self.database = database + def __init__( + self, context_client : ContextClient, driver_instance_cache : DriverInstanceCache, + #monitoring_loops : MonitoringLoops, + address=BIND_ADDRESS, port=GRPC_SERVICE_PORT, max_workers=GRPC_MAX_WORKERS, + grace_period=GRPC_GRACE_PERIOD): + + self.context_client = context_client + self.driver_instance_cache = driver_instance_cache + #self.monitoring_loops = monitoring_loops self.address = address self.port = port self.endpoint = None @@ -26,14 +34,17 @@ class DeviceService: self.server = None def start(self): - self.endpoint = '{}:{}'.format(self.address, self.port) - LOGGER.debug('Starting Service (tentative endpoint: {}, max_workers: {})...'.format( - self.endpoint, self.max_workers)) + self.endpoint = '{:s}:{:s}'.format(str(self.address), str(self.port)) + LOGGER.info('Starting Service (tentative endpoint: {:s}, max_workers: {:s})...'.format( + str(self.endpoint), str(self.max_workers))) self.pool = futures.ThreadPoolExecutor(max_workers=self.max_workers) self.server = grpc.server(self.pool) # , interceptors=(tracer_interceptor,)) - self.device_servicer = DeviceServiceServicerImpl(self.database) + self.device_servicer = DeviceServiceServicerImpl( + self.context_client, self.driver_instance_cache, + #self.monitoring_loops + ) add_DeviceServiceServicer_to_server(self.device_servicer, self.server) self.health_servicer = HealthServicer( @@ -41,15 +52,15 @@ class DeviceService: add_HealthServicer_to_server(self.health_servicer, self.server) port = self.server.add_insecure_port(self.endpoint) - self.endpoint = '{}:{}'.format(self.address, port) - LOGGER.info('Listening on {}...'.format(self.endpoint)) + self.endpoint = '{:s}:{:s}'.format(str(self.address), str(port)) + LOGGER.info('Listening on {:s}...'.format(str(self.endpoint))) self.server.start() self.health_servicer.set(OVERALL_HEALTH, HealthCheckResponse.SERVING) # pylint: disable=maybe-no-member LOGGER.debug('Service started') def stop(self): - LOGGER.debug('Stopping service (grace period {} seconds)...'.format(self.grace_period)) + LOGGER.debug('Stopping service (grace period {:s} seconds)...'.format(str(self.grace_period))) self.health_servicer.enter_graceful_shutdown() self.server.stop(self.grace_period) LOGGER.debug('Service stopped') diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py index e07925aae31b7e2f275360e61fee3a8fe1347a2e..6c559fda37b7e4f8798be3747261e559a3eb0953 100644 --- a/src/device/service/DeviceServiceServicerImpl.py +++ b/src/device/service/DeviceServiceServicerImpl.py @@ -1,206 +1,290 @@ -import grpc, logging -from prometheus_client import Counter, Histogram -from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID -from common.database.api.Database import Database -from common.database.api.context.topology.device.OperationalStatus import OperationalStatus -from common.exceptions.ServiceException import ServiceException -from device.proto.context_pb2 import DeviceId, Device, Empty -from device.proto.device_pb2 import MonitoringSettings +import grpc, json, logging +from typing import Any, List, Tuple +from google.protobuf.json_format import MessageToDict +from common.orm.Database import Database +from common.orm.Factory import get_database_backend +from common.orm.HighLevel import get_object, update_or_create_object +from common.orm.backend.BackendEnum import BackendEnum +from common.orm.backend.Tools import key_to_str +from common.rpc_method_wrapper.Decorator import create_metrics, safe_and_metered_rpc_method +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentException, OperationFailedException +from context.client.ContextClient import ContextClient +from device.proto.context_pb2 import ConfigActionEnum, Device, DeviceConfig, DeviceId, Empty +#from device.proto.device_pb2 import MonitoringSettings from device.proto.device_pb2_grpc import DeviceServiceServicer -from device.service.Tools import check_device_id_request, check_device_request +#from .MonitoringLoops import MonitoringLoops +from .database.ConfigModel import ( + ConfigModel, ConfigRuleModel, ORM_ConfigActionEnum, get_config_rules, grpc_config_rules_to_raw, update_config) +from .database.DatabaseTools import ( + delete_device_from_context, get_device_driver_filter_fields, sync_device_from_context, sync_device_to_context, + update_device_in_local_database) +from .database.DeviceModel import DeviceModel, DriverModel +from .database.EndPointModel import EndPointModel +#from .database.KpiModel import KpiModel +#from .database.KpiSampleType import grpc_to_enum__kpi_sample_type +from .driver_api._Driver import _Driver, RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES +from .driver_api.DriverInstanceCache import DriverInstanceCache +from .driver_api.Tools import ( + check_delete_errors, check_set_errors, + #check_subscribe_errors, check_unsubscribe_errors +) LOGGER = logging.getLogger(__name__) -ADDDEVICE_COUNTER_STARTED = Counter ('device_adddevice_counter_started', - 'Device:AddDevice counter of requests started' ) -ADDDEVICE_COUNTER_COMPLETED = Counter ('device_adddevice_counter_completed', - 'Device:AddDevice counter of requests completed') -ADDDEVICE_COUNTER_FAILED = Counter ('device_adddevice_counter_failed', - 'Device:AddDevice counter of requests failed' ) -ADDDEVICE_HISTOGRAM_DURATION = Histogram('device_adddevice_histogram_duration', - 'Device:AddDevice histogram of request duration') - -CONFIGUREDEVICE_COUNTER_STARTED = Counter ('device_configuredevice_counter_started', - 'Device:ConfigureDevice counter of requests started' ) -CONFIGUREDEVICE_COUNTER_COMPLETED = Counter ('device_configuredevice_counter_completed', - 'Device:ConfigureDevice counter of requests completed') -CONFIGUREDEVICE_COUNTER_FAILED = Counter ('device_configuredevice_counter_failed', - 'Device:ConfigureDevice counter of requests failed' ) -CONFIGUREDEVICE_HISTOGRAM_DURATION = Histogram('device_configuredevice_histogram_duration', - 'Device:ConfigureDevice histogram of request duration') - -DELETEDEVICE_COUNTER_STARTED = Counter ('device_deletedevice_counter_started', - 'Device:DeleteDevice counter of requests started' ) -DELETEDEVICE_COUNTER_COMPLETED = Counter ('device_deletedevice_counter_completed', - 'Device:DeleteDevice counter of requests completed') -DELETEDEVICE_COUNTER_FAILED = Counter ('device_deletedevice_counter_failed', - 'Device:DeleteDevice counter of requests failed' ) -DELETEDEVICE_HISTOGRAM_DURATION = Histogram('device_deletedevice_histogram_duration', - 'Device:DeleteDevice histogram of request duration') - -MONITORDEVICEKPI_COUNTER_STARTED = Counter ('device_monitordevicekpi_counter_started', - 'Device:MonitorDeviceKpi counter of requests started' ) -MONITORDEVICEKPI_COUNTER_COMPLETED = Counter ('device_monitordevicekpi_counter_completed', - 'Device:MonitorDeviceKpi counter of requests completed') -MONITORDEVICEKPI_COUNTER_FAILED = Counter ('device_monitordevicekpi_counter_failed', - 'Device:MonitorDeviceKpi counter of requests failed' ) -MONITORDEVICEKPI_HISTOGRAM_DURATION = Histogram('device_monitordevicekpi_histogram_duration', - 'Device:MonitorDeviceKpi histogram of request duration') - +SERVICE_NAME = 'Device' +METHOD_NAMES = ['AddDevice', 'ConfigureDevice', 'DeleteDevice', 'GetInitialConfig', 'MonitorDeviceKpi'] +METRICS = create_metrics(SERVICE_NAME, METHOD_NAMES) class DeviceServiceServicerImpl(DeviceServiceServicer): - def __init__(self, database : Database): + def __init__( + self, context_client : ContextClient, driver_instance_cache : DriverInstanceCache, + #monitoring_loops : MonitoringLoops + ): + LOGGER.debug('Creating Servicer...') - self.database = database + self.context_client = context_client + self.database = Database(get_database_backend(backend=BackendEnum.INMEMORY)) + self.driver_instance_cache = driver_instance_cache + #self.monitoring_loops = monitoring_loops LOGGER.debug('Servicer Created') - @ADDDEVICE_HISTOGRAM_DURATION.time() - def AddDevice(self, request : Device, grpc_context : grpc.ServicerContext) -> DeviceId: - ADDDEVICE_COUNTER_STARTED.inc() - try: - LOGGER.debug('AddDevice request: {}'.format(str(request))) - - # ----- Validate request data and pre-conditions ----------------------------------------------------------- - device_id, device_type, device_config, device_opstat, db_endpoints_ports = \ - check_device_request('AddDevice', request, self.database, LOGGER) - - # ----- Implement changes in the database ------------------------------------------------------------------ - db_context = self.database.context(DEFAULT_CONTEXT_ID).create() - db_topology = db_context.topology(DEFAULT_TOPOLOGY_ID).create() - db_device = db_topology.device(device_id).create(device_type, device_config, device_opstat) - for db_endpoint,port_type in db_endpoints_ports: - db_endpoint.create(port_type) - - # ----- Compose reply -------------------------------------------------------------------------------------- - reply = DeviceId(**db_device.dump_id()) - LOGGER.debug('AddDevice reply: {}'.format(str(reply))) - ADDDEVICE_COUNTER_COMPLETED.inc() - return reply - except ServiceException as e: - LOGGER.exception('AddDevice exception') - ADDDEVICE_COUNTER_FAILED.inc() - grpc_context.abort(e.code, e.details) - except Exception as e: # pragma: no cover - LOGGER.exception('AddDevice exception') - ADDDEVICE_COUNTER_FAILED.inc() - grpc_context.abort(grpc.StatusCode.INTERNAL, str(e)) - - @CONFIGUREDEVICE_HISTOGRAM_DURATION.time() - def ConfigureDevice(self, request : Device, grpc_context : grpc.ServicerContext) -> DeviceId: - CONFIGUREDEVICE_COUNTER_STARTED.inc() - try: - LOGGER.debug('ConfigureDevice request: {}'.format(str(request))) - - # ----- Validate request data and pre-conditions ----------------------------------------------------------- - device_id, device_type, device_config, device_opstat, db_endpoints_ports = \ - check_device_request('UpdateDevice', request, self.database, LOGGER) - - # ----- Implement changes in the database ------------------------------------------------------------------ - db_context = self.database.context(DEFAULT_CONTEXT_ID).create() - db_topology = db_context.topology(DEFAULT_TOPOLOGY_ID).create() - db_device = db_topology.device(device_id) - - db_device_attributes = db_device.attributes.get(attributes=['device_type']) - # should not happen, device creation through Database API ensures all fields are always present - if len(db_device_attributes) == 0: # pragma: no cover - msg = 'Attribute device_type for Device({}) does not exist in the database.' # pragma: no cover - msg = msg.format(device_id) # pragma: no cover - raise ServiceException(grpc.StatusCode.FAILED_PRECONDITION, msg) # pragma: no cover - - db_device_type = db_device_attributes.get('device_type') - # should not happen, device creation through Database API ensures all fields are always present - if len(db_device_type) == 0: # pragma: no cover - msg = 'Attribute device_type for Device({}) is empty in the database.' # pragma: no cover - msg = msg.format(device_id) # pragma: no cover - raise ServiceException(grpc.StatusCode.FAILED_PRECONDITION, msg) # pragma: no cover - - if db_device_type != device_type: - msg = 'Device({}) has Type({}) in the database. Cannot be changed to Type({}).' - msg = msg.format(device_id, db_device_type, device_type) - raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, msg) - - if len(db_endpoints_ports) > 0: - msg = 'Endpoints belonging to Device({}) cannot be modified.' - msg = msg.format(device_id) - raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, msg) - - update_attributes = {} - - if len(device_config) > 0: - update_attributes['device_config'] = device_config - - if device_opstat != OperationalStatus.KEEP_STATE: - update_attributes['device_operational_status'] = device_opstat - - if len(update_attributes) == 0: - msg = ' '.join([ - 'Any change has been requested for Device({}).', - 'Either specify a new configuration or a new device operational status.', - ]) - msg = msg.format(device_id) - raise ServiceException(grpc.StatusCode.ABORTED, msg) - - db_device.update(update_attributes=update_attributes) - - # ----- Compose reply -------------------------------------------------------------------------------------- - reply = DeviceId(**db_device.dump_id()) - LOGGER.debug('ConfigureDevice reply: {}'.format(str(reply))) - CONFIGUREDEVICE_COUNTER_COMPLETED.inc() - return reply - except ServiceException as e: - LOGGER.exception('ConfigureDevice exception') - CONFIGUREDEVICE_COUNTER_FAILED.inc() - grpc_context.abort(e.code, e.details) - except Exception as e: # pragma: no cover - LOGGER.exception('ConfigureDevice exception') - CONFIGUREDEVICE_COUNTER_FAILED.inc() - grpc_context.abort(grpc.StatusCode.INTERNAL, str(e)) - - @DELETEDEVICE_HISTOGRAM_DURATION.time() - def DeleteDevice(self, request : DeviceId, grpc_context : grpc.ServicerContext) -> Empty: - DELETEDEVICE_COUNTER_STARTED.inc() - try: - LOGGER.debug('DeleteDevice request: {}'.format(str(request))) - - # ----- Validate request data and pre-conditions ----------------------------------------------------------- - device_id = check_device_id_request('DeleteDevice', request, self.database, LOGGER) - - # ----- Implement changes in the database ------------------------------------------------------------------ - db_context = self.database.context(DEFAULT_CONTEXT_ID).create() - db_topology = db_context.topology(DEFAULT_TOPOLOGY_ID).create() - db_topology.device(device_id).delete() - - # ----- Compose reply -------------------------------------------------------------------------------------- - reply = Empty() - LOGGER.debug('DeleteDevice reply: {}'.format(str(reply))) - DELETEDEVICE_COUNTER_COMPLETED.inc() - return reply - except ServiceException as e: - LOGGER.exception('DeleteDevice exception') - DELETEDEVICE_COUNTER_FAILED.inc() - grpc_context.abort(e.code, e.details) - except Exception as e: # pragma: no cover - LOGGER.exception('DeleteDevice exception') - DELETEDEVICE_COUNTER_FAILED.inc() - grpc_context.abort(grpc.StatusCode.INTERNAL, str(e)) - - @MONITORDEVICEKPI_HISTOGRAM_DURATION.time() - def MonitorDeviceKpi(self, request : MonitoringSettings, grpc_context : grpc.ServicerContext) -> Empty: - MONITORDEVICEKPI_COUNTER_STARTED.inc() - try: - LOGGER.debug('MonitorDeviceKpi request: {}'.format(str(request))) - - # ---- Implement method ------------------------------------------------------------------------------------ - - reply = Empty() - LOGGER.debug('MonitorDeviceKpi reply: {}'.format(str(reply))) - MONITORDEVICEKPI_COUNTER_COMPLETED.inc() - return reply - except ServiceException as e: - LOGGER.exception('MonitorDeviceKpi exception') - MONITORDEVICEKPI_COUNTER_FAILED.inc() - grpc_context.abort(e.code, e.details) - except Exception as e: - LOGGER.exception('MonitorDeviceKpi exception') - MONITORDEVICEKPI_COUNTER_FAILED.inc() - grpc_context.abort(grpc.StatusCode.INTERNAL, str(e)) + @safe_and_metered_rpc_method(METRICS, LOGGER) + def AddDevice(self, request : Device, context : grpc.ServicerContext) -> DeviceId: + device_id = request.device_id + device_uuid = device_id.device_uuid.uuid + + connection_config_rules = {} + unexpected_config_rules = [] + for config_rule in request.device_config.config_rules: + if (config_rule.action == ConfigActionEnum.CONFIGACTION_SET) and \ + (config_rule.resource_key.startswith('_connect/')): + connection_config_rules[config_rule.resource_key.replace('_connect/', '')] = config_rule.resource_value + else: + unexpected_config_rules.append(config_rule) + if len(unexpected_config_rules) > 0: + unexpected_config_rules = MessageToDict( + request.device_config, including_default_value_fields=True, + preserving_proto_field_name=True, use_integers_for_enums=True) + unexpected_config_rules = unexpected_config_rules['config_rules'] + unexpected_config_rules = list(filter( + lambda cr: cr['resource_key'].replace('_connect/', '') not in connection_config_rules, + unexpected_config_rules)) + str_unexpected_config_rules = json.dumps(unexpected_config_rules, sort_keys=True) + raise InvalidArgumentException( + 'device.device_config.config_rules', str_unexpected_config_rules, + extra_details='RPC method AddDevice only accepts connection Config Rules that should start '\ + 'with "_connect/" tag. Others should be configured after adding the device.') + + if len(request.device_endpoints) > 0: + unexpected_endpoints = MessageToDict( + request.device_endpoints, including_default_value_fields=True, preserving_proto_field_name=True, + use_integers_for_enums=True) + str_unexpected_endpoints = json.dumps(unexpected_endpoints, sort_keys=True) + raise InvalidArgumentException( + 'device.device_endpoints', str_unexpected_endpoints, + extra_details='RPC method AddDevice does not accept endpoints. Endpoints are discovered through '\ + 'interrogation of the physical device.') + + # Remove device configuration + json_request = MessageToDict( + request, including_default_value_fields=True, preserving_proto_field_name=True, + use_integers_for_enums=True) + json_request['device_config'] = {} + request = Device(**json_request) + + sync_device_from_context(device_uuid, self.context_client, self.database) + db_device,_ = update_device_in_local_database(self.database, request) + + driver_filter_fields = get_device_driver_filter_fields(db_device) + + address = connection_config_rules.pop('address', None) + port = connection_config_rules.pop('port', None) + driver : _Driver = self.driver_instance_cache.get( + device_uuid, filter_fields=driver_filter_fields, address=address, port=port, + settings=connection_config_rules) + driver.Connect() + + endpoints = driver.GetConfig([RESOURCE_ENDPOINTS]) + for _, resource_value in endpoints: + endpoint_uuid = resource_value.get('name') + endpoint_type = resource_value.get('type') + str_endpoint_key = key_to_str([device_uuid, endpoint_uuid]) + update_or_create_object( + self.database, EndPointModel, str_endpoint_key, { + 'device_fk' : db_device, + 'endpoint_uuid': endpoint_uuid, + 'endpoint_type': endpoint_type, + }) + + running_config_rules = driver.GetConfig([RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES]) + running_config_rules = [ + (ORM_ConfigActionEnum.SET, config_rule[0], json.dumps(config_rule[1], sort_keys=True)) + for config_rule in running_config_rules + ] + #for running_config_rule in running_config_rules: + # LOGGER.info('[AddDevice] running_config_rule: {:s}'.format(str(running_config_rule))) + + update_config(self.database, device_uuid, 'running', running_config_rules) + + initial_config_rules = driver.GetInitialConfig() + update_config(self.database, device_uuid, 'initial', initial_config_rules) + + sync_device_to_context(db_device, self.context_client) + return DeviceId(**db_device.dump_id()) + + @safe_and_metered_rpc_method(METRICS, LOGGER) + def ConfigureDevice(self, request : Device, context : grpc.ServicerContext) -> DeviceId: + device_id = request.device_id + device_uuid = device_id.device_uuid.uuid + + sync_device_from_context(device_uuid, self.context_client, self.database) + + context_config_rules = get_config_rules(self.database, device_uuid, 'running') + context_config_rules = {config_rule[1]: config_rule[2] for config_rule in context_config_rules} + LOGGER.info('[ConfigureDevice] context_config_rules = {:s}'.format(str(context_config_rules))) + + db_device,_ = update_device_in_local_database(self.database, request) + + request_config_rules = grpc_config_rules_to_raw(request.device_config.config_rules) + LOGGER.info('[ConfigureDevice] request_config_rules = {:s}'.format(str(request_config_rules))) + + resources_to_set : List[Tuple[str, Any]] = [] # key, value + resources_to_delete : List[Tuple[str, Any]] = [] # key, value + + for config_rule in request_config_rules: + action, key, value = config_rule + if action == ORM_ConfigActionEnum.SET: + if (key not in context_config_rules) or (context_config_rules[key] != value): + resources_to_set.append((key, value)) + elif action == ORM_ConfigActionEnum.DELETE: + if key in context_config_rules: + resources_to_delete.append((key, value)) + + LOGGER.info('[ConfigureDevice] resources_to_set = {:s}'.format(str(resources_to_set))) + LOGGER.info('[ConfigureDevice] resources_to_delete = {:s}'.format(str(resources_to_delete))) + + # TODO: use of datastores (might be virtual ones) to enable rollbacks + + errors = [] + + driver : _Driver = self.driver_instance_cache.get(device_uuid) + if driver is None: + errors.append('Device({:s}) has not been added to this Device instance'.format(str(device_uuid))) + + if len(errors) == 0: + results_setconfig = driver.SetConfig(resources_to_set) + errors.extend(check_set_errors(resources_to_set, results_setconfig)) + + if len(errors) == 0: + results_deleteconfig = driver.DeleteConfig(resources_to_delete) + errors.extend(check_delete_errors(resources_to_delete, results_deleteconfig)) + + if len(errors) > 0: + raise OperationFailedException('ConfigureDevice', extra_details=errors) + + sync_device_to_context(db_device, self.context_client) + return DeviceId(**db_device.dump_id()) + + @safe_and_metered_rpc_method(METRICS, LOGGER) + def DeleteDevice(self, request : DeviceId, context : grpc.ServicerContext) -> Empty: + device_uuid = request.device_uuid.uuid + + sync_device_from_context(device_uuid, self.context_client, self.database) + db_device : DeviceModel = get_object(self.database, DeviceModel, device_uuid, raise_if_not_found=False) + if db_device is None: return Empty() + + self.driver_instance_cache.delete(device_uuid) + delete_device_from_context(db_device, self.context_client) + + for db_endpoint_pk,_ in db_device.references(EndPointModel): + EndPointModel(self.database, db_endpoint_pk).delete() + + for db_driver_pk,_ in db_device.references(DriverModel): + DriverModel(self.database, db_driver_pk).delete() + + db_initial_config = ConfigModel(self.database, db_device.device_initial_config_fk) + for db_config_rule_pk,_ in db_initial_config.references(ConfigRuleModel): + ConfigRuleModel(self.database, db_config_rule_pk).delete() + + db_running_config = ConfigModel(self.database, db_device.device_running_config_fk) + for db_config_rule_pk,_ in db_running_config.references(ConfigRuleModel): + ConfigRuleModel(self.database, db_config_rule_pk).delete() + + db_device.delete() + db_initial_config.delete() + db_running_config.delete() + return Empty() + + @safe_and_metered_rpc_method(METRICS, LOGGER) + def GetInitialConfig(self, request : DeviceId, context : grpc.ServicerContext) -> DeviceConfig: + device_uuid = request.device_uuid.uuid + + sync_device_from_context(device_uuid, self.context_client, self.database) + db_device : DeviceModel = get_object(self.database, DeviceModel, device_uuid, raise_if_not_found=False) + + config_rules = {} if db_device is None else db_device.dump_initial_config() + return DeviceConfig(config_rules=config_rules) + +# # Code under implemention and testing +# @safe_and_metered_rpc_method(METRICS, LOGGER) +# def MonitorDeviceKpi(self, request : MonitoringSettings, context : grpc.ServicerContext) -> Empty: +# kpi_uuid = request.kpi_id.kpi_id.uuid +# +# device_uuid = request.kpi_descriptor.device_id.device_uuid.uuid +# db_device : DeviceModel = get_object(self.database, DeviceModel, device_uuid, raise_if_not_found=False) +# +# endpoint_id = request.kpi_descriptor.endpoint_id +# endpoint_uuid = endpoint_id.endpoint_uuid.uuid +# endpoint_device_uuid = endpoint_id.device_id.device_uuid.uuid +# if len(endpoint_device_uuid) == 0: endpoint_device_uuid = device_uuid +# str_endpoint_key = key_to_str([device_uuid, endpoint_uuid]) +# endpoint_topology_context_uuid = endpoint_id.topology_id.context_id.context_uuid.uuid +# endpoint_topology_uuid = endpoint_id.topology_id.topology_uuid.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, raise_if_not_found=False) +# +# #db_kpi_prev = get_object(self.database, KpiModel, kpi_uuid, raise_if_not_found=False) +# result : Tuple[KpiModel, bool] = update_or_create_object(self.database, KpiModel, kpi_uuid, { +# 'kpi_uuid' : request.kpi_id.kpi_id.uuid, +# 'kpi_description' : request.kpi_descriptor.kpi_description, +# 'kpi_sample_type' : grpc_to_enum__kpi_sample_type(request.kpi_descriptor.kpi_sample_type), +# 'device_fk' : db_device, +# 'endpoint_fk' : db_endpoint, +# 'sampling_duration': request.sampling_duration_s, +# 'sampling_interval': request.sampling_interval_s, +# }) +# db_kpi, updated = result +# +# driver : _Driver = self.driver_instance_cache.get(device_uuid) +# if driver is None: +# msg = 'Device({:s}) has not been added to this Device instance'.format(str(device_uuid)) +# raise OperationFailedException('ConfigureDevice', extra_details=msg) +# +# sampling_resource = driver.GetResource(db_endpoint.endpoint_uuid) +# +# #resources_to_subscribe : List[Tuple[str, float, float]] = [] # key, sampling_duration, sampling_interval +# #resources_to_unsubscribe : List[Tuple[str, float, float]] = [] # key, sampling_duration, sampling_interval +# #LOGGER.info('[ConfigureDevice] resources_to_subscribe = {:s}'.format(str(resources_to_subscribe))) +# #LOGGER.info('[ConfigureDevice] resources_to_unsubscribe = {:s}'.format(str(resources_to_unsubscribe))) +# # TODO: Implement configuration of subscriptions +# +# #if len(errors) == 0: +# # results_subscribestate = driver.SubscribeState(resources_to_subscribe) +# # errors.extend(check_subscribe_errors(resources_to_delete, results_subscribestate)) +# +# #if len(errors) == 0: +# # results_unsubscribestate = driver.UnsubscribeState(resources_to_unsubscribe) +# # errors.extend(check_unsubscribe_errors(resources_to_delete, results_unsubscribestate)) +# +# results = driver.SubscribeState([ +# (sampling_resource, db_kpi.sampling_duration, db_kpi.sampling_interval), +# ]) +# assert len(results) == 4 +# for result in results: assert isinstance(result, bool) and result +# +# self.monitoring_loops.add(device_uuid, driver) +# +# return Empty() diff --git a/src/device/service/MonitoringLoops.py b/src/device/service/MonitoringLoops.py new file mode 100644 index 0000000000000000000000000000000000000000..658e1de0a99db161fabb88733182d3386b165cbd --- /dev/null +++ b/src/device/service/MonitoringLoops.py @@ -0,0 +1,83 @@ +#import logging, queue, threading +#from typing import Dict +#from monitoring.client.monitoring_client import MonitoringClient +#from monitoring.proto.monitoring_pb2 import Kpi +#from .driver_api._Driver import _Driver +# +#LOGGER = logging.getLogger(__name__) +#QUEUE_GET_WAIT_TIMEOUT = 0.5 +# +#class MonitoringLoop: +# def __init__(self, driver : _Driver, samples_queue : queue.Queue) -> None: +# self._driver = driver +# self._samples_queue = samples_queue +# self._running = threading.Event() +# self._terminate = threading.Event() +# self._samples_stream = self._driver.GetState(blocking=True) +# self._collector_thread = threading.Thread(target=self._collect, daemon=False) +# +# def _collect(self) -> None: +# for sample in self._samples_stream: +# if self._terminate.is_set(): break +# LOGGER.info('[MonitoringLoop:_collect] sample={:s}'.format(str(sample))) +# # TODO: add timestamp (if not present) +# self._samples_queue.put_nowait(sample) +# +# def start(self): +# self._collector_thread.start() +# self._running.set() +# +# @property +# def is_running(self): return self._running.is_set() +# +# def stop(self): +# self._terminate.set() +# self._samples_stream.cancel() +# self._collector_thread.join() +# +#class MonitoringLoops: +# def __init__(self, monitoring_client : MonitoringClient) -> None: +# self._monitoring_client = monitoring_client +# self._samples_queue = queue.Queue() +# self._running = threading.Event() +# self._terminate = threading.Event() +# self._lock = threading.Lock() +# self._device_uuid__to__monitoring_loop : Dict[str, MonitoringLoop] = {} +# self._exporter_thread = threading.Thread(target=self._export, daemon=False) +# +# def add(self, device_uuid : str, driver : _Driver) -> None: +# with self._lock: +# monitoring_loop = self._device_uuid__to__monitoring_loop.get(device_uuid) +# if (monitoring_loop is not None) and monitoring_loop.is_running: return +# monitoring_loop = MonitoringLoop(driver, self._samples_queue) +# self._device_uuid__to__monitoring_loop[device_uuid] = monitoring_loop +# monitoring_loop.start() +# +# def remove(self, device_uuid : str) -> None: +# with self._lock: +# monitoring_loop = self._device_uuid__to__monitoring_loop.get(device_uuid) +# if monitoring_loop is None: return +# if monitoring_loop.is_running: monitoring_loop.stop() +# self._device_uuid__to__monitoring_loop.pop(device_uuid, None) +# +# def start(self): +# self._exporter_thread.start() +# self._running.set() +# +# @property +# def is_running(self): return self._running.is_set() +# +# def stop(self): +# self._terminate.set() +# self._exporter_thread.join() +# +# def _export(self) -> None: +# while not self._terminate.is_set(): +# try: +# sample = self._samples_queue.get(block=True, timeout=QUEUE_GET_WAIT_TIMEOUT) +# LOGGER.info('[MonitoringLoops:_export] sample={:s}'.format(str(sample))) +# except queue.Empty: +# continue +# # TODO: find in database the KpiId, format KPI and send to Monitoring +# kpi_data = {} +# self._monitoring_client.IncludeKpi(Kpi(**kpi_data)) diff --git a/src/device/service/__main__.py b/src/device/service/__main__.py index 6958d7e434f3f1765f209dfe63e4748cda4b7c1c..77572c51f9064712c2d9e4d9ccc9e943fe0df1c7 100644 --- a/src/device/service/__main__.py +++ b/src/device/service/__main__.py @@ -1,52 +1,83 @@ import logging, signal, sys, threading from prometheus_client import start_http_server from common.Settings import get_setting -from common.database.Factory import get_database -from device.service.DeviceService import DeviceService -from device.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD, LOG_LEVEL, METRICS_PORT +from context.client.ContextClient import ContextClient +from device.Config import ( + CONTEXT_SERVICE_HOST, CONTEXT_SERVICE_PORT, GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD, LOG_LEVEL, + METRICS_PORT, MONITORING_SERVICE_HOST, MONITORING_SERVICE_PORT) +#from monitoring.client.monitoring_client import MonitoringClient +from .DeviceService import DeviceService +#from .MonitoringLoops import MonitoringLoops +from .driver_api.DriverFactory import DriverFactory +from .driver_api.DriverInstanceCache import DriverInstanceCache +from .drivers import DRIVERS terminate = threading.Event() -logger = None +LOGGER = None -def signal_handler(signal, frame): - global terminate, logger - logger.warning('Terminate signal received') +def signal_handler(signal, frame): # pylint: disable=redefined-outer-name + LOGGER.warning('Terminate signal received') terminate.set() def main(): - global terminate, logger + global LOGGER # pylint: disable=global-statement - service_port = get_setting('DEVICESERVICE_SERVICE_PORT_GRPC', default=GRPC_SERVICE_PORT) - max_workers = get_setting('MAX_WORKERS', default=GRPC_MAX_WORKERS ) - grace_period = get_setting('GRACE_PERIOD', default=GRPC_GRACE_PERIOD) - log_level = get_setting('LOG_LEVEL', default=LOG_LEVEL ) - metrics_port = get_setting('METRICS_PORT', default=METRICS_PORT ) + grpc_service_port = get_setting('DEVICESERVICE_SERVICE_PORT_GRPC', default=GRPC_SERVICE_PORT ) + max_workers = get_setting('MAX_WORKERS', default=GRPC_MAX_WORKERS ) + grace_period = get_setting('GRACE_PERIOD', default=GRPC_GRACE_PERIOD ) + log_level = get_setting('LOG_LEVEL', default=LOG_LEVEL ) + metrics_port = get_setting('METRICS_PORT', default=METRICS_PORT ) + context_service_host = get_setting('CONTEXTSERVICE_SERVICE_HOST', default=CONTEXT_SERVICE_HOST ) + context_service_port = get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC', default=CONTEXT_SERVICE_PORT ) + monitoring_service_host = get_setting('MONITORINGSERVICE_SERVICE_HOST', default=MONITORING_SERVICE_HOST) + monitoring_service_port = get_setting('MONITORINGSERVICE_SERVICE_PORT_GRPC', default=MONITORING_SERVICE_PORT) logging.basicConfig(level=log_level) - logger = logging.getLogger(__name__) + LOGGER = logging.getLogger(__name__) signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) - logger.info('Starting...') + LOGGER.info('Starting...') # Start metrics server start_http_server(metrics_port) - # Get database instance - database = get_database() + # Initialize Context Client + if context_service_host is None or context_service_port is None: + raise Exception('Wrong address({:s}):port({:s}) of Context component'.format( + str(context_service_host), str(context_service_port))) + context_client = ContextClient(context_service_host, context_service_port) + + ## Initialize Monitoring Client + #if monitoring_service_host is None or monitoring_service_port is None: + # raise Exception('Wrong address({:s}):port({:s}) of Monitoring component'.format( + # str(monitoring_service_host), str(monitoring_service_port))) + #monitoring_client = MonitoringClient(monitoring_service_host, monitoring_service_port) + + # Initialize Driver framework + driver_factory = DriverFactory(DRIVERS) + driver_instance_cache = DriverInstanceCache(driver_factory) + #monitoring_loops = MonitoringLoops(monitoring_client) # Starting device service - grpc_service = DeviceService(database, port=service_port, max_workers=max_workers, grace_period=grace_period) + grpc_service = DeviceService( + context_client, driver_instance_cache, + #monitoring_loops, + port=grpc_service_port, max_workers=max_workers, + grace_period=grace_period) grpc_service.start() + #monitoring_loops.start() # Wait for Ctrl+C or termination signal while not terminate.wait(timeout=0.1): pass - logger.info('Terminating...') + LOGGER.info('Terminating...') + #monitoring_loops.stop() grpc_service.stop() + driver_instance_cache.terminate() - logger.info('Bye') + LOGGER.info('Bye') return 0 if __name__ == '__main__': diff --git a/src/device/service/database/ConfigModel.py b/src/device/service/database/ConfigModel.py new file mode 100644 index 0000000000000000000000000000000000000000..82697bfbae7d1f58fdc851aa66f86f0fc78a767e --- /dev/null +++ b/src/device/service/database/ConfigModel.py @@ -0,0 +1,98 @@ +import functools, logging, operator +from enum import Enum +from typing import Dict, List, Tuple, Union +from common.orm.Database import Database +from common.orm.HighLevel import get_object, get_or_create_object, update_or_create_object +from common.orm.backend.Tools import key_to_str +from common.orm.fields.EnumeratedField import EnumeratedField +from common.orm.fields.ForeignKeyField import ForeignKeyField +from common.orm.fields.IntegerField import IntegerField +from common.orm.fields.PrimaryKeyField import PrimaryKeyField +from common.orm.fields.StringField import StringField +from common.orm.model.Model import Model +from device.proto.context_pb2 import ConfigActionEnum +from .Tools import fast_hasher, grpc_to_enum, remove_dict_key + +LOGGER = logging.getLogger(__name__) + +class ORM_ConfigActionEnum(Enum): + UNDEFINED = ConfigActionEnum.CONFIGACTION_UNDEFINED + SET = ConfigActionEnum.CONFIGACTION_SET + DELETE = ConfigActionEnum.CONFIGACTION_DELETE + +grpc_to_enum__config_action = functools.partial( + grpc_to_enum, ConfigActionEnum, ORM_ConfigActionEnum) + +class ConfigModel(Model): # pylint: disable=abstract-method + pk = PrimaryKeyField() + + def dump(self) -> List[Dict]: + db_config_rule_pks = self.references(ConfigRuleModel) + config_rules = [ConfigRuleModel(self.database, pk).dump(include_position=True) for pk,_ in db_config_rule_pks] + config_rules = sorted(config_rules, key=operator.itemgetter('position')) + return [remove_dict_key(config_rule, 'position') for config_rule in config_rules] + +class ConfigRuleModel(Model): # pylint: disable=abstract-method + pk = PrimaryKeyField() + config_fk = ForeignKeyField(ConfigModel) + position = IntegerField(min_value=0, required=True) + action = EnumeratedField(ORM_ConfigActionEnum, required=True) + key = StringField(required=True, allow_empty=False) + value = StringField(required=False, allow_empty=True) + + def dump(self, include_position=True) -> Dict: # pylint: disable=arguments-differ + result = { + 'action': self.action.value, + 'resource_key': self.key, + 'resource_value': self.value, + } + if include_position: result['position'] = self.position + return result + +def delete_all_config_rules(database : Database, db_parent_pk : str, config_name : str) -> None: + str_config_key = key_to_str([db_parent_pk, config_name], separator=':') + db_config : ConfigModel = get_object(database, ConfigModel, str_config_key, raise_if_not_found=False) + if db_config is None: return + db_config_rule_pks = db_config.references(ConfigRuleModel) + for pk,_ in db_config_rule_pks: ConfigRuleModel(database, pk).delete() + +def grpc_config_rules_to_raw(grpc_config_rules) -> List[Tuple[ORM_ConfigActionEnum, str, str]]: + def translate(grpc_config_rule): + action = grpc_to_enum__config_action(grpc_config_rule.action) + return action, grpc_config_rule.resource_key, grpc_config_rule.resource_value + return [translate(grpc_config_rule) for grpc_config_rule in grpc_config_rules] + +def get_config_rules( + database : Database, db_parent_pk : str, config_name : str + ) -> List[Tuple[ORM_ConfigActionEnum, str, str]]: + + str_config_key = key_to_str([db_parent_pk, config_name], separator=':') + db_config = get_object(database, ConfigModel, str_config_key, raise_if_not_found=False) + return [] if db_config is None else [ + (ORM_ConfigActionEnum._value2member_map_.get(config_rule['action']), + config_rule['resource_key'], config_rule['resource_value']) + for config_rule in db_config.dump() + ] + +def update_config( + database : Database, db_parent_pk : str, config_name : str, + raw_config_rules : List[Tuple[ORM_ConfigActionEnum, str, str]] + ) -> List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]]: + + str_config_key = key_to_str([db_parent_pk, config_name], separator=':') + result : Tuple[ConfigModel, bool] = get_or_create_object(database, ConfigModel, str_config_key) + db_config, created = result + + db_objects : List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]] = [(db_config, created)] + + for position,(action, resource_key, resource_value) in enumerate(raw_config_rules): + str_rule_key_hash = fast_hasher(resource_key) + str_config_rule_key = key_to_str([db_config.pk, str_rule_key_hash], separator=':') + result : Tuple[ConfigRuleModel, bool] = update_or_create_object( + database, ConfigRuleModel, str_config_rule_key, { + 'config_fk': db_config, 'position': position, 'action': action, 'key': resource_key, + 'value': resource_value}) + db_config_rule, updated = result + db_objects.append((db_config_rule, updated)) + + return db_objects diff --git a/src/device/service/database/ContextModel.py b/src/device/service/database/ContextModel.py new file mode 100644 index 0000000000000000000000000000000000000000..f4da5097e3f1ab0298ec66ff6007fb6a21be65ed --- /dev/null +++ b/src/device/service/database/ContextModel.py @@ -0,0 +1,24 @@ +import logging +from typing import Dict, List +from common.orm.fields.PrimaryKeyField import PrimaryKeyField +from common.orm.fields.StringField import StringField +from common.orm.model.Model import Model + +LOGGER = logging.getLogger(__name__) + +class ContextModel(Model): + pk = PrimaryKeyField() + context_uuid = StringField(required=True, allow_empty=False) + +# def dump_id(self) -> Dict: +# return {'context_uuid': {'uuid': self.context_uuid}} + +# def dump_topology_ids(self) -> List[Dict]: +# from .TopologyModel import TopologyModel # pylint: disable=import-outside-toplevel +# db_topology_pks = self.references(TopologyModel) +# return [TopologyModel(self.database, pk).dump_id() for pk,_ in db_topology_pks] + +# def dump(self, include_topologies=True) -> Dict: # pylint: disable=arguments-differ +# result = {'context_id': self.dump_id()} +# if include_topologies: result['topology_ids'] = self.dump_topology_ids() +# return result diff --git a/src/device/service/database/DatabaseTools.py b/src/device/service/database/DatabaseTools.py new file mode 100644 index 0000000000000000000000000000000000000000..5b43aae70af054f5d6da0bd92d9f2e59d152dc84 --- /dev/null +++ b/src/device/service/database/DatabaseTools.py @@ -0,0 +1,110 @@ +import grpc +from typing import Any, Dict, Tuple +from common.orm.Database import Database +from common.orm.HighLevel import get_or_create_object, update_or_create_object +from common.orm.backend.Tools import key_to_str +from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentException +from context.client.ContextClient import ContextClient +from device.proto.context_pb2 import Device, DeviceId +from device.service.driver_api.FilterFields import FilterFieldEnum +from .ConfigModel import delete_all_config_rules, grpc_config_rules_to_raw, update_config +from .ContextModel import ContextModel +from .DeviceModel import DeviceModel, DriverModel, grpc_to_enum__device_operational_status, set_drivers +from .EndPointModel import EndPointModel +from .TopologyModel import TopologyModel + +def update_device_in_local_database(database : Database, device : Device) -> Tuple[DeviceModel, bool]: + device_uuid = device.device_id.device_uuid.uuid + + for i,endpoint in enumerate(device.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: + 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)]) + + initial_config_result = update_config(database, device_uuid, 'initial', []) + + config_rules = grpc_config_rules_to_raw(device.device_config.config_rules) + delete_all_config_rules(database, device_uuid, 'running') + running_config_result = update_config(database, device_uuid, 'running', config_rules) + + result : Tuple[DeviceModel, bool] = update_or_create_object(database, DeviceModel, device_uuid, { + 'device_uuid' : device_uuid, + 'device_type' : device.device_type, + 'device_operational_status': grpc_to_enum__device_operational_status(device.device_operational_status), + 'device_initial_config_fk' : initial_config_result[0][0], + 'device_running_config_fk' : running_config_result[0][0], + }) + db_device, updated = result + set_drivers(database, db_device, device.device_drivers) + + for i,endpoint in enumerate(device.device_endpoints): + endpoint_uuid = endpoint.endpoint_id.endpoint_uuid.uuid + endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid + if len(endpoint_device_uuid) == 0: endpoint_device_uuid = device_uuid + + str_endpoint_key = key_to_str([device_uuid, endpoint_uuid]) + endpoint_attributes = { + 'device_fk' : db_device, + 'endpoint_uuid': endpoint_uuid, + 'endpoint_type': endpoint.endpoint_type, + } + + endpoint_topology_context_uuid = endpoint.endpoint_id.topology_id.context_id.context_uuid.uuid + endpoint_topology_uuid = endpoint.endpoint_id.topology_id.topology_uuid.uuid + if len(endpoint_topology_context_uuid) > 0 and len(endpoint_topology_uuid) > 0: + result : Tuple[ContextModel, bool] = get_or_create_object( + database, ContextModel, endpoint_topology_context_uuid, defaults={ + 'context_uuid': endpoint_topology_context_uuid, + }) + db_context, _ = result + + str_topology_key = key_to_str([endpoint_topology_context_uuid, endpoint_topology_uuid]) + result : Tuple[TopologyModel, bool] = get_or_create_object( + database, TopologyModel, str_topology_key, defaults={ + 'context_fk': db_context, + 'topology_uuid': endpoint_topology_uuid, + }) + db_topology, _ = result + + str_endpoint_key = key_to_str([str_endpoint_key, str_topology_key], separator=':') + endpoint_attributes['topology_fk'] = db_topology + + result : Tuple[EndPointModel, bool] = update_or_create_object( + database, EndPointModel, str_endpoint_key, endpoint_attributes) + _, db_endpoint_updated = result + updated = updated or db_endpoint_updated + + return db_device, updated + +def sync_device_from_context( + device_uuid : str, context_client : ContextClient, database : Database + ) -> Tuple[DeviceModel, bool]: + + try: + device : Device = context_client.GetDevice(DeviceId(device_uuid={'uuid': device_uuid})) + except grpc.RpcError as e: + if e.code() != grpc.StatusCode.NOT_FOUND: raise # pylint: disable=no-member + return None + return update_device_in_local_database(database, device) + +def sync_device_to_context(db_device : DeviceModel, context_client : ContextClient) -> None: + if db_device is None: return + context_client.SetDevice(Device(**db_device.dump( + include_config_rules=True, include_drivers=True, include_endpoints=True))) + +def delete_device_from_context(db_device : DeviceModel, context_client : ContextClient) -> None: + if db_device is None: return + context_client.RemoveDevice(DeviceId(**db_device.dump_id())) + +def get_device_driver_filter_fields(db_device : DeviceModel) -> Dict[FilterFieldEnum, Any]: + if db_device is None: return {} + database = db_device.database + db_driver_pks = db_device.references(DriverModel) + db_driver_names = [DriverModel(database, pk).driver.value for pk,_ in db_driver_pks] + return { + FilterFieldEnum.DEVICE_TYPE: db_device.device_type, + FilterFieldEnum.DRIVER : db_driver_names, + } diff --git a/src/device/service/database/DeviceModel.py b/src/device/service/database/DeviceModel.py new file mode 100644 index 0000000000000000000000000000000000000000..bba19d787622019b7b8f25de9c07b7c0984ec42c --- /dev/null +++ b/src/device/service/database/DeviceModel.py @@ -0,0 +1,91 @@ +import functools, logging +from enum import Enum +from typing import Dict, List +from common.orm.Database import Database +from common.orm.backend.Tools import key_to_str +from common.orm.fields.EnumeratedField import EnumeratedField +from common.orm.fields.ForeignKeyField import ForeignKeyField +from common.orm.fields.PrimaryKeyField import PrimaryKeyField +from common.orm.fields.StringField import StringField +from common.orm.model.Model import Model +from device.proto.context_pb2 import DeviceDriverEnum, DeviceOperationalStatusEnum +from .ConfigModel import ConfigModel +from .Tools import grpc_to_enum + +LOGGER = logging.getLogger(__name__) + +class ORM_DeviceDriverEnum(Enum): + UNDEFINED = DeviceDriverEnum.DEVICEDRIVER_UNDEFINED + OPENCONFIG = DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG + TRANSPORT_API = DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API + P4 = DeviceDriverEnum.DEVICEDRIVER_P4 + IETF_NETWORK_TOPOLOGY = DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY + ONF_TR_352 = DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352 + +grpc_to_enum__device_driver = functools.partial( + grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum) + +class ORM_DeviceOperationalStatusEnum(Enum): + UNDEFINED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED + DISABLED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED + ENABLED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED + +grpc_to_enum__device_operational_status = functools.partial( + grpc_to_enum, DeviceOperationalStatusEnum, ORM_DeviceOperationalStatusEnum) + +class DeviceModel(Model): + pk = PrimaryKeyField() + device_uuid = StringField(required=True, allow_empty=False) + device_type = StringField() + device_initial_config_fk = ForeignKeyField(ConfigModel) + device_running_config_fk = ForeignKeyField(ConfigModel) + device_operational_status = EnumeratedField(ORM_DeviceOperationalStatusEnum, required=True) + + def dump_id(self) -> Dict: + return {'device_uuid': {'uuid': self.device_uuid}} + + def dump_initial_config(self) -> Dict: + return ConfigModel(self.database, self.device_initial_config_fk).dump() + + def dump_running_config(self) -> Dict: + return ConfigModel(self.database, self.device_running_config_fk).dump() + + def dump_drivers(self) -> List[int]: + db_driver_pks = self.references(DriverModel) + return [DriverModel(self.database, pk).dump() for pk,_ in db_driver_pks] + + def dump_endpoints(self) -> List[Dict]: + from .EndPointModel import EndPointModel # pylint: disable=import-outside-toplevel + db_endpoints_pks = self.references(EndPointModel) + return [EndPointModel(self.database, pk).dump() for pk,_ in db_endpoints_pks] + + def dump( # pylint: disable=arguments-differ + self, include_config_rules=True, include_drivers=True, include_endpoints=True + ) -> Dict: + result = { + 'device_id': self.dump_id(), + 'device_type': self.device_type, + 'device_operational_status': self.device_operational_status.value, + } + if include_config_rules: result.setdefault('device_config', {})['config_rules'] = self.dump_running_config() + if include_drivers: result['device_drivers'] = self.dump_drivers() + if include_endpoints: result['device_endpoints'] = self.dump_endpoints() + return result + +class DriverModel(Model): # pylint: disable=abstract-method + pk = PrimaryKeyField() + device_fk = ForeignKeyField(DeviceModel) + driver = EnumeratedField(ORM_DeviceDriverEnum, required=True) + + def dump(self) -> Dict: + return self.driver.value + +def set_drivers(database : Database, db_device : DeviceModel, grpc_device_drivers): + db_device_pk = db_device.pk + for driver in grpc_device_drivers: + orm_driver = grpc_to_enum__device_driver(driver) + str_device_driver_key = key_to_str([db_device_pk, orm_driver.name]) + db_device_driver = DriverModel(database, str_device_driver_key) + db_device_driver.device_fk = db_device + db_device_driver.driver = orm_driver + db_device_driver.save() diff --git a/src/device/service/database/EndPointModel.py b/src/device/service/database/EndPointModel.py new file mode 100644 index 0000000000000000000000000000000000000000..38b87d6f37c4e99dd3790f4d8802acd03873f77d --- /dev/null +++ b/src/device/service/database/EndPointModel.py @@ -0,0 +1,33 @@ +import logging +from typing import Dict +from common.orm.fields.ForeignKeyField import ForeignKeyField +from common.orm.fields.PrimaryKeyField import PrimaryKeyField +from common.orm.fields.StringField import StringField +from common.orm.model.Model import Model +from .DeviceModel import DeviceModel +from .TopologyModel import TopologyModel + +LOGGER = logging.getLogger(__name__) + +class EndPointModel(Model): + pk = PrimaryKeyField() + topology_fk = ForeignKeyField(TopologyModel, required=False) + device_fk = ForeignKeyField(DeviceModel) + endpoint_uuid = StringField(required=True, allow_empty=False) + endpoint_type = StringField() + + def dump_id(self) -> Dict: + device_id = DeviceModel(self.database, self.device_fk).dump_id() + result = { + 'device_id': device_id, + 'endpoint_uuid': {'uuid': self.endpoint_uuid}, + } + if self.topology_fk is not None: + result['topology_id'] = TopologyModel(self.database, self.topology_fk).dump_id() + return result + + def dump(self) -> Dict: + return { + 'endpoint_id': self.dump_id(), + 'endpoint_type': self.endpoint_type, + } diff --git a/src/device/service/database/KpiModel.py b/src/device/service/database/KpiModel.py new file mode 100644 index 0000000000000000000000000000000000000000..1bed9fc7a169665eb459b295a6fc9903513e13f0 --- /dev/null +++ b/src/device/service/database/KpiModel.py @@ -0,0 +1,45 @@ +import logging +from typing import Dict +from common.orm.fields.EnumeratedField import EnumeratedField +from common.orm.fields.FloatField import FloatField +from common.orm.fields.ForeignKeyField import ForeignKeyField +from common.orm.fields.PrimaryKeyField import PrimaryKeyField +from common.orm.fields.StringField import StringField +from common.orm.model.Model import Model +from .DeviceModel import DeviceModel +from .EndPointModel import EndPointModel +from .KpiSampleType import ORM_KpiSampleType + +LOGGER = logging.getLogger(__name__) + +class KpiModel(Model): + pk = PrimaryKeyField() + kpi_uuid = StringField(required=True, allow_empty=False) + kpi_description = StringField(required=False, allow_empty=True) + kpi_sample_type = EnumeratedField(ORM_KpiSampleType, required=True) + device_fk = ForeignKeyField(DeviceModel) + endpoint_fk = ForeignKeyField(EndPointModel) + sampling_duration = FloatField(min_value=0, required=True) + sampling_interval = FloatField(min_value=0, required=True) + + def dump_id(self) -> Dict: + return {'kpi_id': {'uuid': self.kpi_uuid}} + + def dump_descriptor(self) -> Dict: + result = { + 'kpi_description': self.kpi_description, + 'kpi_sample_type': self.kpi_sample_type.value, + } + if self.device_fk is not None: + result['device_id'] = DeviceModel(self.database, self.device_fk).dump_id() + if self.endpoint_fk is not None: + result['endpoint_id'] = EndPointModel(self.database, self.endpoint_fk).dump_id() + return result + + def dump(self) -> Dict: + return { + 'kpi_id': self.dump_id(), + 'kpi_descriptor': self.dump_descriptor(), + 'sampling_duration_s': self.sampling_duration, + 'sampling_interval_s': self.sampling_interval, + } diff --git a/src/device/service/database/KpiSampleType.py b/src/device/service/database/KpiSampleType.py new file mode 100644 index 0000000000000000000000000000000000000000..e5c4c5bbc0407e7dd3650ca4ff2f2e95a1202472 --- /dev/null +++ b/src/device/service/database/KpiSampleType.py @@ -0,0 +1,14 @@ +import functools +from enum import Enum +from device.proto.kpi_sample_types_pb2 import KpiSampleType +from .Tools import grpc_to_enum + +class ORM_KpiSampleType(Enum): + UNKNOWN = KpiSampleType.UNKNOWN + PACKETS_TRANSMITTED = KpiSampleType.PACKETS_TRANSMITTED + PACKETS_RECEIVED = KpiSampleType.PACKETS_RECEIVED + BYTES_TRANSMITTED = KpiSampleType.BYTES_TRANSMITTED + BYTES_RECEIVED = KpiSampleType.BYTES_RECEIVED + +grpc_to_enum__kpi_sample_type = functools.partial( + grpc_to_enum, KpiSampleType, ORM_KpiSampleType) diff --git a/src/device/service/database/Tools.py b/src/device/service/database/Tools.py new file mode 100644 index 0000000000000000000000000000000000000000..36ffbcd46fcf686371b0799445ce4f9ce5b75838 --- /dev/null +++ b/src/device/service/database/Tools.py @@ -0,0 +1,58 @@ +import hashlib, re +from enum import Enum +from typing import Dict, List, Tuple, Union + +# Convenient helper function to remove dictionary items in dict/list/set comprehensions. + +def remove_dict_key(dictionary : Dict, key : str): + dictionary.pop(key, None) + return dictionary + +# Enumeration classes are redundant with gRPC classes, but gRPC does not provide a programmatical method to retrieve +# the values it expects from strings containing the desired value symbol or its integer value, so a kind of mapping is +# required. Besides, ORM Models expect Enum classes in EnumeratedFields; we create specific and conveniently defined +# Enum classes to serve both purposes. + +def grpc_to_enum(grpc_enum_class, orm_enum_class : Enum, grpc_enum_value): + grpc_enum_name = grpc_enum_class.Name(grpc_enum_value) + grpc_enum_prefix = orm_enum_class.__name__.upper() + grpc_enum_prefix = re.sub(r'^ORM_(.+)$', r'\1', grpc_enum_prefix) + grpc_enum_prefix = re.sub(r'^(.+)ENUM$', r'\1', grpc_enum_prefix) + grpc_enum_prefix = grpc_enum_prefix + '_' + orm_enum_name = grpc_enum_name.replace(grpc_enum_prefix, '') + orm_enum_value = orm_enum_class._member_map_.get(orm_enum_name) # pylint: disable=protected-access + return orm_enum_value + +# For some models, it is convenient to produce a string hash for fast comparisons of existence or modification. Method +# fast_hasher computes configurable length (between 1 and 64 byte) hashes and retrieves them in hex representation. + +FASTHASHER_ITEM_ACCEPTED_FORMAT = 'Union[bytes, str]' +FASTHASHER_DATA_ACCEPTED_FORMAT = 'Union[{fmt:s}, List[{fmt:s}], Tuple[{fmt:s}]]'.format( + fmt=FASTHASHER_ITEM_ACCEPTED_FORMAT) + +def fast_hasher(data : Union[bytes, str, List[Union[bytes, str]], Tuple[Union[bytes, str]]], digest_size : int = 8): + hasher = hashlib.blake2b(digest_size=digest_size) + # Do not accept sets, dicts, or other unordered dats tructures since their order is arbitrary thus producing + # different hashes depending on the order. Consider adding support for sets or dicts with previous sorting of + # items by their key. + + if isinstance(data, bytes): + data = [data] + elif isinstance(data, str): + data = [data.encode('UTF-8')] + elif isinstance(data, (list, tuple)): + pass + else: + msg = 'data({:s}) must be {:s}, found {:s}' + raise TypeError(msg.format(str(data), FASTHASHER_DATA_ACCEPTED_FORMAT, str(type(data)))) + + for i,item in enumerate(data): + if isinstance(item, str): + item = item.encode('UTF-8') + elif isinstance(item, bytes): + pass + else: + msg = 'data[{:d}]({:s}) must be {:s}, found {:s}' + raise TypeError(msg.format(i, str(item), FASTHASHER_ITEM_ACCEPTED_FORMAT, str(type(item)))) + hasher.update(item) + return hasher.hexdigest() diff --git a/src/device/service/database/TopologyModel.py b/src/device/service/database/TopologyModel.py new file mode 100644 index 0000000000000000000000000000000000000000..71c1067f03803c6d89c69910c82a3c1e24970eee --- /dev/null +++ b/src/device/service/database/TopologyModel.py @@ -0,0 +1,25 @@ +import logging +from typing import Dict +from common.orm.fields.ForeignKeyField import ForeignKeyField +from common.orm.fields.PrimaryKeyField import PrimaryKeyField +from common.orm.fields.StringField import StringField +from common.orm.model.Model import Model +from .ContextModel import ContextModel + +LOGGER = logging.getLogger(__name__) + +class TopologyModel(Model): + pk = PrimaryKeyField() + context_fk = ForeignKeyField(ContextModel) + topology_uuid = StringField(required=True, allow_empty=False) + +# def dump_id(self) -> Dict: +# context_id = ContextModel(self.database, self.context_fk).dump_id() +# return { +# 'context_id': context_id, +# 'topology_uuid': {'uuid': self.topology_uuid}, +# } + +# def dump(self) -> Dict: +# result = {'topology_id': self.dump_id()} +# return result diff --git a/src/device/service/database/__init__.py b/src/device/service/database/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ff9b7da0cd0f83f8e01bbb904d8e2471503f00ca --- /dev/null +++ b/src/device/service/database/__init__.py @@ -0,0 +1,2 @@ +# In-Memory database with a simplified representation of Context Database focused on the Device model. +# Used as an internal configuration cache, for message validation, and message formatting purposes. diff --git a/src/device/service/driver_api/AnyTreeTools.py b/src/device/service/driver_api/AnyTreeTools.py new file mode 100644 index 0000000000000000000000000000000000000000..df61c7e030a13a3d0d758ce51a011aaa95deb49f --- /dev/null +++ b/src/device/service/driver_api/AnyTreeTools.py @@ -0,0 +1,60 @@ +import anytree +from typing import Any, List, Optional + +class TreeNode(anytree.node.Node): + def __init__(self, name, parent=None, children=None, **kwargs) -> None: + super().__init__(name, parent=parent, children=children, **kwargs) + self.value : Optional[Any] = None + + def get_full_path(self): + return self.separator.join([''] + [str(node.name) for node in self.path]) + +class RawStyle(anytree.render.AbstractStyle): + def __init__(self): + """ + Raw style. + + >>> from anytree import Node, RenderTree + >>> root = Node("root") + >>> s0 = Node("sub0", parent=root) + >>> s0b = Node("sub0B", parent=s0) + >>> s0a = Node("sub0A", parent=s0) + >>> s1 = Node("sub1", parent=root) + >>> print(RenderTree(root, style=RawStyle())) + Node('/root') + Node('/root/sub0') + Node('/root/sub0/sub0B') + Node('/root/sub0/sub0A') + Node('/root/sub1') + """ + super(RawStyle, self).__init__(u'', u'', u'') + +def get_subnode(resolver : anytree.Resolver, root : TreeNode, path : List[str], default : Optional[Any] = None): + node = root + for path_item in path: + try: + node = resolver.get(node, path_item) + except anytree.ChildResolverError: + return default + return node + +def set_subnode_value(resolver : anytree.Resolver, root : TreeNode, path : List[str], value : Any): + node = root + for path_item in path: + try: + node = resolver.get(node, path_item) + except anytree.ChildResolverError: + node = TreeNode(path_item, parent=node) + node.value = value + +def dump_subtree(root : TreeNode): + if not isinstance(root, TreeNode): raise Exception('root must be a TreeNode') + results = [] + for row in anytree.RenderTree(root, style=RawStyle()): + node : TreeNode = row.node + path = node.get_full_path()[2:] # get full path except the heading root placeholder "/." + if len(path) == 0: continue + value = node.value + if value is None: continue + results.append((path, value)) + return results diff --git a/src/device/service/driver_api/DriverFactory.py b/src/device/service/driver_api/DriverFactory.py index c226e434c75286d99c2051098e0d18d9cf483caa..10b4961fcf98871cc4cbf3e078391006591b606c 100644 --- a/src/device/service/driver_api/DriverFactory.py +++ b/src/device/service/driver_api/DriverFactory.py @@ -1,50 +1,73 @@ -from typing import Dict, Set -from device.service.driver_api.QueryFields import QUERY_FIELDS +import logging, operator +from enum import Enum +from typing import Any, Dict, Iterable, List, Set, Tuple from device.service.driver_api._Driver import _Driver -from device.service.driver_api.Exceptions import MultipleResultsForQueryException, UnsatisfiedQueryException, \ - UnsupportedDriverClassException, UnsupportedQueryFieldException, UnsupportedQueryFieldValueException +from device.service.driver_api.Exceptions import ( + UnsatisfiedFilterException, UnsupportedDriverClassException, UnsupportedFilterFieldException, + UnsupportedFilterFieldValueException) +from device.service.driver_api.FilterFields import FILTER_FIELD_ALLOWED_VALUES, FilterFieldEnum + +LOGGER = logging.getLogger(__name__) class DriverFactory: - def __init__(self) -> None: + def __init__(self, drivers : List[Tuple[type, List[Dict[FilterFieldEnum, Any]]]]) -> None: self.__indices : Dict[str, Dict[str, Set[_Driver]]] = {} # Dict{field_name => Dict{field_value => Set{Driver}}} - def register_driver_class(self, driver_class, **query_fields): + for driver_class,filter_field_sets in drivers: + for filter_fields in filter_field_sets: + filter_fields = {k.value:v for k,v in filter_fields.items()} + self.register_driver_class(driver_class, **filter_fields) + + def register_driver_class(self, driver_class, **filter_fields): if not issubclass(driver_class, _Driver): raise UnsupportedDriverClassException(str(driver_class)) driver_name = driver_class.__name__ - unsupported_query_fields = set(query_fields.keys()).difference(set(QUERY_FIELDS.keys())) - if len(unsupported_query_fields) > 0: - raise UnsupportedQueryFieldException(unsupported_query_fields, driver_class_name=driver_name) + supported_filter_fields = set(FILTER_FIELD_ALLOWED_VALUES.keys()) + unsupported_filter_fields = set(filter_fields.keys()).difference(supported_filter_fields) + if len(unsupported_filter_fields) > 0: + raise UnsupportedFilterFieldException(unsupported_filter_fields, driver_class_name=driver_name) - for field_name, field_value in query_fields.items(): + for field_name, field_values in filter_fields.items(): field_indice = self.__indices.setdefault(field_name, dict()) - field_enum_values = QUERY_FIELDS.get(field_name) - if field_enum_values is not None and field_value not in field_enum_values: - raise UnsupportedQueryFieldValueException( - field_name, field_value, field_enum_values, driver_class_name=driver_name) - field_indice_drivers = field_indice.setdefault(field_name, set()) - field_indice_drivers.add(driver_class) - - def get_driver_class(self, **query_fields) -> _Driver: - unsupported_query_fields = set(query_fields.keys()).difference(set(QUERY_FIELDS.keys())) - if len(unsupported_query_fields) > 0: raise UnsupportedQueryFieldException(unsupported_query_fields) + field_enum_values = FILTER_FIELD_ALLOWED_VALUES.get(field_name) + if not isinstance(field_values, Iterable) or isinstance(field_values, str): + field_values = [field_values] + for field_value in field_values: + if isinstance(field_value, Enum): field_value = field_value.value + if field_enum_values is not None and field_value not in field_enum_values: + raise UnsupportedFilterFieldValueException( + field_name, field_value, field_enum_values, driver_class_name=driver_name) + field_indice_drivers = field_indice.setdefault(field_value, set()) + field_indice_drivers.add(driver_class) - candidate_driver_classes = None + def get_driver_class(self, **filter_fields) -> _Driver: + supported_filter_fields = set(FILTER_FIELD_ALLOWED_VALUES.keys()) + unsupported_filter_fields = set(filter_fields.keys()).difference(supported_filter_fields) + if len(unsupported_filter_fields) > 0: raise UnsupportedFilterFieldException(unsupported_filter_fields) - for field_name, field_value in query_fields.items(): + candidate_driver_classes : Dict[_Driver, int] = None # number of filter hits per driver + for field_name, field_values in filter_fields.items(): field_indice = self.__indices.get(field_name) if field_indice is None: continue - field_enum_values = QUERY_FIELDS.get(field_name) - if field_enum_values is not None and field_value not in field_enum_values: - raise UnsupportedQueryFieldValueException(field_name, field_value, field_enum_values) - field_indice_drivers = field_indice.get(field_name) - if field_indice_drivers is None: continue - - candidate_driver_classes = set().union(field_indice_drivers) if candidate_driver_classes is None else \ - candidate_driver_classes.intersection(field_indice_drivers) - - if len(candidate_driver_classes) == 0: raise UnsatisfiedQueryException(query_fields) - if len(candidate_driver_classes) > 1: - # TODO: Consider choosing driver with more query fields being satisfied (i.e., the most restrictive one) - raise MultipleResultsForQueryException(query_fields, {d.__name__ for d in candidate_driver_classes}) - return candidate_driver_classes.pop() + field_enum_values = FILTER_FIELD_ALLOWED_VALUES.get(field_name) + if not isinstance(field_values, Iterable) or isinstance(field_values, str): + field_values = [field_values] + + field_candidate_driver_classes = set() + for field_value in field_values: + if field_enum_values is not None and field_value not in field_enum_values: + raise UnsupportedFilterFieldValueException(field_name, field_value, field_enum_values) + field_indice_drivers = field_indice.get(field_value) + if field_indice_drivers is None: continue + field_candidate_driver_classes = field_candidate_driver_classes.union(field_indice_drivers) + + if candidate_driver_classes is None: + candidate_driver_classes = {k:1 for k in field_candidate_driver_classes} + else: + for candidate_driver_class in candidate_driver_classes: + if candidate_driver_class not in field_candidate_driver_classes: continue + candidate_driver_classes[candidate_driver_class] += 1 + + if len(candidate_driver_classes) == 0: raise UnsatisfiedFilterException(filter_fields) + candidate_driver_classes = sorted(candidate_driver_classes.items(), key=operator.itemgetter(1), reverse=True) + return candidate_driver_classes[0][0] diff --git a/src/device/service/driver_api/DriverInstanceCache.py b/src/device/service/driver_api/DriverInstanceCache.py new file mode 100644 index 0000000000000000000000000000000000000000..f960e37cbd22a7d4c06c9119ffaf64540dfc791a --- /dev/null +++ b/src/device/service/driver_api/DriverInstanceCache.py @@ -0,0 +1,57 @@ +import logging, threading +from typing import Any, Dict, Optional + +from device.service.driver_api.FilterFields import FilterFieldEnum +from ._Driver import _Driver +from .DriverFactory import DriverFactory +from .Exceptions import DriverInstanceCacheTerminatedException + +LOGGER = logging.getLogger(__name__) + +class DriverInstanceCache: + def __init__(self, driver_factory : DriverFactory) -> None: + self._lock = threading.Lock() + self._terminate = threading.Event() + self._device_uuid__to__driver_instance : Dict[str, _Driver] = {} + self._driver_factory = driver_factory + + def get( + self, device_uuid : str, filter_fields : Dict[FilterFieldEnum, Any] = {}, address : Optional[str] = None, + port : Optional[int] = None, settings : Dict[str, Any] = {}) -> _Driver: + + if self._terminate.is_set(): + raise DriverInstanceCacheTerminatedException() + + filter_fields = {k.value:v for k,v in filter_fields.items()} + + with self._lock: + driver_instance = self._device_uuid__to__driver_instance.get(device_uuid) + if driver_instance is not None: return driver_instance + + if len(filter_fields) == 0: return None + MSG = 'Selecting driver for device({:s}) with filter_fields({:s})...' + LOGGER.info(MSG.format(str(device_uuid), str(filter_fields))) + driver_class = self._driver_factory.get_driver_class(**filter_fields) + MSG = 'Driver({:s}) selected for device({:s}) with filter_fields({:s})...' + LOGGER.info(MSG.format(str(driver_class.__name__), str(device_uuid), str(filter_fields))) + driver_instance : _Driver = driver_class(address, port, **settings) + self._device_uuid__to__driver_instance[device_uuid] = driver_instance + return driver_instance + + def delete(self, device_uuid : str) -> None: + with self._lock: + device_driver = self._device_uuid__to__driver_instance.pop(device_uuid, None) + if device_driver is None: return + device_driver.Disconnect() + + def terminate(self) -> None: + self._terminate.set() + with self._lock: + while len(self._device_uuid__to__driver_instance) > 0: + try: + device_uuid,device_driver = self._device_uuid__to__driver_instance.popitem() + device_driver.Disconnect() + except: # pylint: disable=bare-except + msg = 'Error disconnecting Driver({:s}) from device. Will retry later...' + LOGGER.exception(msg.format(device_uuid)) + self._device_uuid__to__driver_instance[device_uuid] = device_driver diff --git a/src/device/service/driver_api/Exceptions.py b/src/device/service/driver_api/Exceptions.py index 2275bb04cbf9334a6823544bc48e8ad345d2dc20..c35d6372d60b4ea465b40d98e9e43e979835451d 100644 --- a/src/device/service/driver_api/Exceptions.py +++ b/src/device/service/driver_api/Exceptions.py @@ -1,30 +1,54 @@ -class MultipleResultsForQueryException(Exception): - def __init__(self, query_fields, driver_names): - super().__init__('Multiple Drivers({}) satisfy QueryFields({})'.format(str(driver_names), str(query_fields))) - -class UnsatisfiedQueryException(Exception): - def __init__(self, query_fields): - super().__init__('No Driver satisfies QueryFields({})'.format(str(query_fields))) +class UnsatisfiedFilterException(Exception): + def __init__(self, filter_fields): + msg = 'No Driver satisfies FilterFields({:s})' + super().__init__(msg.format(str(filter_fields))) class UnsupportedDriverClassException(Exception): def __init__(self, driver_class_name): - super().__init__('Class({}) is not a subclass of _Driver'.format(str(driver_class_name))) + msg = 'Class({:s}) is not a subclass of _Driver' + super().__init__(msg.format(str(driver_class_name))) -class UnsupportedQueryFieldException(Exception): - def __init__(self, unsupported_query_fields, driver_class_name=None): +class UnsupportedFilterFieldException(Exception): + def __init__(self, unsupported_filter_fields, driver_class_name=None): if driver_class_name: - msg = 'QueryFields({}) specified by Driver({}) are not supported'.format( - str(unsupported_query_fields), str(driver_class_name)) + msg = 'FilterFields({:s}) specified by Driver({:s}) are not supported' + msg = msg.format(str(unsupported_filter_fields), str(driver_class_name)) else: - msg = 'QueryFields({}) specified in query are not supported'.format(str(unsupported_query_fields)) + msg = 'FilterFields({:s}) specified in Filter are not supported' + msg = msg.format(str(unsupported_filter_fields)) super().__init__(msg) -class UnsupportedQueryFieldValueException(Exception): - def __init__(self, query_field_name, query_field_value, allowed_query_field_values, driver_class_name=None): +class UnsupportedFilterFieldValueException(Exception): + def __init__(self, filter_field_name, filter_field_value, allowed_filter_field_values, driver_class_name=None): if driver_class_name: - msg = 'QueryField({}={}) specified by Driver({}) is not supported. Allowed values are {}'.format( - str(query_field_name), str(query_field_value), str(driver_class_name), str(allowed_query_field_values)) + msg = 'FilterField({:s}={:s}) specified by Driver({:s}) is not supported. Allowed values are {:s}' + msg = msg.format( + str(filter_field_name), str(filter_field_value), str(driver_class_name), + str(allowed_filter_field_values)) else: - msg = 'QueryField({}={}) specified in query is not supported. Allowed values are {}'.format( - str(query_field_name), str(query_field_value), str(allowed_query_field_values)) + msg = 'FilterField({:s}={:s}) specified in Filter is not supported. Allowed values are {:s}' + msg = msg.format(str(filter_field_name), str(filter_field_value), str(allowed_filter_field_values)) + super().__init__(msg) + +class DriverInstanceCacheTerminatedException(Exception): + def __init__(self): + msg = 'DriverInstanceCache is terminated. No new instances can be processed.' + super().__init__(msg) + +class UnsupportedResourceKeyException(Exception): + def __init__(self, resource_key): + msg = 'ResourceKey({:s}) not supported' + msg = msg.format(str(resource_key)) + super().__init__(msg) + +class ConfigFieldNotFoundException(Exception): + def __init__(self, config_field_name): + msg = 'ConfigField({:s}) not specified in resource' + msg = msg.format(str(config_field_name)) + super().__init__(msg) + +class ConfigFieldsNotSupportedException(Exception): + def __init__(self, config_fields): + msg = 'ConfigFields({:s}) not supported in resource' + msg = msg.format(str(config_fields)) super().__init__(msg) diff --git a/src/device/service/driver_api/FilterFields.py b/src/device/service/driver_api/FilterFields.py new file mode 100644 index 0000000000000000000000000000000000000000..c7de05f92a743c826d54897930b10013bd09c2b7 --- /dev/null +++ b/src/device/service/driver_api/FilterFields.py @@ -0,0 +1,26 @@ +from enum import Enum +from device.service.database.DeviceModel import ORM_DeviceDriverEnum + +class DeviceTypeFilterFieldEnum(Enum): + EMULATED = 'emulated' + OPTICAL_ROADM = 'optical-roadm' + OPTICAL_TRANDPONDER = 'optical-trandponder' + OPTICAL_LINE_SYSTEM = 'optical-line-system' + PACKET_ROUTER = 'packet-router' + PACKET_SWITCH = 'packet-switch' + +class FilterFieldEnum(Enum): + DEVICE_TYPE = 'device_type' + DRIVER = 'driver' + VENDOR = 'vendor' + MODEL = 'model' + SERIAL_NUMBER = 'serial_number' + +# Map allowed filter fields to allowed values per Filter field. If no restriction (free text) None is specified +FILTER_FIELD_ALLOWED_VALUES = { + FilterFieldEnum.DEVICE_TYPE.value : {i.value for i in DeviceTypeFilterFieldEnum}, + FilterFieldEnum.DRIVER.value : {i.value for i in ORM_DeviceDriverEnum}, + FilterFieldEnum.VENDOR.value : None, + FilterFieldEnum.MODEL.value : None, + FilterFieldEnum.SERIAL_NUMBER.value : None, +} diff --git a/src/device/service/driver_api/Tools.py b/src/device/service/driver_api/Tools.py new file mode 100644 index 0000000000000000000000000000000000000000..ab22cbc040daee7e47e80b0235b79b19cdb7acbc --- /dev/null +++ b/src/device/service/driver_api/Tools.py @@ -0,0 +1,57 @@ +import operator +from typing import Any, Callable, List, Tuple, Union + +ACTION_MSG_GET = 'Get resource(key={:s})' +ACTION_MSG_SET = 'Set resource(key={:s}, value={:s})' +ACTION_MSG_DELETE = 'Delete resource(key={:s}, value={:s})' +ACTION_MSG_SUBSCRIBE = 'Subscribe subscription(key={:s}, duration={:s}, interval={:s})' +ACTION_MSG_UNSUBSCRIBE = 'Unsubscribe subscription(key={:s}, duration={:s}, interval={:s})' + +def _get(resource_key : str): + return ACTION_MSG_GET.format(str(resource_key)) + +def _set(resource : Tuple[str, Any]): + return ACTION_MSG_SET.format(*tuple(map(str, resource))) + +def _delete(resource : Tuple[str, Any]): + return ACTION_MSG_SET.format(*tuple(map(str, resource))) + +def _subscribe(subscription : Tuple[str, float, float]): + return ACTION_MSG_SUBSCRIBE.format(*tuple(map(str, subscription))) + +def _unsubscribe(subscription : Tuple[str, float, float]): + return ACTION_MSG_UNSUBSCRIBE.format(*tuple(map(str, subscription))) + +def _check_errors( + error_func : Callable, parameters_list : List[Any], results_list : List[Union[bool, Exception]] + ) -> List[str]: + errors = [] + for parameters, results in zip(parameters_list, results_list): + if not isinstance(results, Exception): continue + errors.append('Unable to {:s}; error({:s})'.format(error_func(parameters), str(results))) + return errors + +def check_get_errors( + resource_keys : List[str], results : List[Tuple[str, Union[Any, None, Exception]]] + ) -> List[str]: + return _check_errors(_get, resource_keys, map(operator.itemgetter(1), results)) + +def check_set_errors( + resources : List[Tuple[str, Any]], results : List[Union[bool, Exception]] + ) -> List[str]: + return _check_errors(_set, resources, results) + +def check_delete_errors( + resources : List[Tuple[str, Any]], results : List[Union[bool, Exception]] + ) -> List[str]: + return _check_errors(_delete, resources, results) + +def check_subscribe_errors( + subscriptions : List[Tuple[str, float, float]], results : List[Union[bool, Exception]] + ) -> List[str]: + return _check_errors(_subscribe, subscriptions, results) + +def check_unsubscribe_errors( + subscriptions : List[Tuple[str, float, float]], results : List[Union[bool, Exception]] + ) -> List[str]: + return _check_errors(_unsubscribe, subscriptions, results) diff --git a/src/device/service/driver_api/_Driver.py b/src/device/service/driver_api/_Driver.py index 69ac93cb6a071a40aca25b28f930e390bfbfe6b0..73174ba53ac6e0b357d3bd790c53f429bea36d87 100644 --- a/src/device/service/driver_api/_Driver.py +++ b/src/device/service/driver_api/_Driver.py @@ -1,15 +1,21 @@ from typing import Any, Iterator, List, Tuple, Union +# Special resource names to request to the driver to retrieve the specified configuration/structural resources. +# These resource names should be used with GetConfig() method. +RESOURCE_ENDPOINTS = '__endpoints__' +RESOURCE_INTERFACES = '__interfaces__' +RESOURCE_NETWORK_INSTANCES = '__network_instances__' + class _Driver: - def __init__(self, address : str, port : int, **kwargs) -> None: + def __init__(self, address : str, port : int, **settings) -> None: """ Initialize Driver. Parameters: address : str The address of the device port : int The port of the device - **kwargs - Extra attributes can be configured using kwargs. + **settings + Extra settings required by the driver. """ raise NotImplementedError() @@ -29,20 +35,38 @@ class _Driver: """ raise NotImplementedError() - def GetConfig(self, resource_keys : List[str]) -> List[Union[Any, None, Exception]]: + def GetInitialConfig(self) -> List[Tuple[str, Any]]: + """ Retrieve initial configuration of entire device. + Returns: + values : List[Tuple[str, Any]] + List of tuples (resource key, resource value) for resource keys. + """ + raise NotImplementedError() + + def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: """ Retrieve running configuration of entire device, or selected resource keys. Parameters: resource_keys : List[str] List of keys pointing to the resources to be retrieved. Returns: - values : List[Union[Any, None, Exception]] - List of values for resource keys requested. Return values must be in the same order than resource - keys requested. If a resource is found, the appropriate value type must be retrieved, if a resource - is not found, None must be retrieved in the List for that resource. In case of Exception processing - a resource, the Exception must be retrieved. + values : List[Tuple[str, Union[Any, None, Exception]]] + List of tuples (resource key, resource value) for resource keys requested. If a resource is found, + the appropriate value type must be retrieved. If a resource is not found, None must be retrieved as + value for that resource. In case of Exception, the Exception must be retrieved as value. """ raise NotImplementedError() + #def GetResource(self, endpoint_uuid : str) -> Optional[str]: + # """ Retrieve the endpoint path for subscriptions. + # Parameters: + # endpoint_uuid : str + # Target endpoint UUID + # Returns: + # resource_path : Optional[str] + # The path of the endpoint, or None if it is not found. + # """ + # raise NotImplementedError() + def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: """ Create/Update configuration for a list of resources. Parameters: @@ -57,11 +81,12 @@ class _Driver: """ raise NotImplementedError() - def DeleteConfig(self, resource_keys : List[str]) -> List[Union[bool, Exception]]: - """ Delete configuration for a list of resource keys. + def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + """ Delete configuration for a list of resources. Parameters: - resource_keys : List[str] - List of keys pointing to the resources to be deleted. + resources : List[Tuple[str, Any]] + List of tuples, each containing a resource_key pointing the resource to be modified, and a + resource_value containing possible additionally required values to locate the value to be removed. Returns: results : List[bool] List of results for resource key deletions requested. Return values must be in the same order than diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e59bae207e4cd14f238aabcb7e373bb973374005 100644 --- a/src/device/service/drivers/__init__.py +++ b/src/device/service/drivers/__init__.py @@ -0,0 +1,25 @@ +from ..driver_api.FilterFields import FilterFieldEnum, DeviceTypeFilterFieldEnum, ORM_DeviceDriverEnum +from .emulated.EmulatedDriver import EmulatedDriver +from .openconfig.OpenConfigDriver import OpenConfigDriver +from .transport_api.TransportApiDriver import TransportApiDriver + +DRIVERS = [ + (EmulatedDriver, [ + { + FilterFieldEnum.DEVICE_TYPE: DeviceTypeFilterFieldEnum.EMULATED, + FilterFieldEnum.DRIVER : ORM_DeviceDriverEnum.UNDEFINED, + } + ]), + (OpenConfigDriver, [ + { + FilterFieldEnum.DEVICE_TYPE: DeviceTypeFilterFieldEnum.PACKET_ROUTER, + FilterFieldEnum.DRIVER : ORM_DeviceDriverEnum.OPENCONFIG, + } + ]), + (TransportApiDriver, [ + { + FilterFieldEnum.DEVICE_TYPE: DeviceTypeFilterFieldEnum.OPTICAL_LINE_SYSTEM, + FilterFieldEnum.DRIVER : ORM_DeviceDriverEnum.TRANSPORT_API, + } + ]), +] diff --git a/src/device/service/drivers/emulated/EmulatedDriver.py b/src/device/service/drivers/emulated/EmulatedDriver.py index 7dc5757f7afb928bd56e64b5a87d4c414171cd6b..06dc4bd7c36e99d5f081f97e2caa46b8bb5fd2d6 100644 --- a/src/device/service/drivers/emulated/EmulatedDriver.py +++ b/src/device/service/drivers/emulated/EmulatedDriver.py @@ -1,23 +1,25 @@ import anytree, logging, pytz, queue, random, threading from datetime import datetime, timedelta -from typing import Any, Iterator, List, Tuple, Union +from typing import Any, Iterator, List, Optional, Tuple, Union from apscheduler.executors.pool import ThreadPoolExecutor from apscheduler.job import Job from apscheduler.jobstores.memory import MemoryJobStore from apscheduler.schedulers.background import BackgroundScheduler -from common.Checkers import chk_float, chk_length, chk_string, chk_type +from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk_type from device.service.driver_api._Driver import _Driver -from .AnyTreeTools import TreeNode, dump_subtree, get_subnode, set_subnode_value +from device.service.driver_api.AnyTreeTools import TreeNode, dump_subtree, get_subnode, set_subnode_value LOGGER = logging.getLogger(__name__) -def sample(resource_key : str, out_samples : queue.Queue): +def do_sampling(resource_key : str, out_samples : queue.Queue): out_samples.put_nowait((datetime.timestamp(datetime.utcnow()), resource_key, random.random())) class EmulatedDriver(_Driver): - def __init__(self, address : str, port : int, **kwargs) -> None: + def __init__(self, address : str, port : int, **settings) -> None: # pylint: disable=super-init-not-called self.__lock = threading.Lock() - self.__root = TreeNode('.') + self.__initial = TreeNode('.') + self.__running = TreeNode('.') + self.__started = threading.Event() self.__terminate = threading.Event() self.__scheduler = BackgroundScheduler(daemon=True) # scheduler used to emulate sampling events self.__scheduler.configure( @@ -28,21 +30,35 @@ class EmulatedDriver(_Driver): self.__out_samples = queue.Queue() def Connect(self) -> bool: + # If started, assume it is already connected + if self.__started.is_set(): return True + # Connect triggers activation of sampling events that will be scheduled based on subscriptions self.__scheduler.start() + + # Indicate the driver is now connected to the device + self.__started.set() return True def Disconnect(self) -> bool: # Trigger termination of loops and processes self.__terminate.set() + + # If not started, assume it is already disconnected + if not self.__started.is_set(): return True + # Disconnect triggers deactivation of sampling events self.__scheduler.shutdown() return True - def GetConfig(self, resource_keys : List[str] = []) -> List[Union[Any, None, Exception]]: + def GetInitialConfig(self) -> List[Tuple[str, Any]]: + with self.__lock: + return dump_subtree(self.__initial) + + def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: chk_type('resources', resource_keys, list) with self.__lock: - if len(resource_keys) == 0: return dump_subtree(self.__root) + if len(resource_keys) == 0: return dump_subtree(self.__running) results = [] resolver = anytree.Resolver(pathattr='name') for i,resource_key in enumerate(resource_keys): @@ -50,16 +66,23 @@ class EmulatedDriver(_Driver): try: chk_string(str_resource_name, resource_key, allow_empty=False) resource_path = resource_key.split('/') - except Exception as e: - LOGGER.exception('Exception validating {}: {}'.format(str_resource_name, str(resource_key))) - results.append(e) # if validation fails, store the exception + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception validating {:s}: {:s}'.format(str_resource_name, str(resource_key))) + results.append((resource_key, e)) # if validation fails, store the exception continue - resource_node = get_subnode(resolver, self.__root, resource_path, default=None) + resource_node = get_subnode(resolver, self.__running, resource_path, default=None) # if not found, resource_node is None - results.append(None if resource_node is None else dump_subtree(resource_node)) + if resource_node is None: continue + results.extend(dump_subtree(resource_node)) return results + def GetResource(self, endpoint_uuid : str) -> Optional[str]: + chk_string('endpoint_uuid', endpoint_uuid) + return { + #'key': 'value', + }.get(endpoint_uuid) + def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: chk_type('resources', resources, list) if len(resources) == 0: return [] @@ -70,35 +93,39 @@ class EmulatedDriver(_Driver): str_resource_name = 'resources[#{:d}]'.format(i) try: chk_type(str_resource_name, resource, (list, tuple)) - chk_length(str_resource_name, resource, allowed_lengths=2) + chk_length(str_resource_name, resource, min_length=2, max_length=2) resource_key,resource_value = resource + chk_string(str_resource_name, resource_key, allow_empty=False) resource_path = resource_key.split('/') - except Exception as e: - LOGGER.exception('Exception validating {}: {}'.format(str_resource_name, str(resource_key))) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception validating {:s}: {:s}'.format(str_resource_name, str(resource_key))) results.append(e) # if validation fails, store the exception continue - set_subnode_value(resolver, self.__root, resource_path, resource_value) + set_subnode_value(resolver, self.__running, resource_path, resource_value) results.append(True) return results - def DeleteConfig(self, resource_keys : List[str]) -> List[Union[bool, Exception]]: - chk_type('resources', resource_keys, list) - if len(resource_keys) == 0: return [] + def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + chk_type('resources', resources, list) + if len(resources) == 0: return [] results = [] resolver = anytree.Resolver(pathattr='name') with self.__lock: - for i,resource_key in enumerate(resource_keys): - str_resource_name = 'resource_key[#{:d}]'.format(i) + for i,resource in enumerate(resources): + str_resource_name = 'resources[#{:d}]'.format(i) try: + chk_type(str_resource_name, resource, (list, tuple)) + chk_length(str_resource_name, resource, min_length=2, max_length=2) + resource_key,_ = resource chk_string(str_resource_name, resource_key, allow_empty=False) resource_path = resource_key.split('/') - except Exception as e: - LOGGER.exception('Exception validating {}: {}'.format(str_resource_name, str(resource_key))) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception validating {:s}: {:s}'.format(str_resource_name, str(resource_key))) results.append(e) # if validation fails, store the exception continue - resource_node = get_subnode(resolver, self.__root, resource_path, default=None) + resource_node = get_subnode(resolver, self.__running, resource_path, default=None) # if not found, resource_node is None if resource_node is None: results.append(False) @@ -111,24 +138,24 @@ class EmulatedDriver(_Driver): results.append(True) return results - def SubscribeState(self, resources : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: - chk_type('resources', resources, list) - if len(resources) == 0: return [] + def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: + chk_type('subscriptions', subscriptions, list) + if len(subscriptions) == 0: return [] results = [] resolver = anytree.Resolver(pathattr='name') with self.__lock: - for i,resource in enumerate(resources): - str_resource_name = 'resources[#{:d}]'.format(i) + for i,subscription in enumerate(subscriptions): + str_subscription_name = 'subscriptions[#{:d}]'.format(i) try: - chk_type(str_resource_name, resource, (list, tuple)) - chk_length(str_resource_name, resource, allowed_lengths=3) - resource_key,sampling_duration,sampling_interval = resource - chk_string(str_resource_name + '.resource_key', resource_key, allow_empty=False) + chk_type(str_subscription_name, subscription, (list, tuple)) + chk_length(str_subscription_name, subscription, min_length=3, max_length=3) + resource_key,sampling_duration,sampling_interval = subscription + chk_string(str_subscription_name + '.resource_key', resource_key, allow_empty=False) resource_path = resource_key.split('/') - chk_float(str_resource_name + '.sampling_duration', sampling_duration, min_value=0) - chk_float(str_resource_name + '.sampling_interval', sampling_interval, min_value=0) - except Exception as e: - LOGGER.exception('Exception validating {}: {}'.format(str_resource_name, str(resource_key))) + chk_float(str_subscription_name + '.sampling_duration', sampling_duration, min_value=0) + chk_float(str_subscription_name + '.sampling_interval', sampling_interval, min_value=0) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception validating {:s}: {:s}'.format(str_subscription_name, str(resource_key))) results.append(e) # if validation fails, store the exception continue @@ -139,39 +166,39 @@ class EmulatedDriver(_Driver): job_id = 'k={:s}/d={:f}/i={:f}'.format(resource_key, sampling_duration, sampling_interval) job = self.__scheduler.add_job( - sample, args=(resource_key, self.__out_samples), kwargs={}, + do_sampling, args=(resource_key, self.__out_samples), kwargs={}, id=job_id, trigger='interval', seconds=sampling_interval, start_date=start_date, end_date=end_date, timezone=pytz.utc) subscription_path = resource_path + ['{:.3f}:{:.3f}'.format(sampling_duration, sampling_interval)] - set_subnode_value(resolver, self.__root, subscription_path, job) + set_subnode_value(resolver, self.__running, subscription_path, job) results.append(True) return results - def UnsubscribeState(self, resources : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: - chk_type('resources', resources, list) - if len(resources) == 0: return [] + def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: + chk_type('subscriptions', subscriptions, list) + if len(subscriptions) == 0: return [] results = [] resolver = anytree.Resolver(pathattr='name') with self.__lock: - for i,resource in enumerate(resources): - str_resource_name = 'resources[#{:d}]'.format(i) + for i,resource in enumerate(subscriptions): + str_subscription_name = 'resources[#{:d}]'.format(i) try: - chk_type(str_resource_name, resource, (list, tuple)) - chk_length(str_resource_name, resource, allowed_lengths=3) + chk_type(str_subscription_name, resource, (list, tuple)) + chk_length(str_subscription_name, resource, min_length=3, max_length=3) resource_key,sampling_duration,sampling_interval = resource - chk_string(str_resource_name + '.resource_key', resource_key, allow_empty=False) + chk_string(str_subscription_name + '.resource_key', resource_key, allow_empty=False) resource_path = resource_key.split('/') - chk_float(str_resource_name + '.sampling_duration', sampling_duration, min_value=0) - chk_float(str_resource_name + '.sampling_interval', sampling_interval, min_value=0) - except Exception as e: - LOGGER.exception('Exception validating {}: {}'.format(str_resource_name, str(resource_key))) + chk_float(str_subscription_name + '.sampling_duration', sampling_duration, min_value=0) + chk_float(str_subscription_name + '.sampling_interval', sampling_interval, min_value=0) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception validating {:s}: {:s}'.format(str_subscription_name, str(resource_key))) results.append(e) # if validation fails, store the exception continue subscription_path = resource_path + ['{:.3f}:{:.3f}'.format(sampling_duration, sampling_interval)] - subscription_node = get_subnode(resolver, self.__root, subscription_path) - + subscription_node = get_subnode(resolver, self.__running, subscription_path) + # if not found, resource_node is None if subscription_node is None: results.append(False) @@ -179,7 +206,7 @@ class EmulatedDriver(_Driver): job : Job = getattr(subscription_node, 'value', None) if job is None or not isinstance(job, Job): - raise Exception('Malformed subscription node or wrong resource key: {}'.format(str(resource))) + raise Exception('Malformed subscription node or wrong resource key: {:s}'.format(str(resource))) job.remove() parent = subscription_node.parent diff --git a/src/device/service/drivers/openconfig/OpenConfigDriver.py b/src/device/service/drivers/openconfig/OpenConfigDriver.py new file mode 100644 index 0000000000000000000000000000000000000000..e2381d81e5e1aa81907f90b6e473efb154e92e79 --- /dev/null +++ b/src/device/service/drivers/openconfig/OpenConfigDriver.py @@ -0,0 +1,231 @@ +import logging, pytz, queue, threading +#from datetime import datetime, timedelta +from typing import Any, List, Tuple, Union +#from apscheduler.executors.pool import ThreadPoolExecutor +#from apscheduler.job import Job +#from apscheduler.jobstores.memory import MemoryJobStore +#from apscheduler.schedulers.background import BackgroundScheduler +from netconf_client.connect import connect_ssh +from netconf_client.ncclient import Manager +from common.type_checkers.Checkers import chk_length, chk_string, chk_type +from device.service.driver_api.Exceptions import UnsupportedResourceKeyException +from device.service.driver_api._Driver import _Driver +from device.service.driver_api.AnyTreeTools import set_subnode_value +from device.service.drivers.openconfig.Tools import xml_pretty_print, xml_to_dict, xml_to_file +from device.service.drivers.openconfig.templates import ALL_RESOURCE_KEYS, compose_config, get_filter, parse + +#logging.getLogger('ncclient.transport.ssh').setLevel(logging.WARNING) + +LOGGER = logging.getLogger(__name__) + +#def do_sampling(resource_key : str, out_samples : queue.Queue): +# out_samples.put_nowait((datetime.timestamp(datetime.utcnow()), resource_key, random.random())) + +class OpenConfigDriver(_Driver): + def __init__(self, address : str, port : int, **settings) -> None: # pylint: disable=super-init-not-called + self.__address = address + self.__port = int(port) + self.__settings = settings + self.__lock = threading.Lock() + #self.__initial = TreeNode('.') + #self.__running = TreeNode('.') + self.__started = threading.Event() + self.__terminate = threading.Event() + self.__netconf_manager : Manager = None + #self.__scheduler = BackgroundScheduler(daemon=True) # scheduler used to emulate sampling events + #self.__scheduler.configure( + # jobstores = {'default': MemoryJobStore()}, + # executors = {'default': ThreadPoolExecutor(max_workers=1)}, + # job_defaults = {'coalesce': False, 'max_instances': 3}, + # timezone=pytz.utc) + #self.__out_samples = queue.Queue() + + def Connect(self) -> bool: + with self.__lock: + if self.__started.is_set(): return True + username = self.__settings.get('username') + password = self.__settings.get('password') + timeout = int(self.__settings.get('timeout', 120)) + session = connect_ssh( + host=self.__address, port=self.__port, username=username, password=password) + self.__netconf_manager = Manager(session, timeout=timeout) + self.__netconf_manager.set_logger_level(logging.DEBUG) + # Connect triggers activation of sampling events that will be scheduled based on subscriptions + #self.__scheduler.start() + self.__started.set() + return True + + def Disconnect(self) -> bool: + with self.__lock: + # Trigger termination of loops and processes + self.__terminate.set() + # If not started, assume it is already disconnected + if not self.__started.is_set(): return True + # Disconnect triggers deactivation of sampling events + #self.__scheduler.shutdown() + self.__netconf_manager.close_session() + return True + + def GetInitialConfig(self) -> List[Tuple[str, Any]]: + with self.__lock: + return [] + + def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: + chk_type('resources', resource_keys, list) + results = [] + with self.__lock: + if len(resource_keys) == 0: resource_keys = ALL_RESOURCE_KEYS + for i,resource_key in enumerate(resource_keys): + str_resource_name = 'resource_key[#{:d}]'.format(i) + try: + chk_string(str_resource_name, resource_key, allow_empty=False) + str_filter = get_filter(resource_key) + if str_filter is None: str_filter = resource_key + xml_data = self.__netconf_manager.get(filter=str_filter).data_ele + if isinstance(xml_data, Exception): raise xml_data + results.extend(parse(resource_key, xml_data)) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception retrieving {:s}: {:s}'.format(str_resource_name, str(resource_key))) + results.append((resource_key, e)) # if validation fails, store the exception + return results + + #def GetResource(self, endpoint_uuid : str) -> Optional[str]: + # chk_string('endpoint_uuid', endpoint_uuid) + # return { + # #'key': 'value', + # }.get(endpoint_uuid) + + def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + chk_type('resources', resources, list) + if len(resources) == 0: return [] + results = [] + with self.__lock: + for i,resource in enumerate(resources): + str_resource_name = 'resources[#{:d}]'.format(i) + try: + #LOGGER.info('resource = {:s}'.format(str(resource))) + chk_type(str_resource_name, resource, (list, tuple)) + chk_length(str_resource_name, resource, min_length=2, max_length=2) + resource_key,resource_value = resource + chk_string(str_resource_name + '.key', resource_key, allow_empty=False) + str_config_message = compose_config(resource_key, resource_value) + if str_config_message is None: raise UnsupportedResourceKeyException(resource_key) + #LOGGER.info('str_config_message = {:s}'.format(str(str_config_message))) + self.__netconf_manager.edit_config(str_config_message, target='running') + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception setting {:s}: {:s}'.format(str_resource_name, str(resource))) + results.append(e) # if validation fails, store the exception + return results + + def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + chk_type('resources', resources, list) + if len(resources) == 0: return [] + results = [] + with self.__lock: + for i,resource in enumerate(resources): + str_resource_name = 'resources[#{:d}]'.format(i) + try: + #LOGGER.info('resource = {:s}'.format(str(resource))) + chk_type(str_resource_name, resource, (list, tuple)) + chk_length(str_resource_name, resource, min_length=2, max_length=2) + resource_key,resource_value = resource + chk_string(str_resource_name + '.key', resource_key, allow_empty=False) + str_config_message = compose_config(resource_key, resource_value, delete=True) + if str_config_message is None: raise UnsupportedResourceKeyException(resource_key) + #LOGGER.info('str_config_message = {:s}'.format(str(str_config_message))) + self.__netconf_manager.edit_config(str_config_message, target='running') + results.append(True) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception deleting {:s}: {:s}'.format(str_resource_name, str(resource_key))) + results.append(e) # if validation fails, store the exception + return results + +# def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: +# chk_type('subscriptions', subscriptions, list) +# if len(subscriptions) == 0: return [] +# results = [] +# resolver = anytree.Resolver(pathattr='name') +# with self.__lock: +# for i,subscription in enumerate(subscriptions): +# str_subscription_name = 'subscriptions[#{:d}]'.format(i) +# try: +# chk_type(str_subscription_name, subscription, (list, tuple)) +# chk_length(str_subscription_name, subscription, min_length=3, max_length=3) +# resource_key,sampling_duration,sampling_interval = subscription +# chk_string(str_subscription_name + '.resource_key', resource_key, allow_empty=False) +# resource_path = resource_key.split('/') +# chk_float(str_subscription_name + '.sampling_duration', sampling_duration, min_value=0) +# chk_float(str_subscription_name + '.sampling_interval', sampling_interval, min_value=0) +# except Exception as e: # pylint: disable=broad-except +# LOGGER.exception('Exception validating {:s}: {:s}'.format(str_subscription_name, str(resource_key))) +# results.append(e) # if validation fails, store the exception +# continue +# +# start_date,end_date = None,None +# if sampling_duration <= 1.e-12: +# start_date = datetime.utcnow() +# end_date = start_date + timedelta(seconds=sampling_duration) +# +# job_id = 'k={:s}/d={:f}/i={:f}'.format(resource_key, sampling_duration, sampling_interval) +# job = self.__scheduler.add_job( +# do_sampling, args=(resource_key, self.__out_samples), kwargs={}, +# id=job_id, trigger='interval', seconds=sampling_interval, +# start_date=start_date, end_date=end_date, timezone=pytz.utc) +# +# subscription_path = resource_path + ['{:.3f}:{:.3f}'.format(sampling_duration, sampling_interval)] +# set_subnode_value(resolver, self.__running, subscription_path, job) +# results.append(True) +# return results +# +# def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: +# chk_type('subscriptions', subscriptions, list) +# if len(subscriptions) == 0: return [] +# results = [] +# resolver = anytree.Resolver(pathattr='name') +# with self.__lock: +# for i,resource in enumerate(subscriptions): +# str_subscription_name = 'resources[#{:d}]'.format(i) +# try: +# chk_type(str_subscription_name, resource, (list, tuple)) +# chk_length(str_subscription_name, resource, min_length=3, max_length=3) +# resource_key,sampling_duration,sampling_interval = resource +# chk_string(str_subscription_name + '.resource_key', resource_key, allow_empty=False) +# resource_path = resource_key.split('/') +# chk_float(str_subscription_name + '.sampling_duration', sampling_duration, min_value=0) +# chk_float(str_subscription_name + '.sampling_interval', sampling_interval, min_value=0) +# except Exception as e: # pylint: disable=broad-except +# LOGGER.exception('Exception validating {:s}: {:s}'.format(str_subscription_name, str(resource_key))) +# results.append(e) # if validation fails, store the exception +# continue +# +# subscription_path = resource_path + ['{:.3f}:{:.3f}'.format(sampling_duration, sampling_interval)] +# subscription_node = get_subnode(resolver, self.__running, subscription_path) +# +# # if not found, resource_node is None +# if subscription_node is None: +# results.append(False) +# continue +# +# job : Job = getattr(subscription_node, 'value', None) +# if job is None or not isinstance(job, Job): +# raise Exception('Malformed subscription node or wrong resource key: {:s}'.format(str(resource))) +# job.remove() +# +# parent = subscription_node.parent +# children = list(parent.children) +# children.remove(subscription_node) +# parent.children = tuple(children) +# +# results.append(True) +# return results +# +# def GetState(self, blocking=False) -> Iterator[Tuple[str, Any]]: +# while not self.__terminate.is_set(): +# try: +# sample = self.__out_samples.get(block=blocking, timeout=0.1) +# except queue.Empty: +# if blocking: continue +# return +# if sample is None: continue +# yield sample diff --git a/src/device/service/drivers/openconfig/Tools.py b/src/device/service/drivers/openconfig/Tools.py new file mode 100644 index 0000000000000000000000000000000000000000..230a6e3c33586c5d1771a6da2fd9dabc533e9538 --- /dev/null +++ b/src/device/service/drivers/openconfig/Tools.py @@ -0,0 +1,11 @@ +import xml.dom.minidom, xmltodict + +def xml_pretty_print(data : str): + return xml.dom.minidom.parseString(data).toprettyxml() + +def xml_to_file(data : str, file_path : str) -> None: + with open(file_path, mode='w', encoding='UTF-8') as f: + f.write(xml_pretty_print(data)) + +def xml_to_dict(data : str): + return xmltodict.parse(data) diff --git a/src/device/service/drivers/openconfig/templates/EndPoints.py b/src/device/service/drivers/openconfig/templates/EndPoints.py new file mode 100644 index 0000000000000000000000000000000000000000..4908c818374ca3b94fb77c5d5cd88d97d3c881b5 --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/EndPoints.py @@ -0,0 +1,27 @@ +import logging, lxml.etree as ET +from typing import Any, Dict, List, Tuple +from .Namespace import NAMESPACES +from .Tools import add_value_from_tag + +LOGGER = logging.getLogger(__name__) + +XPATH_PORTS = "//ocp:components/ocp:component/ocp:state[ocp:type='PORT']/.." + +def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: + response = [] + for xml_component in xml_data.xpath(XPATH_PORTS, namespaces=NAMESPACES): + #LOGGER.info('xml_component = {:s}'.format(str(ET.tostring(xml_component)))) + + endpoint = {} + + component_name = xml_component.find('ocp:name', namespaces=NAMESPACES) + if component_name is None or component_name.text is None: continue + add_value_from_tag(endpoint, 'name', component_name) + + component_type = xml_component.find( + 'ocpp:port/ocpp:breakout-mode/ocpp:state/ocpp:channel-speed', namespaces=NAMESPACES) + add_value_from_tag(endpoint, 'type', component_type) + + if len(endpoint) == 0: continue + response.append(('endpoint[{:s}]'.format(endpoint['name']), endpoint)) + return response diff --git a/src/device/service/drivers/openconfig/templates/Interfaces.py b/src/device/service/drivers/openconfig/templates/Interfaces.py new file mode 100644 index 0000000000000000000000000000000000000000..0bbd70d04a3c093dcdbad4966be3030dbc8ba0fb --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/Interfaces.py @@ -0,0 +1,65 @@ +import logging, lxml.etree as ET +from typing import Any, Dict, List, Tuple +from .Namespace import NAMESPACES +from .Tools import add_value_from_collection, add_value_from_tag + +LOGGER = logging.getLogger(__name__) + +XPATH_INTERFACES = "//oci:interfaces/oci:interface" +XPATH_SUBINTERFACES = ".//oci:subinterfaces/oci:subinterface" +XPATH_IPV4ADDRESSES = ".//ociip:ipv4/ociip:addresses/ociip:address" + +def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: + response = [] + for xml_interface in xml_data.xpath(XPATH_INTERFACES, namespaces=NAMESPACES): + LOGGER.info('xml_interface = {:s}'.format(str(ET.tostring(xml_interface)))) + + interface = {} + + interface_name = xml_interface.find('oci:name', namespaces=NAMESPACES) + if interface_name is None or interface_name.text is None: continue + add_value_from_tag(interface, 'name', interface_name) + + interface_type = xml_interface.find('oci:config/oci:type', namespaces=NAMESPACES) + add_value_from_tag(interface, 'type', interface_type) + + for xml_subinterface in xml_interface.xpath(XPATH_SUBINTERFACES, namespaces=NAMESPACES): + LOGGER.info('xml_subinterface = {:s}'.format(str(ET.tostring(xml_subinterface)))) + + subinterface = {} + + subinterface_index = xml_subinterface.find('oci:index', namespaces=NAMESPACES) + if subinterface_index is None or subinterface_index.text is None: continue + add_value_from_tag(subinterface, 'index', subinterface_index) + + vlan_id = xml_subinterface.find('ocv:vlan/ocv:config/ocv:vlan-id', namespaces=NAMESPACES) + add_value_from_tag(subinterface, 'vlan_id', vlan_id, cast=int) + + ipv4_addresses = [] + for xml_ipv4_address in xml_subinterface.xpath(XPATH_IPV4ADDRESSES, namespaces=NAMESPACES): + LOGGER.info('xml_ipv4_address = {:s}'.format(str(ET.tostring(xml_ipv4_address)))) + + ipv4_address = {} + + origin = xml_ipv4_address.find('ociip:state/ociip:origin', namespaces=NAMESPACES) + add_value_from_tag(ipv4_address, 'origin', origin) + + address = xml_ipv4_address.find('ociip:state/ociip:ip', namespaces=NAMESPACES) + add_value_from_tag(ipv4_address, 'ip', address) + + prefix = xml_ipv4_address.find('ociip:state/ociip:prefix-length', namespaces=NAMESPACES) + add_value_from_tag(ipv4_address, 'prefix_length', prefix) + + if len(ipv4_address) == 0: continue + ipv4_addresses.append(ipv4_address) + + add_value_from_collection(subinterface, 'ipv4_addresses', ipv4_addresses) + + if len(subinterface) == 0: continue + resource_key = 'interface[{:s}]/subinterface[{:s}]'.format(interface['name'], subinterface['index']) + response.append((resource_key, subinterface)) + + if len(interface) == 0: continue + response.append(('interface[{:s}]'.format(interface['name']), interface)) + + return response diff --git a/src/device/service/drivers/openconfig/templates/Namespace.py b/src/device/service/drivers/openconfig/templates/Namespace.py new file mode 100644 index 0000000000000000000000000000000000000000..ff4b7c9c747b4efa872ba177e6e6a4fd7f6203b4 --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/Namespace.py @@ -0,0 +1,23 @@ + +NAMESPACE_NETCONF = 'urn:ietf:params:xml:ns:netconf:base:1.0' + +NAMESPACE_INTERFACES = 'http://openconfig.net/yang/interfaces' +NAMESPACE_INTERFACES_IP = 'http://openconfig.net/yang/interfaces/ip' +NAMESPACE_NETWORK_INSTANCE = 'http://openconfig.net/yang/network-instance' +NAMESPACE_NETWORK_INSTANCE_TYPES = 'http://openconfig.net/yang/network-instance-types' +NAMESPACE_OPENCONFIG_TYPES = 'http://openconfig.net/yang/openconfig-types' +NAMESPACE_PLATFORM = 'http://openconfig.net/yang/platform' +NAMESPACE_PLATFORM_PORT = 'http://openconfig.net/yang/platform/port' +NAMESPACE_VLAN = 'http://openconfig.net/yang/vlan' + +NAMESPACES = { + 'nc' : NAMESPACE_NETCONF, + 'oci' : NAMESPACE_INTERFACES, + 'ociip': NAMESPACE_INTERFACES_IP, + 'ocni' : NAMESPACE_NETWORK_INSTANCE, + 'ocnit': NAMESPACE_NETWORK_INSTANCE_TYPES, + 'ococt': NAMESPACE_OPENCONFIG_TYPES, + 'ocp' : NAMESPACE_PLATFORM, + 'ocpp' : NAMESPACE_PLATFORM_PORT, + 'ocv' : NAMESPACE_VLAN, +} diff --git a/src/device/service/drivers/openconfig/templates/NetworkInstances.py b/src/device/service/drivers/openconfig/templates/NetworkInstances.py new file mode 100644 index 0000000000000000000000000000000000000000..06bf5cd0f38aaf8c61f2919c25891e15f9ac4343 --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/NetworkInstances.py @@ -0,0 +1,35 @@ +import logging, lxml.etree as ET +from typing import Any, Dict, List, Tuple +from .Namespace import NAMESPACES +from .Tools import add_value_from_collection, add_value_from_tag + +LOGGER = logging.getLogger(__name__) + +XPATH_NETWORK_INSTANCES = "//ocni:network-instances/ocni:network-instance" + +def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: + response = [] + for xml_network_instance in xml_data.xpath(XPATH_NETWORK_INSTANCES, namespaces=NAMESPACES): + #LOGGER.info('xml_network_instance = {:s}'.format(str(ET.tostring(xml_network_instance)))) + + network_instance = {} + + ni_name = xml_network_instance.find('ocni:name', namespaces=NAMESPACES) + if ni_name is None or ni_name.text is None: continue + add_value_from_tag(network_instance, 'name', ni_name) + + ni_type = xml_network_instance.find('ocni:config/ocni:type', namespaces=NAMESPACES) + add_value_from_tag(network_instance, 'type', ni_type) + + ni_router_id = xml_network_instance.find('ocni:config/ocni:router-id', namespaces=NAMESPACES) + add_value_from_tag(network_instance, 'router_id', ni_router_id) + + ni_route_dist = xml_network_instance.find('ocni:config/ocni:route-distinguisher', namespaces=NAMESPACES) + add_value_from_tag(network_instance, 'route_distinguisher', ni_route_dist) + + ni_address_families = [] + add_value_from_collection(network_instance, 'address_families', ni_address_families) + + if len(network_instance) == 0: continue + response.append(('network_instance[{:s}]'.format(network_instance['name']), network_instance)) + return response diff --git a/src/device/service/drivers/openconfig/templates/Tools.py b/src/device/service/drivers/openconfig/templates/Tools.py new file mode 100644 index 0000000000000000000000000000000000000000..e95167dc56dfd323b6fe88a716573a4246305df0 --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/Tools.py @@ -0,0 +1,12 @@ +import lxml.etree as ET +from typing import Collection, Dict + +def add_value_from_tag(target : Dict, field_name: str, field_value : ET.Element, cast=None) -> None: + if field_value is None or field_value.text is None: return + field_value = field_value.text + if cast is not None: field_value = cast(field_value) + target[field_name] = field_value + +def add_value_from_collection(target : Dict, field_name: str, field_value : Collection) -> None: + if field_value is None or len(field_value) == 0: return + target[field_name] = field_value diff --git a/src/device/service/drivers/openconfig/templates/__init__.py b/src/device/service/drivers/openconfig/templates/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c1d1450568ac6e7efc7265b434de8f6ebabd61bc --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/__init__.py @@ -0,0 +1,47 @@ +import json, logging, lxml.etree as ET, re +from typing import Any, Dict +from jinja2 import Environment, PackageLoader, select_autoescape +from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES +from .EndPoints import parse as parse_endpoints +from .Interfaces import parse as parse_interfaces +from .NetworkInstances import parse as parse_network_instances + +ALL_RESOURCE_KEYS = [ + RESOURCE_ENDPOINTS, + RESOURCE_INTERFACES, + RESOURCE_NETWORK_INSTANCES, +] + +RESOURCE_KEY_MAPPINGS = { + RESOURCE_ENDPOINTS : 'component', + RESOURCE_INTERFACES : 'interface', + RESOURCE_NETWORK_INSTANCES: 'network_instance', +} + +RESOURCE_PARSERS = { + 'component' : parse_endpoints, + 'interface' : parse_interfaces, + 'network_instance': parse_network_instances, +} + +LOGGER = logging.getLogger(__name__) +RE_REMOVE_FILTERS = re.compile(r'\[[^\]]+\]') +JINJA_ENV = Environment(loader=PackageLoader('device.service.drivers.openconfig'), autoescape=select_autoescape()) + +def get_filter(resource_key : str): + resource_key = RESOURCE_KEY_MAPPINGS.get(resource_key, resource_key) + template_name = '{:s}/get.xml'.format(RE_REMOVE_FILTERS.sub('', resource_key)) + template = JINJA_ENV.get_template(template_name) + return '<filter>{:s}</filter>'.format(template.render()) + +def parse(resource_key : str, xml_data : ET.Element): + parser = RESOURCE_PARSERS.get(RESOURCE_KEY_MAPPINGS.get(resource_key, resource_key)) + if parser is None: return [(resource_key, xml_data)] + return parser(xml_data) + +def compose_config(resource_key : str, resource_value : str, delete : bool = False) -> str: + template_name = '{:s}/edit_config.xml'.format(RE_REMOVE_FILTERS.sub('', resource_key)) + template = JINJA_ENV.get_template(template_name) + data : Dict[str, Any] = json.loads(resource_value) + operation = 'delete' if delete else 'merge' + return '<config>{:s}</config>'.format(template.render(**data, operation=operation)) diff --git a/src/device/service/drivers/openconfig/templates/component/get.xml b/src/device/service/drivers/openconfig/templates/component/get.xml new file mode 100644 index 0000000000000000000000000000000000000000..aa25ed1e3b11e0c324b361eb52d064dac87a64c5 --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/component/get.xml @@ -0,0 +1,3 @@ +<components xmlns="http://openconfig.net/yang/platform"> + <component/> +</components> diff --git a/src/device/service/drivers/openconfig/templates/interface/edit_config.xml b/src/device/service/drivers/openconfig/templates/interface/edit_config.xml new file mode 100644 index 0000000000000000000000000000000000000000..ae29586a607b8ffd25e61c0aa9056109aacd3cb9 --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/interface/edit_config.xml @@ -0,0 +1,12 @@ +<interfaces xmlns="http://openconfig.net/yang/interfaces"> + <interface{% if operation is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %}> + <name>{{name}}</name> + {% if operation is not defined or operation != 'delete' %} + <config> + <name>{{name}}</name> + <description>{{description}}</description> + <mtu>{{mtu}}</mtu> + </config> + {% endif %} + </interface> +</interfaces> diff --git a/src/device/service/drivers/openconfig/templates/interface/get.xml b/src/device/service/drivers/openconfig/templates/interface/get.xml new file mode 100644 index 0000000000000000000000000000000000000000..c0867655bd325ee9c3cdd74077ac905e36808d5f --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/interface/get.xml @@ -0,0 +1,3 @@ +<interfaces xmlns="http://openconfig.net/yang/interfaces"> + <interface/> +</interfaces> diff --git a/src/device/service/drivers/openconfig/templates/interface/subinterface/edit_config.xml b/src/device/service/drivers/openconfig/templates/interface/subinterface/edit_config.xml new file mode 100644 index 0000000000000000000000000000000000000000..bdc698eeffd626076f6f62e576fe6ef916361412 --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/interface/subinterface/edit_config.xml @@ -0,0 +1,22 @@ +<interfaces xmlns="http://openconfig.net/yang/interfaces"> + <interface> + <name>{{name}}</name> + {% if operation is not defined or operation != 'delete' %} + <config> + <name>{{name}}</name> + <description>{{description}}</description> + <mtu>{{mtu}}</mtu> + </config> + {% endif %} + <subinterfaces> + <subinterface{% if operation is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %}> + <index>{{index}}</index> + {% if operation is not defined or operation != 'delete' %} + <config> + <index>{{index}}</index> + </config> + {% endif %} + </subinterface> + </subinterfaces> + </interface> +</interfaces> diff --git a/src/device/service/drivers/openconfig/templates/network_instance/edit_config.xml b/src/device/service/drivers/openconfig/templates/network_instance/edit_config.xml new file mode 100644 index 0000000000000000000000000000000000000000..fab1fdc61f0b6add9c915e914f830270d9875a0a --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/network_instance/edit_config.xml @@ -0,0 +1,16 @@ +<network-instances xmlns="http://openconfig.net/yang/network-instance"> + <network-instance{% if operation is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %}> + <name>{{name}}</name> + {% if operation is not defined or operation != 'delete' %} + <config> + <name>{{name}}</name> + <type xmlns:oc-ni-types="http://openconfig.net/yang/network-instance-types">oc-ni-types:{{type}}</type> + {% for address_family in address_families %} + <enabled-address-families xmlns:oc-types="http://openconfig.net/yang/openconfig-types">oc-types:{{address_family}}</enabled-address-families> + {% endfor %} + <router-id>{{router_id}}</router-id> + <route-distinguisher>{{route_distinguisher}}</route-distinguisher> + </config> + {% endif %} + </network-instance> +</network-instances> diff --git a/src/device/service/drivers/openconfig/templates/network_instance/get.xml b/src/device/service/drivers/openconfig/templates/network_instance/get.xml new file mode 100644 index 0000000000000000000000000000000000000000..9a439926a782cae27cc6aea347454215492ba323 --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/network_instance/get.xml @@ -0,0 +1,3 @@ +<network-instances xmlns="http://openconfig.net/yang/network-instance"> + <network-instance/> +</network-instances> diff --git a/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml b/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml new file mode 100644 index 0000000000000000000000000000000000000000..51f2d4318fbdd2d6da120851a72a6edafe173c73 --- /dev/null +++ b/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml @@ -0,0 +1,16 @@ +<network-instances xmlns="http://openconfig.net/yang/network-instance"> + <network-instance> + <name>{{name}}</name> + <interfaces> + <interface{% if operation is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %}> + <id>{{id}}</id> + {% if operation is not defined or operation != 'delete' %} + <config> + <id>{{id}}</id> + <interface>{{id}}</interface> + </config> + {% endif %} + </interface> + </interfaces> + </network-instance> +</network-instances> diff --git a/src/device/service/drivers/transport_api/TransportApiDriver.py b/src/device/service/drivers/transport_api/TransportApiDriver.py new file mode 100644 index 0000000000000000000000000000000000000000..f20173dd022a517d1e5630dc23c3455b0ed3c710 --- /dev/null +++ b/src/device/service/drivers/transport_api/TransportApiDriver.py @@ -0,0 +1,9 @@ +import logging +from device.service.driver_api._Driver import _Driver + +LOGGER = logging.getLogger(__name__) + +# TODO: Implement TransportAPI Driver + +class TransportApiDriver(_Driver): + pass diff --git a/src/device/service/drivers/transport_api/__init__.py b/src/device/service/drivers/transport_api/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/device/tests/.gitignore b/src/device/tests/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..067c7b77db596a97883a03426735b6ede9c6fa48 --- /dev/null +++ b/src/device/tests/.gitignore @@ -0,0 +1,2 @@ +# Add here your files containing confidential testbed details such as IP addresses, ports, usernames, passwords, etc. +Device_OpenConfig_Infinera.py diff --git a/src/device/tests/CommonObjects.py b/src/device/tests/CommonObjects.py new file mode 100644 index 0000000000000000000000000000000000000000..2b51dcd2322e70dff9a5229e65e6a220708a834f --- /dev/null +++ b/src/device/tests/CommonObjects.py @@ -0,0 +1,21 @@ +from copy import deepcopy +from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID + +# use "deepcopy" to prevent propagating forced changes during tests + +CONTEXT_ID = {'context_uuid': {'uuid': DEFAULT_CONTEXT_UUID}} +CONTEXT = { + 'context_id': deepcopy(CONTEXT_ID), + 'topology_ids': [], + 'service_ids': [], +} + +TOPOLOGY_ID = { + 'context_id': deepcopy(CONTEXT_ID), + 'topology_uuid': {'uuid': DEFAULT_TOPOLOGY_UUID}, +} +TOPOLOGY = { + 'topology_id': deepcopy(TOPOLOGY_ID), + 'device_ids': [], + 'link_ids': [], +} diff --git a/src/device/tests/Device_Emulated.py b/src/device/tests/Device_Emulated.py new file mode 100644 index 0000000000000000000000000000000000000000..155383b49fd12d780e901db1aa2614a55d4e5e14 --- /dev/null +++ b/src/device/tests/Device_Emulated.py @@ -0,0 +1,47 @@ +from copy import deepcopy +from device.proto.context_pb2 import DeviceDriverEnum, DeviceOperationalStatusEnum +from .Tools import config_rule_set, config_rule_delete + +# use "deepcopy" to prevent propagating forced changes during tests + +DEVICE_EMU_UUID = 'EMULARED' +DEVICE_EMU_TYPE = 'emulated' +DEVICE_EMU_ADDRESS = '127.0.0.1' +DEVICE_EMU_PORT = '0' +DEVICE_EMU_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_UNDEFINED] + +DEVICE_EMU_ID = {'device_uuid': {'uuid': DEVICE_EMU_UUID}} +DEVICE_EMU = { + 'device_id': deepcopy(DEVICE_EMU_ID), + 'device_type': DEVICE_EMU_TYPE, + 'device_config': {'config_rules': []}, + 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED, + 'device_drivers': DEVICE_EMU_DRIVERS, + 'device_endpoints': [], +} + +DEVICE_EMU_CONNECT_RULES = [ + config_rule_set('_connect/address', DEVICE_EMU_ADDRESS ), + config_rule_set('_connect/port', DEVICE_EMU_PORT ), +] + +DEVICE_EMU_CONFIG_RULES = [ + config_rule_set('dev/rsrc1/value', 'value1'), + config_rule_set('dev/rsrc2/value', 'value2'), + config_rule_set('dev/rsrc3/value', 'value3'), +] + +DEVICE_EMU_RECONFIG_RULES = [ + config_rule_delete('dev/rsrc1/value', ''), + config_rule_set ('dev/rsrc10/value', 'value10'), + config_rule_set ('dev/rsrc11/value', 'value11'), + config_rule_set ('dev/rsrc12/value', 'value12'), +] + +DEVICE_EMU_DECONFIG_RULES = [ + config_rule_delete('dev/rsrc2/value', 'value2'), + config_rule_delete('dev/rsrc3/value', 'value3'), + config_rule_delete('dev/rsrc10/value', 'value10'), + config_rule_delete('dev/rsrc11/value', 'value11'), + config_rule_delete('dev/rsrc12/value', 'value12'), +] diff --git a/src/device/tests/Device_OpenConfig_Template.py b/src/device/tests/Device_OpenConfig_Template.py new file mode 100644 index 0000000000000000000000000000000000000000..73b6d4f55e8ffb08eb4c2e0badf8aa8d012c0d2b --- /dev/null +++ b/src/device/tests/Device_OpenConfig_Template.py @@ -0,0 +1,34 @@ +from copy import deepcopy +from device.proto.context_pb2 import DeviceDriverEnum, DeviceOperationalStatusEnum +from .Tools import config_rule_set, config_rule_delete + +# use "deepcopy" to prevent propagating forced changes during tests + +DEVICE_OC_UUID = 'DEV2' +DEVICE_OC_TYPE = 'packet-router' +DEVICE_OC_ADDRESS = '127.0.0.1' # populate the Netconf Server IP address of the device to test +DEVICE_OC_PORT = '830' # populate the Netconf Server port of the device to test +DEVICE_OC_USERNAME = 'username' # populate the Netconf Server username of the device to test +DEVICE_OC_PASSWORD = 'password' # populate the Netconf Server password of the device to test +DEVICE_OC_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG] + +DEVICE_OC_ID = {'device_uuid': {'uuid': DEVICE_OC_UUID}} +DEVICE_OC = { + 'device_id': deepcopy(DEVICE_OC_ID), + 'device_type': DEVICE_OC_TYPE, + 'device_config': {'config_rules': []}, + 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED, + 'device_drivers': DEVICE_OC_DRIVERS, + 'device_endpoints': [], # populated through the driver, leave this list empty +} + +DEVICE_OC_CONNECT_RULES = [ + config_rule_set('_connect/address', DEVICE_OC_ADDRESS ), + config_rule_set('_connect/port', DEVICE_OC_PORT ), + config_rule_set('_connect/username', DEVICE_OC_USERNAME), + config_rule_set('_connect/password', DEVICE_OC_PASSWORD), +] + +DEVICE_OC_CONFIG_RULES = [] # populate your configuration rules to test + +DEVICE_OC_DECONFIG_RULES = [] # populate your deconfiguration rules to test diff --git a/src/device/tests/Tools.py b/src/device/tests/Tools.py new file mode 100644 index 0000000000000000000000000000000000000000..94a6d50900eb1865c69064b2e98bca0d6e91643b --- /dev/null +++ b/src/device/tests/Tools.py @@ -0,0 +1,21 @@ +import json +from copy import deepcopy +from typing import Any, Dict, Union +from device.proto.context_pb2 import ConfigActionEnum + +def config_rule(action : ConfigActionEnum, resource_key : str, resource_value : Union[str, Dict[str, Any]]): + if not isinstance(resource_value, str): resource_value = json.dumps(resource_value, sort_keys=True) + return {'action': action, 'resource_key': resource_key, 'resource_value': resource_value} + +def config_rule_set(resource_key : str, resource_value : Union[str, Dict[str, Any]]): + return config_rule(ConfigActionEnum.CONFIGACTION_SET, resource_key, resource_value) + +def config_rule_delete(resource_key : str, resource_value : Union[str, Dict[str, Any]]): + return config_rule(ConfigActionEnum.CONFIGACTION_DELETE, resource_key, resource_value) + +def endpoint_id(topology_id, device_id, endpoint_uuid): + return {'topology_id': deepcopy(topology_id), 'device_id': deepcopy(device_id), + 'endpoint_uuid': {'uuid': endpoint_uuid}} + +def endpoint(topology_id, device_id, endpoint_uuid, endpoint_type): + return {'endpoint_id': endpoint_id(topology_id, device_id, endpoint_uuid), 'endpoint_type': endpoint_type} diff --git a/src/device/tests/test_unitary.py b/src/device/tests/test_unitary.py new file mode 100644 index 0000000000000000000000000000000000000000..fc9175620b7763cabc9da58756054fda9092490d --- /dev/null +++ b/src/device/tests/test_unitary.py @@ -0,0 +1,394 @@ +import copy, grpc, logging, operator, os, pytest +from typing import Tuple +from google.protobuf.json_format import MessageToDict +from common.orm.Database import Database +from common.orm.Factory import get_database_backend, BackendEnum as DatabaseBackendEnum +from common.message_broker.Factory import get_messagebroker_backend, BackendEnum as MessageBrokerBackendEnum +from common.message_broker.MessageBroker import MessageBroker +from context.Config import ( + GRPC_SERVICE_PORT as CONTEXT_GRPC_SERVICE_PORT, GRPC_MAX_WORKERS as CONTEXT_GRPC_MAX_WORKERS, + GRPC_GRACE_PERIOD as CONTEXT_GRPC_GRACE_PERIOD) +from context.client.ContextClient import ContextClient +from context.proto.context_pb2 import DeviceId +from context.service.grpc_server.ContextService import ContextService +from device.Config import ( + GRPC_SERVICE_PORT as DEVICE_GRPC_SERVICE_PORT, GRPC_MAX_WORKERS as DEVICE_GRPC_MAX_WORKERS, + GRPC_GRACE_PERIOD as DEVICE_GRPC_GRACE_PERIOD) +from device.client.DeviceClient import DeviceClient +from device.proto.context_pb2 import ConfigActionEnum, Context, Device, Topology +from device.service.DeviceService import DeviceService +#from device.service.MonitoringLoops import MonitoringLoops +from device.service.driver_api._Driver import _Driver +from device.service.driver_api.DriverFactory import DriverFactory +from device.service.driver_api.DriverInstanceCache import DriverInstanceCache +from device.service.drivers import DRIVERS +#from monitoring.client.monitoring_client import MonitoringClient +from .CommonObjects import CONTEXT, TOPOLOGY +from .Device_Emulated import ( + DEVICE_EMU, DEVICE_EMU_CONFIG_RULES, DEVICE_EMU_CONNECT_RULES, DEVICE_EMU_DECONFIG_RULES, DEVICE_EMU_ID, + DEVICE_EMU_RECONFIG_RULES, DEVICE_EMU_UUID) +try: + from .Device_OpenConfig_Infinera import( + DEVICE_OC, DEVICE_OC_CONFIG_RULES, DEVICE_OC_DECONFIG_RULES, DEVICE_OC_CONNECT_RULES, DEVICE_OC_ID, + DEVICE_OC_UUID) + ENABLE_OPENCONFIG = True +except ImportError: + ENABLE_OPENCONFIG = False + # Create a Device_OpenConfig_??.py file with the details for your device to test it and import it as follows in the + # try block of this import statement. + # from .Device_OpenConfig_?? import( + # DEVICE_OC, DEVICE_OC_CONFIG_RULES, DEVICE_OC_DECONFIG_RULES, DEVICE_OC_CONNECT_RULES, DEVICE_OC_ID, + # DEVICE_OC_UUID) + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +CONTEXT_GRPC_SERVICE_PORT = 10000 + CONTEXT_GRPC_SERVICE_PORT # avoid privileged ports +DEVICE_GRPC_SERVICE_PORT = 10000 + DEVICE_GRPC_SERVICE_PORT # avoid privileged ports + +DEFAULT_REDIS_SERVICE_HOST = '127.0.0.1' +DEFAULT_REDIS_SERVICE_PORT = 6379 +DEFAULT_REDIS_DATABASE_ID = 0 + +REDIS_CONFIG = { + 'REDIS_SERVICE_HOST': os.environ.get('REDIS_SERVICE_HOST', DEFAULT_REDIS_SERVICE_HOST), + 'REDIS_SERVICE_PORT': os.environ.get('REDIS_SERVICE_PORT', DEFAULT_REDIS_SERVICE_PORT), + 'REDIS_DATABASE_ID' : os.environ.get('REDIS_DATABASE_ID', DEFAULT_REDIS_DATABASE_ID ), +} + +SCENARIOS = [ + ('all_inmemory', DatabaseBackendEnum.INMEMORY, {}, MessageBrokerBackendEnum.INMEMORY, {} ), + #('all_redis', DatabaseBackendEnum.REDIS, REDIS_CONFIG, MessageBrokerBackendEnum.REDIS, REDIS_CONFIG), +] + +@pytest.fixture(scope='session', ids=[str(scenario[0]) for scenario in SCENARIOS], params=SCENARIOS) +def context_db_mb(request) -> Tuple[Database, MessageBroker]: + name,db_backend,db_settings,mb_backend,mb_settings = request.param + msg = 'Running scenario {:s} db_backend={:s}, db_settings={:s}, mb_backend={:s}, mb_settings={:s}...' + LOGGER.info(msg.format(str(name), str(db_backend.value), str(db_settings), str(mb_backend.value), str(mb_settings))) + _database = Database(get_database_backend(backend=db_backend, **db_settings)) + _message_broker = MessageBroker(get_messagebroker_backend(backend=mb_backend, **mb_settings)) + yield _database, _message_broker + _message_broker.terminate() + +@pytest.fixture(scope='session') +def context_service(context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name + _service = ContextService( + context_db_mb[0], context_db_mb[1], port=CONTEXT_GRPC_SERVICE_PORT, max_workers=CONTEXT_GRPC_MAX_WORKERS, + grace_period=CONTEXT_GRPC_GRACE_PERIOD) + _service.start() + yield _service + _service.stop() + +@pytest.fixture(scope='session') +def context_client(context_service : ContextService): # pylint: disable=redefined-outer-name + _client = ContextClient(address='127.0.0.1', port=CONTEXT_GRPC_SERVICE_PORT) + yield _client + _client.close() + +@pytest.fixture(scope='session') +def device_service(context_client : ContextClient): # pylint: disable=redefined-outer-name + _driver_factory = DriverFactory(DRIVERS) + _driver_instance_cache = DriverInstanceCache(_driver_factory) + #_monitoring_loops = MonitoringLoops(None) # TODO: replace by monitoring client + #_monitoring_loops.start() + _service = DeviceService( + context_client, _driver_instance_cache, + #_monitoring_loops, + port=DEVICE_GRPC_SERVICE_PORT, max_workers=DEVICE_GRPC_MAX_WORKERS, grace_period=DEVICE_GRPC_GRACE_PERIOD) + _service.start() + yield _service + #_monitoring_loops.stop() + _service.stop() + +@pytest.fixture(scope='session') +def device_client(device_service : DeviceService): # pylint: disable=redefined-outer-name + _client = DeviceClient(address='127.0.0.1', port=DEVICE_GRPC_SERVICE_PORT) + yield _client + _client.close() + +def grpc_message_to_json_string(message): + return str(MessageToDict( + message, including_default_value_fields=True, preserving_proto_field_name=True, use_integers_for_enums=False)) + + +def test_prepare_environment( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + context_client.SetContext(Context(**CONTEXT)) + context_client.SetTopology(Topology(**TOPOLOGY)) + + +# ----- Test Device Driver Emulated ------------------------------------------------------------------------------------ + +def test_device_emulated_add_error_cases( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + with pytest.raises(grpc.RpcError) as e: + DEVICE_EMU_WITH_EXTRA_RULES = copy.deepcopy(DEVICE_EMU) + DEVICE_EMU_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONNECT_RULES) + DEVICE_EMU_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONFIG_RULES) + device_client.AddDevice(Device(**DEVICE_EMU_WITH_EXTRA_RULES)) + assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT + msg_head = 'device.device_config.config_rules([' + msg_tail = ']) is invalid; RPC method AddDevice only accepts connection Config Rules that should start '\ + 'with "_connect/" tag. Others should be configured after adding the device.' + except_msg = str(e.value.details()) + assert except_msg.startswith(msg_head) and except_msg.endswith(msg_tail) + + +def test_device_emulated_add_correct( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + DEVICE_EMU_WITH_CONNECT_RULES = copy.deepcopy(DEVICE_EMU) + DEVICE_EMU_WITH_CONNECT_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONNECT_RULES) + device_client.AddDevice(Device(**DEVICE_EMU_WITH_CONNECT_RULES)) + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID) # we know the driver exists now + assert driver is not None + + +def test_device_emulated_get( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + initial_config = device_client.GetInitialConfig(DeviceId(**DEVICE_EMU_ID)) + LOGGER.info('initial_config = {:s}'.format(grpc_message_to_json_string(initial_config))) + + device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) + LOGGER.info('device_data = {:s}'.format(grpc_message_to_json_string(device_data))) + + +def test_device_emulated_configure( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID) # we know the driver exists now + assert driver is not None + + driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + assert len(driver_config) == 0 + + DEVICE_EMU_WITH_CONFIG_RULES = copy.deepcopy(DEVICE_EMU) + DEVICE_EMU_WITH_CONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONFIG_RULES) + device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_CONFIG_RULES)) + + driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + assert len(driver_config) == 3 + assert driver_config[0] == ('/dev/rsrc1/value', 'value1') + assert driver_config[1] == ('/dev/rsrc2/value', 'value2') + assert driver_config[2] == ('/dev/rsrc3/value', 'value3') + + device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) + config_rules = [ + (ConfigActionEnum.Name(config_rule.action), config_rule.resource_key, config_rule.resource_value) + for config_rule in device_data.device_config.config_rules + ] + LOGGER.info('device_data.device_config.config_rules = \n{:s}'.format( + '\n'.join(['{:s} {:s} = {:s}'.format(*config_rule) for config_rule in config_rules]))) + for config_rule in DEVICE_EMU_CONFIG_RULES: + config_rule = ( + ConfigActionEnum.Name(config_rule['action']), config_rule['resource_key'], config_rule['resource_value']) + assert config_rule in config_rules + + # Try to reconfigure... + + DEVICE_EMU_WITH_RECONFIG_RULES = copy.deepcopy(DEVICE_EMU) + DEVICE_EMU_WITH_RECONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_RECONFIG_RULES) + device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_RECONFIG_RULES)) + + driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + assert len(driver_config) == 5 + assert driver_config[0] == ('/dev/rsrc10/value', 'value10') + assert driver_config[1] == ('/dev/rsrc11/value', 'value11') + assert driver_config[2] == ('/dev/rsrc12/value', 'value12') + assert driver_config[3] == ('/dev/rsrc2/value', 'value2') + assert driver_config[4] == ('/dev/rsrc3/value', 'value3') + + device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) + config_rules = [ + (ConfigActionEnum.Name(config_rule.action), config_rule.resource_key, config_rule.resource_value) + for config_rule in device_data.device_config.config_rules + ] + LOGGER.info('device_data.device_config.config_rules = \n{:s}'.format( + '\n'.join(['{:s} {:s} = {:s}'.format(*config_rule) for config_rule in config_rules]))) + final_config_rules = DEVICE_EMU_CONFIG_RULES[1:] + DEVICE_EMU_RECONFIG_RULES[1:] # remove '/dev/rsrc1/value' + for config_rule in final_config_rules: + config_rule = ( + ConfigActionEnum.Name(config_rule['action']), config_rule['resource_key'], config_rule['resource_value']) + assert config_rule in config_rules + + +def test_device_emulated_deconfigure( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID) # we know the driver exists now + assert driver is not None + + driver_config = driver.GetConfig() + LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + + DEVICE_EMU_WITH_DECONFIG_RULES = copy.deepcopy(DEVICE_EMU) + DEVICE_EMU_WITH_DECONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_DECONFIG_RULES) + device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_DECONFIG_RULES)) + + driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + assert len(driver_config) == 0 + + device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID)) + assert len(device_data.device_config.config_rules) == 0 + + +def test_device_emulated_delete( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + device_client.DeleteDevice(DeviceId(**DEVICE_EMU_ID)) + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID, {}) + assert driver is None + + +# ----- Test Device Driver OpenConfig ---------------------------------------------------------------------------------- + +def test_device_openconfig_add_error_cases( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + if not ENABLE_OPENCONFIG: return # if there is no device to test against, asusme test is silently passed. + + with pytest.raises(grpc.RpcError) as e: + DEVICE_OC_WITH_EXTRA_RULES = copy.deepcopy(DEVICE_OC) + DEVICE_OC_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_OC_CONNECT_RULES) + DEVICE_OC_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_OC_CONFIG_RULES) + device_client.AddDevice(Device(**DEVICE_OC_WITH_EXTRA_RULES)) + assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT + msg_head = 'device.device_config.config_rules([' + msg_tail = ']) is invalid; RPC method AddDevice only accepts connection Config Rules that should start '\ + 'with "_connect/" tag. Others should be configured after adding the device.' + except_msg = str(e.value.details()) + assert except_msg.startswith(msg_head) and except_msg.endswith(msg_tail) + + +def test_device_openconfig_add_correct( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + if not ENABLE_OPENCONFIG: return # if there is no device to test against, asusme test is silently passed. + + DEVICE_OC_WITH_CONNECT_RULES = copy.deepcopy(DEVICE_OC) + DEVICE_OC_WITH_CONNECT_RULES['device_config']['config_rules'].extend(DEVICE_OC_CONNECT_RULES) + device_client.AddDevice(Device(**DEVICE_OC_WITH_CONNECT_RULES)) + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_OC_UUID) # we know the driver exists now + assert driver is not None + + +def test_device_openconfig_get( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + if not ENABLE_OPENCONFIG: return # if there is no device to test against, asusme test is silently passed. + + initial_config = device_client.GetInitialConfig(DeviceId(**DEVICE_OC_ID)) + LOGGER.info('initial_config = {:s}'.format(grpc_message_to_json_string(initial_config))) + + device_data = context_client.GetDevice(DeviceId(**DEVICE_OC_ID)) + LOGGER.info('device_data = {:s}'.format(grpc_message_to_json_string(device_data))) + + +def test_device_openconfig_configure( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + if not ENABLE_OPENCONFIG: return # if there is no device to test against, asusme test is silently passed. + + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_OC_UUID) # we know the driver exists now + assert driver is not None + + # Requires to retrieve data from device; might be slow. Uncomment only when needed and test does not pass directly. + #driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + #LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + + DEVICE_OC_WITH_CONFIG_RULES = copy.deepcopy(DEVICE_OC) + DEVICE_OC_WITH_CONFIG_RULES['device_config']['config_rules'].extend(DEVICE_OC_CONFIG_RULES) + device_client.ConfigureDevice(Device(**DEVICE_OC_WITH_CONFIG_RULES)) + + # Requires to retrieve data from device; might be slow. Uncomment only when needed and test does not pass directly. + #driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + #LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + + device_data = context_client.GetDevice(DeviceId(**DEVICE_OC_ID)) + config_rules = [ + (ConfigActionEnum.Name(config_rule.action), config_rule.resource_key, config_rule.resource_value) + for config_rule in device_data.device_config.config_rules + ] + LOGGER.info('device_data.device_config.config_rules = \n{:s}'.format( + '\n'.join(['{:s} {:s} = {:s}'.format(*config_rule) for config_rule in config_rules]))) + for config_rule in DEVICE_OC_CONFIG_RULES: + config_rule = ( + ConfigActionEnum.Name(config_rule['action']), config_rule['resource_key'], config_rule['resource_value']) + assert config_rule in config_rules + + +def test_device_openconfig_deconfigure( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + if not ENABLE_OPENCONFIG: return # if there is no device to test against, asusme test is silently passed. + + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_OC_UUID) # we know the driver exists now + assert driver is not None + + # Requires to retrieve data from device; might be slow. Uncomment only when needed and test does not pass directly. + #driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + #LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + + DEVICE_OC_WITH_DECONFIG_RULES = copy.deepcopy(DEVICE_OC) + DEVICE_OC_WITH_DECONFIG_RULES['device_config']['config_rules'].extend(DEVICE_OC_DECONFIG_RULES) + device_client.ConfigureDevice(Device(**DEVICE_OC_WITH_DECONFIG_RULES)) + + # Requires to retrieve data from device; might be slow. Uncomment only when needed and test does not pass directly. + #driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0)) + #LOGGER.info('driver_config = {:s}'.format(str(driver_config))) + + device_data = context_client.GetDevice(DeviceId(**DEVICE_OC_ID)) + config_rules = [ + (ConfigActionEnum.Name(config_rule.action), config_rule.resource_key, config_rule.resource_value) + for config_rule in device_data.device_config.config_rules + ] + LOGGER.info('device_data.device_config.config_rules = \n{:s}'.format( + '\n'.join(['{:s} {:s} = {:s}'.format(*config_rule) for config_rule in config_rules]))) + for config_rule in DEVICE_OC_DECONFIG_RULES: + action_set = ConfigActionEnum.Name(ConfigActionEnum.CONFIGACTION_SET) + config_rule = (action_set, config_rule['resource_key'], config_rule['resource_value']) + assert config_rule not in config_rules + + +def test_device_openconfig_delete( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + device_service : DeviceService): # pylint: disable=redefined-outer-name + + if not ENABLE_OPENCONFIG: return # if there is no device to test against, asusme test is silently passed. + + device_client.DeleteDevice(DeviceId(**DEVICE_OC_ID)) + driver : _Driver = device_service.driver_instance_cache.get(DEVICE_OC_UUID, {}) + assert driver is None diff --git a/src/device/tests/test_unitary_driverapi.py b/src/device/tests/test_unitary_driverapi.py index ac7231cf76d4bcba0ea37da0cab781e21bc1c560..027e7775eae4a3f7a19c056266e1fc807b09cf2d 100644 --- a/src/device/tests/test_unitary_driverapi.py +++ b/src/device/tests/test_unitary_driverapi.py @@ -37,44 +37,44 @@ def device_driverapi_emulated(): yield _driver _driver.Disconnect() -def test_device_driverapi_emulated_setconfig(device_driverapi_emulated : EmulatedDriver): - # should work +def test_device_driverapi_emulated_setconfig( + device_driverapi_emulated : EmulatedDriver): # pylint: disable=redefined-outer-name + results = device_driverapi_emulated.SetConfig(DEVICE_CONFIG_IF1) - LOGGER.info('results:\n{}'.format('\n'.join(map(str, results)))) + LOGGER.info('results:\n{:s}'.format('\n'.join(map(str, results)))) assert len(results) == len(DEVICE_CONFIG_IF1) for result in results: assert isinstance(result, bool) and result results = device_driverapi_emulated.SetConfig(DEVICE_CONFIG_IF2) - LOGGER.info('results:\n{}'.format('\n'.join(map(str, results)))) + LOGGER.info('results:\n{:s}'.format('\n'.join(map(str, results)))) assert len(results) == len(DEVICE_CONFIG_IF2) for result in results: assert isinstance(result, bool) and result -def test_device_driverapi_emulated_getconfig(device_driverapi_emulated : EmulatedDriver): +def test_device_driverapi_emulated_getconfig( + device_driverapi_emulated : EmulatedDriver): # pylint: disable=redefined-outer-name + stored_config = device_driverapi_emulated.GetConfig() - LOGGER.info('stored_config:\n{}'.format('\n'.join(map(str, stored_config)))) + LOGGER.info('stored_config:\n{:s}'.format('\n'.join(map(str, stored_config)))) assert len(stored_config) == len(DEVICE_CONFIG_IF1) + len(DEVICE_CONFIG_IF2) for config_row in stored_config: assert (config_row in DEVICE_CONFIG_IF1) or (config_row in DEVICE_CONFIG_IF2) for config_row in DEVICE_CONFIG_IF1: assert config_row in stored_config for config_row in DEVICE_CONFIG_IF2: assert config_row in stored_config - # should work stored_config = device_driverapi_emulated.GetConfig([PATH_IF.format('IF2')]) - LOGGER.info('stored_config:\n{}'.format('\n'.join(map(str, stored_config)))) - assert len(stored_config) == 1 - stored_config = stored_config[0] - LOGGER.info('stored_config[0]:\n{}'.format('\n'.join(map(str, stored_config)))) + LOGGER.info('stored_config:\n{:s}'.format('\n'.join(map(str, stored_config)))) assert len(stored_config) == len(DEVICE_CONFIG_IF2) for config_row in stored_config: assert config_row in DEVICE_CONFIG_IF2 for config_row in DEVICE_CONFIG_IF2: assert config_row in stored_config -def test_device_driverapi_emulated_deleteconfig(device_driverapi_emulated : EmulatedDriver): - # should work - results = device_driverapi_emulated.DeleteConfig([PATH_ADDRIPV4.format('IF2', 0, '10.2.0.1')]) - LOGGER.info('results:\n{}'.format('\n'.join(map(str, results)))) +def test_device_driverapi_emulated_deleteconfig( + device_driverapi_emulated : EmulatedDriver): # pylint: disable=redefined-outer-name + + results = device_driverapi_emulated.DeleteConfig([(PATH_ADDRIPV4.format('IF2', 0, '10.2.0.1'), '')]) + LOGGER.info('results:\n{:s}'.format('\n'.join(map(str, results)))) assert (len(results) == 1) and isinstance(results[0], bool) and results[0] stored_config = device_driverapi_emulated.GetConfig() - LOGGER.info('stored_config:\n{}'.format('\n'.join(map(str, stored_config)))) + LOGGER.info('stored_config:\n{:s}'.format('\n'.join(map(str, stored_config)))) device_config_if2 = list(filter(lambda row: '10.2.0.1' not in row[0], copy.deepcopy(DEVICE_CONFIG_IF2))) assert len(stored_config) == len(DEVICE_CONFIG_IF1) + len(device_config_if2) @@ -82,8 +82,9 @@ def test_device_driverapi_emulated_deleteconfig(device_driverapi_emulated : Emul for config_row in DEVICE_CONFIG_IF1: assert config_row in stored_config for config_row in device_config_if2: assert config_row in stored_config -def test_device_driverapi_emulated_subscriptions(device_driverapi_emulated : EmulatedDriver): - # should work +def test_device_driverapi_emulated_subscriptions( + device_driverapi_emulated : EmulatedDriver): # pylint: disable=redefined-outer-name + duration = 10.0 interval = 1.5 results = device_driverapi_emulated.SubscribeState([ @@ -92,21 +93,21 @@ def test_device_driverapi_emulated_subscriptions(device_driverapi_emulated : Emu (DEVICE_STATE_IF2_TX_PKTS, duration, interval), (DEVICE_STATE_IF2_RX_PKTS, duration, interval), ]) - LOGGER.info('results:\n{}'.format('\n'.join(map(str, results)))) + LOGGER.info('results:\n{:s}'.format('\n'.join(map(str, results)))) assert len(results) == 4 for result in results: assert isinstance(result, bool) and result stored_config = device_driverapi_emulated.GetConfig() - LOGGER.info('stored_config:\n{}'.format('\n'.join(map(str, stored_config)))) + LOGGER.info('stored_config:\n{:s}'.format('\n'.join(map(str, stored_config)))) time.sleep(duration + 1.0) # let time to generate samples, plus 1 second extra time samples = [] for sample in device_driverapi_emulated.GetState(blocking=False): - LOGGER.info('sample: {}'.format(str(sample))) + LOGGER.info('sample: {:s}'.format(str(sample))) timestamp,resource_key,resource_value = sample samples.append((timestamp, resource_key, resource_value)) - LOGGER.info('samples:\n{}'.format('\n'.join(map(str, samples)))) + LOGGER.info('samples:\n{:s}'.format('\n'.join(map(str, samples)))) assert len(samples) == 4 * (math.floor(duration/interval) + 1) results = device_driverapi_emulated.UnsubscribeState([ @@ -115,12 +116,12 @@ def test_device_driverapi_emulated_subscriptions(device_driverapi_emulated : Emu (DEVICE_STATE_IF2_TX_PKTS, 10.0, 1.5), (DEVICE_STATE_IF2_RX_PKTS, 10.0, 1.5), ]) - LOGGER.info('results:\n{}'.format('\n'.join(map(str, results)))) + LOGGER.info('results:\n{:s}'.format('\n'.join(map(str, results)))) assert len(results) == 4 for result in results: assert isinstance(result, bool) and result stored_config = device_driverapi_emulated.GetConfig() - LOGGER.info('stored_config:\n{}'.format('\n'.join(map(str, stored_config)))) + LOGGER.info('stored_config:\n{:s}'.format('\n'.join(map(str, stored_config)))) device_config_if2 = list(filter(lambda row: '10.2.0.1' not in row[0], copy.deepcopy(DEVICE_CONFIG_IF2))) assert len(stored_config) == len(DEVICE_CONFIG_IF1) + len(device_config_if2) for config_row in stored_config: assert (config_row in DEVICE_CONFIG_IF1) or (config_row in device_config_if2)