diff --git a/scripts/show_logs_pcep.sh b/scripts/show_logs_pcep.sh new file mode 100755 index 0000000000000000000000000000000000000000..af7cccd96c7ab774974bbf6a2802e397f7b0f24f --- /dev/null +++ b/scripts/show_logs_pcep.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# 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. + +######################################################################################################################## +# Define your deployment settings here +######################################################################################################################## + +# If not already set, set the name of the Kubernetes namespace to deploy to. +export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"} + +######################################################################################################################## +# Automated steps start here +######################################################################################################################## + +kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/pcepservice -c server diff --git a/src/common/Constants.py b/src/common/Constants.py index 668fbc28a3818eb6e4d17ae80adcda17375043c2..52d6d9ee799582ba26a42ed1329af93ec8933f0b 100644 --- a/src/common/Constants.py +++ b/src/common/Constants.py @@ -82,9 +82,8 @@ DEFAULT_SERVICE_GRPC_PORTS = { ServiceNameEnum.OPTICALATTACKMANAGER .value : 10005, ServiceNameEnum.INTERDOMAIN .value : 10010, ServiceNameEnum.PATHCOMP .value : 10020, - ServiceNameEnum.TE .value : 10030, ServiceNameEnum.PCEP .value : 10050, - + ServiceNameEnum.TE .value : 10030, # Used for test and debugging only ServiceNameEnum.DLT_GATEWAY .value : 50051, diff --git a/src/device/service/driver_api/_Driver.py b/src/device/service/driver_api/_Driver.py index 0aa1a6c5a8697d4c75f7044981221c6dd47e3aff..bfd81b867da678c629201f838bc0bb81f3573dfc 100644 --- a/src/device/service/driver_api/_Driver.py +++ b/src/device/service/driver_api/_Driver.py @@ -24,8 +24,6 @@ RESOURCE_NETWORK_INSTANCES = '__network_instances__' RESOURCE_ROUTING_POLICIES = '__routing_policies__' RESOURCE_SERVICES = '__services__' RESOURCE_ACL = '__acl__' -RESOURCE_INVENTORY = '__inventory__' - class _Driver: def __init__(self, name : str, address: str, port: int, **settings) -> None: diff --git a/src/device/service/drivers/openconfig/templates/Interfaces_mng.py b/src/device/service/drivers/openconfig/templates/Interfaces_mng.py deleted file mode 100644 index ced1932523a4ed83afefa3c318135f1b92b7fb2b..0000000000000000000000000000000000000000 --- a/src/device/service/drivers/openconfig/templates/Interfaces_mng.py +++ /dev/null @@ -1,100 +0,0 @@ -# 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. - - -""" -#Method Name: parse - -#Parameters: - - - xml_data: [ET.Element] Represents the XML data to be parsed. - -# Functionality: - -The parse function of the interfaces_mng class has the functionality to parse -an XML document represented by the xml_data parameter and extract specific -information from the XML elements, namely the active interfaces with their name, -type, ipv4 and ipv6 addresses in case they have. - -To generate the template the following steps are performed: - -1) An empty list called response is created to store the results of the analysis. - -2) Iterate over the XML elements that match the pattern specified by the XPATH_PORTS -expression. These elements represent management interfaces in the XML document. - -3) For each management interfaces: -A dictionary called interfaces_mng is initialized that will store the information extracted -from the interfaces.The values of the relevant XML elements are extracted and added to -the dictionary. - -#Return: -List[Tuple[str, Dict[str, Any]]] The response list containing the tuples (path, dictionary) -with the information extracted from the XML document interfaces is returned. - -""" - - -import logging, lxml.etree as ET -from typing import Any, Dict, List, Tuple -from .Namespace import NAMESPACES -from .Tools import add_value_from_tag - -LOGGER = logging.getLogger(__name__) - -XPATH_PORTS = "//oci:interfaces/oci:interface" -XPATH_SUBINTERFACES = ".//oci:subinterfaces/oci:subinterface" -XPATH_IPV4ADDRESSES = ".//ociip:ipv4/ociip:addresses/ociip:address" -XPATH_IPV6ADDRESSES = ".//ociip:ipv6/ociip:addresses/ociip:address" - -def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: - response = [] - LOGGER.debug("Interfaces_mngPrueba") - - for xml_interface_mng in xml_data.xpath(XPATH_PORTS, namespaces=NAMESPACES): - LOGGER.info('xml_component xml_interfaces_mng = {:s}'.format(str(ET.tostring(xml_interface_mng)))) - interfaces_mng = {} - - interface_enabled = xml_interface_mng.find('oci:config/oci:enabled', namespaces=NAMESPACES) - if interface_enabled == None: - interface_enabled = xml_interface_mng.find('oci:state/oci:enabled', namespaces=NAMESPACES) - if interface_enabled == None: continue - if 'false' in interface_enabled or 'false' in interface_enabled.text: continue - - interface_name = xml_interface_mng.find('oci:name', namespaces=NAMESPACES) - if interface_name is None or interface_name.text is None: continue - add_value_from_tag(interfaces_mng, 'name', interface_name) - - interface_type = xml_interface_mng.find('oci:config/oci:type', namespaces=NAMESPACES) - if interface_type is None: - interface_type = xml_interface_mng.find('oci:state/oci:type', namespaces=NAMESPACES) - if interface_type is None: continue - interface_type.text = interface_type.text.replace('ianaift:','') - add_value_from_tag(interfaces_mng, 'type', interface_type) - - for xml_subinterface in xml_interface_mng.xpath(XPATH_SUBINTERFACES, namespaces=NAMESPACES): - for xml_ipv4_address in xml_subinterface.xpath(XPATH_IPV4ADDRESSES, namespaces=NAMESPACES): - address_ipv4 = xml_ipv4_address.find('ociip:state/ociip:ip', namespaces=NAMESPACES) - if not address_ipv4 is None: - add_value_from_tag(interfaces_mng, 'ipv4', address_ipv4) - - for xml_ipv6_address in xml_subinterface.xpath(XPATH_IPV6ADDRESSES, namespaces=NAMESPACES): - address_ipv6 = xml_ipv6_address.find('ociip:state/ociip:ip', namespaces=NAMESPACES) - if not address_ipv6 is None: - add_value_from_tag(interfaces_mng, 'ipv6', address_ipv6) - if not 'ipv4' in interfaces_mng and not 'ipv6' in interfaces_mng: - if 'ip' in interfaces_mng['type'] or 'Loopback' in interfaces_mng['type']: continue - response.append(('/interfaces_mng/{:s}'.format(interfaces_mng['name']), interfaces_mng)) - - return response diff --git a/src/device/service/drivers/openconfig/templates/Inventory.py b/src/device/service/drivers/openconfig/templates/Inventory.py deleted file mode 100644 index 5775ac963956d77c77616d9bb23833a0e9b6ff5b..0000000000000000000000000000000000000000 --- a/src/device/service/drivers/openconfig/templates/Inventory.py +++ /dev/null @@ -1,186 +0,0 @@ -# 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. - - -""" -#Method Name: parse - -#Parameters: - - - xml_data: [ET.Element] Represents the XML data to be parsed. - -# Functionality: - -The parse function of the inventerio class has the functionality to parse -an XML document represented by the xml_data parameter and extract specific -information from the XML elements, namely the relevant characteristics of the -components. - -To generate the template the following steps are performed: - -1) An empty list called response is created to store the results of the analysis. - -2) Iterate over the XML elements that match the pattern specified by the XPATH_PORTS -expression. These elements represent components in the XML document. - -3) For each component element: -A dictionary called inventory is initialized that will store the information extracted -from the component.The values of the relevant XML elements are extracted and added to -the dictionary. - -#Return: -List[Tuple[str, Dict[str, Any]]] The response list containing the tuples (path, dictionary) -with the information extracted from the XML document components is returned. - -""" - - -import logging, lxml.etree as ET -from typing import Any, Dict, List, Tuple -from .Namespace import NAMESPACES -from .Tools import add_value_from_tag - -LOGGER = logging.getLogger(__name__) - -XPATH_PORTS = "//ocp:components/ocp:component" - -def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: - response = [] - LOGGER.debug("InventoryPrueba") - parent_types = {} - for xml_component in xml_data.xpath(XPATH_PORTS, namespaces=NAMESPACES): - LOGGER.info('xml_component inventario = {:s}'.format(str(ET.tostring(xml_component)))) - inventory = {} - inventory['parent-component-references'] = '' - inventory['uuid'] = '' - inventory['name'] = '' - inventory['class'] = '' - inventory['attributes'] = {} - component_reference = [] - - component_name = xml_component.find('ocp:name', namespaces=NAMESPACES) - if component_name is None or component_name.text is None: continue - add_value_from_tag(inventory, 'uuid', component_name) - add_value_from_tag(inventory, 'name', component_name) - - component_description = xml_component.find('ocp:state/ocp:description', namespaces=NAMESPACES) - if not component_description is None: - add_value_from_tag(inventory['attributes'], 'description', component_description) - #PodrÃa estar presente en lugar del name - component_alias = xml_component.find('ocp:state/ocp:alias', namespaces=NAMESPACES) - if not component_alias is None: - add_value_from_tag(inventory['attributes'], 'alias', component_alias) - - component_location = xml_component.find('ocp:state/ocp:location', namespaces=NAMESPACES) - if not component_location is None: - add_value_from_tag(inventory['attributes'], 'location', component_location) - - component_type = xml_component.find('ocp:state/ocp:type', namespaces=NAMESPACES) - component_type.text = component_type.text.replace('oc-platform-types:','') - if component_type is None: continue - add_value_from_tag(inventory, 'class', component_type) - if inventory['class'] == 'CPU' or inventory['class'] == 'STORAGE': continue - - component_empty = xml_component.find('ocp:state/ocp:empty', namespaces=NAMESPACES) - if not component_empty is None: - add_value_from_tag(inventory['attributes'], 'contained-child', component_empty) - - #añadir el parent pos - - component_parent = xml_component.find('ocp:state/ocp:parent', namespaces=NAMESPACES) - if component_parent is None or component_parent.text is None: - add_value_from_tag(inventory, 'parent-component-references', component_type) - else: - add_value_from_tag(inventory, 'parent-component-references', component_parent) - - component_HW = xml_component.find('ocp:state/ocp:hardware-version', namespaces=NAMESPACES) - if not component_HW is None: - add_value_from_tag(inventory['attributes'], 'hardware-rev', component_HW) - - component_firmware_version = xml_component.find('ocp:state/ocp:firmware-version', namespaces=NAMESPACES) - if not component_firmware_version is None: - add_value_from_tag(inventory['attributes'], 'firmware-rev', component_firmware_version) - - component_SW = xml_component.find('ocp:state/ocp:software-version', namespaces=NAMESPACES) - if not component_SW is None: - add_value_from_tag(inventory['attributes'], 'software-rev', component_SW) - - component_serial = xml_component.find('ocp:state/ocp:serial-no', namespaces=NAMESPACES) - if not component_serial is None: - add_value_from_tag(inventory['attributes'], 'serial-num', component_serial) - - component_serial_t = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:serial-no', namespaces=NAMESPACES) - if not component_serial_t is None: - add_value_from_tag(inventory['attributes'], 'serial-num', component_serial_t) - - component_mfg_name = xml_component.find('ocp:state/ocp:mfg-name', namespaces=NAMESPACES) - if not component_mfg_name is None: - add_value_from_tag(inventory['attributes'], 'mfg-name', component_mfg_name) - - component_part_no = xml_component.find('ocp:state/ocp:part-no', namespaces=NAMESPACES) - if not component_part_no is None: - add_value_from_tag(inventory['attributes'], 'part-number', component_part_no) - - #modificar es un identificador de seguimiento de activos asignado por el usuario para el componente - component_asset_id = xml_component.find('ocp:state/ocp:asset-id', namespaces=NAMESPACES) - if not component_asset_id is None: - add_value_from_tag(inventory['attributes'], 'asset-id', component_asset_id) - - component_removable = xml_component.find('ocp:state/ocp:removable', namespaces=NAMESPACES) - if not component_removable is None: - add_value_from_tag(inventory['attributes'], 'is-fru', component_removable) - - component_mfg_date = xml_component.find('ocp:state/ocp:mfg-date', namespaces=NAMESPACES) - if not component_mfg_date is None: - add_value_from_tag(inventory['attributes'], 'mfg-date', component_mfg_date) - - #modificar "Este nodo contiene información de identificación sobre el componente" - component_uri = xml_component.find('ocp:state/ocp:uri', namespaces=NAMESPACES) - if not component_uri is None: - add_value_from_tag(inventory['attributes'], 'uri', component_uri) - - #Para transceiver - component_present = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:present', namespaces=NAMESPACES) - if component_present is not None and 'NOT_PRESENT' in component_present.text: continue - - component_vendor = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:vendor', namespaces=NAMESPACES) - if not component_vendor is None: - add_value_from_tag(inventory['attributes'], 'vendor', component_vendor) - component_connector = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:connector-type', namespaces=NAMESPACES) - if not component_connector is None: - component_connector.text = component_connector.text.replace('oc-opt-types:','') - add_value_from_tag(inventory['attributes'], 'connector-type', component_connector) - - component_form = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:form-factor', namespaces=NAMESPACES) - if not component_form is None: - component_form.text = component_form.text.replace('oc-opt-types:','') - add_value_from_tag(inventory['attributes'], 'form-factor', component_form) - #añadir caracterÃsticas del parent references - if inventory['parent-component-references'] not in parent_types: - parent_types[inventory['parent-component-references']] = len(parent_types) + 1 - - component_reference.extend([parent_types[inventory['parent-component-references']]]) - - - - response.append(('/inventory/{:s}'.format(inventory['name']), inventory)) - - for tupla in response: - if inventory['parent-component-references'] in tupla[0]: - component_reference.extend([tupla[1]['class']]) - component_reference.extend([tupla[1]['uuid']]) - - inventory['component-reference'] = component_reference - - return response \ No newline at end of file diff --git a/src/device/service/drivers/openconfig/templates/__init__.py b/src/device/service/drivers/openconfig/templates/__init__.py index 40fc823da3f64e24f4099438febf0245c86b8ce2..d9358ec620cf689bc29ae8c6f4742ebad0279fd9 100644 --- a/src/device/service/drivers/openconfig/templates/__init__.py +++ b/src/device/service/drivers/openconfig/templates/__init__.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ast import List, Tuple import json, logging, lxml.etree as ET, re import time from typing import Any, Dict, Optional @@ -20,7 +19,7 @@ from jinja2 import Environment, PackageLoader, select_autoescape import paramiko from .Tools import generate_templates from device.service.driver_api._Driver import ( - RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_INTERFACES_MNG,RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_ACL, RESOURCE_INVENTORY) + RESOURCE_ENDPOINTS, RESOURCE_INTERFACES,RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_ACL) from .EndPoints import parse as parse_endpoints from .Interfaces import parse as parse_interfaces, parse_counters from .NetworkInstances import parse as parse_network_instances @@ -30,7 +29,6 @@ from .Inventory import parse as parse_inventory LOGGER = logging.getLogger(__name__) ALL_RESOURCE_KEYS = [ - RESOURCE_INVENTORY, RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_ROUTING_POLICIES, # routing policies should come before network instances @@ -39,7 +37,6 @@ ALL_RESOURCE_KEYS = [ ] RESOURCE_KEY_MAPPINGS = { - RESOURCE_INVENTORY : 'inventory', RESOURCE_ENDPOINTS : 'component', RESOURCE_INTERFACES : 'interface', RESOURCE_NETWORK_INSTANCES: 'network_instance', @@ -48,7 +45,6 @@ RESOURCE_KEY_MAPPINGS = { } RESOURCE_PARSERS = { - 'inventory' : parse_inventory, 'component' : parse_endpoints, 'interface' : parse_interfaces, 'network_instance': parse_network_instances, diff --git a/src/pcep/Dockerfile b/src/pcep/Dockerfile index 0229d098d409eb89c27c7cc6efb89e6bf4a3238a..615bc058a2ca7f1086302d10f6bc2654a6e0e42b 100644 --- a/src/pcep/Dockerfile +++ b/src/pcep/Dockerfile @@ -27,6 +27,10 @@ RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ chmod +x /bin/grpc_health_probe +#Ping +RUN apt-get update && apt-get install -y iputils-ping g++ && \ + rm -rf /var/lib/apt/lists/* + # Get generic Python packages RUN python3 -m pip install --upgrade pip RUN python3 -m pip install --upgrade setuptools wheel diff --git a/src/pcep/service/PcepServiceServicerImpl.py b/src/pcep/service/PcepServiceServicerImpl.py index c70a6043f7a675836c5812b8ff00636e82ac4ef6..e83895ea7771c0da8368065cfc0bc7dad77c9610 100644 --- a/src/pcep/service/PcepServiceServicerImpl.py +++ b/src/pcep/service/PcepServiceServicerImpl.py @@ -12,26 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import grpc, json, logging -from typing import Optional +import grpc, logging from pcep.service.tools.GrpcServer import GrpcServer from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method -from common.method_wrappers.ServiceExceptions import AlreadyExistsException, InvalidArgumentException -from common.proto.context_pb2 import (DeviceId, Empty, EndPointId, Link, Service, ServiceId, ServiceStatusEnum, ServiceTypeEnum, TopologyId,ContextId,Topology - ,Device,DeviceDriverEnum, Uuid) -from common.proto.pathcomp_pb2 import PathCompRequest -from common.proto.service_pb2_grpc import ServiceServiceServicer - -from common.tools.grpc.Tools import grpc_message_to_json, grpc_message_to_json_string -from context.client.ContextClient import ContextClient -from pathcomp.frontend.client.PathCompClient import PathCompClient - from common.proto.pcep_pb2 import (RequestRq, RequestRp, PceIpRq, PceIpRp) from common.proto.pcep_pb2_grpc import PcepServiceServicer -# from .task_scheduler.TaskScheduler import TasksScheduler -# from .tools.ContextGetters import get_service - LOGGER = logging.getLogger(__name__) METRICS_POOL = MetricsPool('Service', 'RPC') @@ -47,11 +33,13 @@ class PcepServiceServicerImpl(PcepServiceServicer): LOGGER.debug("(ConfiguratePCE) Create pce instance %s",request) - configurateIP=self.pcepServer.connectToJavaPcep(request.address) - return PceIpRp(addressRp=configurateIP) + # configurateIP=self.pcepServer.connectToJavaPcep(request.address) + #return PceIpRp(addressRp=configurateIP) + return PceIpRp(addressRp="127.0.0.1") @safe_and_metered_rpc_method(METRICS_POOL, LOGGER) def sendRequest(self, request : RequestRq, context : grpc.ServicerContext) -> RequestRp: + LOGGER.debug("(Send Request) Send: %s",request.command) message=self.pcepServer.requestToJavaPcep(request.command) return RequestRp(commandRp=message) diff --git a/src/pcep/service/__main__.py b/src/pcep/service/__main__.py index e084fd0a78546c7b4e7602dd3fb5b1f15a5b44e6..9716b1e411dcaaac22d72e40809ae47d6418d682 100644 --- a/src/pcep/service/__main__.py +++ b/src/pcep/service/__main__.py @@ -12,15 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging, signal, sys, threading, time +import logging, signal, sys, threading from prometheus_client import start_http_server -from common.Constants import ServiceNameEnum -from common.Settings import ( - ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name, get_log_level, get_metrics_port, - wait_for_environment_variables) from .PcepService import PcepService -from .tools.JavaRunner import JavaRunner from .tools.GrpcServer import GrpcServer +import socket terminate = threading.Event() LOGGER : logging.Logger = None @@ -59,21 +55,19 @@ def main(): ###service_handler_factory = ServiceHandlerFactory(SERVICE_HANDLERS) #DB=DiscoveredDBManager() - pcep_server = GrpcServer() - #pcep_server.Connect() - - pcep_server.connectToJavaPcep("10.95.41.240") - time.sleep(30) - n = "initiate lsp directo 10.95.86.214 1.1.1.1 1.1.1.3 m1228800 na192.168.3.11-192.168.3.13" - pcep_server.requestToJavaPcep(n) - + pcep_server.Connect() + ip_address = socket.gethostbyname(socket.gethostname()) + #pcep_server.connectToJavaPcep("10.95.86.69") + #pcep_server.connectToJavaPcep(ip_address) + #time.sleep(30) + #n = "initiate lsp directo 10.95.86.214 1.1.1.1 1.1.1.3 m1228800 na192.168.3.11-192.168.3.13" + #pcep_server.requestToJavaPcep(n) + #pcep_server.update(n) # Starting pcep service pcep_service = PcepService(pcep_server) pcep_service.start() - - # Wait for Ctrl+C or termination signal while not terminate.wait(timeout=0.1): pass LOGGER.info('Terminating...') diff --git a/src/pcep/service/tools/GrpcServer.py b/src/pcep/service/tools/GrpcServer.py index 3e3353cb1930ea92be3b2e0650b60aa3c50e6947..fa1c2b5c8825c7ad2faeafb876b3e4c17f678ea8 100644 --- a/src/pcep/service/tools/GrpcServer.py +++ b/src/pcep/service/tools/GrpcServer.py @@ -12,28 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json, logging,threading, queue,time,signal -from datetime import datetime, timedelta -from typing import Any, Iterator, List, Optional, Tuple, Union -# from apscheduler.executors.pool import ThreadPoolExecutor -# from apscheduler.job import Job -# from apscheduler.jobstores.memory import MemoryJobStore -# from apscheduler.schedulers.background import BackgroundScheduler -# from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, metered_subclass_method, INF -# from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk_type - - +import logging,threading, queue,time import logging,threading import grpc - -from .protos import grpcService_pb2_grpc -from .protos import grpcService_pb2 - +from .protos import grpcService_pb2_grpc, grpcService_pb2 from concurrent import futures -import os -import subprocess -from multiprocessing import Pool import logging +import time from .JavaRunner import JavaRunner @@ -50,29 +35,16 @@ class GrpcServer(): self.__terminate = threading.Event() self.__out_samples = queue.Queue() self.__server=grpc.aio.server() - # self.__address="10.95.86.214" - # self.__port=179 - # self.__asNumber=65006 - # self.__configFile="TMConfiguration_guillermo.xml" - # self.__process=0 - # self.__javaLocalPort=0 # --> BGP4Port in XML file - self.__mngPort=0 # Port used in XML config file for management (NOT used in TFS) self.__runnerList=[] - # Data base for saving all new devices discovered - #self.__discoveredDB=DiscoveredDB - # self.__comms=grpcComms - # Este tendrÃa que tener la info del runner al que se connecta¿ def ConnectThread(self) -> bool: # TODO: Metodos necesarios para conectarte al speaker # If started, assume it is already connected if self.__started.is_set(): return True - self.__started.set() #notifyAll -->event.is_set() - # 10 workers ? + self.__started.set() self.__server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) grpcService_pb2_grpc.add_pceServiceServicer_to_server(self, self.__server) self.__server.add_insecure_port(SERVER_ADDRESS) - # server.add_secure_port(SERVER_ADDRESS) LOGGER.info("Starting server on %s", SERVER_ADDRESS) self.__server.start() try: @@ -99,61 +71,43 @@ class GrpcServer(): # exit(0) return True - - def update(self,request, context) -> bool: - """ - Processes the messages recived by de grpc server - """ - with self.__lock: - #TODO: Get update - LOGGER.info("(server) Update message from pcep: \n %s" % (request)) - response = grpcService_pb2.commandResponse(commandResp="OK") - LOGGER.debug("Update class string %s",response.commandResp) - return response - - - - #def connectToJavaPcep(self, address : str = "10.95.86.214", port : str = "11179", asNumber : str = "1"): def connectToJavaPcep(self, address): # Get unused* port - #self.setLocalPort() - #runner = JavaRunner(self.__javaLocalPort,address,self.__mngPort) - LOGGER.debug("Ejecutando el servidor java") runner = JavaRunner(address) # Sets port in XML config file for java program - #runner.setAsNumber(asNumber) - #runner.setPort(port) - runner.setPeer() - process=runner.execPcep() + #runner.setPeer() + #process=runner.execPcep() + process_thread = threading.Thread(target=runner.execPcep) + process_thread.start() self.__runnerList.append(runner) - return process.pid + return process_thread + + def update(): + with grpc.insecure_channel('localhost:10060') as channel: + #n = "initiate lsp directo 10.95.86.214 1.1.1.1 1.1.1.3 m1228800 na192.168.3.11-192.168.3.13" + n = "terminate lsp 10.95.86.214 0 nombre" + #n="create candidatepath 10.95.86.214 1.1.1.1 4 97 m69644288 nn1.1.1.3 m69640192 nn1.1.1.2" + stub = grpcService_pb2_grpc.pceServiceStub(channel) + request = grpcService_pb2.commandRequest(command=n) + print("updateService req: " ,request) + response = stub.update(request) + print("updateService client received: " ,response.commandResp) + def requestToJavaPcep(self,message): - """ - If java already running add 1 to current used port, - else initialize port . - initPort --> BGP4Port, usually 179 corresponding to BGP - """ - with grpc.insecure_channel('localhost:10050') as channel: + with grpc.insecure_channel('localhost:10060') as channel: #n = "initiate lsp largo2 10.95.86.214 1.1.1.1 1.1.1.2 m69644288 nn1.1.1.3 m69640192 nn1.1.1.2" #n = "initiate lsp directo 10.95.86.214 1.1.1.1 1.1.1.3 m1228800 na192.168.3.11-192.168.3.13" - #n="initiate lsp largo 10.95.86.214 1.1.1.1 1.1.1.3 m61849600 na192.168.1.11-192.168.1.12 m62259200 na192.168.2.12-192.168.2.13" - #n = "terminate lsp 10.95.86.214 0 nombre" - #n="create candidatepath 10.95.86.214 1.1.1.1 4 97 m69644288 nn1.1.1.3 m69640192 nn1.1.1.2" - #n="fallo" - #n="quit"; LOGGER.debug("LLego al request") stub = grpcService_pb2_grpc.pceServiceStub(channel) - LOGGER.debug("LLego al request 2") + LOGGER.debug("updateService req 2: %s" ,message) request = grpcService_pb2.commandRequest(command=message) - print("updateService req: %s" ,request) + LOGGER.debug("updateService req 2: %s" ,request) response = stub.update(request) - #response=stub.GetCommand(grpcService_pb2.commandRequest(command=n)) - #response_observer = ResponseObserver() - #stub.update(response, response_observer) - print("updateServide client received: %s" ,response.commandResp) - return response.commandResp + LOGGER.debug("updateServide client received: %s" ,response.commandResp) + LOGGER.debug("updateServide client received IP: %s" ,response.ipAddress) + return response.ipAddress def terminateRunners(self): for runner in self.__runnerList: @@ -178,23 +132,4 @@ class GrpcServer(): self.__runnerList.remove(runner) return True - - def setLocalPort(self,initPort=22179): - """ - If java already running add 1 to current used port, - else initialize port . - initPort --> BGP4Port, usually 179 corresponding to BGP - """ - with self.__lock: - if(self.__runnerList): - LOGGER.debug("Port exists %s",self.__javaLocalPort) - lastRunner=self.__runnerList[-1] - self.__javaLocalPort=lastRunner.getCurrentLocalPort()+1 - self.__mngPort=lastRunner.getCurrentMngPort()+1 - else: - LOGGER.debug("Port DONT exists %s",self.__javaLocalPort) - self.__javaLocalPort=initPort - self.__mngPort=1112 # default management port - return self.__javaLocalPort - - \ No newline at end of file + \ No newline at end of file diff --git a/src/pcep/service/tools/JavaRunner.py b/src/pcep/service/tools/JavaRunner.py index 1e1cd0314d80d71352253cc6245277b1cadd25bc..eb67ddbb8f2f8bc47cd446f82d9d9484fb3adc2e 100644 --- a/src/pcep/service/tools/JavaRunner.py +++ b/src/pcep/service/tools/JavaRunner.py @@ -12,45 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json, logging,threading, queue,time,signal -from datetime import datetime, timedelta -from typing import Any, Iterator, List, Optional, Tuple, Union +import logging,threading, time import logging -import grpc - -from concurrent import futures from lxml import etree import os import subprocess -from multiprocessing import Pool - SERVER_ADDRESS = 'localhost:2021' SERVER_ID = 1 -_ONE_DAY_IN_SECONDS = 60 * 60 * 24 -#XML_FILE="/var/teraflow/bgpls_speaker/service/resources/BGP4Parameters_2.xml" XML_CONFIG_FILE="/var/teraflow/pcep/resources/PCEServerConfiguration.xml" LOGGER = logging.getLogger(__name__) - class JavaRunner: - #def __init__(self,localPort : int, address : str ="10.95.86.214", mngPort : int = 1112): def __init__(self,address): - #self.__peerPort=11179 - #self.__localPort=localPort - #self.__managementPort=mngPort - # To support multiple speakers at same time - # Add 1 to port and then pass port to subproccess call - #self.__configFile=XML_CONFIG_FILE - #self.__process=0 + self.__process=None self.__lock = threading.Lock() self.__address = address - #self.__portConf=6666 - #self.__pceAddress="10.95.43.16" - #self.__asNumber=1 def getCurrentLocalPort(self): with self.__lock: @@ -69,7 +49,7 @@ class JavaRunner: cwd = os.getcwd() LOGGER.info("Current working directory: %s", cwd) # Security shell=False - self.__process=subprocess.Popen(['java -jar Ejecutable.jar '+ XML_CONFIG_FILE], + self.__process=subprocess.Popen(['java -jar Ejecutable.jar '],#+ XML_CONFIG_FILE shell=False,start_new_session=True,stdout=subprocess.PIPE) LOGGER.debug("Time to sleep") java_pid = self.__process.pid @@ -77,19 +57,41 @@ class JavaRunner: time.sleep(15) self.__process.terminate() - def execPcep(self) -> bool: """ Executes java pcep in non-blocking process """ - # CHECKEAR muchas cosas LOGGER.debug("Before exec") os.chdir("/var/teraflow/pcep/service/resources/") - # Security reasons shell=False - self.__process=subprocess.Popen(['java' , '-jar' , 'Ejecutable.jar' , XML_CONFIG_FILE], - shell=False,start_new_session=True) + try: + self.__process = subprocess.Popen(['java', '-jar', 'Ejecutable.jar'], + shell=False, start_new_session=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + stdout_thread = threading.Thread(target=self.read_stdout) + stderr_thread = threading.Thread(target=self.read_stderr) + + stdout_thread.start() + stderr_thread.start() + + self.__process.wait() + + stdout_thread.join() + stderr_thread.join() + + except subprocess.CalledProcessError as err: + LOGGER.debug('ERROR: %s', err) + return self.__process + def read_stdout(self): + for line in self.__process.stdout: + print(line.decode(), end='') + + def read_stderr(self): + for line in self.__process.stderr: + print(line.decode(), end='') + def setPort(self,port): self.__peerPort=port return True @@ -102,26 +104,9 @@ class JavaRunner: Sets XML existing config file with peer address and port. TODO: as_number """ - #XMLParser = etree.XMLParser(remove_blank_text=False) - #tree = etree.parse(XML_FILE, parser=XMLParser) - #root = tree.getroot() - ##peerAddress = root.find(".//peer") - ##peerAddress.text=self.__address - #peerPort = root.find(".//peerPort") - #peerPort.text=str(self.__peerPort) - #localPort = root.find(".//BGP4Port") - #localPort.text=str(self.__localPort) - #myAutonomousSystem = root.find(".//myAutonomousSystem") - #myAutonomousSystem.text=str(self.__asNumber) - #managePort = root.find(".//BGP4ManagementPort") - #managePort.text=str(self.__managementPort) - #tree.write(XML_FILE) #with ... as .. - XMLParser = etree.XMLParser(remove_blank_text=False) tree = etree.parse(XML_CONFIG_FILE, parser=XMLParser) root = tree.getroot() - #portConf = root.find(".//PCEManagementPort") - #portConf.text=str(self.__portConf) pceAddress = root.find(".//LocalPCEAddress") LOGGER.debug("Valor anterior de LocalPCEAddress: %s", pceAddress.text) @@ -135,13 +120,10 @@ class JavaRunner: Kills java program connected to BGPLS Speaker with SIGKILL signal """ LOGGER.debug("sending kill signal to process %s",self.__process.pid) - # time.sleep(15) LOGGER.debug("PID: %d",self.__process.pid) - # LOGGER.debug("Group PID: %d",os.getpgid(self.__process.pid)) - # os.killpg(os.getpgid(self.__process.pid), signal.SIGKILL) self.__process.kill() - # .terminate() for SIGTERM return True def getRunnerInfo(self): - return self.__address,self.__asNumber,self.__peerPort \ No newline at end of file + return self.__address,self.__asNumber,self.__peerPort + \ No newline at end of file diff --git a/src/webui/Dockerfile b/src/webui/Dockerfile index 2a1510954dbd2a9b0817f94145baaa22ac9d3a3f..29f1b95bcf87ed86296f1f3bb3087c875b5bdce6 100644 --- a/src/webui/Dockerfile +++ b/src/webui/Dockerfile @@ -85,6 +85,8 @@ COPY --chown=webui:webui src/service/client/. service/client/ COPY --chown=webui:webui src/slice/__init__.py slice/__init__.py COPY --chown=webui:webui src/slice/client/. slice/client/ COPY --chown=webui:webui src/webui/. webui/ +COPY --chown=webui:webui src/pcep/__init__.py pcep/__init__.py +COPY --chown=webui:webui src/pcep/client/. pcep/client/ # Start the service ENTRYPOINT ["python", "-m", "webui.service"] diff --git a/src/webui/service/__init__.py b/src/webui/service/__init__.py index 3c64f45c90457e1b6a9553e60634879a28910a31..313efa91ec64bb7671549d2018e204f676480ffb 100644 --- a/src/webui/service/__init__.py +++ b/src/webui/service/__init__.py @@ -98,6 +98,9 @@ def create_app(use_config=None, web_app_root=None): from webui.service.policy_rule.routes import policy_rule # pylint: disable=import-outside-toplevel app.register_blueprint(policy_rule) + from webui.service.pcep.routes import pcep # pylint: disable=import-outside-toplevel + app.register_blueprint(pcep) + app.jinja_env.globals.update({ # pylint: disable=no-member 'enumerate' : enumerate, 'json_to_list' : json_to_list, diff --git a/src/webui/service/pcep/__init__.py b/src/webui/service/pcep/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612 --- /dev/null +++ b/src/webui/service/pcep/__init__.py @@ -0,0 +1,14 @@ +# 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. + diff --git a/src/webui/service/pcep/forms.py b/src/webui/service/pcep/forms.py new file mode 100644 index 0000000000000000000000000000000000000000..d034e0f7f8fb07060ee59f7a353592f0cdd55b50 --- /dev/null +++ b/src/webui/service/pcep/forms.py @@ -0,0 +1,70 @@ +# 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. + +# external imports +#TIPOS DE FORMULARIO + +from flask_wtf import FlaskForm +from wtforms import SelectField, SubmitField +from wtforms import StringField, SelectField, TextAreaField, SubmitField, BooleanField +from wtforms.validators import DataRequired, Length, NumberRange, ValidationError +from common.proto.context_pb2 import DeviceOperationalStatusEnum + +class AddDeviceForm(FlaskForm): + device_id = StringField('ID', + validators=[DataRequired(), Length(min=5)]) + device_type = SelectField('Type', choices = []) + operational_status = SelectField('Operational Status', + # choices=[(-1, 'Select...'), (0, 'Undefined'), (1, 'Disabled'), (2, 'Enabled')], + coerce=int, + validators=[NumberRange(min=0)]) + device_drivers_undefined = BooleanField('UNDEFINED / EMULATED') + device_drivers_openconfig = BooleanField('OPENCONFIG') + device_drivers_transport_api = BooleanField('TRANSPORT_API') + device_drivers_p4 = BooleanField('P4') + device_drivers_ietf_network_topology = BooleanField('IETF_NETWORK_TOPOLOGY') + device_drivers_onf_tr_352 = BooleanField('ONF_TR_352') + device_drivers_xr = BooleanField('XR') + device_config_address = StringField('connect/address',default='127.0.0.1',validators=[DataRequired(), Length(min=5)]) + device_config_port = StringField('connect/port',default='0',validators=[DataRequired(), Length(min=1)]) + device_config_settings = TextAreaField('connect/settings',default='{}',validators=[DataRequired(), Length(min=2)]) + submit = SubmitField('Add') + + def validate_operational_status(form, field): + if field.data not in DeviceOperationalStatusEnum.DESCRIPTOR.values_by_number: + raise ValidationError('The operational status value selected is incorrect!') + +class ConfigForm(FlaskForm): + device_key_config = StringField('Key configuration') + device_value_config = StringField('Value configuration') + submit = SubmitField('Add') + + +class UpdateDeviceForm(FlaskForm): + update_operational_status = SelectField('Operational Status', + choices=[(-1, 'Select...'), (0, 'Undefined'), (1, 'Disabled'), (2, 'Enabled')], + coerce=int, + validators=[NumberRange(min=0)]) + + submit = SubmitField('Update') + +class ConfigIpPCEForm(FlaskForm): + + pce_address = StringField('ip',default='127.0.0.1',validators=[DataRequired(), Length(min=5)]) + submit = SubmitField('Submit') + +class SendPathForm(FlaskForm): + + command = StringField('command',default='terminate lsp 10.95.86.214 0 nombre',validators=[DataRequired(), Length(min=5)]) + submit = SubmitField('Submit') diff --git a/src/webui/service/pcep/routes.py b/src/webui/service/pcep/routes.py new file mode 100644 index 0000000000000000000000000000000000000000..590bbb5d0a81a69e537c93b8d1cd054e019aaf33 --- /dev/null +++ b/src/webui/service/pcep/routes.py @@ -0,0 +1,225 @@ +# 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 json,logging +from flask import render_template, Blueprint, flash, session, redirect, url_for, request +from common.proto.context_pb2 import ( + ConfigActionEnum, Device, DeviceDriverEnum, DeviceId, DeviceList, DeviceOperationalStatusEnum, + Empty, TopologyId) +from common.tools.object_factory.Context import json_context_id +from common.tools.object_factory.Topology import json_topology_id +from context.client.ContextClient import ContextClient +from device.client.DeviceClient import DeviceClient +from webui.service.device.forms import AddDeviceForm +from common.DeviceTypes import DeviceTypeEnum +from webui.service.pcep.forms import ConfigIpPCEForm, SendPathForm + +from pcep.client.PcepClient import PcepClient +from common.proto.pcep_pb2 import (PceIpRq, RequestRq) + +pcep = Blueprint('pcep', __name__, url_prefix='/pcep') +context_client = ContextClient() +device_client = DeviceClient() +pcep_client = PcepClient() +logger = logging.getLogger(__name__) + +@pcep.get('/') +def home(): + if 'context_uuid' not in session or 'topology_uuid' not in session: + flash("Please select a context!", "warning") + return redirect(url_for("main.home")) + + context_uuid = session['context_uuid'] + topology_uuid = session['topology_uuid'] + + context_client.connect() + json_topo_id = json_topology_id(topology_uuid, context_id=json_context_id(context_uuid)) + grpc_topology = context_client.GetTopology(TopologyId(**json_topo_id)) + topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids} + + if grpc_topology is None: + flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') + devices = [] + else: + topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids} + grpc_devices: DeviceList = context_client.ListDevices(Empty()) + devices = [ + device for device in grpc_devices.devices + if device.device_id.device_uuid.uuid in topo_device_uuids + ] + + # ListNewDevices discovered from bgpls + logger.info('pcep/home') + pcep_client.connect() + logger.info('pcep_client.connect %s',pcep_client) + + context_client.close() + pcep_client.close() + + return render_template( + 'pcep/home.html', devices=devices, dde=DeviceDriverEnum, + dose=DeviceOperationalStatusEnum) + +@pcep.route('add/<path:device_name>', methods=['GET', 'POST']) +def add(device_name): + """" + Add a discovered device from bgpls protocol. Populate form from + existent info in bgpls. + """ + # TODO: Conect to device and get necessary info + form = AddDeviceForm() + + logger.info('pcep/add') + + # listing enum values + form.operational_status.choices = [] + for key, _ in DeviceOperationalStatusEnum.DESCRIPTOR.values_by_name.items(): + form.operational_status.choices.append( + (DeviceOperationalStatusEnum.Value(key), key.replace('DEVICEOPERATIONALSTATUS_', ''))) + + form.device_type.choices = [] + # items for Device Type field + for device_type in DeviceTypeEnum: + form.device_type.choices.append((device_type.value,device_type.value)) + + if form.validate_on_submit(): + device_obj = Device() + # Device UUID: + device_obj.device_id.device_uuid.uuid = form.device_id.data # pylint: disable=no-member + + # Device type: + device_obj.device_type = str(form.device_type.data) + + # Device configurations: + config_rule = device_obj.device_config.config_rules.add() # pylint: disable=no-member + config_rule.action = ConfigActionEnum.CONFIGACTION_SET + config_rule.custom.resource_key = '_connect/address' + config_rule.custom.resource_value = form.device_config_address.data + + config_rule = device_obj.device_config.config_rules.add() # pylint: disable=no-member + config_rule.action = ConfigActionEnum.CONFIGACTION_SET + config_rule.custom.resource_key = '_connect/port' + config_rule.custom.resource_value = form.device_config_port.data + + config_rule = device_obj.device_config.config_rules.add() # pylint: disable=no-member + config_rule.action = ConfigActionEnum.CONFIGACTION_SET + config_rule.custom.resource_key = '_connect/settings' + + try: + device_config_settings = json.loads(form.device_config_settings.data) + except: # pylint: disable=bare-except + device_config_settings = form.device_config_settings.data + + if isinstance(device_config_settings, dict): + config_rule.custom.resource_value = json.dumps(device_config_settings) + else: + config_rule.custom.resource_value = str(device_config_settings) + + # Device status: + device_obj.device_operational_status = form.operational_status.data + + # Device drivers: + if form.device_drivers_undefined.data: + device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_UNDEFINED) + if form.device_drivers_openconfig.data: + device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG) + if form.device_drivers_transport_api.data: + device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API) + if form.device_drivers_p4.data: + device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_P4) + if form.device_drivers_ietf_network_topology.data: + device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY) + if form.device_drivers_onf_tr_352.data: + device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352) + if form.device_drivers_xr.data: + device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_XR) + + try: + device_client.connect() + logger.info('add device from pcep:%s',device_obj) + response: DeviceId = device_client.AddDevice(device_obj) + device_client.close() + flash(f'New device was created with ID "{response.device_uuid.uuid}".', 'success') + #pcep_client.connect() + #pcep_client.configuratePCE(PceIpRq(address=device_obj.device_id.device_uuid.uuid)) + #pcep_client.close() + return redirect(url_for('device.home')) + except Exception as e: + flash(f'Problem adding the device. {e.details()}', 'danger') + + # Prefill data with discovered info from speaker + # Device Name from bgpls + form.device_name=device_name + device=device_name + form.device_id.data=device_name + # Default values (TODO: NOT WORKING) + form.device_type.data=DeviceTypeEnum.EMULATED_PACKET_ROUTER + form.device_config_settings.data=str('{"username": "admin", "password": "admin"}') + + return render_template('pcep/add.html', form=form, device=device, + submit_text='Add New Device') + +@pcep.route('detail/<path:device_uuid>', methods=['GET', 'POST']) +def detail(device_uuid: str): + request = DeviceId() + request.device_uuid.uuid = device_uuid + context_client.connect() + response = context_client.GetDevice(request) + context_client.close() + return render_template('pcep/detail.html', device=response, + dde=DeviceDriverEnum, + dose=DeviceOperationalStatusEnum) + +@pcep.route('addPcep', methods=['GET', 'POST']) +def addPcep(): + + pcep_client.connect() + form = ConfigIpPCEForm() + if form.validate_on_submit(): + logger.info('addPcep ip:%s',form.pce_address.data) + pcep_client.configuratePCE(PceIpRq(address=form.pce_address.data)) + logger.info('Prueba 1') + flash(f'Pcep "{form.pce_address.data}" added successfully!', 'success') + logger.info('Prueba 2') + pcep_client.close() + logger.info('Prueba 3') + return render_template('pcep/addPcep.html',form=form) + + +@pcep.route('sendPath', methods=['GET', 'POST']) +def sendPath(): + + pcep_client.connect() + form = SendPathForm() + if form.validate_on_submit(): + logger.info('Send Path ip:%s',form.command.data) + pcep_client.sendRequest(RequestRq(command=form.command.data)) + logger.info('Prueba 1') + flash(f'Command "{form.command.data}" added successfully!', 'success') + logger.info('Prueba 2') + pcep_client.close() + logger.info('Prueba 3') + return render_template('pcep/sendPath.html',form=form) + +@pcep.route('formPcep', methods=['GET','POST']) +def formPcep(): + #conectar con pcep? + form = ConfigIpPCEForm() + if request.method=="POST": + address = form.pce_address.data + logger.info("FORM formPcep: %s ", address) + + flash(f'Pcep "{address}" added successfully!', 'success') + + return redirect(url_for('pcep.home'))