Skip to content
Snippets Groups Projects
Commit 92dfd5b4 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Service component:

- Removed deprecated PathComputationElement class
- Migrated old L3NMOpenConfig Service Handler to the new framework
- Removed unneeded file in L3NMEmulated Service Handler
parent f2a1b9ea
No related branches found
No related tags found
1 merge request!54Release 2.0.0
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from enum import Enum
class NodeTypeEnum(Enum):
DEVICE = 'device'
ENDPOINT = 'endpoint'
class EndPointTypeEnum(Enum):
COPPER = 'copper'
OPTICAL = 'optical'
MICROWAVE = 'microwave'
class EdgeTypeEnum(Enum):
INTERNAL = 'internal'
COPPER = 'copper'
OPTICAL = 'optical'
MICROWAVE = 'microwave'
VIRTUAL = 'virtual'
OTHER = 'other'
class LayerTypeEnum(Enum):
COPPER = 'copper'
OPTICAL = 'optical'
MICROWAVE = 'microwave'
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import grpc, json, logging, networkx, uuid
from queue import Queue
from typing import Dict, List, Tuple
from networkx.drawing.nx_pydot import write_dot
from common.Constants import DEFAULT_CONTEXT_UUID
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import (
ConfigActionEnum, Connection, Device, Empty, EndPoint, EndPointId, Service, ServiceId, ServiceStatusEnum,
ServiceTypeEnum)
from common.tools.grpc.Tools import (
grpc_message_list_to_json, grpc_message_list_to_json_string, grpc_message_to_json, grpc_message_to_json_string)
from context.client.ContextClient import ContextClient
from .Enums import EdgeTypeEnum, NodeTypeEnum
from .Tools import get_device, get_device_key, get_edge_type, get_endpoint, get_endpoint_key, get_link_key
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.INFO)
SUB_SERVICE_TYPES = {
DeviceTypeEnum.EMULATED_PACKET_ROUTER.value : ServiceTypeEnum.SERVICETYPE_L3NM,
DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM.value: ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE,
DeviceTypeEnum.PACKET_ROUTER.value : ServiceTypeEnum.SERVICETYPE_L3NM,
DeviceTypeEnum.OPEN_LINE_SYSTEM.value : ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE,
}
DEFAULT_SUB_SERVICE_TYPE = ServiceTypeEnum.SERVICETYPE_UNKNOWN
def dump_requirements(requirements):
if requirements is None: return None
return [
{
'sub_service': grpc_message_to_json(sub_service),
'sub_connections': grpc_message_list_to_json(sub_connections),
}
for sub_service,sub_connections in requirements
]
def dump_connectivity(connectivity):
if connectivity is None: return None
return {
'service': grpc_message_to_json(connectivity.get('service')),
'connections': grpc_message_list_to_json(connectivity.get('connections', [])),
'requirements': dump_requirements(connectivity.get('requirements', [])),
}
def dump_hops(hops):
if hops is None: return None
return [
'in_endpoint={:s}, device={:s}, out_endpoint={:s}'.format(
grpc_message_to_json_string(in_endpoint), grpc_message_to_json_string(device),
grpc_message_to_json_string(out_endpoint))
for in_endpoint,device,out_endpoint in hops
]
class PathComputationElement:
def __init__(self) -> None:
self.__topology = networkx.Graph()
self.__connectivity = {} # (a_ep_key, z_ep_key) => {service, connection, sub_services: [], sub_connections: []}
self.__service_endpoints = {} # (context_uuid, service_uuid) => (a_ep_key, z_ep_key)
def dump_topology_to_file(self, dot_filepath : str):
write_dot(self.__topology, dot_filepath)
def dump_connectivity_to_file(self, filepath : str):
with open(filepath, 'w', encoding='UTF-8') as f:
f.write(str(self.__connectivity)) # do not use json; it contains protobuf objects
def load_topology(self, context_client : ContextClient):
response_devices = context_client.ListDevices(Empty())
devices = response_devices.devices
LOGGER.debug('Devices[{:d}] = {:s}'.format(len(devices), grpc_message_to_json_string(response_devices)))
assert len(devices) > 0
response_links = context_client.ListLinks(Empty())
links = response_links.links
LOGGER.debug('Links[{:d}] = {:s}'.format(len(links), grpc_message_to_json_string(response_links)))
assert len(links) > 0
for device in response_devices.devices:
device_uuid = get_device_key(device.device_id)
self.__topology.add_node(device_uuid, node_type=NodeTypeEnum.DEVICE, device=device)
for endpoint in device.device_endpoints:
endpoint_key = get_endpoint_key(endpoint.endpoint_id, device_uuid=device_uuid)
self.__topology.add_node(endpoint_key, node_type=NodeTypeEnum.ENDPOINT, endpoint=endpoint)
self.__topology.add_edge(device_uuid, endpoint_key, edge_type=EdgeTypeEnum.INTERNAL)
for link in response_links.links:
link_uuid = get_link_key(link.link_id)
if len(link.link_endpoint_ids) != 2:
msg = 'Link({:s}) with {:d} != 2 endpoints'
raise NotImplementedError(msg.format(link_uuid, len(link.link_endpoint_ids)))
endpoint_keys = [get_endpoint_key(endpoint_id) for endpoint_id in link.link_endpoint_ids]
edge_type = get_edge_type(self.__topology, endpoint_keys)
self.__topology.add_edge(endpoint_keys[0], endpoint_keys[1], link=link, edge_type=edge_type)
def load_connectivity(self, context_client : ContextClient, service_id : ServiceId):
pending_service_ids = Queue()
pending_service_ids.put((service_id, True))
connectivity = {}
requirements : List[Tuple[Service, List[Connection]]] = connectivity.setdefault('requirements', [])
connections : List[Connection] = connectivity.setdefault('connections', [])
while not pending_service_ids.empty():
service_id,is_main = pending_service_ids.get()
try:
service = context_client.GetService(service_id)
LOGGER.debug('[load_connectivity] GetService({:s}) = {:s}'.format(
grpc_message_to_json_string(service_id), grpc_message_to_json_string(service)))
except grpc.RpcError as e:
if is_main and e.code() == grpc.StatusCode.NOT_FOUND: continue # pylint: disable=no-member
raise
# TODO: implement support for services with more than 2 endpoints;
# Right now, services with less than 2 endpoints are ignored; with more than 2 endpoints throws exception.
# e.g., compute pairs such as:
# list(filter(lambda ep: ep[0] < ep[1], itertools.product(service_endpoint_ids, service_endpoint_ids)))
service_endpoint_ids = service.service_endpoint_ids
if len(service_endpoint_ids) < 2: continue
if len(service_endpoint_ids) > 2: raise NotImplementedError('Service with more than 2 endpoints')
service_connections = context_client.ListConnections(service_id)
LOGGER.debug('[load_connectivity] ListConnections({:s}) = {:s}'.format(
grpc_message_to_json_string(service_id), grpc_message_to_json_string(service_connections)))
if is_main:
connectivity['service'] = service
a_endpoint_key = get_endpoint_key(service_endpoint_ids[0])
z_endpoint_key = get_endpoint_key(service_endpoint_ids[-1])
self.__connectivity[(a_endpoint_key, z_endpoint_key)] = connectivity
self.__connectivity[(z_endpoint_key, a_endpoint_key)] = connectivity
context_service_id = (service_id.context_id.context_uuid.uuid, service_id.service_uuid.uuid)
self.__service_endpoints[context_service_id] = (a_endpoint_key, z_endpoint_key)
connections.extend(service_connections.connections)
else:
requirements.append((service, service_connections.connections))
for connection in service_connections.connections:
for service_id in connection.sub_service_ids:
pending_service_ids.put((service_id, False))
def get_connectivity_from_service_id(self, service_id : ServiceId) -> Dict:
LOGGER.debug('[get_connectivity_from_service_id] service_id={:s}'.format(
grpc_message_to_json_string(service_id)))
context_uuid = service_id.context_id.context_uuid.uuid
service_uuid = service_id.service_uuid.uuid
context_service_id = (context_uuid, service_uuid)
if context_service_id in self.__service_endpoints:
a_endpoint_key, z_endpoint_key = self.__service_endpoints[context_service_id]
else:
return None
if (a_endpoint_key, z_endpoint_key) in self.__connectivity:
connectivity = self.__connectivity.get((a_endpoint_key, z_endpoint_key))
elif (z_endpoint_key, a_endpoint_key) in self.__connectivity:
connectivity = self.__connectivity.get((z_endpoint_key, a_endpoint_key))
else:
connectivity = None
if connectivity is None or connectivity.get('connections') is None: return None
LOGGER.debug('[get_connectivity_from_service_id] Connectivity: {:s}'.format(
str(dump_connectivity(connectivity))))
return connectivity
def get_connectivity(self, service : Service) -> Tuple[Dict, str, str]:
LOGGER.debug('[get_connectivity] service.service_id = {:s}'.format(
grpc_message_to_json_string(service.service_id)))
context_uuid = service.service_id.context_id.context_uuid.uuid
service_uuid = service.service_id.service_uuid.uuid
context_service_id = (context_uuid, service_uuid)
if context_service_id in self.__service_endpoints:
LOGGER.debug('[get_connectivity] exists')
a_endpoint_key, z_endpoint_key = self.__service_endpoints[context_service_id]
LOGGER.debug('[get_connectivity] a_endpoint_key={:s}'.format(str(a_endpoint_key)))
LOGGER.debug('[get_connectivity] z_endpoint_key={:s}'.format(str(z_endpoint_key)))
else:
LOGGER.debug('[get_connectivity] new')
# TODO: implement support for services with more than 2 endpoints;
# Right now, less than 2 reports None, more than 2 endpoints throws an exception.
# e.g., compute pairs such as:
# list(filter(lambda ep: ep[0] < ep[1], itertools.product(service_endpoint_ids, service_endpoint_ids)))
service_endpoint_ids = service.service_endpoint_ids
LOGGER.debug('[get_connectivity] service_endpoint_ids[{:d}] = {:s}'.format(
len(service_endpoint_ids), grpc_message_list_to_json_string(service_endpoint_ids)))
if len(service_endpoint_ids) < 2: return None
if len(service_endpoint_ids) > 2: raise NotImplementedError('Service with more than 2 endpoints')
a_endpoint_key = get_endpoint_key(service_endpoint_ids[0])
z_endpoint_key = get_endpoint_key(service_endpoint_ids[-1])
LOGGER.debug('[get_connectivity] a_endpoint_key={:s}'.format(str(a_endpoint_key)))
LOGGER.debug('[get_connectivity] z_endpoint_key={:s}'.format(str(z_endpoint_key)))
if (a_endpoint_key, z_endpoint_key) in self.__connectivity:
connectivity = self.__connectivity.get((a_endpoint_key, z_endpoint_key))
elif (z_endpoint_key, a_endpoint_key) in self.__connectivity:
connectivity = self.__connectivity.get((z_endpoint_key, a_endpoint_key))
else:
connectivity = None
LOGGER.debug('[get_connectivity] connectivity = {:s}'.format(str(dump_connectivity(connectivity))))
if connectivity is None or connectivity.get('connections') is None: return None, a_endpoint_key, z_endpoint_key
return connectivity, a_endpoint_key, z_endpoint_key
def route_service(self, service : Service):
if self.__topology is None: raise Exception('Topology has not been loaded')
connectivity = self.get_connectivity(service)
if connectivity is None:
LOGGER.debug('[route_service] connectivity = None')
return None
_, a_endpoint_key, z_endpoint_key = connectivity
LOGGER.debug('[route_service] a_endpoint_key={:s}'.format(str(a_endpoint_key)))
LOGGER.debug('[route_service] z_endpoint_key={:s}'.format(str(z_endpoint_key)))
# TODO: consider implementing something like a K-shortest path instead of a simple shortest path
# pylint: disable=no-value-for-parameter,unexpected-keyword-arg
#paths = networkx.all_shortest_paths(self.__topology, source=a_endpoint_key, target=z_endpoint_key)
path_node_keys = networkx.shortest_path(
self.__topology, source=a_endpoint_key, target=z_endpoint_key)
LOGGER.debug('[route_service] Path[{:d}] = {:s}'.format(len(path_node_keys), str(path_node_keys)))
if len(path_node_keys) % 3 != 0:
msg = 'Weird path: length({:d}) mod 3 != 0. Path should be a sequence of endpoint-device-endpoint, '\
' so it must be multiple of 3'
raise Exception(msg.format(len(path_node_keys)))
hops : List[Tuple[EndPoint, Device, EndPoint]] = []
device_type__to__hops : Dict[str, List[int]] = {}
for i in range(0, len(path_node_keys), 3):
hop_device = get_device(self.__topology, path_node_keys[i+1])
hop_a_endpoint = get_endpoint(self.__topology, path_node_keys[i+0])
hop_z_endpoint = get_endpoint(self.__topology, path_node_keys[i+2])
hop_device_key = get_device_key(hop_device.device_id)
hop_a_endpoint_device_key = get_device_key(hop_a_endpoint.endpoint_id.device_id)
hop_z_endpoint_device_key = get_device_key(hop_z_endpoint.endpoint_id.device_id)
if hop_a_endpoint_device_key != hop_device_key:
msg = 'Weird path: Hop[{:d}] a_endpoint.device({:s}) != device({:s})'
raise Exception(msg.format(i/3, str(hop_a_endpoint_device_key), str(hop_device_key)))
if hop_z_endpoint_device_key != hop_device_key:
msg = 'Weird path: Hop[{:d}] z_endpoint.device({:s}) != device({:s})'
raise Exception(msg.format(i/3, str(hop_z_endpoint_device_key), str(hop_device_key)))
hops.append((hop_a_endpoint, hop_device, hop_z_endpoint))
device_type__to__hops.setdefault(hop_device.device_type, []).append(len(hops) - 1)
LOGGER.debug('[route_service] hops[{:d}] = {:s}'.format(
len(hops), str(dump_hops(hops))))
LOGGER.debug('[route_service] device_type__to__hops = {:s}'.format(str(device_type__to__hops)))
context_uuid = service.service_id.context_id.context_uuid.uuid
service_uuid = service.service_id.service_uuid.uuid
# create main service's connection
main_service_device_type = hops[0][1].device_type
main_service_hop_indexes = device_type__to__hops.pop(main_service_device_type)
# create sub-service and sub-services' connections
sub_service_ids = []
requirements : List[Tuple[Service, List[Connection]]] = []
for sub_service_device_type, sub_service_hop_indexes in device_type__to__hops.items():
LOGGER.debug('[route_service] sub_service_device_type = {:s}'.format(str(sub_service_device_type)))
LOGGER.debug('[route_service] sub_service_hop_indexes = {:s}'.format(str(sub_service_hop_indexes)))
# create sub-service
sub_service_uuid = '{:s}:optical'.format(service_uuid)
sub_service_id = {
'context_id': {'context_uuid': {'uuid': context_uuid}},
'service_uuid': {'uuid': sub_service_uuid},
}
sub_service = Service(**{
'service_id': sub_service_id,
'service_type' : SUB_SERVICE_TYPES.get(sub_service_device_type, DEFAULT_SUB_SERVICE_TYPE),
'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_PLANNED},
'service_endpoint_ids': [
hops[sub_service_hop_indexes[ 0]][ 0].endpoint_id,
hops[sub_service_hop_indexes[-1]][-1].endpoint_id,
],
'service_config': {'config_rules': [
{
'action': ConfigActionEnum.CONFIGACTION_SET,
'custom': {
'resource_key': 'settings',
'resource_value': json.dumps({
'capacity_value': 1,
'capacity_unit': 'GHz',
'layer_proto_name': 'PHOTONIC_MEDIA',
'layer_proto_qual': 'tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC',
'direction': 'UNIDIRECTIONAL',
}, sort_keys=True),
}
}
]},
})
LOGGER.debug('[route_service] sub_service = {:s}'.format(grpc_message_to_json_string(sub_service)))
# create sub-service's connection
sub_connection_uuid = '{:s}:{:s}'.format(sub_service_uuid, sub_service_device_type)
sub_conn_path_hops = []
for i in sub_service_hop_indexes:
sub_conn_path_hops.extend([hops[i][0].endpoint_id, hops[i][2].endpoint_id])
sub_connection = Connection(**{
'connection_id': {'connection_uuid': {'uuid': sub_connection_uuid}},
'service_id': sub_service_id,
'path_hops_endpoint_ids': sub_conn_path_hops,
})
LOGGER.debug('[route_service] sub_connection = {:s}'.format(grpc_message_to_json_string(sub_connection)))
sub_service_ids.append(sub_service_id)
requirements.append((sub_service, [sub_connection]))
LOGGER.debug('[route_service] sub_service_ids = {:s}'.format(str(sub_service_ids)))
LOGGER.debug('[route_service] requirements = {:s}'.format(str(dump_requirements(requirements))))
LOGGER.debug('[route_service] requirements[{:d}] = {:s}'.format(
len(requirements), str(dump_requirements(requirements))))
connections : List[Connection] = []
connection_uuid = '{:s}:{:s}'.format(service_uuid, main_service_device_type)
connection_path_hops : List[EndPointId] = []
for i in main_service_hop_indexes:
connection_path_hops.extend([hops[i][0].endpoint_id, hops[i][2].endpoint_id])
connection = Connection(**{
'connection_id': {'connection_uuid': {'uuid': connection_uuid}},
'service_id': grpc_message_to_json(service.service_id),
'path_hops_endpoint_ids': connection_path_hops,
'sub_service_ids': sub_service_ids,
})
LOGGER.debug('[route_service] connection = {:s}'.format(grpc_message_to_json_string(connection)))
connections.append(connection)
LOGGER.debug('[route_service] connections[{:d}] = {:s}'.format(
len(connections), grpc_message_list_to_json_string(connections)))
connectivity = {
'service': service,
'connections': connections,
'requirements': requirements,
}
LOGGER.debug('[route_service] connectivity = {:s}'.format(str(dump_connectivity(connectivity))))
self.__connectivity[(a_endpoint_key, z_endpoint_key)] = connectivity
self.__connectivity[(z_endpoint_key, a_endpoint_key)] = connectivity
context_service_id = (context_uuid, service_uuid)
self.__service_endpoints[context_service_id] = (a_endpoint_key, z_endpoint_key)
return connectivity
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import networkx
from typing import List, Optional
from common.proto.context_pb2 import Device, DeviceId, EndPoint, EndPointId, LinkId
from .Enums import EdgeTypeEnum
def get_device_key(device_id : DeviceId) -> str:
return device_id.device_uuid.uuid # pylint: disable=no-member
def get_endpoint_key(endpoint_id : EndPointId, device_uuid : Optional[str] = None) -> str:
if device_uuid is None: device_uuid = endpoint_id.device_id.device_uuid.uuid # pylint: disable=no-member
endpoint_uuid = endpoint_id.endpoint_uuid.uuid # pylint: disable=no-member
return '{:s}/{:s}'.format(device_uuid, endpoint_uuid)
def get_link_key(link_id : LinkId) -> str:
return link_id.link_uuid.uuid # pylint: disable=no-member
def get_device(topology : networkx.Graph, device_key : str) -> Device:
return topology.nodes[device_key]['device']
def get_endpoint(topology : networkx.Graph, endpoint_key : str) -> EndPoint:
return topology.nodes[endpoint_key]['endpoint']
def get_edge_type(topology : networkx.Graph, endpoint_keys : List[str]) -> EdgeTypeEnum:
# pylint: disable=no-member,protected-access
endpoint_types = {get_endpoint(topology, endpoint_key).endpoint_type for endpoint_key in endpoint_keys}
edge_type = None if len(endpoint_types) > 1 else \
EdgeTypeEnum._value2member_map_.get(endpoint_types.pop())
if edge_type is None: edge_type = EdgeTypeEnum.OTHER
return edge_type
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import functools, networkx
from typing import List, Optional, Union
from common.proto.context_pb2 import EndPoint
from context.service.database.EndPointModel import EndPointModel
from .Enums import EdgeTypeEnum, LayerTypeEnum
#from .Tools import get_endpoint
def select_copper_edges(topology, n1, n2):
selected_edges = {EdgeTypeEnum.COPPER, EdgeTypeEnum.INTERNAL, EdgeTypeEnum.OTHER}
return topology[n1][n2].get('edge_type', EdgeTypeEnum.OTHER) in selected_edges
def select_optical_edges(topology, n1, n2):
selected_edges = {EdgeTypeEnum.OPTICAL, EdgeTypeEnum.INTERNAL, EdgeTypeEnum.OTHER}
return topology[n1][n2].get('edge_type', EdgeTypeEnum.OTHER) in selected_edges
def select_microwave_edges(topology, n1, n2):
selected_edges = {EdgeTypeEnum.MICROWAVE, EdgeTypeEnum.INTERNAL, EdgeTypeEnum.OTHER}
return topology[n1][n2].get('edge_type', EdgeTypeEnum.OTHER) in selected_edges
SELECT_LAYER = {
LayerTypeEnum.COPPER : select_copper_edges,
LayerTypeEnum.OPTICAL : select_optical_edges,
LayerTypeEnum.MICROWAVE : select_microwave_edges,
}
def get_layer(topology : networkx.Graph, layer : LayerTypeEnum):
filter_edge = functools.partial(SELECT_LAYER[layer], topology)
return networkx.subgraph_view(topology, filter_edge=filter_edge)
def select_layer_from_endpoints(endpoints : List[Union[EndPointModel, EndPoint]]) -> Optional[LayerTypeEnum]:
endpoint_types = set()
for endpoint in endpoints: endpoint_types.add(endpoint.endpoint_type)
if len(endpoint_types) != 1: return None
# pylint: disable=no-member,protected-access
return LayerTypeEnum._value2member_map_.get(endpoint_types.pop())
#a_endpoint = get_endpoint(self.__topology, a_endpoint_key)
#z_endpoint = get_endpoint(self.__topology, z_endpoint_key)
#endpoints = [a_endpoint, z_endpoint]
#layer_type = select_layer_from_endpoints(endpoints)
#topology = self.__topology if layer_type is None else get_layer(self.__topology, layer_type)
#write_dot(topology, '../data/layer-{:s}.dot'.format('all' if layer_type is None else str(layer_type.value)))
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# json_endpoint_settings : Dict = endpoint_settings.value
# #router_id = json_endpoint_settings.get('router_id', '0.0.0.0') # '10.95.0.10'
# route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0' ) # '60001:801'
# sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0 ) # 1
# vlan_id = json_endpoint_settings.get('vlan_id', 1 ) # 400
# address_ip = json_endpoint_settings.get('address_ip', '0.0.0.0') # '2.2.2.1'
# address_prefix = json_endpoint_settings.get('address_prefix', 24 ) # 30
# if_subif_name = '{:s}.{:d}'.format(endpoint_uuid, vlan_id)
# db_device : DeviceModel = get_object(self.__database, DeviceModel, device_uuid, raise_if_not_found=True)
# device = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
# json_device = db_device.dump(include_config_rules=False, include_drivers=True, include_endpoints=True)
# json_device_config : Dict = json_device.setdefault('device_config', {})
# json_device_config_rules : List = json_device_config.setdefault('config_rules', [])
# json_device_config_rules.extend([
# json_config_rule_set(
# '/network_instance[{:s}]'.format(network_instance_name), {
# 'name': network_instance_name, 'description': network_interface_desc, 'type': 'L3VRF',
# 'route_distinguisher': route_distinguisher,
# #'router_id': router_id, 'address_families': address_families,
# }),
# json_config_rule_set(
# '/interface[{:s}]'.format(endpoint_uuid), {
# 'name': endpoint_uuid, 'description': network_interface_desc, 'mtu': mtu,
# }),
# json_config_rule_set(
# '/interface[{:s}]/subinterface[{:d}]'.format(endpoint_uuid, sub_interface_index), {
# 'name': endpoint_uuid, 'index': sub_interface_index,
# 'description': network_subinterface_desc, 'vlan_id': vlan_id,
# 'address_ip': address_ip, 'address_prefix': address_prefix,
# }),
# json_config_rule_set(
# '/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
# 'name': network_instance_name, 'id': if_subif_name, 'interface': endpoint_uuid,
# 'subinterface': sub_interface_index,
# }),
# json_config_rule_set(
# '/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
# 'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP', 'as': bgp_as,
# }),
# json_config_rule_set(
# '/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
# 'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
# 'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
# }),
# json_config_rule_set(
# '/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
# network_instance_name), {
# 'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
# 'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
# }),
# json_config_rule_set(
# '/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
# 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
# network_instance_name, bgp_route_target), {
# 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
# 'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
# }),
# json_config_rule_set(
# '/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
# 'policy_name': '{:s}_import'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
# network_instance_name, '3'), {
# 'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
# 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
# 'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
# }),
# json_config_rule_set(
# # pylint: disable=duplicate-string-formatting-argument
# '/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
# network_instance_name, network_instance_name), {
# 'name': network_instance_name, 'import_policy': '{:s}_import'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
# 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
# network_instance_name, bgp_route_target), {
# 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
# 'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
# }),
# json_config_rule_set(
# '/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
# 'policy_name': '{:s}_export'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
# network_instance_name, '3'), {
# 'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
# 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
# 'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
# }),
# json_config_rule_set(
# # pylint: disable=duplicate-string-formatting-argument
# '/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
# network_instance_name, network_instance_name), {
# 'name': network_instance_name, 'export_policy': '{:s}_export'.format(network_instance_name),
# }),
# ])
# self.__device_client.ConfigureDevice(Device(**json_device))
# results.append(True)
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Dict, List
from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set
from service.service.service_handler_api.AnyTreeTools import TreeNode
def setup_config_rules(
service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str,
service_settings : TreeNode, endpoint_settings : TreeNode
) -> List[Dict]:
json_settings : Dict = {} if service_settings is None else service_settings.value
json_endpoint_settings : Dict = {} if endpoint_settings is None else endpoint_settings.value
service_short_uuid = service_uuid.split('-')[-1]
network_instance_name = '{:s}-NetInst'.format(service_short_uuid)
network_interface_desc = '{:s}-NetIf'.format(service_uuid)
network_subinterface_desc = '{:s}-NetSubIf'.format(service_uuid)
mtu = json_settings.get('mtu', 1450 ) # 1512
#address_families = json_settings.get('address_families', [] ) # ['IPV4']
bgp_as = json_settings.get('bgp_as', 0 ) # 65000
bgp_route_target = json_settings.get('bgp_route_target', '0:0') # 65000:333
#router_id = json_endpoint_settings.get('router_id', '0.0.0.0') # '10.95.0.10'
route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0' ) # '60001:801'
sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0 ) # 1
vlan_id = json_endpoint_settings.get('vlan_id', 1 ) # 400
address_ip = json_endpoint_settings.get('address_ip', '0.0.0.0') # '2.2.2.1'
address_prefix = json_endpoint_settings.get('address_prefix', 24 ) # 30
if_subif_name = '{:s}.{:d}'.format(endpoint_uuid, vlan_id)
json_config_rules = [
json_config_rule_set(
'/network_instance[{:s}]'.format(network_instance_name), {
'name': network_instance_name, 'description': network_interface_desc, 'type': 'L3VRF',
'route_distinguisher': route_distinguisher,
#'router_id': router_id, 'address_families': address_families,
}),
json_config_rule_set(
'/interface[{:s}]'.format(endpoint_uuid), {
'name': endpoint_uuid, 'description': network_interface_desc, 'mtu': mtu,
}),
json_config_rule_set(
'/interface[{:s}]/subinterface[{:d}]'.format(endpoint_uuid, sub_interface_index), {
'name': endpoint_uuid, 'index': sub_interface_index,
'description': network_subinterface_desc, 'vlan_id': vlan_id,
'address_ip': address_ip, 'address_prefix': address_prefix,
}),
json_config_rule_set(
'/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
'name': network_instance_name, 'id': if_subif_name, 'interface': endpoint_uuid,
'subinterface': sub_interface_index,
}),
json_config_rule_set(
'/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP', 'as': bgp_as,
}),
json_config_rule_set(
'/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
}),
json_config_rule_set(
'/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
network_instance_name), {
'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
}),
json_config_rule_set(
'/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
network_instance_name, bgp_route_target), {
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
}),
json_config_rule_set(
'/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
'policy_name': '{:s}_import'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
network_instance_name, '3'), {
'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
}),
json_config_rule_set(
# pylint: disable=duplicate-string-formatting-argument
'/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
network_instance_name, network_instance_name), {
'name': network_instance_name, 'import_policy': '{:s}_import'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
network_instance_name, bgp_route_target), {
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
}),
json_config_rule_set(
'/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
'policy_name': '{:s}_export'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
network_instance_name, '3'), {
'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
}),
json_config_rule_set(
# pylint: disable=duplicate-string-formatting-argument
'/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
network_instance_name, network_instance_name), {
'name': network_instance_name, 'export_policy': '{:s}_export'.format(network_instance_name),
}),
]
return json_config_rules
def teardown_config_rules(
service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str,
service_settings : TreeNode, endpoint_settings : TreeNode
) -> List[Dict]:
json_settings : Dict = {} if service_settings is None else service_settings.value
json_endpoint_settings : Dict = {} if endpoint_settings is None else endpoint_settings.value
#mtu = json_settings.get('mtu', 1450 ) # 1512
#address_families = json_settings.get('address_families', [] ) # ['IPV4']
#bgp_as = json_settings.get('bgp_as', 0 ) # 65000
bgp_route_target = json_settings.get('bgp_route_target', '0:0') # 65000:333
#router_id = json_endpoint_settings.get('router_id', '0.0.0.0') # '10.95.0.10'
#route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0' ) # '60001:801'
sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0 ) # 1
vlan_id = json_endpoint_settings.get('vlan_id', 1 ) # 400
#address_ip = json_endpoint_settings.get('address_ip', '0.0.0.0') # '2.2.2.1'
#address_prefix = json_endpoint_settings.get('address_prefix', 24 ) # 30
if_subif_name = '{:s}.{:d}'.format(endpoint_uuid, vlan_id)
service_short_uuid = service_uuid.split('-')[-1]
network_instance_name = '{:s}-NetInst'.format(service_short_uuid)
#network_interface_desc = '{:s}-NetIf'.format(service_uuid)
#network_subinterface_desc = '{:s}-NetSubIf'.format(service_uuid)
json_config_rules = [
json_config_rule_delete(
'/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
'name': network_instance_name, 'id': if_subif_name,
}),
json_config_rule_delete(
'/interface[{:s}]/subinterface[{:d}]'.format(endpoint_uuid, sub_interface_index), {
'name': endpoint_uuid, 'index': sub_interface_index,
}),
json_config_rule_delete(
'/interface[{:s}]'.format(endpoint_uuid), {
'name': endpoint_uuid,
}),
json_config_rule_delete(
'/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
network_instance_name), {
'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
'address_family': 'IPV4',
}),
json_config_rule_delete(
'/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
'address_family': 'IPV4',
}),
json_config_rule_delete(
'/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP',
}),
json_config_rule_delete(
# pylint: disable=duplicate-string-formatting-argument
'/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
network_instance_name, network_instance_name), {
'name': network_instance_name,
}),
json_config_rule_delete(
'/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
network_instance_name, '3'), {
'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
}),
json_config_rule_delete(
'/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
'policy_name': '{:s}_import'.format(network_instance_name),
}),
json_config_rule_delete(
'/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
network_instance_name, bgp_route_target), {
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
}),
json_config_rule_delete(
'/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
}),
json_config_rule_delete(
# pylint: disable=duplicate-string-formatting-argument
'/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
network_instance_name, network_instance_name), {
'name': network_instance_name,
}),
json_config_rule_delete(
'/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
network_instance_name, '3'), {
'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
}),
json_config_rule_delete(
'/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
'policy_name': '{:s}_export'.format(network_instance_name),
}),
json_config_rule_delete(
'/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
network_instance_name, bgp_route_target), {
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
}),
json_config_rule_delete(
'/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
}),
json_config_rule_delete(
'/network_instance[{:s}]'.format(network_instance_name), {
'name': network_instance_name
}),
]
return json_config_rules
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