Skip to content
Snippets Groups Projects
Commit dd6b162d authored by Pablo Armingol's avatar Pablo Armingol
Browse files

L3SM testing

parent 8fcdf991
No related branches found
No related tags found
2 merge requests!341Draft: Resolve "optical bandwidth expansion",!239Draft: Resolve "(TID) Creation of IP link with supporting coherent pluggable to pluggable connection"
{
"l3vpn-svc": {
"vpn-services": {
"vpn-service": [
{
"vpn-id": "vpn2"
}
]
},
"sites": {
"site": [
{
"site-id": "site_OLT",
"locations": {
"location": [
{
"location-id": "OLT"
}
]
},
"devices": {
"device": [
{
"device-id": "128.32.33.5",
"location": "OLT"
}
]
},
"management": {
"type": "ietf-l3vpn-svc:provider-managed"
},
"routing-protocols": {
"routing-protocol": [
{
"type": "ietf-l3vpn-svc:static",
"static": {
"cascaded-lan-prefixes": {
"ipv4-lan-prefixes": [
{
"lan": "128.32.10.0/24",
"next-hop": "128.32.33.2",
"lan-tag": "vlan31"
},
{
"lan": "128.32.20.0/24",
"next-hop": "128.32.33.2",
"lan-tag": "vlan31"
}
]
}
}
}
]
},
"site-network-accesses": {
"site-network-access": [
{
"site-network-access-id": "500",
"site-network-access-type": "ietf-l3vpn-svc:multipoint",
"device-reference": "128.32.33.5",
"ip-connection": {
"ipv4": {
"address-allocation-type": "ietf-l3vpn-svc:static-address",
"addresses": {
"provider-address": "128.32.33.254",
"customer-address": "128.32.33.2",
"prefix-length": 24
}
}
},
"service": {
"svc-input-bandwidth": 1000000000,
"svc-output-bandwidth": 1000000000,
"svc-mtu": 1500,
"qos": {
"qos-profile": {
"classes": {
"class": [
{
"class-id": "qos-realtime",
"direction": "ietf-l3vpn-svc:both",
"latency": {
"latency-boundary": 10
},
"bandwidth": {
"guaranteed-bw-percent": 100.0
}
}
]
}
}
}
},
"routing-protocols": {
"routing-protocol": [
{
"type": "ietf-l3vpn-svc:static",
"static": {
"cascaded-lan-prefixes": {
"ipv4-lan-prefixes": [
{
"lan": "172.1.201.0/24",
"next-hop": "128.32.33.254",
"lan-tag": "vlan31"
}
]
}
}
}
]
},
"vpn-attachment": {
"vpn-id": "vpn2",
"site-role": "ietf-l3vpn-svc:spoke-role"
}
}
]
}
},
{
"site-id": "site_POP",
"locations": {
"location": [
{
"location-id": "POP"
}
]
},
"devices": {
"device": [
{
"device-id": "172.10.33.5",
"location": "POP"
}
]
},
"management": {
"type": "ietf-l3vpn-svc:provider-managed"
},
"routing-protocols": {
"routing-protocol": [
{
"type": "ietf-l3vpn-svc:static",
"static": {
"cascaded-lan-prefixes": {
"ipv4-lan-prefixes": [
{
"lan": "172.1.201.0/24",
"next-hop": "172.10.33.2",
"lan-tag": "vlan201"
}
]
}
}
}
]
},
"site-network-accesses": {
"site-network-access": [
{
"site-network-access-id": "500",
"site-network-access-type": "ietf-l3vpn-svc:multipoint",
"device-reference": "172.10.33.5",
"ip-connection": {
"ipv4": {
"address-allocation-type": "ietf-l3vpn-svc:static-address",
"addresses": {
"provider-address": "172.10.33.254",
"customer-address": "172.10.33.2",
"prefix-length": 24
}
}
},
"service": {
"svc-input-bandwidth": 1000000000,
"svc-output-bandwidth": 1000000000,
"svc-mtu": 1500,
"qos": {
"qos-profile": {
"classes": {
"class": [
{
"class-id": "qos-realtime",
"direction": "ietf-l3vpn-svc:both",
"latency": {
"latency-boundary": 10
},
"bandwidth": {
"guaranteed-bw-percent": 100.0
}
}
]
}
}
}
},
"routing-protocols": {
"routing-protocol": [
{
"type": "ietf-l3vpn-svc:static",
"static": {
"cascaded-lan-prefixes": {
"ipv4-lan-prefixes": [
{
"lan": "128.32.10.0/24",
"next-hop": "172.10.33.254",
"lan-tag": "vlan201"
},
{
"lan": "128.32.20.0/24",
"next-hop": "172.10.33.254",
"lan-tag": "vlan201"
}
]
}
}
}
]
},
"vpn-attachment": {
"vpn-id": "vpn2",
"site-role": "ietf-l3vpn-svc:hub-role"
}
}
]
}
}
]
}
}
}
\ No newline at end of file
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import logging, netaddr import logging, netaddr, json
from typing import Dict, List, Optional, Tuple from typing import Dict, List, Optional, Tuple
from common.Constants import DEFAULT_CONTEXT_NAME from common.Constants import DEFAULT_CONTEXT_NAME
from common.proto.context_pb2 import Service, ServiceStatusEnum, ServiceTypeEnum from common.proto.context_pb2 import Service, ServiceStatusEnum, ServiceTypeEnum
...@@ -26,6 +26,9 @@ from common.tools.grpc.EndPointIds import update_endpoint_ids ...@@ -26,6 +26,9 @@ from common.tools.grpc.EndPointIds import update_endpoint_ids
from context.client.ContextClient import ContextClient from context.client.ContextClient import ContextClient
from service.client.ServiceClient import ServiceClient from service.client.ServiceClient import ServiceClient
from .ReadServiceFunctionDefinition import ReadServiceFunctionDefinition
from .WriteNetworkFunctionDefinition import WriteNetworkFunctionDefinition
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
def create_service( def create_service(
...@@ -209,3 +212,55 @@ def process_site(site : Dict, errors : List[Dict]) -> None: ...@@ -209,3 +212,55 @@ def process_site(site : Dict, errors : List[Dict]) -> None:
network_accesses : List[Dict] = site['site-network-accesses']['site-network-access'] network_accesses : List[Dict] = site['site-network-accesses']['site-network-access']
for network_access in network_accesses: for network_access in network_accesses:
process_site_network_access(site_id, network_access, site_static_routing, errors) process_site_network_access(site_id, network_access, site_static_routing, errors)
def convert_l3sm_to_l3nm():
jsonRequest = open("/home/ubuntu/tfs-ctrl/src/nbi/tests/ietf_l3vpn_req_svc1.json", "r") #devuelve un file-object. "r" es por reading
output_file_path = "/home/ubuntu/tfs-ctrl/src/nbi/service/rest_server/nbi_plugins/ietf_l3vpn/EstructuraIntermedia.json"
jsonRequestData : str = jsonRequest.read() #jsonRequestData es de tipo str. Para leer el contenido, usamos read()
jParse : Dict = json.loads(jsonRequestData) #jParse es de tipo Dict. esto va a parsear jsonRequetData.
#cuando obtengamos el valor de una clave, y ese valor sea un array [], el tipo será 'list'
#in order to convert a jsonObject to an string, you can use .dumps
ietf_l3vpn : Dict = jParse['ietf-l3vpn-svc:l3vpn-svc']
vpn_services : Dict = ietf_l3vpn['vpn-services']
#print(vpn_services)
# vpn_service = vpn_services['vpn-service'] #ahora, al ser vpn-service un array, creo que la variable vpn_service es de tipo 'list'
# print(type(vpn_service)) #list
# print("VPN_SERVICE: " + str(vpn_service))
# print(vpn_service[0])
# print(vpn_service[0]['vpn-id'])
bd : Dict[any, any] = {} #Base datos de variables del JSON
#vpn_id = MiClase.readVpnServices(vpn_services) #vpn_id es variable de tipo List[str] con todas las vpn posibles
#try:
bd = ReadServiceFunctionDefinition.writeVpnServices( ReadServiceFunctionDefinition.readVpnServices(vpn_services) , bd)
#print(json.dumps(bd, indent=2))
sites : List = ietf_l3vpn['sites']['site'] #En sites se almacena el valor de la clave 'sites'.
#print(json.dumps(sites, indent=2))
#### PEQUEÑA CHAPUZA PARA CUANDO SOLO HAY UNA VPN ####
lista_VPNs : list = bd["VPN_IDs"]
bd["VPNs_Dict"][lista_VPNs[0]].update(ReadServiceFunctionDefinition.readSiteArray(sites, bd)) #vpn1.update Updatea el valor de vpn1
#### # ####
# except Exception as e: #En principio llegaran valueError o NoJSONFieldException
# print(e)
#print(json.dumps(bd, indent=2))
#YANG SUITE ENTRADA, SERVICE ->creo que IETF-NBI-TEF-DECEMBER-23; ietf-l3vpn-svc; edit-config; none selected
#YANG SUITE SALIDA, RED (RFC9182) -> IETF-NBI-TEF-DECEMBER-23; ietf-l3vpn-ntw; edit-config; none selected
#Codigo para crear archivo .json de salida
with open(output_file_path, 'w') as json_file:
json.dump(bd, json_file, indent=3)
jsonL3VPN_net : Dict = WriteNetworkFunctionDefinition.write()
# print(json.dumps(jsonL3VPN_net, indent = 3))
...@@ -11,9 +11,8 @@ ...@@ -11,9 +11,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import json, logging
import logging
from typing import Dict, List from typing import Dict, List
from flask import request from flask import request
from flask.json import jsonify from flask.json import jsonify
...@@ -24,11 +23,6 @@ from nbi.service.rest_server.nbi_plugins.tools.Authentication import HTTP_AUTH ...@@ -24,11 +23,6 @@ from nbi.service.rest_server.nbi_plugins.tools.Authentication import HTTP_AUTH
from .Handlers import process_site, process_vpn_service from .Handlers import process_site, process_vpn_service
from .YangValidator import YangValidator from .YangValidator import YangValidator
# from FunctionDefinition import FunctionDefinition
# from FunctionDefinitionNetwork import FunctionDefinitionNetwork
# import FunctionDefinition
# import FunctionDefinitionNetwork
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
class L3VPN_Services(Resource): class L3VPN_Services(Resource):
...@@ -38,16 +32,9 @@ class L3VPN_Services(Resource): ...@@ -38,16 +32,9 @@ class L3VPN_Services(Resource):
@HTTP_AUTH.login_required @HTTP_AUTH.login_required
def post(self): def post(self):
jsonAValidar = open("/home/ubuntu/Documents/json1.json", "r")
jsonAValidarData : str = jsonAValidar.read()
jsonAValidarDict : Dict = json.loads(jsonAValidarData)
output_file_path = "/home/ubuntu/Documents/EstructuraIntermedia.json"
if not request.is_json: raise UnsupportedMediaType('JSON payload is required') if not request.is_json: raise UnsupportedMediaType('JSON payload is required')
request_data : Dict = request.json request_data : Dict = request.json
# LOGGER.debug('Request: {:s}'.format(str(request_data))) LOGGER.debug('Request: {:s}'.format(str(request_data)))
LOGGER.debug('Request: {:s}'.format(str(jsonAValidarDict)))
errors = list() errors = list()
if 'ietf-l3vpn-svc:l3vpn-services' in request_data: if 'ietf-l3vpn-svc:l3vpn-services' in request_data:
...@@ -79,53 +66,15 @@ class L3VPN_Services(Resource): ...@@ -79,53 +66,15 @@ class L3VPN_Services(Resource):
def _process_l3vpn(self, request_data : Dict) -> List[Dict]: def _process_l3vpn(self, request_data : Dict) -> List[Dict]:
yang_validator = YangValidator('ietf-l3vpn-svc') yang_validator = YangValidator('ietf-l3vpn-svc')
request_data = yang_validator.parse_to_dict(jsonAValidarDict) request_data = yang_validator.parse_to_dict(request_data)
yang_validator.destroy() yang_validator.destroy()
#se supone que a partir de aqui ya ha validado errors = list()
jParse = jsonAValidarDict
ietf_l3vpn : Dict = jParse['ietf-l3vpn-svc:l3vpn-svc']
vpn_services : Dict = ietf_l3vpn['vpn-services']
bd : Dict[any, any] = {} #Base datos de variables del JSON
bd = FunctionDefinition.writeVpnServices( FunctionDefinition.readVpnServices(vpn_services) , bd)
sites : List = ietf_l3vpn['sites']['site'] #En sites se almacena el valor de la clave 'sites'.
#### FUNCIONA SOLO CON 1 VPN ####
lista_VPNs = bd["VPN_IDs"]
bd["VPNs_Dict"][lista_VPNs[0]].update(FunctionDefinition.readSiteArray(sites, bd))
#### --------------------- ####
with open(output_file_path, 'w') as json_file:
json.dump(bd, json_file, indent=3)
jsonL3VPN_net : Dict = FunctionDefinitionNetwork.write()
# print(json.dumps(jsonL3VPN_net, indent = 3))
######
errors = []
# for vpn_service in request_data['l3vpn-svc']['vpn-services']['vpn-service']: for vpn_service in request_data['l3vpn-svc']['vpn-services']['vpn-service']:
# process_vpn_service(vpn_service, errors) process_vpn_service(vpn_service, errors)
# for site in request_data['l3vpn-svc']['sites']['site']: for site in request_data['l3vpn-svc']['sites']['site']:
# process_site(site, errors) process_site(site, errors)
# response = jsonify(errors)
# response.status_code = HTTP_CREATED if len(errors) == 0 else HTTP_SERVERERROR
# return response
return errors return errors
from typing import Dict, List
class ReadServiceFunctionDefinition:
#Metodo para leer el campo vpn-services
@staticmethod
def readVpnServices(vpnServicesALeer: Dict) -> List:
# Acceder al campo 'vpn-service' que es un array de Dict con un campo vpn-id
vpn_service_list = vpnServicesALeer.get('vpn-service', [])#Utilizar get para manejar casos donde 'vpn-service' no está presente
vpn_ids = [] #Array con todos los ID de cada VPN
# Iterar sobre los elementos de la lista
for vpn_serviceEnFor in vpn_service_list:
vpn_id : str = vpn_serviceEnFor.get('vpn-id') #obtengo vpn-id del json iterando
# baseDatos["vpn-id_" + str(i)] = vpn_id # Utilizar f-strings para formatear las claves
vpn_ids.append(vpn_id)
return vpn_ids
#Metodo para escribir en la baseDatos lo leido en vpn-services
@staticmethod
def writeVpnServices(listaVPNs : List, baseDatos : Dict) -> Dict:
baseDatos["VPN_IDs"] = listaVPNs
#baseDatos.update({"VPN_IDs": vpn_ids}) #ambas lineas son validas para añadir al Dict
baseDatos["VPNs_Dict"] = {}
#Obtengo cada vpn-id del array y lo meto en VPNs_Dict
for clave in baseDatos["VPN_IDs"]:
baseDatos["VPNs_Dict"][clave] = {}#ya tengo un Dict asociado a cada clave
return baseDatos #devuelve la baseDatos pasada por argumento pero actualizada
#Lee el array site
@staticmethod
def readSiteArray(site: List, baseDatos: Dict) -> Dict:
print("Elementos en site: " + str(len(site)))
temp : Dict = {} #Diccionario temporal que guarda el ultimo site leido
temp2 : Dict = {} #Diccionario temporal que registra todos los sites leidos
lista_SitesID = [] #lista que almacenara los IDs de cada site del array
i = 1
for siteElement in site:
temp = ReadServiceFunctionDefinition.readSiteElement(lista_SitesID, siteElement) #Leo un site y me quedo con ID y Dict
temp2.update({lista_SitesID[-1] : temp}) # Almaceno esos datos en temp2
i += 1
res : Dict = {}
res["sitesIDs"] = lista_SitesID
res["sites_Dict"] = temp2 # A sites_Dict se le añaden todos los sites
return res
#Lee un site
@staticmethod
def readSiteElement(listaID: List, siteElement: Dict) -> Dict:
res: Dict = {}
listaID.append(siteElement.get('site-id'))
res.update({"site-id": siteElement.get('site-id')})
res.update({"management": siteElement.get("management")}) #revistar si está bien
res.update({"locations":siteElement.get("locations")})
res.update({"devices": ReadServiceFunctionDefinition.readDevices(siteElement.get('devices'))})
res.update({"routing-protocol" : ReadServiceFunctionDefinition.readRoutingProtocols(siteElement.get('routing-protocols'))})
res.update({"site-network-accesses" : ReadServiceFunctionDefinition.readSiteNetworkAccesses(siteElement.get('site-network-accesses'))})
print("readSiteElement Finiquitaoooo")
return res
#FALTAN MUCHOS CAMPOS A LEER EN site, como site-diversity, maximum-routes, security, service, traffic-protection
#Lee array de Devices. Si hay más de un device, cambiar código
@staticmethod
def readDevices(devices: Dict) -> Dict:
res: Dict = {}
devices_list: List = devices.get('device', []) # Cambié 'devices' por 'device' aquí
if len(devices_list) > 1:
i: int = 1
for eachDevice in devices_list:
res.update({f"device-id {i}": eachDevice.get('device-id')})
i += 1
elif len(devices_list) == 1:
res.update({"device-id": devices_list[0].get('device-id')})
return res
@staticmethod
def readRoutingProtocols(routingProtocols : Dict) -> Dict:
res : Dict = {} #todo el dict routing-protocols
rpArray : List = routingProtocols.get("routing-protocol") #el array routing-protocol
res.update({"type":rpArray[0].get("type")})#escribo el tipo en el diccionario
tipoRoutingProtocol : str = rpArray[0].get("type")#obtiene string "ietf-l3vpn-svc:static"
tipoResumido : str = tipoRoutingProtocol.split(":")[1] #se queda con la palabra, ospf, bgp, static,... sin el ietf...
#print("El tipo de routingProtocol es: "+ str(tipoResumido))
def case1():
ospfEntrada : Dict = rpArray[0].get("ospf",{}) #Funciona solo en caso de que el array tenga un elemento
ospfIntermedio : Dict = {}
ospfIntermedio.update({"address-family":ospfEntrada.get("address-family",{})})
ospfIntermedio.update({"area-address":ospfEntrada.get("area-address",{})})
ospfIntermedio.update({"metric":ospfEntrada.get("metric",{})})
arrayShamLinksEntrada : List = ospfEntrada.get("sham-links",[]) #el array
shamLinksFinal : Dict = {}
arrayShamLinksFinal : List = []
for elemento in arrayShamLinksEntrada:
shamLinksFinal.update({"target-site":elemento.get("target-site")})
shamLinksFinal.update({"metric":elemento.get("metric")})
arrayShamLinksFinal.append(shamLinksFinal)
ospfIntermedio.update({"sham-links":shamLinksFinal})
res.update({"ospf":ospfIntermedio})
def case2():
bgpEntrada : Dict = rpArray[0].get("bgp",{})
bgpSalida : Dict = {}
bgpSalida.update({"autonomous-system":bgpEntrada.get("autonomous-system")})
bgpSalida.update({"address-family":bgpEntrada.get("address-family")})
res.update({"bgp":bgpSalida})
def case3(): #SIMPLEMENTE COPIA, NO LEE. A IMPLEMENTAR
cascadedDict: Dict = rpArray[0].get("static", {}).get("cascaded-lan-prefixes", {})
valueRoutingProtocol = cascadedDict
res.update({"static":valueRoutingProtocol})
print("se ha copiado 'static' pero no se ha leido, falta implementar")
def case4():
ripEntrada : Dict = rpArray[0].get("rip",{})
ripSalida : Dict = {}
ripSalida.update({"address-family":ripEntrada.get("address-family")})
res.update({"rip":ripSalida})
def case5():
vrrpEntrada : Dict = rpArray[0].get("vrrp",{})
vrrpSalida : Dict = {}
vrrpSalida.update({"address-family":vrrpEntrada.get("address-family")})
res.update({"vrrp":vrrpSalida})
def default():
#return ValueError(f"Tipo de protocolo no compatible: {tipoResumido}")
print("TIPO DE PROTOCOLO NO VALIDO")
switch = {
"ospf": case1,
"bgp": case2,
"static": case3,
"rip":case4,
"vrrp": case5
}
#res.update({tipoResumido: switch.get(tipoResumido, default)()})
switch.get(tipoResumido)()
# print("_______________________d____________"+str(res))
print("read Routing Protocols finished")
return res
@staticmethod
def readSiteNetworkAccesses(siteNetworkAccesses : Dict) -> Dict:
siteNetworkAccessArray : List = siteNetworkAccesses.get("site-network-access")
res : Dict = {}
arrayDeIDs : List = []
for siteNetworkAccess in siteNetworkAccessArray:
variableIncial : str = siteNetworkAccess.get("site-network-access-id")
variableIncial = variableIncial.replace(" ", "-")#ESTO LO HAGO PARA QUE NO HAYA PROBLEMAS CON LOS ESPACIOS A LA HORA DE LEER EL JSON
arrayDeIDs.append(variableIncial)
res.update({"site-network-accesses-IDs":arrayDeIDs})
dictSiteNetworkAccesses : Dict = {}
for site in arrayDeIDs:
dictDeCadaID : Dict = {}
# try:
dictDeCadaID.update({"site-network-access-type":siteNetworkAccess.get("site-network-access-type")})
dictDeCadaID.update({"device-reference":siteNetworkAccess.get("device-reference")})
dictDeCadaID.update({"site-role":siteNetworkAccess.get("vpn-attachment", {}).get("site-role")})
#dictDeCadaID.update({"location-flavor" : FunctionDefinition.readLocationFlavor(siteNetworkAccess.get("location-flavor"))}) DE MOMENTO DA ERROR PORQUE ESE CAMPO NO EXISTE
#dictDeCadaID.update({"access-diversity" : FunctionDefinition.readAccessDiversity(siteNetworkAccess.get("access-diversity"))}) CAMPO NO EXISTE AUN
#dictDeCadaID.update({"bearer" : FunctionDefinition.readBearer(siteNetworkAccess.get("bearer"))}) CAMPO NO EXISTE AUN
dictDeCadaID.update({"ip-connection":ReadServiceFunctionDefinition.readIpConnection(siteNetworkAccess.get("ip-connection"))})
dictDeCadaID.update({"routing-protocols":ReadServiceFunctionDefinition.readRoutingProtocols(siteNetworkAccess.get("routing-protocols"))})
dictDeCadaID.update({"service":ReadServiceFunctionDefinition.readService(siteNetworkAccess.get("service"))})
# except NoJSONFieldException as e:
# print(e)
dictSiteNetworkAccesses.update({site:dictDeCadaID})
print("readSiteNetworkAccesses finiquitaoo")
res.update({"site-network-accesses-Dict": dictSiteNetworkAccesses})
return res
@staticmethod
def readLocationFlavor(locationFlavor : Dict) -> Dict:
res : Dict = {}
if "location" in locationFlavor:
res.update({"location-reference":locationFlavor.get("location", {}).get("location-reference")})
elif "device" in locationFlavor:
res.update({"device-reference":locationFlavor.get("device", {}).get("device-reference")})
# else:
# raise NoJSONFieldException("location-flavor")
return res
@staticmethod
def readAccessDiversity(accessDiversity : Dict) -> Dict:
res : Dict = {}
arrayGroupsIni : List = accessDiversity.get("groups",{}).get("group") #obtengo el array de objetos
arrayGroupsIDs : List = []
for groupId in arrayGroupsIni:
arrayGroupsIDs.append(groupId.get("group-id"))
res.update({"groups":arrayGroupsIDs})
arrayConstraintsIni : List = accessDiversity.get("constraints", {}).get("constraint")
arrayConstraintsFin : List = []
for constraint in arrayConstraintsIni: #recordar que constraint es un objeto dentro del array arrayConstraintsIni
dictConstraint : Dict = {}
dictConstraint.update({"constraint-type" : constraint.get("constraint-type")})
dictTargetFlavor : Dict = constraint.get("target", {}).get("target-flavor")
if "id" in dictTargetFlavor:
dictConstraint.update({"target-flavor": dictTargetFlavor.get("id")})
elif "all-accesses" in dictTargetFlavor:
dictConstraint.update({"target-flavor": dictTargetFlavor.get("all-accesses")})
elif "all-groups" in dictTargetFlavor:
dictConstraint.update({"target-flavor": dictTargetFlavor.get("all-groups")})
# else:
# raise NoJSONFieldException("read-access-divesity>constraints>constraint>target>target-flavor")
arrayConstraintsFin.append(dictConstraint)
res.update({"constraints":arrayConstraintsFin})
return res
@staticmethod
def readBearer(bearer : Dict) -> Dict:
res : Dict = {}
res.update({"always-on":bearer.get("always-on")})
res.update({"bearer-reference":bearer.get("bearer-reference")})
res.update({"requested-type":bearer.get("requested-type",{}).get("requested-type")})
res.update({"strict":bearer.get("requested-type",{}).get("strict")})
return res
@staticmethod
def readIpConnection(ipConnection : Dict) -> Dict: #IPV4 E IPV6 TIENEN LOS MISMOS CAMPOS
res : Dict = {}
if ipConnection.get("ipv4") is not None:
res.update({"ipv4": ReadServiceFunctionDefinition.readIpv4_Ipv6(ipConnection.get("ipv4"))})
elif ipConnection.get("ipv6") is not None:
res.update({"ipv6":ReadServiceFunctionDefinition.readIpv4_Ipv6(ipConnection.get("ipv6"))})
# else:
# raise NoJSONFieldException("ip-connection>ipv4/6")
bfd : Dict = ipConnection.get("oam",{}).get("bfd")
if bfd is not None:
oamFinal : Dict = {}
oamFinal.update({"enabled":bfd.get("enabled")})
holdtime : Dict = bfd.get("holdtime")
holdtimeFinal : Dict = {}
if "fixed" in holdtime:
holdtimeFinal.update({"fixed":holdtime.get("fixed")})
elif "profile" in holdtime:
holdtimeFinal.update({"profile":holdtime.get("profile")})
# else:
# raise NoJSONFieldException("oam>bfd>holdtime")
oamFinal.update({"holdtime":holdtimeFinal})
res.update({"oam":oamFinal})
return res
@staticmethod
def readIpv4_Ipv6(ipv : Dict) -> Dict :
res : Dict = {}
res.update({"address-allocation-type":ipv.get("address-allocation-type")})
providerDHCP : Dict = ipv.get("provider-dhcp") #None si no existe ese campo, puede mejorarse eficiencia
if providerDHCP is not None:
providerDHCPFinal : Dict = {}
providerDHCPFinal.update({"provider-dhcp":providerDHCP.get("provider-address")})
providerDHCPFinal.update({"prefix-length":providerDHCP.get("prefix-lenght")})
addressAsign : Dict = providerDHCP.get("address-asign")
addressAsignFinal : Dict = {}
if "number" in addressAsign:
addressAsignFinal.update({"number":addressAsign.get("number")})
elif "explicit" in addressAsign:
addressAsignFinal.update({"explicit":addressAsign.get("explicit")})
# else:
# raise NoJSONFieldException("ipv4/6>address-asign")
providerDHCPFinal.update({"address-asign":addressAsignFinal})
res.update({"provider-dhcp":providerDHCPFinal})
dhcpRelay : Dict = ipv.get("dhcp-relay")
if dhcpRelay is not None:
dhcpRelayFinal : Dict = {}
dhcpRelayFinal.update({"provider-address":dhcpRelay.get("provider-address")})
dhcpRelayFinal.update({"prefix-lenght":dhcpRelay.get("prefix-lenght")})
dhcpRelayFinal.update({"server-ip-address":dhcpRelay.get("customer-dhcp-servers",{}).get("server-ip-address")})
res.update({"dhcp-relay":dhcpRelayFinal})
addresses : Dict = ipv.get("addresses")
if addresses is not None:
addressesFinal : Dict = {}
addressesFinal.update({"provider-address":addresses.get("provider-address")})
addressesFinal.update({"customer-address":addresses.get("customer-address")})
addressesFinal.update({"prefixe-length":addresses.get("prefixe-length")})
res.update({"addresses":addressesFinal})
return res
# @staticmethod
# def readSecurity(security : Dict) -> Dict:
# res : Dict = {}
# res.update({"authentication" : security.get("authentication")})
# encryption : Dict = security.get("encryption")
# encryptionFinal : Dict = {}
# return res
#readService todavía me da error
@staticmethod
def readService(service : Dict) -> Dict :
res : Dict = {}
#try:
res.update({"svc-mtu":service.get("svc-mtu")})
res.update({"svc-input-bandwidth":service.get("svc-input-bandwidth")})
res.update({"svc-output-bandwidth":service.get("svc-output-bandwidth")})
qos : Dict = service.get("qos")
class_id = qos["qos-profile"]["classes"]["class"][0]["class-id"]
direction = qos["qos-profile"]["classes"]["class"][0]["direction"]
latency_boundary = qos["qos-profile"]["classes"]["class"][0]["latency"]["latency-boundary"]
guaranteed_bw_percent = qos["qos-profile"]["classes"]["class"][0]["bandwidth"]["guaranteed-bw-percent"]
res.update({"class-id":class_id})
res.update({"direction":direction})
res.update({"latency-boundary":latency_boundary})
res.update({"guaranteed-bw-percent":guaranteed_bw_percent})
#Clase que lee el campo custom varias lineas mas adelante
def readCustom (custom : Dict) -> Dict: #custom es un Dict que es: {classes: [class-id: *, ..., latency: {flavor:{lowest:*///boundary:*}}],[...],[...]}
res : Dict = {}
arrayClassesEntrada : List = custom.get("class") #un array con elementos indeterminados
arrayClassesFinal : List = []
for elementEntrada in arrayClassesEntrada:
elementFinal : Dict = {}
elementFinal.update({"class-id":elementEntrada.get("class-id")})
elementFinal.update({"direction":elementEntrada.get("direction")})
elementFinal.update({"rate-limit":elementEntrada.get("rate-limit")})
#Campo latency--->
#latency: {
# flavor:{
# lowest:*
# o quizás
# boundary:*
# }
# }
latency : Dict = elementEntrada.get("latency")
jitter : Dict = elementEntrada.get("jitter")
if latency is not None:
if "use-lowest-latency" in latency:
elementFinal.update({"latency-flavor-lowest":latency.get("use-lowest-latency")})
elif "latency-boundary" in latency:
elementFinal.update({"latency-flavor-boundary":latency.get("latency-boundary")})
elif jitter is not None:
if "use-lowest-jitter" in jitter:
elementFinal.update({"jitter-flavor-lowest":jitter.get("use-lowest-jiter")})
elif "latency-boundary" in jitter:
elementFinal.update({"jitter-flavor-boundary":jitter.get("latency-boundary")})
else:
print("Debe haber un campo lowest o boundary dentro de jitter>flavor")
else:
print("FALTAN CAMPOS EN CUSTOM")
bandwidthEntrada : Dict = elementEntrada.get("bandwidth")
bandwidthSalida : Dict = {}
bandwidthSalida.update({"guaranteed-bw-percent":bandwidthEntrada.get("guaranteed-bw-percent")})
bandwidthSalida.update({"end-to-end":bandwidthEntrada.get("end-to-end")})
elementFinal.update({"bandwidth":bandwidthSalida})
arrayClassesFinal.append(elementFinal)
# res.update({"latency-flavor":arrayClassesFinal})
# return res
# #END READCUSTOM
# qosProfileEntrada : Dict = qos.get("qos-profile")
# qosProfileFin : Dict = {}
# if "profile" in qosProfileEntrada:
# qosProfileFin.update({"standard-profile":qosProfileEntrada.get("standard")})
# elif "classes" in qosProfileEntrada:
# qosProfileFin.update({"custom-classes":readCustom(qosProfileEntrada.get("classes"))})
# else:
# print("falta campo en qos>qos-profile")
# #raise NoJSONFieldException("qos>qos-profile")
# res.update({"qos-profile":qosProfileFin})
# res.update({"carrierscarrier":qos.get("carrierscarrier")})
# multicastEntrada : Dict = qos.get("multicast")
# multicastSalida : Dict = {}
# multicastSalida.update({"multicast-site-type":multicastEntrada.get("multicast-site-type")})
# multicastAddressSalida : Dict = {}
# multicastAddressSalida.update({"ipv4":multicastEntrada.get("multicast-address-family", {}).get("ipv4")})
# multicastAddressSalida.update({"ipv6":multicastEntrada.get("multicast-address-family", {}).get("ipv6")})
# multicastSalida.update({"multicast-address-family":multicastAddressSalida})
# multicastSalida.update({"protocol-type":multicastEntrada.get("protocol-type")})
# res.update({"multicast":multicastSalida})
# # except KeyError:
# # print("falta alguna clave en service")
# # except NoJSONFieldException as e:
# # print(e)
# # finally:
return res
\ No newline at end of file
from typing import Dict, List from typing import Dict, List
import json import json, os
class FunctionDefinitionNetwork: class WriteNetworkFunctionDefinition:
jsonEstructuraIntermedia = open("/home/ubuntu/Documents/EstructuraIntermedia.json", "r") input_file_path : str ="/home/ubuntu/Documents/EstructuraIntermedia.json"
output_file_path = "/home/ubuntu/Documents/L3VPN_ntw.json" output_file_path = "/home/ubuntu/Documents/L3VPN_ntw.json"
jsonEstructuraIntermedia = open(input_file_path, "r")
jsonEstructuraIntermediaData : str = jsonEstructuraIntermedia.read() jsonEstructuraIntermediaData : str = jsonEstructuraIntermedia.read()
jsonEstIntDict : Dict = json.loads(jsonEstructuraIntermediaData) jsonEstIntDict : Dict = json.loads(jsonEstructuraIntermediaData)
@staticmethod @staticmethod
def numberVpnIDs() -> int : def numberVpnIDs() -> int :
vpnIDs : List = FunctionDefinitionNetwork.jsonEstIntDict["VPN_IDs"] vpnIDs : List = WriteNetworkFunctionDefinition.jsonEstIntDict["VPN_IDs"]
return len(vpnIDs) return len(vpnIDs)
#Este metodo devuelve el numero de sites, y es necesario porque el numero de sites es el numero de nodes #Este metodo devuelve el numero de sites, y es necesario porque el numero de sites es el numero de nodes
@staticmethod @staticmethod
def numberSitesIDS() -> int : def numberSitesIDS() -> int :
sitesIDs : List = FunctionDefinitionNetwork.jsonEstIntDict["VPNs_Dict"]["vpn1"]["sitesIDs"] sitesIDs : List = WriteNetworkFunctionDefinition.jsonEstIntDict["VPNs_Dict"]["vpn1"]["sitesIDs"]
return len(sitesIDs) return len(sitesIDs)
@staticmethod @staticmethod
...@@ -24,7 +26,7 @@ class FunctionDefinitionNetwork: ...@@ -24,7 +26,7 @@ class FunctionDefinitionNetwork:
jsonNet : Dict = {} jsonNet : Dict = {}
jsonNet.update({"vpn-service":{}}) #no tenemos en cuenta que puede haber más de 1 VPN. Codigo valido para 1 VPN solo jsonNet.update({"vpn-service":{}}) #no tenemos en cuenta que puede haber más de 1 VPN. Codigo valido para 1 VPN solo
vpn_id : str = FunctionDefinitionNetwork.jsonEstIntDict["VPN_IDs"][0].split("vpn")[1] #obtengo el numero de vpn_id vpn_id : str = WriteNetworkFunctionDefinition.jsonEstIntDict["VPN_IDs"][0].split("vpn")[1] #obtengo el numero de vpn_id
jsonNet["vpn-service"]["vpn-id"] = vpn_id #de momento solo 1 vpn jsonNet["vpn-service"]["vpn-id"] = vpn_id #de momento solo 1 vpn
# jsonNet["vpn-service"]["customer-name"] = "_" # jsonNet["vpn-service"]["customer-name"] = "_"
# jsonNet["vpn-service"]["parent-service-id"] = "_" # jsonNet["vpn-service"]["parent-service-id"] = "_"
...@@ -33,24 +35,24 @@ class FunctionDefinitionNetwork: ...@@ -33,24 +35,24 @@ class FunctionDefinitionNetwork:
jsonNet["vpn-service"]["vpn-nodes"] = {} jsonNet["vpn-service"]["vpn-nodes"] = {}
arrayVpnNode : List = [] arrayVpnNode : List = []
print(FunctionDefinitionNetwork.numberSitesIDS()) print(WriteNetworkFunctionDefinition.numberSitesIDS())
for numeroDeNode in range(FunctionDefinitionNetwork.numberSitesIDS()): for numeroDeNode in range(WriteNetworkFunctionDefinition.numberSitesIDS()):
sites : List = FunctionDefinitionNetwork.jsonEstIntDict["VPNs_Dict"]["vpn1"]["sitesIDs"] sites : List = WriteNetworkFunctionDefinition.jsonEstIntDict["VPNs_Dict"]["vpn1"]["sitesIDs"]
site: str = FunctionDefinitionNetwork.jsonEstIntDict["VPNs_Dict"]["vpn1"]["sitesIDs"][numeroDeNode] site: str = WriteNetworkFunctionDefinition.jsonEstIntDict["VPNs_Dict"]["vpn1"]["sitesIDs"][numeroDeNode]
service_access: str = FunctionDefinitionNetwork.jsonEstIntDict["VPNs_Dict"]["vpn1"]["sites_Dict"][sites[numeroDeNode]]["site-network-accesses"]["site-network-accesses-IDs"][0] service_access: str = WriteNetworkFunctionDefinition.jsonEstIntDict["VPNs_Dict"]["vpn1"]["sites_Dict"][sites[numeroDeNode]]["site-network-accesses"]["site-network-accesses-IDs"][0]
#con los siguientes ifs hago que las politicas cambien de lugar, uno si y uno no constantemente #con los siguientes ifs hago que las politicas cambien de lugar, uno si y uno no constantemente
if numeroDeNode % 2 is 0: if numeroDeNode % 2 is 0:
arrayVpnNode.append(FunctionDefinitionNetwork.writeNode(FunctionDefinitionNetwork.jsonEstIntDict,site,service_access,numeroDeNode, 0)) arrayVpnNode.append(WriteNetworkFunctionDefinition.writeNode(WriteNetworkFunctionDefinition.jsonEstIntDict,site,service_access,numeroDeNode, 0))
if numeroDeNode % 2 is not 0: if numeroDeNode % 2 is not 0:
arrayVpnNode.append(FunctionDefinitionNetwork.writeNode(FunctionDefinitionNetwork.jsonEstIntDict,site,service_access,numeroDeNode, 1)) arrayVpnNode.append(WriteNetworkFunctionDefinition.writeNode(WriteNetworkFunctionDefinition.jsonEstIntDict,site,service_access,numeroDeNode, 1))
jsonNet["vpn-service"]["vpn-nodes"]["vpn-node"] = arrayVpnNode jsonNet["vpn-service"]["vpn-nodes"]["vpn-node"] = arrayVpnNode
#Codigo para crear el archivo y escribir el json en el #Codigo para crear el archivo y escribir el json en el
with open(FunctionDefinitionNetwork.output_file_path, 'w') as json_file: with open(WriteNetworkFunctionDefinition.output_file_path, 'w') as json_file:
json.dump(jsonNet, json_file, indent = 3) json.dump(jsonNet, json_file, indent = 3)
return jsonNet return jsonNet
...@@ -133,7 +135,7 @@ class FunctionDefinitionNetwork: ...@@ -133,7 +135,7 @@ class FunctionDefinitionNetwork:
} }
} }
vpnNetworkAccessElement.update({"status":status}) vpnNetworkAccessElement.update({"status":status})
vpnNetworkAccessElement.update({"connection":FunctionDefinitionNetwork.writeConnection()}) vpnNetworkAccessElement.update({"connection":WriteNetworkFunctionDefinition.writeConnection()})
vpn_id : str = jsonEstDict["VPN_IDs"][0]#valido cuando solo hay una VPN. vpn_id : str = jsonEstDict["VPN_IDs"][0]#valido cuando solo hay una VPN.
#de momento no IPv6, campo vacio, solo IPv4 #de momento no IPv6, campo vacio, solo IPv4
......
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from typing import Dict, List
from flask import request
from flask.json import jsonify
from flask_restful import Resource
from werkzeug.exceptions import UnsupportedMediaType
from nbi.service.rest_server.nbi_plugins.tools.HttpStatusCodes import HTTP_CREATED, HTTP_SERVERERROR
from nbi.service.rest_server.nbi_plugins.tools.Authentication import HTTP_AUTH
from .Handlers import process_site, process_vpn_service
from .YangValidator import YangValidator
LOGGER = logging.getLogger(__name__)
class L3VPN_Services(Resource):
@HTTP_AUTH.login_required
def get(self):
return {}
@HTTP_AUTH.login_required
def post(self):
if not request.is_json: raise UnsupportedMediaType('JSON payload is required')
request_data : Dict = request.json
LOGGER.debug('Request: {:s}'.format(str(request_data)))
errors = list()
if 'ietf-l3vpn-svc:l3vpn-services' in request_data:
# processing multiple L3VPN service requests formatted as:
#{
# "ietf-l3vpn-svc:l3vpn-services": {
# "l3vpn-svc": [
# {
# "service-id": "vpn1",
# "vpn-services": {
# "vpn-service": [
for l3vpn_svc in request_data['ietf-l3vpn-svc:l3vpn-services']['l3vpn-svc']:
l3vpn_svc.pop('service-id', None)
l3vpn_svc_request_data = {'ietf-l3vpn-svc:l3vpn-svc': l3vpn_svc}
errors.extend(self._process_l3vpn(l3vpn_svc_request_data))
elif 'ietf-l3vpn-svc:l3vpn-svc' in request_data:
# processing single (standard) L3VPN service request formatted as:
#{
# "ietf-l3vpn-svc:l3vpn-svc": {
# "vpn-services": {
# "vpn-service": [
errors.extend(self._process_l3vpn(request_data))
else:
errors.append('unexpected request: {:s}'.format(str(request_data)))
response = jsonify(errors)
response.status_code = HTTP_CREATED if len(errors) == 0 else HTTP_SERVERERROR
return response
def _process_l3vpn(self, request_data : Dict) -> List[Dict]:
yang_validator = YangValidator('ietf-l3vpn-svc')
request_data = yang_validator.parse_to_dict(request_data)
yang_validator.destroy()
errors = list()
for vpn_service in request_data['l3vpn-svc']['vpn-services']['vpn-service']:
process_vpn_service(vpn_service, errors)
for site in request_data['l3vpn-svc']['sites']['site']:
process_site(site, errors)
return errors
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