Skip to content
Snippets Groups Projects
Commit 2c370a0b authored by Pedro Paulo Tavares's avatar Pedro Paulo Tavares
Browse files

Added components to service

parent 6c4ef63c
No related branches found
No related tags found
2 merge requests!294Release TeraFlowSDN 4.0,!263Resolve "(OPT) QKD Network Control and Management Integration (Service)"
......@@ -214,6 +214,7 @@ enum DeviceDriverEnum {
DEVICEDRIVER_OPTICAL_TFS = 9;
DEVICEDRIVER_IETF_ACTN = 10;
DEVICEDRIVER_OC = 11;
DEVICEDRIVER_QKD = 12;
}
enum DeviceOperationalStatusEnum {
......@@ -300,6 +301,7 @@ enum ServiceTypeEnum {
SERVICETYPE_TE = 4;
SERVICETYPE_E2E = 5;
SERVICETYPE_OPTICAL_CONNECTIVITY = 6;
SERVICETYPE_QKD = 7;
}
enum ServiceStatusEnum {
......
......@@ -33,7 +33,8 @@ class ORM_DeviceDriverEnum(enum.Enum):
GNMI_OPENCONFIG = DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG
OPTICAL_TFS = DeviceDriverEnum.DEVICEDRIVER_OPTICAL_TFS
IETF_ACTN = DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN
OC = DeviceDriverEnum.DEVICEDRIVER_OC
OC = DeviceDriverEnum.DEVICEDRIVER_OC,
QKD = DeviceDriverEnum.DEVICEDRIVER_QKD
grpc_to_enum__device_driver = functools.partial(
grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum)
......@@ -29,6 +29,7 @@ class ORM_ServiceTypeEnum(enum.Enum):
TE = ServiceTypeEnum.SERVICETYPE_TE
E2E = ServiceTypeEnum.SERVICETYPE_E2E
OPTICAL_CONNECTIVITY = ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY
QKD = ServiceTypeEnum.SERVICETYPE_QKD
grpc_to_enum__service_type = functools.partial(
grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum)
......@@ -26,7 +26,8 @@ SERVICE_TYPE_VALUES = {
ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE,
ServiceTypeEnum.SERVICETYPE_TE,
ServiceTypeEnum.SERVICETYPE_E2E,
ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY
ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY,
ServiceTypeEnum.SERVICETYPE_QKD
}
DEVICE_DRIVER_VALUES = {
......@@ -41,7 +42,8 @@ DEVICE_DRIVER_VALUES = {
DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG,
DeviceDriverEnum.DEVICEDRIVER_OPTICAL_TFS,
DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN,
DeviceDriverEnum.DEVICEDRIVER_OC
DeviceDriverEnum.DEVICEDRIVER_OC,
DeviceDriverEnum.DEVICEDRIVER_QKD
}
# Map allowed filter fields to allowed values per Filter field. If no restriction (free text) None is specified
......
......@@ -27,6 +27,7 @@ from .tapi_tapi.TapiServiceHandler import TapiServiceHandler
from .tapi_xr.TapiXrServiceHandler import TapiXrServiceHandler
from .e2e_orch.E2EOrchestratorServiceHandler import E2EOrchestratorServiceHandler
from .oc.OCServiceHandler import OCServiceHandler
from .qkd.qkd_service_handler import QKDServiceHandler
SERVICE_HANDLERS = [
(L2NMEmulatedServiceHandler, [
......@@ -106,5 +107,11 @@ SERVICE_HANDLERS = [
FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY,
FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_OC,
}
]),
(QKDServiceHandler, [
{
FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_QKD,
FilterFieldEnum.DEVICE_DRIVER : [DeviceDriverEnum.DEVICEDRIVER_QKD],
}
])
]
import json, logging, uuid
from typing import Any, Dict, List, Optional, Tuple, Union
from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method
from common.proto.context_pb2 import ConfigRule, DeviceId, Service
from common.proto.app_pb2 import App, QKDAppStatusEnum, QKDAppTypesEnum
from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set
from common.tools.object_factory.Device import json_device_id
from common.type_checkers.Checkers import chk_type
from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching
from service.service.service_handler_api._ServiceHandler import _ServiceHandler
from service.service.service_handler_api.SettingsHandler import SettingsHandler
from service.service.task_scheduler.TaskExecutor import TaskExecutor
LOGGER = logging.getLogger(__name__)
def get_endpoint_name_by_uuid(device, uuid):
for device_endpoint in device.device_endpoints:
if device_endpoint.endpoint_id.endpoint_uuid.uuid == uuid:
return device_endpoint.name
return None
class QKDServiceHandler(_ServiceHandler):
def __init__( # pylint: disable=super-init-not-called
self, service : Service, task_executor : TaskExecutor, **settings
) -> None:
self.__service = service
self.__task_executor = task_executor
self.__settings_handler = SettingsHandler(service.service_config, **settings)
# Optare: This function is where the service is created
# Optare: It already receives the path provided by pathcomp in endpoints variable
# Optare: It then checks for each respective QKD Node and requests SBI to inform of the new connection
# Optare: It also requests app module for a creation of internal service if the service is virtual
def SetEndpoint(
self, endpoints : List[Tuple[str, str, Optional[str]]],
connection_uuid : Optional[str] = None
) -> List[Union[bool, Exception]]:
chk_type('endpoints', endpoints, list)
if len(endpoints) < 2 or len(endpoints) % 2: return []
LOGGER.info('Endpoints: ' + str(endpoints))
service_uuid = self.__service.service_id.service_uuid.uuid
settings = self.__settings_handler.get('/settings')
context_uuid = self.__service.service_id.context_id.context_uuid.uuid
results = []
try:
if len(endpoints) > 4:
is_virtual = True
else:
is_virtual = False
devices = []
qkdn_ids = []
interfaces = []
links = []
# Optare: First a big iteration through all devices is done in order to obtain all information needed for the whole operation
# Optare: This is a way to minimize time of operation. Otherwise it would require many O(N) operations. This way we can reduce it to one
# Populate devices and QKDN ids
for idx, endpoint in enumerate(endpoints[::2]):
device_uuid, endpoint_left_uuid = get_device_endpoint_uuids(endpoint)
_, endpoint_right_uuid = get_device_endpoint_uuids(endpoints[2 * idx + 1])
device = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
devices.append(device)
interfaces.append([0,0])
links.append([])
endpoint_left = get_endpoint_name_by_uuid(device, endpoint_left_uuid) if idx > 0 else None
endpoint_right = get_endpoint_name_by_uuid(device, endpoint_right_uuid) if 2 * idx + 2 < len(endpoints) else None
for config_rule in device.device_config.config_rules:
resource_key = config_rule.custom.resource_key
if resource_key == '__node__':
value = json.loads(config_rule.custom.resource_value)
qkdn_ids.append(value['qkdn_id'])
elif resource_key.startswith('/interface'):
value = json.loads(config_rule.custom.resource_value)
try:
endpoint_str = value['qkdi_att_point']['uuid']
LOGGER.info("A: " + str(endpoint_str) + "....." + str(endpoint_left) + "....." + str(endpoint_right))
if endpoint_str == endpoint_left:
interfaces[idx][0] = value['qkdi_id']
elif endpoint_str == endpoint_right:
interfaces[idx][1] = value['qkdi_id']
except KeyError:
pass
elif resource_key.startswith('/link'):
value = json.loads(config_rule.custom.resource_value)
links[idx].append(( value['uuid'],
(value['src_qkdn_id'], value['src_interface_id']),
(value['dst_qkdn_id'], value['dst_interface_id'])
))
LOGGER.info("IFs: " + str(interfaces))
LOGGER.info("Links: " + str(links))
LOGGER.info("context_: " + context_uuid)
# Optare: From here now is where the work is really done. It iterates over every device in use for the service (ordered)
src_device_uuid, src_endpoint_uuid = get_device_endpoint_uuids(endpoints[0])
src_device = devices[0]
src_endpoint = get_endpoint_matching(src_device, src_endpoint_uuid)
dst_device_uuid, dst_endpoint_uuid = get_device_endpoint_uuids(endpoints[-1])
dst_device = devices[-1]
dst_endpoint = get_endpoint_matching(dst_device, dst_endpoint_uuid)
src_qkdn_id = qkdn_ids[0]
dst_qkdn_id = qkdn_ids[-1]
src_interface_id = interfaces[0][1]
dst_interface_id = interfaces[-1][0]
service_qkdl_id_src_dst = str(uuid.uuid4())
service_qkdl_id_dst_src = str(uuid.uuid4())
for idx, device in enumerate(devices):
# Even though we always create them together. There is a chance the admin deletes one of the rules manually
phys_qkdl_id_right = None if idx == (len(devices) - 1) else '' # None == impossible
phys_qkdl_id_left = None if idx == 0 else '' # None == impossible
for link_uuid, link_src, link_dst in links[idx]:
qkdn_link_src, qkdn_interface_src = link_src
qkdn_link_dst, qkdn_interface_dst = link_dst
if phys_qkdl_id_right == '' and \
qkdn_link_src == qkdn_ids[idx] and qkdn_interface_src == interfaces[idx][1] and \
qkdn_link_dst[idx+1] and qkdn_interface_dst == interfaces[idx+1][0]:
phys_qkdl_id_right = link_uuid
if phys_qkdl_id_left == '' and \
qkdn_link_src == qkdn_ids[idx] and qkdn_interface_src == interfaces[idx][0] and \
qkdn_link_dst[idx-1] and qkdn_interface_dst == interfaces[idx-1][1]:
phys_qkdl_id_left = link_uuid
# Optare: Before adding information to config_rules you have to delete the list first otherwise old content will be called again
del device.device_config.config_rules[:]
if phys_qkdl_id_right:
if not is_virtual:
service_qkdl_id_src_dst = phys_qkdl_id_right
elif phys_qkdl_id_right == '':
qkdl_id_src_dst = str(uuid.uuid4()) if is_virtual else service_qkdl_id_src_dst
json_config_rule = json_config_rule_set('/link/link[{:s}]'.format(qkdl_id_src_dst), {
'uuid' : qkdl_id_src_dst,
'type' : 'DIRECT',
'src_qkdn_id' : qkdn_ids[idx],
'src_interface_id' : interfaces[idx][1],
'dst_qkdn_id' : qkdn_ids[idx+1],
'dst_interface_id' : interfaces[idx+1][0],
})
device.device_config.config_rules.append(ConfigRule(**json_config_rule))
if phys_qkdl_id_left:
if not is_virtual:
service_qkdl_id_dst_src = phys_qkdl_id_left
elif phys_qkdl_id_left == '':
qkdl_id_dst_src = str(uuid.uuid4()) if is_virtual else service_qkdl_id_dst_src
json_config_rule = json_config_rule_set('/link/link[{:s}]'.format(qkdl_id_dst_src), {
'uuid' : qkdl_id_dst_src,
'type' : 'DIRECT',
'src_qkdn_id' : qkdn_ids[idx],
'src_interface_id' : interfaces[idx][0],
'dst_qkdn_id' : qkdn_ids[idx-1],
'dst_interface_id' : interfaces[idx-1][1],
})
device.device_config.config_rules.append(ConfigRule(**json_config_rule))
if is_virtual:
if idx < len(qkdn_ids) - 1:
json_config_rule = json_config_rule_set('/link/link[{:s}]'.format(service_qkdl_id_src_dst), {
'uuid' : service_qkdl_id_src_dst,
'type' : 'VIRTUAL',
'src_qkdn_id' : src_qkdn_id,
'src_interface_id' : src_interface_id,
'dst_qkdn_id' : dst_qkdn_id,
'dst_interface_id' : dst_interface_id,
'virt_prev_hop' : qkdn_ids[idx-1] if idx > 0 else None,
'virt_next_hops' : qkdn_ids[idx+1:],
'virt_bandwidth' : 0,
})
device.device_config.config_rules.append(ConfigRule(**json_config_rule))
if idx > 0:
json_config_rule = json_config_rule_set('/link/link[{:s}]'.format(service_qkdl_id_dst_src), {
'uuid' : service_qkdl_id_dst_src,
'type' : 'VIRTUAL',
'src_qkdn_id' : dst_qkdn_id,
'src_interface_id' : dst_interface_id,
'dst_qkdn_id' : src_qkdn_id,
'dst_interface_id' : src_interface_id,
'virt_prev_hop' : qkdn_ids[idx+1] if idx < len(qkdn_ids) - 1 else None,
'virt_next_hops' : qkdn_ids[idx-1::-1],
'virt_bandwidth' : 0,
})
device.device_config.config_rules.append(ConfigRule(**json_config_rule))
json_config_rule = json_config_rule_set('/services/service[{:s}]'.format(service_uuid), {
'uuid' : service_uuid,
'qkdl_id_src_dst' : service_qkdl_id_src_dst,
'qkdl_id_dst_src' : service_qkdl_id_dst_src,
})
device.device_config.config_rules.append(ConfigRule(**json_config_rule))
self.__task_executor.configure_device(device)
if is_virtual:
# Register App
internal_app_src_dst = {
'app_id': {'context_id': {'context_uuid': {'uuid': context_uuid}}, 'app_uuid': {'uuid': str(uuid.uuid4())}},
'app_status': QKDAppStatusEnum.QKDAPPSTATUS_ON,
'app_type': QKDAppTypesEnum.QKDAPPTYPES_INTERNAL,
'server_app_id': '',
'client_app_id': [],
'backing_qkdl_id': [{'qkdl_uuid': {'uuid': service_qkdl_id_src_dst}}],
'local_device_id': src_device.device_id,
'remote_device_id': dst_device.device_id,
}
self.__task_executor.register_app(App(**internal_app_src_dst))
# Register App
internal_app_dst_src = {
'app_id': {'context_id': {'context_uuid': {'uuid': context_uuid}}, 'app_uuid': {'uuid': str(uuid.uuid4())}},
'app_status': QKDAppStatusEnum.QKDAPPSTATUS_ON,
'app_type': QKDAppTypesEnum.QKDAPPTYPES_INTERNAL,
'server_app_id': '',
'client_app_id': [],
'backing_qkdl_id': [{'qkdl_uuid': {'uuid': service_qkdl_id_dst_src}}],
'local_device_id': dst_device.device_id,
'remote_device_id': src_device.device_id,
}
self.__task_executor.register_app(App(**internal_app_dst_src))
results.append(True)
except Exception as e: # pylint: disable=broad-except
LOGGER.exception('Unable to SetEndpoint for Service({:s})'.format(str(service_uuid)))
results.append(e)
return results
# Optare: This will be to delete a service
def DeleteEndpoint(
self, endpoints : List[Tuple[str, str, Optional[str]]],
connection_uuid : Optional[str] = None
) -> List[Union[bool, Exception]]:
""" Delete service endpoints form a list.
Parameters:
endpoints: List[Tuple[str, str, Optional[str]]]
List of tuples, each containing a device_uuid,
endpoint_uuid, and the topology_uuid of the endpoint
to be removed.
connection_uuid : Optional[str]
If specified, is the UUID of the connection this endpoint is associated to.
Returns:
results: List[Union[bool, Exception]]
List of results for endpoint deletions requested.
Return values must be in the same order as the requested
endpoints. If an endpoint is properly deleted, True must be
returned; otherwise, the Exception that is raised during
the processing must be returned.
"""
raise NotImplementedError()
# Optare: Can be ingored. It's in case if a service is later updated. Not required to proper functioning
def SetConstraint(self, constraints: List[Tuple[str, Any]]) \
-> List[Union[bool, Exception]]:
""" Create/Update service constraints.
Parameters:
constraints: List[Tuple[str, Any]]
List of tuples, each containing a constraint_type and the
new constraint_value to be set.
Returns:
results: List[Union[bool, Exception]]
List of results for constraint changes requested.
Return values must be in the same order as the requested
constraints. If a constraint is properly set, True must be
returned; otherwise, the Exception that is raised during
the processing must be returned.
"""
raise NotImplementedError()
def DeleteConstraint(self, constraints: List[Tuple[str, Any]]) \
-> List[Union[bool, Exception]]:
""" Delete service constraints.
Parameters:
constraints: List[Tuple[str, Any]]
List of tuples, each containing a constraint_type pointing
to the constraint to be deleted, and a constraint_value
containing possible additionally required values to locate
the constraint to be removed.
Returns:
results: List[Union[bool, Exception]]
List of results for constraint deletions requested.
Return values must be in the same order as the requested
constraints. If a constraint is properly deleted, True must
be returned; otherwise, the Exception that is raised during
the processing must be returned.
"""
raise NotImplementedError()
def SetConfig(self, resources: List[Tuple[str, Any]]) \
-> List[Union[bool, Exception]]:
""" Create/Update configuration for a list of service resources.
Parameters:
resources: List[Tuple[str, Any]]
List of tuples, each containing a resource_key pointing to
the resource to be modified, and a resource_value
containing the new value to be set.
Returns:
results: List[Union[bool, Exception]]
List of results for resource key changes requested.
Return values must be in the same order as the requested
resource keys. If a resource is properly set, True must be
returned; otherwise, the Exception that is raised during
the processing must be returned.
"""
raise NotImplementedError()
def DeleteConfig(self, resources: List[Tuple[str, Any]]) \
-> List[Union[bool, Exception]]:
""" Delete configuration for a list of service resources.
Parameters:
resources: List[Tuple[str, Any]]
List of tuples, each containing a resource_key pointing to
the resource to be modified, and a resource_value containing
possible additionally required values to locate the value
to be removed.
Returns:
results: List[Union[bool, Exception]]
List of results for resource key deletions requested.
Return values must be in the same order as the requested
resource keys. If a resource is properly deleted, True must
be returned; otherwise, the Exception that is raised during
the processing must be returned.
"""
raise NotImplementedError()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment