From b1afc14b5a6fddb8207eeb85b5fdb722753a871c Mon Sep 17 00:00:00 2001 From: armingol Date: Fri, 7 Jul 2023 17:41:16 +0200 Subject: [PATCH 1/4] webui componet initial commit --- deploy/webui.sh | 181 +++++++ src/webui/requirements.in | 1 + src/webui/service/__init__.py | 2 + src/webui/service/service/forms.py | 295 ++++++++++ src/webui/service/service/routes.py | 422 ++++++++++++++- src/webui/service/templates/service/add.html | 53 ++ .../templates/service/configure_ACL_IPV4.html | 433 +++++++++++++++ .../templates/service/configure_ACL_IPV6.html | 388 +++++++++++++ .../templates/service/configure_ACL_L2.html | 343 ++++++++++++ .../templates/service/configure_L2VPN.html | 434 +++++++++++++++ .../templates/service/configure_L3VPN.html | 510 ++++++++++++++++++ .../service/templates/service/detail.html | 63 +++ src/webui/service/templates/service/home.html | 11 +- 13 files changed, 3113 insertions(+), 23 deletions(-) create mode 100755 deploy/webui.sh create mode 100644 src/webui/service/service/forms.py create mode 100644 src/webui/service/templates/service/add.html create mode 100644 src/webui/service/templates/service/configure_ACL_IPV4.html create mode 100644 src/webui/service/templates/service/configure_ACL_IPV6.html create mode 100644 src/webui/service/templates/service/configure_ACL_L2.html create mode 100644 src/webui/service/templates/service/configure_L2VPN.html create mode 100644 src/webui/service/templates/service/configure_L3VPN.html diff --git a/deploy/webui.sh b/deploy/webui.sh new file mode 100755 index 000000000..94cc12122 --- /dev/null +++ b/deploy/webui.sh @@ -0,0 +1,181 @@ +#!/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. + + +######################################################################################################################## +# Read deployment settings +######################################################################################################################## + + +# ----- TeraFlowSDN ------------------------------------------------------------ + +# If not already set, set the URL of the Docker registry where the images will be uploaded to. +# By default, assume internal MicroK8s registry is used. +export TFS_REGISTRY_IMAGES=${TFS_REGISTRY_IMAGES:-"http://localhost:32000/tfs/"} + +# If not already set, set the list of components, separated by spaces, you want to build images for, and deploy. +# By default, only basic components are deployed +export TFS_COMPONENTS=${TFS_COMPONENTS:-"context device service compute webui"} + +# If not already set, set the tag you want to use for your images. +export TFS_IMAGE_TAG=${TFS_IMAGE_TAG:-"dev"} + +# If not already set, set the name of the Kubernetes namespace to deploy TFS to. +export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"} + +# If not already set, set additional manifest files to be applied after the deployment +export TFS_EXTRA_MANIFESTS=${TFS_EXTRA_MANIFESTS:-""} + +# If not already set, set the new Grafana admin password +export TFS_GRAFANA_PASSWORD=${TFS_GRAFANA_PASSWORD:-"admin123+"} + +# If not already set, disable skip-build flag to rebuild the Docker images. +# If TFS_SKIP_BUILD is "YES", the containers are not rebuilt-retagged-repushed and existing ones are used. +export TFS_SKIP_BUILD=${TFS_SKIP_BUILD:-""} + + +# ----- CockroachDB ------------------------------------------------------------ + +# If not already set, set the namespace where CockroackDB will be deployed. +export CRDB_NAMESPACE=${CRDB_NAMESPACE:-"crdb"} + +# If not already set, set the external port CockroackDB Postgre SQL interface will be exposed to. +export CRDB_EXT_PORT_SQL=${CRDB_EXT_PORT_SQL:-"26257"} + +# If not already set, set the external port CockroackDB HTTP Mgmt GUI interface will be exposed to. +export CRDB_EXT_PORT_HTTP=${CRDB_EXT_PORT_HTTP:-"8081"} + +# If not already set, set the database username to be used by Context. +export CRDB_USERNAME=${CRDB_USERNAME:-"tfs"} + +# If not already set, set the database user's password to be used by Context. +export CRDB_PASSWORD=${CRDB_PASSWORD:-"tfs123"} + +# If not already set, set the database name to be used by Context. +export CRDB_DATABASE=${CRDB_DATABASE:-"tfs"} + +# If not already set, set CockroachDB installation mode. Accepted values are: 'single' and 'cluster'. +# "YES", the database pointed by variable CRDB_NAMESPACE will be dropped while +# checking/deploying CockroachDB. +# - If CRDB_DEPLOY_MODE is "single", CockroachDB is deployed in single node mode. It is convenient for +# development and testing purposes and should fit in a VM. IT SHOULD NOT BE USED IN PRODUCTION ENVIRONMENTS. +# - If CRDB_DEPLOY_MODE is "cluster", CockroachDB is deployed in cluster mode, and an entire CockroachDB cluster +# with 3 replicas and version v22.2 (set by default) will be deployed. It is convenient for production and +# provides scalability features. If you are deploying for production, also read the following link providing +# details on deploying CockroachDB for production environments: +# Ref: https://www.cockroachlabs.com/docs/stable/recommended-production-settings.html +export CRDB_DEPLOY_MODE=${CRDB_DEPLOY_MODE:-"single"} + +# If not already set, disable flag for dropping database, if it exists. +# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE DATABASE INFORMATION! +# If CRDB_DROP_DATABASE_IF_EXISTS is "YES", the database pointed by variable CRDB_NAMESPACE will be dropped while +# checking/deploying CockroachDB. +export CRDB_DROP_DATABASE_IF_EXISTS=${CRDB_DROP_DATABASE_IF_EXISTS:-""} + +# If not already set, disable flag for re-deploying CockroachDB from scratch. +# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE DATABASE INFORMATION! +# WARNING: THE REDEPLOY MIGHT TAKE FEW MINUTES TO COMPLETE GRACEFULLY IN CLUSTER MODE +# If CRDB_REDEPLOY is "YES", the database will be dropped while checking/deploying CockroachDB. +export CRDB_REDEPLOY=${CRDB_REDEPLOY:-""} + + +# ----- NATS ------------------------------------------------------------------- + +# If not already set, set the namespace where NATS will be deployed. +export NATS_NAMESPACE=${NATS_NAMESPACE:-"nats"} + +# If not already set, set the external port NATS Client interface will be exposed to. +export NATS_EXT_PORT_CLIENT=${NATS_EXT_PORT_CLIENT:-"4222"} + +# If not already set, set the external port NATS HTTP Mgmt GUI interface will be exposed to. +export NATS_EXT_PORT_HTTP=${NATS_EXT_PORT_HTTP:-"8222"} + +# If not already set, disable flag for re-deploying NATS from scratch. +# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE MESSAGE BROKER INFORMATION! +# If NATS_REDEPLOY is "YES", the message broker will be dropped while checking/deploying NATS. +export NATS_REDEPLOY=${NATS_REDEPLOY:-""} + + +# ----- QuestDB ---------------------------------------------------------------- + +# If not already set, set the namespace where QuestDB will be deployed. +export QDB_NAMESPACE=${QDB_NAMESPACE:-"qdb"} + +# If not already set, set the external port QuestDB Postgre SQL interface will be exposed to. +export QDB_EXT_PORT_SQL=${QDB_EXT_PORT_SQL:-"8812"} + +# If not already set, set the external port QuestDB Influx Line Protocol interface will be exposed to. +export QDB_EXT_PORT_ILP=${QDB_EXT_PORT_ILP:-"9009"} + +# If not already set, set the external port QuestDB HTTP Mgmt GUI interface will be exposed to. +export QDB_EXT_PORT_HTTP=${QDB_EXT_PORT_HTTP:-"9000"} + +# If not already set, set the database username to be used for QuestDB. +export QDB_USERNAME=${QDB_USERNAME:-"admin"} + +# If not already set, set the database user's password to be used for QuestDB. +export QDB_PASSWORD=${QDB_PASSWORD:-"quest"} + +# If not already set, set the table name to be used by Monitoring for KPIs. +export QDB_TABLE_MONITORING_KPIS=${QDB_TABLE_MONITORING_KPIS:-"tfs_monitoring_kpis"} + +# If not already set, set the table name to be used by Slice for plotting groups. +export QDB_TABLE_SLICE_GROUPS=${QDB_TABLE_SLICE_GROUPS:-"tfs_slice_groups"} + +# If not already set, disable flag for dropping tables if they exist. +# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE TABLE INFORMATION! +# If QDB_DROP_TABLES_IF_EXIST is "YES", the tables pointed by variables +# QDB_TABLE_MONITORING_KPIS and QDB_TABLE_SLICE_GROUPS will be dropped while +# checking/deploying QuestDB. +export QDB_DROP_TABLES_IF_EXIST=${QDB_DROP_TABLES_IF_EXIST:-""} + +# If not already set, disable flag for re-deploying QuestDB from scratch. +# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE DATABASE INFORMATION! +# If QDB_REDEPLOY is "YES", the database will be dropped while checking/deploying QuestDB. +export QDB_REDEPLOY=${QDB_REDEPLOY:-""} + + +# ----- K8s Observability ------------------------------------------------------ + +# If not already set, set the external port Prometheus Mgmt HTTP GUI interface will be exposed to. +export PROM_EXT_PORT_HTTP=${PROM_EXT_PORT_HTTP:-"9090"} + +# If not already set, set the external port Grafana HTTP Dashboards will be exposed to. +export GRAF_EXT_PORT_HTTP=${GRAF_EXT_PORT_HTTP:-"3000"} + + +######################################################################################################################## +# Automated steps start here +######################################################################################################################## + +# Deploy CockroachDB +./deploy/crdb.sh + +# Deploy NATS +./deploy/nats.sh + +# Deploy QuestDB +./deploy/qdb.sh + +# Expose Dashboard +./deploy/expose_dashboard.sh + +# Deploy TeraFlowSDN +./deploy/tfs.sh + +# Show deploy summary +./deploy/show.sh + +echo "Done!" diff --git a/src/webui/requirements.in b/src/webui/requirements.in index b4a158d39..d9de647f1 100644 --- a/src/webui/requirements.in +++ b/src/webui/requirements.in @@ -17,3 +17,4 @@ Flask-WTF==1.0.0 flask-healthz==0.0.3 flask-unittest==0.1.2 lorem-text==2.1 +APScheduler==3.8.1 diff --git a/src/webui/service/__init__.py b/src/webui/service/__init__.py index 3c64f45c9..05b2eeaf0 100644 --- a/src/webui/service/__init__.py +++ b/src/webui/service/__init__.py @@ -16,6 +16,7 @@ import json from typing import List, Tuple, Union from flask import Flask, request, session from flask_healthz import healthz, HealthError +from common.tools.grpc.Tools import grpc_message_to_json from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient @@ -100,6 +101,7 @@ def create_app(use_config=None, web_app_root=None): app.jinja_env.globals.update({ # pylint: disable=no-member 'enumerate' : enumerate, + 'grpc_message_to_json': grpc_message_to_json, 'json_to_list' : json_to_list, 'round' : round, 'get_working_context' : get_working_context, diff --git a/src/webui/service/service/forms.py b/src/webui/service/service/forms.py new file mode 100644 index 000000000..52fc68302 --- /dev/null +++ b/src/webui/service/service/forms.py @@ -0,0 +1,295 @@ +# 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 re +from flask import flash, Flask +from flask_wtf import FlaskForm +from wtforms import StringField, SelectField, IntegerField, DecimalField +from wtforms.validators import InputRequired, Optional, NumberRange, ValidationError, StopValidation +#from common.proto.context_pb2 import DeviceOperationalStatusEnum +import ipaddress + +def validate_ipv4_address(form, field): #Custom validator for ensuring a valid IPv4 address is submitted + # Check for a valid IPv4 address + # print(field.data) + try: + ipaddress.IPv4Address(field.data) + except ipaddress.AddressValueError: + raise ValidationError('Invalid IPv4 address format') + +def validate_ipv6_address(form, field): #Custom validator for ensuring a valid IPv6 address is submitted + # Check for a valid IPv6 address + try: + ipaddress.IPv6Address(field.data) + except ipaddress.AddressValueError: + raise ValidationError('Invalid IPv6 address format') + +def validate_mac_address(form, field): #Custom validator for ensuring a valid MAC address is submitted + # Check for a valid MAC [L2] address + if not re.match(r'^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$', field.data): + raise ValidationError('Invalid MAC address format') + +def validate_route_distinguisher(form,field): #Custom validator for the input of Route Distinguisher value + pattern = r'^([0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]):([0-9]|[1-9][0-9]{1,8}|[1-3][0-9]{9}|4[01][0-9]{8}|42[0-8][0-9]{7}|429[0-3][0-9]{6}|4294[0-8][0-9]{5}|42949[0-5][0-9]{4}|429496[0-6][0-9]{3}|4294967[01][0-9]{2}|42949672[0-8][0-9]|429496729[0-5])$' + if not re.match(pattern, field.data): + raise ValidationError('Invalid Route Distinguisher') + +def validate_uint32(form, field): #Custom validator for ensuring uint32 integers + if not 0 <= field.data <= 2**32-1: + raise ValidationError('Value must be a positive integer within the range of uint32') + +def validate_NI_as(form, field): #Custom validator that checks if NI_protocol_name is BGP and NI_as is not provided + if form.NI_protocol.data == 'BGP' and field.data == None: + raise StopValidation('AS field is required if the BGP protocol is selected.') + +def validator_ADVA(form, field): + if field.name == 'Device_1_NI_VC_ID' and form.Device_1_IF_vendor.data == 'ADVA' and form.Device_1_NI_VC_ID.data != form.Device_1_IF_vlan_id.data: + raise StopValidation('For the ADVA vendor, it is mandatory that the VC_ID is the same as the Vlan_ID.') + + if field.name == 'Device_2_NI_VC_ID' and form.Device_2_IF_vendor.data == 'ADVA' and form.Device_2_NI_VC_ID.data != form.Device_2_IF_vlan_id.data: + raise StopValidation('For the ADVA vendor, it is mandatory that the VC_ID is the same as the Vlan_ID.') + + + +class CustomInputRequired(): #Custom validator that ensures that the required data is provided + def __init__(self, message=None): #Define a constructor that takes an optional message parameter + self.message = message or "This field is required." #If message is provided, use it. Otherwise, set a default message. + + def __call__(self, form, field): #Define a __call__ method that takes in the form and field to be validated + if field.data is None or field.data == '': #Check if the field data is empty or None + raise StopValidation(self.message) #If the data is empty or None, raise a StopValidation exception with the provided message + +class AddServiceForm_1(FlaskForm): #Form-1 - Formulary Fields -> Select the type of new service to add + service_type = SelectField('Type of service', choices=[('', 'Select a type of service to add'), ('ACL_L2', 'ACL_L2'), ('ACL_IPV4', 'ACL_IPV4'), ('ACL_IPV6', 'ACL_IPV6'), ('L2VPN', 'L2VPN'), ('L3VPN', 'L3VPN')], validators=[InputRequired()]) + +class AddServiceForm_ACL_L2(FlaskForm): #ACL_L2 - Formulary Fields + #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) + service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + service_type = SelectField('Service Type', choices=[(2, '2 (L2NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L3NM + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + + #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + + #MANDATORY_PARAMETERS + name = StringField('ACL Name', validators=[CustomInputRequired("The name of the ACL is a mandatory parameter")]) #MANDATORY PARAMETER + type = SelectField('ACL Type', choices=[('ACL_L2', 'ACL_L2')], validators=[CustomInputRequired("The type of the ACL is a mandatory parameter")]) #MANDATORY PARAMETER + sequence_id = IntegerField('ACL Sequence ID', validators=[CustomInputRequired("The name of the Sequence ID of the ACL is a mandatory parameter"), validate_uint32]) #MANDATORY PARAMETER + forwarding_action = SelectField('ACL Fowarding Action', choices=[('', 'Select an action (Mandatory)'), ('ACCEPT', 'Accept'), ('DROP','Drop'),('REJECT','Reject')], validators=[CustomInputRequired("The Forwarding Action of the ACL is a mandatory parameter")]) + log_action = SelectField('ACL Log Action', choices=[(None, 'Select a log action (Optional)'), ('LOG_SYSLOG', 'Syslog'), ('LOG_NONE','None')], validators=[Optional()]) + + #PARAMETERS FOR Associating ACL to IF + interface = StringField('Interface Name', validators=[CustomInputRequired("The name of the Interface is a mandatory parameter")]) #MANDATORY PARAMETER + subinterface = StringField('Subinterface Index', validators=[Optional()]) + traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[CustomInputRequired("The direction of the traffic flow is a mandatory parameter")]) #MANDATORY PARAMETER + + #SPECIFIC PARAMETERS - Creating ACL Entry [ACL_L2] + source_mac = StringField('Source MAC Address', validators=[Optional(), validate_mac_address]) + destination_mac = StringField('Destination MAC Address', validators=[Optional(), validate_mac_address]) + +class AddServiceForm_ACL_IPV4(FlaskForm): #ACL_IPV4 - Formulary Fields + #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) + service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + service_type = SelectField('Service Type', choices=[(1, '1 (L3NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L3NM + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + + #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + + #MANDATORY_PARAMETERS + name = StringField('ACL Name', validators=[CustomInputRequired("The name of the ACL is a mandatory parameter")]) #MANDATORY PARAMETER + type = SelectField('ACL Type', choices=[('ACL_IPV4', 'ACL_IPV4')], validators=[CustomInputRequired("The type of the ACL is a mandatory parameter")]) #MANDATORY PARAMETER + sequence_id = IntegerField('ACL Sequence ID', validators=[InputRequired(), NumberRange(min=1, message="Sequence ID must be greater than 0")]) #MANDATORY PARAMETER #MANDATORY PARAMETER + forwarding_action = SelectField('ACL Fowarding Action', choices=[(None, 'Select an action (Mandatory)'), ('ACCEPT', 'Accept'), ('DROP','Drop'),('REJECT','Reject')], validators=[InputRequired()]) + log_action = SelectField('ACL Log Action', choices=[(None, 'Select a log action (Optional)'), ('LOG_SYSLOG', 'Syslog'), ('LOG_NONE','None')], validators=[Optional()]) + + #PARAMETERS FOR Associating ACL to IF + interface = StringField('Interface Name', validators=[InputRequired()]) #MANDATORY PARAMETER + subinterface = StringField('Subinterface Index', validators=[Optional()]) + traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[InputRequired()]) #MANDATORY PARAMETER + + #OPTIONAL_PARAMETERS - Creating ACL Entry [ACL_IPV4] + source_address = StringField('Source Address', validators=[Optional(), validate_ipv4_address]) + destination_address = StringField('Destination Address', validators=[Optional(), validate_ipv4_address]) + protocol = IntegerField('Protocol', validators=[Optional(),NumberRange(min=1, max=255, message="Protocol number is between 1 and 255 as defined by IANA")]) #Protocols are defined from 1 - 255 as defined in IANA (https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) + hop_limit = IntegerField('Hop Limit', validators=[Optional(),NumberRange(min=1, max=255, message="The Hop limit value has to be between 0 and 255")]) #Max. value of Hop Limit = 255 + dscp = IntegerField('DSCP', validators=[Optional(),NumberRange(min=1, max=255, message="The DSCP value has to be between 0 and 63")]) #Max. value of DSCP = 63 + source_port = IntegerField('Source Port', validators=[Optional(),NumberRange(min=0, max=65535, message="The Port value has to be between 0 and 655535")]) #Range of existing ports in a PC + destination_port = IntegerField('Destination Port', validators=[Optional(),NumberRange(min=0, max=65535, message="The Port value has to be between 0 and 655535")]) #Range of existing ports in a PC + tcp_flags = SelectField('TCP Flags', choices=[(None, 'Select a TCP Flag (Optional)'),('TCP_SYN', 'TCP_SYN'),('TCP_ACK', 'TCP_ACK'),('TCP_RST', 'TCP_RST'),('TCP_FIN', 'TCP_FIN'),('TCP_PSH', 'TCP_PSH'),('TCP_URG', 'TCP_URG') ,('TCP_ECE', 'TCP_ECE'),('TCP_CWR', 'TCP_CWR')], validators=[Optional()]) + +class AddServiceForm_ACL_IPV6(FlaskForm): #ACL_IPV6 - Formulary Fields + #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) + service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + service_type = SelectField('Service Type', choices=[(1, '1 (L3NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L2NM + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + + #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + + #MANDATORY_PARAMETERS + name = StringField('ACL Name', validators=[InputRequired()]) #MANDATORY PARAMETER + type = SelectField('ACL Type', choices=[('ACL_IPV6', 'ACL_IPV6')], validators=[InputRequired()]) #MANDATORY PARAMETER + sequence_id = IntegerField('ACL Sequence ID', validators=[InputRequired(), NumberRange(min=1, message="Sequence ID must be greater than 0")]) #MANDATORY PARAMETER]) #MANDATORY PARAMETER + forwarding_action = SelectField('ACL Fowarding Action', choices=[(None, 'Select an action (Mandatory)'), ('ACCEPT', 'Accept'), ('DROP','Drop'),('REJECT','Reject')], validators=[InputRequired()]) + log_action = SelectField('ACL Log Action', choices=[(None, 'Select a log action (Optional)'), ('LOG_SYSLOG', 'Syslog'), ('LOG_NONE','None')], validators=[Optional()]) + + #PARAMETERS FOR Associating ACL to IF + interface = StringField('Interface Name', validators=[InputRequired()]) #MANDATORY PARAMETER + subinterface = StringField('Subinterface Index', validators=[Optional()]) + traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[InputRequired()]) #MANDATORY PARAMETER + + #SPECIFIC PARAMETERS - Creating ACL Entry [ACL_IPV6] + source_address = StringField('Source Address', validators=[Optional(), validate_ipv6_address]) + destination_address = StringField('Destination Address', validators=[Optional(), validate_ipv6_address]) + protocol = IntegerField('Protocol', validators=[Optional(),NumberRange(min=1, max=255, message="Protocol number is between 1 and 255 as defined by IANA")]) #Protocols are defined from 1 - 255 as defined in IANA (https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) + hop_limit = IntegerField('Hop Limit', validators=[Optional(),NumberRange(min=1, max=255, message="The Hop limit value has to be between 0 and 255")]) #Max. value of Hop Limit = 255 + dscp = IntegerField('DSCP', validators=[Optional(),NumberRange(min=1, max=255, message="The DSCP value has to be between 0 and 63")]) #Max. value of DSCP = 63 + +class AddServiceForm_L2VPN(FlaskForm): #L2VPN - Formulary Fields + #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) + service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + service_type = SelectField('Service Type', choices=[(2, '2 (L2NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L2NM + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + #Device_1_IF_vendor = SelectField ('Device_1 Vendor', choices=[('', 'Select a vendor (Mandatory)'),('ADVA', 'ADVA'), ('CISCO','CISCO'), ('Huawei', 'Huawei'),('Juniper', 'Juniper'),('Nokia', 'Nokia')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + #Device_2_IF_vendor = SelectField ('Device_2 Vendor', choices=[('', 'Select a vendor (Mandatory)'),('ADVA', 'ADVA'), ('CISCO','CISCO'), ('Huawei', 'Huawei'),('Juniper', 'Juniper'),('Nokia', 'Nokia')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + #Device_1_Template = SelectField ('Device_1 Template', choices=[('', 'Select a type of template (Mandatory)'),('Jinja', 'Jinja'), ('Pyangbind','Pyangbind')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + #Device_2_Template = SelectField ('Device_2 Template', choices=[('', 'Select a type of template (Mandatory)'),('Jinja', 'Jinja'), ('Pyangbind','Pyangbind')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + + + #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + + #NI parameters + #Common for the service + NI_name = StringField('NI Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + #NI_type = SelectField('NI Type', choices=[('L2VSI', 'L2VSI')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L2VSI + NI_mtu = IntegerField('NI MTU', default=1500, validators=[CustomInputRequired(), NumberRange(min=0, message="MTU value can't be negative")]) #MANDATORY PARAMETER - FIXED VALUE -> 1500 + NI_description = StringField('NI Description', validators=[Optional()]) #OPTIONAL PARAMETER + #Device_1 specific + #Device_1_NI_VC_ID = IntegerField('Device_1 NI VC_ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative"), validator_ADVA]) #MANDATORY PARAMETER + Device_1_NI_remote_system = StringField('Device_1 NI Remote System', validators=[CustomInputRequired(),validate_ipv4_address]) #MANDATORY PARAMETER + Device_1_NI_VC_ID = IntegerField('Device_1 NI VC ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative")]) #MANDATORY PARAMETER + Device_1_NI_connection_point = StringField('Device_1 NI Conection Point', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + #Device_2 specific + #Device_2_NI_VC_ID = IntegerField('Device_2 NI VC_ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative"), validator_ADVA]) #MANDATORY PARAMETER + Device_2_NI_remote_system = StringField ('Device_2 NI Remote System', validators=[CustomInputRequired(),validate_ipv4_address]) #MANDATORY PARAMETER + Device_2_NI_VC_ID = IntegerField('Device_2 NI VC ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative")]) #MANDATORY PARAMETER + Device_2_NI_connection_point = StringField ('Device_2 NI Conection Point', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + + #Interface parameters (DEVICE SPECIFIC) + #Device-1 + #Device_1_IF_name = StringField ('Device_1 Interface Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + #Device_1_IF_type = StringField ('Device_1 Interface Type', default="l2vlan", validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> l2vlan? + Device_1_IF_index = IntegerField('Device_1 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) #MANDATORY PARAMETER + Device_1_IF_vlan_id = IntegerField('Device_1 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) #MANDATORY PARAMETER + Device_1_IF_mtu = IntegerField('Device_1 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) #OPTIONAL PARAMETER - FIXED VALUE -> 3000? + Device_1_IF_description = StringField ('Device_1 SubIF Description', validators=[Optional()]) #OPTIONAL PARAMETER + #Device-2 + #Device_2_IF_name = StringField ('Device_2 Interface Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + #Device_2_IF_type = StringField ('Device_2 Interface Type', default="l2vlan", validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> l2vlan? + Device_2_IF_index = IntegerField('Device_2 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) #MANDATORY PARAMETER + Device_2_IF_vlan_id = IntegerField('Device_2 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) #MANDATORY PARAMETER + Device_2_IF_mtu = IntegerField('Device_2 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) #OPTIONAL PARAMETER - FIXED VALUE -> 3000? + Device_2_IF_description = StringField ('Device_2 SubIF Description', validators=[Optional()]) #OPTIONAL PARAMETER + +class AddServiceForm_L3VPN(FlaskForm): #L3VPN - Formulary Fields + #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) + service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + service_type = SelectField('Service Type', choices=[(1, '1 (L3NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L3NM + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + #Device_1_IF_vendor = SelectField ('Device_1 Vendor', choices=[('', 'Select a vendor (Mandatory)'),('ADVA', 'ADVA'), ('CISCO','CISCO'), ('Huawei', 'Huawei'),('Juniper', 'Juniper'),('Nokia', 'Nokia')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER + #Device_2_IF_vendor = SelectField ('Device_2 Vendor', choices=[('', 'Select a vendor (Mandatory)'),('ADVA', 'ADVA'), ('CISCO','CISCO'), ('Huawei', 'Huawei'),('Juniper', 'Juniper'),('Nokia', 'Nokia')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER + #Device_1_Template = SelectField ('Device_1 Template', choices=[('', 'Select a type of template (Mandatory)'),('Jinja', 'Jinja'), ('Pyangbind','Pyangbind')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 + #Device_2_Template = SelectField ('Device_2 Template', choices=[('', 'Select a type of template (Mandatory)'),('Jinja', 'Jinja'), ('Pyangbind','Pyangbind')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + + #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + + ## Network Instance (NI) PARAMS + #Create a NI + NI_name = StringField('Name', validators=[InputRequired()]) #MANDATORY PARAMETER + #NI_type = SelectField('Type', choices=[('L3VRF', 'L3VRF')], validators=[InputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L3VRF + NI_route_distinguisher = StringField('Route Distinguisher', validators=[InputRequired(),validate_route_distinguisher]) #MANDATORY PARAMETER + NI_router_id = StringField('Router ID', validators=[Optional(), validate_ipv4_address]) #OPTIONAL PARAMETER + NI_description = StringField('Description', validators=[Optional()]) #OPTIONAL PARAMETER + #Add a protocol to NI + NI_protocol = SelectField('Protocol', choices=[('', 'Select a type (Mandatory)'),('STATIC', 'STATIC'),('DIRECTLY_CONNECTED', 'DIRECTLY_CONNECTED'),('BGP', 'BGP')], validators=[InputRequired()]) + NI_as = IntegerField('AS', default=None, validators=[validate_NI_as, Optional(), validate_uint32]) + #Create Connections Table + #NI_src_protocol = SelectField('Source Protocol', choices=[('', 'Select a type'),('STATIC', 'STATIC'),('DIRECTLY_CONNECTED', 'DIRECTLY_CONNECTED'),('BGP', 'BGP')], validators=[InputRequired()]) + #NI_dst_protocol = SelectField('Destination Protocol', choices=[('', 'Select a type'),('STATIC', 'STATIC'),('DIRECTLY_CONNECTED', 'DIRECTLY_CONNECTED'),('BGP', 'BGP')], validators=[InputRequired()]) + NI_address_family = SelectField('Protocol Address Family', choices=[('', 'Select a type (Mandatory)'),('IPV4', 'IPV4'),('IPV6', 'IPV6')], validators=[InputRequired()]) + NI_default_import_policy = SelectField('Default Network Instance Import Policy', choices=[('', 'Select a policy (Mandatory)'),('ACCEPT_ROUTE', 'ACCEPT_ROUTE'),('REJECT_ROUTE', 'REJECT_ROUTE')], validators=[Optional()]) + #Associate RP to NI + NI_import_policy = StringField('Name of the Network Instance Import Policy', validators=[Optional()]) #OPTIONAL PARAMETER + NI_export_policy = StringField('Name of the Network Instance Export Policy', validators=[Optional()]) #OPTIONAL PARAMETER + + ## Interface (IF) PARAMS + #Device-1 + #Device_1_IF_name = StringField ('Device_1 Interface Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + #Device_1_IF_type = StringField ('Device_1 Interface Type', default="l3ipvlan", validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> l3ipvlan? + Device_1_IF_index = IntegerField('Device_1 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) #MANDATORY PARAMETER + Device_1_IF_vlan_id = IntegerField('Device_1 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) #MANDATORY PARAMETER + Device_1_IF_mtu = IntegerField('Device_1 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) #OPTIONAL PARAMETER - FIXED VALUE -> 3000? + Device_1_IF_address_ip = StringField('Device_1 IP Address', validators=[CustomInputRequired(), validate_ipv4_address]) #MANDATORY PARAMETER + Device_1_IF_address_prefix = IntegerField('Device_1 IP Prefix length', validators=[CustomInputRequired(), validate_uint32]) #MANDATORY PARAMETER + Device_1_IF_description = StringField ('Device_1 SubIF Description', validators=[Optional()]) #OPTIONAL PARAMETER + #Device-2 + #Device_2_IF_name = StringField ('Device_2 Interface Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + #Device_2_IF_type = StringField ('Device_1 Interface Type', default="l3ipvlan", validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> l3ipvlan? + Device_2_IF_index = IntegerField('Device_2 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) #MANDATORY PARAMETER + Device_2_IF_vlan_id = IntegerField('Device_2 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) #MANDATORY PARAMETER + Device_2_IF_mtu = IntegerField('Device_2 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) #MANDATORY PARAMETER - FIXED VALUE -> 3000? + Device_2_IF_address_ip = StringField('Device_2 IP Address', validators=[CustomInputRequired(), validate_ipv4_address]) #MANDATORY PARAMETER + Device_2_IF_address_prefix = IntegerField('Device_2 IP Prefix length', validators=[CustomInputRequired(), validate_uint32]) #MANDATORY PARAMETER + Device_2_IF_description = StringField ('Device_2 SubIF Description', validators=[Optional()]) #OPTIONAL PARAMETER + + ## Routing Policy (RP) parameters + #RP_policy_name = StringField('Policy Name', validators=[InputRequired()]) #MANDATORY PARAMETER + #RP_statement_name = StringField('Statement Name', validators=[InputRequired()]) #MANDATORY PARAMETER + #RP_policy_result = SelectField('Policy Result', choices=[(None, 'Not Defined'), ('ACCEPT_ROUTE', 'ACCEPT_ROUTE'),('REJECT_ROUTE', 'REJECT_ROUTE')], validators=[Optional()]) + #RP_ext_community_set_name = StringField('Ext Community Set Name', validators=[InputRequired()]) #MANDATORY PARAMETER + #RP_ext_community_member = StringField('Ext Community Member', validators=[InputRequired()]) #MANDATORY PARAMETER + diff --git a/src/webui/service/service/routes.py b/src/webui/service/service/routes.py index 08312e525..9aff0ad79 100644 --- a/src/webui/service/service/routes.py +++ b/src/webui/service/service/routes.py @@ -12,30 +12,52 @@ # See the License for the specific language governing permissions and # limitations under the License. + +import base64, json, logging #, re from contextlib import contextmanager import json import grpc from collections import defaultdict from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for, request from common.proto.context_pb2 import ( - IsolationLevelEnum, Service, ServiceId, ServiceTypeEnum, ServiceStatusEnum, Connection, Empty, DeviceDriverEnum, + ContextId, IsolationLevelEnum, Service, ServiceId, ServiceTypeEnum, ServiceStatusEnum, Connection, Empty, DeviceDriverEnum, ConfigActionEnum, Device, DeviceList) from common.tools.context_queries.Context import get_context from common.tools.context_queries.Topology import get_topology from common.tools.context_queries.EndPoint import get_endpoint_names -from common.tools.context_queries.Service import get_service_by_uuid +from wtforms.validators import ValidationError +from context.client.ContextClient import ContextClient +from service.client.ServiceClient import ServiceClient +from device.client.DeviceClient import DeviceClient +from common.tools.object_factory.Service import ( + json_service_l2nm_planned, json_service_l3nm_planned) +from common.tools.object_factory.Constraint import ( + json_constraint_sla_availability, json_constraint_sla_capacity, json_constraint_sla_isolation, + json_constraint_sla_latency) +from common.tools.descriptor.Loader import DescriptorLoader, compose_notifications from common.tools.object_factory.ConfigRule import json_config_rule_set +from common.tools.object_factory.Device import json_device_id +from common.tools.object_factory.EndPoint import json_endpoint_id +#from src.common.tools.grpc.Tools import grpc_message_to_json_string +from webui.service.service.forms import AddServiceForm_1, AddServiceForm_ACL_L2, AddServiceForm_ACL_IPV4, AddServiceForm_ACL_IPV6, AddServiceForm_L2VPN, AddServiceForm_L3VPN +from common.tools.context_queries.Service import get_service_by_uuid 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 service.client.ServiceClient import ServiceClient from typing import Optional, Set -service = Blueprint('service', __name__, url_prefix='/service') +LOGGER = logging.getLogger(__name__) +service = Blueprint('service', __name__, url_prefix='/service') #Define a flask Blueprint called "service" behind the url "/service" -context_client = ContextClient() -service_client = ServiceClient() +context_client = ContextClient() #Create an instance of ContextClient class as defined in /src/service/client/ContextClient.py +service_client = ServiceClient() #Create an instance of ServiceClient class as defined in /src/service/client/ServiceClient.py +device_client = DeviceClient() +type = ["ACL_UNDEFINED", "ACL_IPV4","ACL_IPV6","ACL_L2","ACL_MPLS","ACL_MIXED"] +f_action = ["UNDEFINED", "DROP","ACCEPT","REJECT"] +l_action = ["UNDEFINED", "LOG_NONE","LOG_SYSLOG"] + +''' +@service.get('/') #Route for the homepage of the created "service" blueprint @contextmanager def connected_client(c): try: @@ -43,7 +65,7 @@ def connected_client(c): yield c finally: c.close() - +''' # Context client must be in connected state when calling this function def get_device_drivers_in_use(topology_uuid: str, context_uuid: str) -> Set[str]: active_drivers = set() @@ -58,15 +80,15 @@ def get_device_drivers_in_use(topology_uuid: str, context_uuid: str) -> Set[str] @service.get('/') def home(): - if 'context_uuid' not in session or 'topology_uuid' not in session: - flash("Please select a context!", "warning") + if 'context_uuid' not in session or 'topology_uuid' not in session: #Check if context_uuid and topology_uuid are defined in the current seession + flash("Please select a context!", "warning") #If they are not defined in the current session [Return to main page - STOP] return redirect(url_for("main.home")) context_uuid = session['context_uuid'] topology_uuid = session['topology_uuid'] - context_client.connect() + context_client.connect() #Creates a connection, as specified in the connect method of the ContextClient() class - context_obj = get_context(context_client, context_uuid, rw_copy=False) + context_obj = get_context(context_client, context_uuid, rw_copy=False) #Using the get_context function, defined in /src/common/ if context_obj is None: flash('Context({:s}) not found'.format(str(context_uuid)), 'danger') services, device_names, endpoints_data = list(), list(), list() @@ -253,7 +275,6 @@ def detail(service_uuid: str): try: context_client.connect() - endpoint_ids = list() service_obj = get_service_by_uuid(context_client, service_uuid, rw_copy=False) if service_obj is None: @@ -271,17 +292,15 @@ def detail(service_uuid: str): device_names, endpoints_data = dict(), dict() context_client.close() - return render_template( 'service/detail.html', service=service_obj, connections=connections, device_names=device_names, - endpoints_data=endpoints_data, ste=ServiceTypeEnum, sse=ServiceStatusEnum, ile=IsolationLevelEnum) + endpoints_data=endpoints_data, ste=ServiceTypeEnum, sse=ServiceStatusEnum, ile=IsolationLevelEnum, type = type, f_action = f_action, l_action = l_action) except Exception as e: flash('The system encountered an error and cannot show the details of this service.', 'warning') current_app.logger.exception(e) return redirect(url_for('service.home')) - -@service.get('/delete') +@service.get('/delete') #Route for deleting a specific service def delete(service_uuid: str): if 'context_uuid' not in session or 'topology_uuid' not in session: flash("Please select a context!", "warning") @@ -301,3 +320,372 @@ def delete(service_uuid: str): flash('Problem deleting service "{:s}": {:s}'.format(service_uuid, str(e.details())), 'danger') current_app.logger.exception(e) return redirect(url_for('service.home')) + +#Added routes for creating a new Service +@service.route('add/configure', methods=['GET', 'POST']) #Route for adding a new service [Selecting the type of operation to be performed - First Form] +def add_configure(): + form_1 = AddServiceForm_1() + if form_1.validate_on_submit(): + #store the selected service type in session + #session['service_type'] = form_1.service_type.data + #redirect to the same page to display the second form + if form_1.service_type.data == 'ACL_L2': + return redirect(url_for('service.add_configure_ACL_L2')) + elif form_1.service_type.data == 'ACL_IPV4': + return redirect(url_for('service.add_configure_ACL_IPV4')) + elif form_1.service_type.data == 'ACL_IPV6': + return redirect(url_for('service.add_configure_ACL_IPV6')) + elif form_1.service_type.data == 'L2VPN': + return redirect(url_for('service.add_configure_L2VPN')) + elif form_1.service_type.data == 'L3VPN': + return redirect(url_for('service.add_configure_L3VPN')) + # display the first form + return render_template('service/add.html', form_1=form_1, submit_text='Continue to configuraton') + +@service.route('add/configure/ACL_L2', methods=['GET', 'POST']) #Route for adding a new ACL_L2 service [Setting the parameters for defining the service] +def add_configure_ACL_L2(): + form_acl = AddServiceForm_ACL_L2() + service_obj = Service() + + context_uuid, topology_uuid = get_context_and_topology_uuids() #Get the topology and context UUIDS + if context_uuid and topology_uuid: #If the UUIDs exist + context_client.connect() #Connects to the context service using the context_client object + grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) #Call the get_topology() function to retrieve the topology information for the given context and topology UUIDs + if grpc_topology: #If the topology is defined + topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids} + #devices = get_filtered_devices(context_client, topo_device_uuids) #Calls the fucntion that returns a list of devices that have UUIDs in the set of topology device UUIDs. + context_obj = get_context(context_client, context_uuid, rw_copy=False) + if context_obj is None: + flash('Context({:s}) not found'.format(str(context_uuid)), 'danger') + return redirect(request.url) + services = context_client.ListServices(context_obj.context_id) + devices = [] + for service in services.services: + devices_services = [] + if service.service_type == ServiceTypeEnum.SERVICETYPE_L2NM: + LOGGER.warning('L2NM service') + for ep in service.service_endpoint_ids: + device_uuid = ep.device_id.device_uuid.uuid + devices_services.append(device_uuid, service.service_name) + LOGGER.warning('device_uuid') + LOGGER.warning(device_uuid) + + grpc_devices = context_client.ListDevices(Empty()) + for device in grpc_devices.devices: + if device.device_id.device_uuid.uuid in devices_services: + devices.append(device) + + choices = get_device_choices(devices) #Returns a list of tuples, where each tuple contains the index of the device in the list and the name of the device + add_device_choices_to_form(choices, form_acl.service_device_1) #Adds the device choices to the select options for the form (Device1) + add_device_choices_to_form(choices, form_acl.service_device_2) #Adds the device choices to the select options for the form (Device2) + else: + flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') #If the topology is not found, display an error message and set the devices list to an empty list + else: + flash('Missing context or topology UUID', 'danger') #If the topology or context UUID is not found, display an error message + if form_acl.validate_on_submit(): + flash(f'New configuration was created', 'success') + return redirect(url_for('service.home')) + + return render_template('service/configure_ACL_L2.html', form_acl=form_acl, submit_text='Add New Service') + +@service.route('add/configure/ACL_IPV4', methods=['GET', 'POST']) #Route for adding a new ACL_IPV4 service [Setting the parameters for defining the service] +def add_configure_ACL_IPV4(): + form_acl = AddServiceForm_ACL_IPV4() + if form_acl.validate_on_submit(): + flash(f'New configuration was created', 'success') + return redirect(url_for('service.home')) + print(form_acl.errors) + return render_template('service/configure_ACL_IPV4.html', form_acl=form_acl, submit_text='Add New Service') + +@service.route('add/configure/ACL_IPV6', methods=['GET', 'POST']) #Route for adding a new ACL_IPV6 service [Setting the parameters for defining the service] +def add_configure_ACL_IPV6(): + form_acl = AddServiceForm_ACL_IPV6() + if form_acl.validate_on_submit(): + flash(f'New configuration was created', 'success') + return redirect(url_for('service.home')) + print(form_acl.errors) + return render_template('service/configure_ACL_IPV6.html', form_acl=form_acl, submit_text='Add New Service') + +@service.route('add/configure/L2VPN', methods=['GET', 'POST']) #Route for adding a new L2VPN service [Setting the parameters for defining the service] +def add_configure_L2VPN(): + form_l2vpn = AddServiceForm_L2VPN() #Load the AddServiceForm_L3VPN form defined in forms.py + service_obj = Service() #Create a new instance of the Service class + + context_uuid, topology_uuid = get_context_and_topology_uuids() #Get the topology and context UUIDS + if context_uuid and topology_uuid: #If the UUIDs exist + context_client.connect() #Connects to the context service using the context_client object + grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) #Call the get_topology() function to retrieve the topology information for the given context and topology UUIDs + if grpc_topology: #If the topology is defined + topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids} + devices = get_filtered_devices(context_client, topo_device_uuids) #Calls the fucntion that returns a list of devices that have UUIDs in the set of topology device UUIDs. + choices = get_device_choices(devices) #Returns a list of tuples, where each tuple contains the index of the device in the list and the name of the device + add_device_choices_to_form(choices, form_l2vpn.service_device_1) #Adds the device choices to the select options for the form (Device1) + add_device_choices_to_form(choices, form_l2vpn.service_device_2) #Adds the device choices to the select options for the form (Device2) + else: + flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') #If the topology is not found, display an error message and set the devices list to an empty list + else: + flash('Missing context or topology UUID', 'danger') #If the topology or context UUID is not found, display an error message + + if form_l2vpn.validate_on_submit(): #Check if the form has been submitted and is valid + try: #Calls a function that validates the selected devices and endpoints exists and are correct + [selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2] = validate_selected_devices_and_endpoints(form_l2vpn, devices) + except Exception as e: #Catch any exception raised during the validation process + flash('{:s}'.format(str(e.args[0])), 'danger') + current_app.logger.exception(e) + return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service') #Render the L2VPN configuration form with the previously entered data and an error message + + #Check the specific values of the parameters dependent by the vendor of the device + [vendor_1, vendor_2] = get_device_vendor(form_l2vpn, devices) + try: + validate_params_vendor(form_l2vpn, vendor_1, 1) + validate_params_vendor(form_l2vpn, vendor_2, 2) + except Exception as e: + flash('{:s}'.format(str(e.args[0])), 'danger') + current_app.logger.exception(e) + return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service') #Render the L2VPN configuration form with the previously entered data and an error message + + #Create definition of the Service: + service_uuid, service_type, endpoint_ids = set_service_parameters(service_obj, form_l2vpn, selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2) #Calls the function to set the Service - Endpoint UUIDS + constraints = add_constraints(form_l2vpn) #Calls the function to add the constraint parameters for defining a service + params_device_1_with_data = get_device_params(form_l2vpn, 1, service_type) #Calls the function that getst the parameters that will configure the service in the device-1 + params_device_2_with_data = get_device_params(form_l2vpn, 2, service_type) #Calls the function that getst the parameters that will configure the service in the device-2 + print(params_device_1_with_data) + print(params_device_2_with_data) + params_settings = {} #Param settings (Defined despite it has no value) -> Avoid error + config_rules = [ #Create the configuration rules from the params_with_data + json_config_rule_set( + '/settings', params_settings + ), + json_config_rule_set( + '/device[{:s}]/endpoint[{:s}]/settings'.format(str(selected_device_1.name), str(selected_endpoint_1)), params_device_1_with_data + ), + json_config_rule_set( + '/device[{:s}]/endpoint[{:s}]/settings'.format(str(selected_device_2.name), str(selected_endpoint_2)), params_device_2_with_data + ) + ] + service_client.connect() + context_client.connect() + device_client.connect() + descriptor_json = json_service_l2nm_planned(service_uuid = service_uuid, endpoint_ids = endpoint_ids, constraints = constraints, config_rules = config_rules, context_uuid= context_uuid) + descriptor_json = {"services": [descriptor_json]} #Wrap the descriptor between the tag: "services": []" + try: + process_descriptors(descriptor_json) + flash('Service "{:s}" added successfully!'.format(service_obj.service_id.service_uuid.uuid), 'success') #If the service was added succesfully -> Flash success message with newly added service UUID. + return redirect(url_for('service.home', service_uuid=service_obj.service_id.service_uuid.uuid)) #If the service was added succesfully -> Redirect to the service.home URL #Call the process_descriptors function to add the new service defined in the descriptor_json variable + except Exception as e: + flash('Problem adding service: {:s}'.format((str(e.args[0]))), 'danger') #If the service was NOT added succesfully -> Include the exception message in a flashed message + current_app.logger.exception(e) #If the service was NOT added succesfully -> Log the exception using Flask's logger + finally: + context_client.close() + device_client.close() + service_client.close() + return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service') + +@service.route('add/configure/L3VPN', methods=['GET', 'POST']) #Route for adding a new L3VPN service [Setting the parameters for defining the service] +def add_configure_L3VPN(): + form_l3vpn = AddServiceForm_L3VPN() #Load the AddServiceForm_L3VPN form defined in forms.py + service_obj = Service() #Create a new instance of the Service class + + context_uuid, topology_uuid = get_context_and_topology_uuids() #Get the topology and context UUIDS + if context_uuid and topology_uuid: #If the UUIDs exist + context_client.connect() #Connects to the context service using the context_client object + grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) #Call the get_topology() function to retrieve the topology information for the given context and topology UUIDs + if grpc_topology: #If the topology is defined + topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids} + devices = get_filtered_devices(context_client, topo_device_uuids) #Calls the fucntion that returns a list of devices that have UUIDs in the set of topology device UUIDs. + choices = get_device_choices(devices) #Returns a list of tuples, where each tuple contains the index of the device in the list and the name of the device + add_device_choices_to_form(choices, form_l3vpn.service_device_1) #Adds the device choices to the select options for the form (Device1) + add_device_choices_to_form(choices, form_l3vpn.service_device_2) #Adds the device choices to the select options for the form (Device2) + else: + flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') #If the topology is not found, display an error message and set the devices list to an empty list + else: + flash('Missing context or topology UUID', 'danger') #If the topology or context UUID is not found, display an error message + + if form_l3vpn.validate_on_submit(): + try: + [selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2] = validate_selected_devices_and_endpoints(form_l3vpn, devices) #Calls a function that validates the selected devices and endpoints exists and are correct + except Exception as e: # Catch any exception raised during the validation process + flash('{:s}'.format(str(e.args[0])), 'danger') + current_app.logger.exception(e) + return render_template('service/configure_L3VPN.html', form_l3vpn=form_l3vpn, submit_text='Add New Service') #Render the L3VPN configuration form with the previously entered data and an error message + #Create definition of the Service: + service_uuid, service_type, endpoint_ids = set_service_parameters(service_obj, form_l3vpn, selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2) #Calls the function to set the Service - Endpoint UUIDS + constraints = add_constraints(form_l3vpn) #Calls the function to add the constraint parameters for defining a service + params_device_1_with_data = get_device_params(form_l3vpn, 1, service_type) + params_device_2_with_data = get_device_params(form_l3vpn, 2, service_type) + params_settings = {} + config_rules = [ #Create the configuration rules from the params_with_data + json_config_rule_set( + '/settings', params_settings + ), + json_config_rule_set( + '/device[{:s}]/endpoint[{:s}]/settings'.format(str(selected_device_1.name), str(selected_endpoint_1)), params_device_1_with_data + ), + json_config_rule_set( + '/device[{:s}]/endpoint[{:s}]/settings'.format(str(selected_device_2.name), str(selected_endpoint_2)), params_device_2_with_data + ) + ] + service_client.connect() + context_client.connect() + device_client.connect() + descriptor_json = json_service_l3nm_planned(service_uuid = service_uuid, endpoint_ids = endpoint_ids, constraints = constraints, config_rules = config_rules, context_uuid= context_uuid) + descriptor_json = {"services": [descriptor_json]} #Wrap the descriptor between the tag: "services": []" + try: + process_descriptors(descriptor_json) + flash('Service "{:s}" added successfully!'.format(service_obj.service_id.service_uuid.uuid), 'success') #If the service was added succesfully -> Flash success message with newly added service UUID. + return redirect(url_for('service.home', service_uuid=service_obj.service_id.service_uuid.uuid)) #If the service was added succesfully -> Redirect to the service.home URL #Call the process_descriptors function to add the new service defined in the descriptor_json variable + except Exception as e: + flash('Problem adding service: {:s}'.format((str(e.args[0]))), 'danger') #If the service was NOT added succesfully -> Include the exception message in a flashed message + current_app.logger.exception(e) #If the service was NOT added succesfully -> Log the exception using Flask's logger + finally: + context_client.close() + device_client.close() + service_client.close() + return render_template('service/configure_L3VPN.html', form_l3vpn=form_l3vpn, submit_text='Add New Service') + + +##Function for creating the service +DESCRIPTOR_LOADER_NUM_WORKERS = 10 + +def process_descriptors(descriptors): #The function receives a "descriptors" parameter which has to be a JSON descriptor object + descriptor_loader = DescriptorLoader(descriptors, num_workers=DESCRIPTOR_LOADER_NUM_WORKERS) #Creates a descriptor_loader object + results = descriptor_loader.process() #Calls the descriptor_loader.process method and saves the result in the results variable + for message,level in compose_notifications(results): #Retrieve the notifications that are obtained in the proccess + if level == 'error': + LOGGER.warning('ERROR message={:s}'.format(str(message))) #Display any error message in the LOG + flash(message, level) #Show any notification message to the user in the webUI by using flash() + +##Functions for having a higher leaver of abstraction and understanding in the code: + +def get_context_and_topology_uuids(): #Retrieve the context and topology UUIDs from the session, if they exist + context_uuid = session.get('context_uuid') + topology_uuid = session.get('topology_uuid') + return context_uuid, topology_uuid #Return the UUIDs as a tuple, or None if either is missing + +def get_filtered_devices(context_client, topo_device_uuids): #Call the ListDevices() method on the context client to retrieve a list of all devices + grpc_devices = context_client.ListDevices(Empty()) + return [device for device in grpc_devices.devices if device.device_id.device_uuid.uuid in topo_device_uuids] #Filter the list of devices to only include those with UUIDs that appear in the topology + +def get_device_choices(devices): #Create the tuple (Number, Device) that will be added to the form + return [(i, str(device.name)) for i, device in enumerate(devices)] + +def add_device_choices_to_form(choices, form): #Add the device choices (tuple) to the select options of the correspondent form + form.choices += choices + +def validate_selected_devices_and_endpoints(form, devices): #Validates that the 2 selected devices and 2 endpoints exist and are valid. Then it returns them + selected_device_1 = devices[int(form.service_device_1.data)] #Selected_Device1 will be the one selected by the user in the previously defined form field + selected_device_2 = devices[int(form.service_device_2.data)] #Selected_Device2 will be the one selected by the user in the previously defined form field + if selected_device_1 == selected_device_2: + raise ValidationError('The devices must be different!. Please select two valid and different devices') # If it is not a valid endpoint -> Raise a Validation Error + elif form.service_endpoint_1.data not in [endpoint.name for endpoint in selected_device_1.device_endpoints]: # Check if the endpoint submitted by the user is a valid endpoint of the selected device + raise ValidationError('The selected endpoint: ' + form.service_endpoint_1.data + ' is not a valid endpoint for: '+ selected_device_1.name + '. Please select an endpoint that is available for this device') + elif form.service_endpoint_2.data not in [endpoint.name for endpoint in selected_device_2.device_endpoints]: # Check if the endpoint submitted by the user is a valid endpoint of the selected device + raise ValidationError('The selected endpoint: ' + form.service_endpoint_2.data + ' is not a valid endpoint for: '+ selected_device_2.name + '. Please select an endpoint that is available for this device') + else: + selected_endpoint_1 = form.service_endpoint_1.data #If the selected endpoint is valid, save it in a variable + selected_endpoint_2 = form.service_endpoint_2.data #If the selected endpoint is valid, save it in a variable + return selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2 #Return the devices and endpoints + +def get_device_vendor(form, devices): + selected_device_1 = devices[int(form.service_device_1.data)] #Selected_Device1 will be the one selected by the user in the previously defined form field + selected_device_2 = devices[int(form.service_device_2.data)] #Selected_Device2 will be the one selected by the user in the previously defined form field + + vendor_value_1 = None + vendor_value_2 = None + + for config_rule in selected_device_1.device_config.config_rules: + if "vendor" in config_rule.custom.resource_value: + vendor_config_rule_1 = config_rule.custom.resource_value + config_rule_dict_1 = json.loads(vendor_config_rule_1) + if "vendor" in config_rule_dict_1: + vendor_value_1 = config_rule_dict_1["vendor"] + break + + for config_rule in selected_device_2.device_config.config_rules: + if "vendor" in config_rule.custom.resource_value: + vendor_config_rule_2 = config_rule.custom.resource_value + config_rule_dict_2 = json.loads(vendor_config_rule_2) + if "vendor" in config_rule_dict_2: + vendor_value_2 = config_rule_dict_2["vendor"] + break + + return vendor_value_1, vendor_value_2 + +def validate_params_vendor(form, vendor, device_num): #num is an auxiliar variable that can be 1 or 2 for knowing if it corresponds to the first or second device + if vendor == "ADVA": + if form.NI_name.data != f"ELAN-AC:{getattr(form, f'Device_{device_num}_IF_vlan_id').data}": + raise ValidationError('For an ADVA device, the name of the Network Instance should have this name: "ELAN-AC:vlanID"') + + elif getattr(form, f'Device_{device_num}_NI_VC_ID').data != getattr(form, f'Device_{device_num}_IF_vlan_id').data: + raise ValidationError('For an ADVA device, the value of the VlanID and the value of the VC_ID must be the same') + else: + None + return None + +def set_service_parameters(service_obj, form, selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2): #Function to retrieve and set the service parameters for defining the service + #Service UUID: + service_obj.service_id.service_uuid.uuid = str(form.service_name.data) #Create the Service UUID (Unique Identifier of the service) from the service name + service_uuid = service_obj.service_id.service_uuid.uuid + #Service type [OPTIONS Defined in Context.proto]: 0(Unknown), 1(L3NM), 2(L2NM), 3(TAPI_CONNECTIVITY_SERVICE), 4(ACL) + service_obj.service_type = int(form.service_type.data) #Set the Service type as selected by the user in the form + service_type = service_obj.service_type + # Set the endpoint IDs + endpoint_ids = [ #Create a list containing a element that represents the Selected Device ID and the Selected Endpoint + json_endpoint_id(json_device_id(selected_device_1.name), str(selected_endpoint_1)), + json_endpoint_id(json_device_id(selected_device_2.name), str(selected_endpoint_2)) + ] + return service_uuid, service_type, endpoint_ids + +def add_constraints(form): #Function to add the constraints for a definition of a service + constraints = [] #Constraints -> Creates a list in which the constraints for the service will be added + if form.service_capacity.data: + constraints.append(json_constraint_sla_capacity(float(form.service_capacity.data))) #Capacity [Gbps] + if form.service_latency.data: + constraints.append(json_constraint_sla_latency(float(form.service_latency.data))) #Latency [ms] + if form.service_availability.data: + constraints.append(json_constraint_sla_availability(1, True, float(form.service_availability.data))) #Availability [%] + if form.service_isolation.data is not None and form.service_isolation.data != '': + constraints.append(json_constraint_sla_isolation([getattr(IsolationLevelEnum, str(form.service_isolation.data))])) #Isolation (Predefined values) + + return constraints #Returns a list with the constraints and values + +def get_device_params(form, device_num, form_type): #Function to retrieve and set the device parameters for defining the service + if form_type == 2: #Type2 = L2NM + device_params = { + 'ni_name': str(getattr(form, 'NI_name').data), + 'sub_interface_index': str(getattr(form, f'Device_{device_num}_IF_index').data), + 'vlan_id': str(getattr(form, f'Device_{device_num}_IF_vlan_id').data), + 'remote_router': str(getattr(form, f'Device_{device_num}_NI_remote_system').data), + 'vc_id': str(getattr(form, f'Device_{device_num}_NI_VC_ID').data), + 'conn_point': str(getattr(form, f'Device_{device_num}_NI_connection_point').data), + 'mtu': str(getattr(form, f'Device_{device_num}_IF_mtu').data), + 'ni_description': str(getattr(form, 'NI_description').data), + 'subif_description': str(getattr(form, f'Device_{device_num}_IF_description').data), + } + elif form_type == 1: #Type1 = L3NM + if device_num == 1: + policy_az_field = 'NI_import_policy' + policy_za_field = 'NI_export_policy' + elif device_num == 2: + policy_az_field = 'NI_export_policy' + policy_za_field = 'NI_import_policy' + device_params = { + 'ni_name': str(getattr(form, 'NI_name').data), + 'bgp_as':str(getattr(form, 'NI_as').data), + 'route_distinguisher': str(getattr(form, 'NI_route_distinguisher').data), + 'sub_interface_index': str(getattr(form, f'Device_{device_num}_IF_index').data), + 'router_id': str(getattr(form, 'NI_router_id').data), + 'vlan_id': str(getattr(form, f'Device_{device_num}_IF_vlan_id').data), + 'address_ip': str(getattr(form, f'Device_{device_num}_IF_address_ip').data), + 'address_prefix': str(getattr(form, f'Device_{device_num}_IF_address_prefix').data), + 'policy_AZ': str(getattr(form, policy_az_field).data), + 'policy_ZA': str(getattr(form, policy_za_field).data), + 'mtu': str(getattr(form, f'Device_{device_num}_IF_mtu').data), + 'ni_description': str(getattr(form, 'NI_description').data), + 'subif_description': str(getattr(form, f'Device_{device_num}_IF_description').data), + } + else: + raise ValueError(f'Unsupported form type: {form_type}') + + params_with_data = {k: v for k, v in device_params.items() if v is not None and str(v) != 'None' and v != ''} #Retrieve the params that do not have value (None or ' ') + return params_with_data diff --git a/src/webui/service/templates/service/add.html b/src/webui/service/templates/service/add.html new file mode 100644 index 000000000..2b03ebcbf --- /dev/null +++ b/src/webui/service/templates/service/add.html @@ -0,0 +1,53 @@ + +{% extends 'base.html' %} + +{% block content %} +

Add New Service

+
+
+ +
+ {{ form_1.hidden_tag() }} +
+
+ {{ form_1.service_type.label(class="col-sm-2 col-form-label") }} +
+ {% if form_1.service_type.errors %} + {{ form_1.service_type(class="form-control is-invalid") }} +
+ {% for error in form_1.service_type.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_1.service_type(class="form-control") }} + {% endif %} +
+
+ + + +
+
+{% endblock %} + diff --git a/src/webui/service/templates/service/configure_ACL_IPV4.html b/src/webui/service/templates/service/configure_ACL_IPV4.html new file mode 100644 index 000000000..43262ebee --- /dev/null +++ b/src/webui/service/templates/service/configure_ACL_IPV4.html @@ -0,0 +1,433 @@ + + +{% extends 'base.html' %} + +{% block content %} +

Add New Service [ACL-IPV4]

+
+
+
+ {{ form_acl.hidden_tag() }} +
+

Generic Service Parameters

+ {% if form_acl.acl_params is not none %} +
+ {{ form_acl.service_name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_name.errors %} + {{ form_acl.service_name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.service_type.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_type.errors %} + {{ form_acl.service_type(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_type.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_type(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.service_device_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_device_1.errors %} + {{ form_acl.service_device_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_device_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_device_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_acl.service_device_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_device_2.errors %} + {{ form_acl.service_device_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_device_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_device_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.service_endpoint_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_endpoint_1.errors %} + {{ form_acl.service_endpoint_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_endpoint_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_endpoint_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_acl.service_endpoint_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_endpoint_2.errors %} + {{ form_acl.service_endpoint_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_endpoint_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_endpoint_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+

Generic Service Constraints

+
+ {{ form_acl.service_capacity.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_capacity.errors %} + {{ form_acl.service_capacity(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_capacity.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_capacity(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.service_latency.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_latency.errors %} + {{ form_acl.service_latency(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_latency.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_latency(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.service_availability.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_availability.errors %} + {{ form_acl.service_availability(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_availability.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_availability(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.service_isolation.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_isolation.errors %} + {{ form_acl.service_isolation(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_isolation.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_isolation(class="form-control") }} + {% endif %} +
+
+
+

Specific Service Parameters

+
+

Generic ACL Parameters

+
+ {{ form_acl.name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.name.errors %} + {{ form_acl.name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.type.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.type.errors %} + {{ form_acl.type(class="form-control is-invalid") }} +
+ {% for error in form_acl.type.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.type(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.sequence_id.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.sequence_id.errors %} + {{ form_acl.sequence_id(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.sequence_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.sequence_id(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.forwarding_action.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.forwarding_action.errors %} + {{ form_acl.forwarding_action(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.forwarding_action.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.forwarding_action(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.log_action.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.log_action.errors %} + {{ form_acl.log_action(class="form-control is-invalid") }} +
+ {% for error in form_acl.log_action.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.log_action(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.traffic_flow.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.traffic_flow.errors %} + {{ form_acl.traffic_flow(class="form-control is-invalid") }} +
+ {% for error in form_acl.traffic_flow.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.traffic_flow(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.interface.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.interface.errors %} + {{ form_acl.interface(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.interface.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.interface(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.subinterface.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.subinterface.errors %} + {{ form_acl.subinterface(class="form-control is-invalid") }} +
+ {% for error in form_acl.subinterface.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.subinterface(class="form-control") }} + {% endif %} +
+
+
+

Specific ACL_IPV4 Parameters

+
+ {{ form_acl.source_address.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.source_address.errors %} + {{ form_acl.source_address(class="form-control is-invalid") }} +
+ {% for error in form_acl.source_address.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.source_address(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.destination_address.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.destination_address.errors %} + {{ form_acl.destination_address(class="form-control is-invalid") }} +
+ {% for error in form_acl.destination_address.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.destination_address(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.protocol.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.protocol.errors %} + {{ form_acl.protocol(class="form-control is-invalid") }} +
+ {% for error in form_acl.protocol.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.protocol(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.hop_limit.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.hop_limit.errors %} + {{ form_acl.hop_limit(class="form-control is-invalid") }} +
+ {% for error in form_acl.hop_limit.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.hop_limit(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.dscp.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.dscp.errors %} + {{ form_acl.dscp(class="form-control is-invalid") }} +
+ {% for error in form_acl.dscp.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.dscp(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.source_port.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.source_port.errors %} + {{ form_acl.source_port(class="form-control is-invalid") }} +
+ {% for error in form_acl.source_port.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.source_port(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.destination_port.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.destination_port.errors %} + {{ form_acl.destination_port(class="form-control is-invalid") }} +
+ {% for error in form_acl.destination_port.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.destination_port(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.tcp_flags.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.tcp_flags.errors %} + {{ form_acl.tcp_flags(class="form-control is-invalid") }} +
+ {% for error in form_acl.tcp_flags.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.tcp_flags(class="form-control") }} + {% endif %} +
+
+ {% endif %} + + +
+
+ {% endblock %} diff --git a/src/webui/service/templates/service/configure_ACL_IPV6.html b/src/webui/service/templates/service/configure_ACL_IPV6.html new file mode 100644 index 000000000..2fb2efbc6 --- /dev/null +++ b/src/webui/service/templates/service/configure_ACL_IPV6.html @@ -0,0 +1,388 @@ + + +{% extends 'base.html' %} + +{% block content %} +

Add New Service [ACL-IPV6]

+
+
+
+ {{ form_acl.hidden_tag() }} +
+

Generic Service Parameters

+ {% if form_acl.acl_params is not none %} +
+ {{ form_acl.service_name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_name.errors %} + {{ form_acl.service_name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.service_type.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_type.errors %} + {{ form_acl.service_type(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_type.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_type(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.service_device_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_device_1.errors %} + {{ form_acl.service_device_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_device_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_device_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_acl.service_device_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_device_2.errors %} + {{ form_acl.service_device_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_device_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_device_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.service_endpoint_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_endpoint_1.errors %} + {{ form_acl.service_endpoint_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_endpoint_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_endpoint_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_acl.service_endpoint_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_endpoint_2.errors %} + {{ form_acl.service_endpoint_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_endpoint_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_endpoint_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+

Generic Service Constraints

+
+ {{ form_acl.service_capacity.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_capacity.errors %} + {{ form_acl.service_capacity(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_capacity.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_capacity(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.service_latency.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_latency.errors %} + {{ form_acl.service_latency(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_latency.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_latency(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.service_availability.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_availability.errors %} + {{ form_acl.service_availability(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_availability.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_availability(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.service_isolation.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_isolation.errors %} + {{ form_acl.service_isolation(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_isolation.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_isolation(class="form-control") }} + {% endif %} +
+
+
+

Specific Service Parameters

+
+

Generic ACL Parameters

+
+ {{ form_acl.name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.name.errors %} + {{ form_acl.name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.type.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.type.errors %} + {{ form_acl.type(class="form-control is-invalid") }} +
+ {% for error in form_acl.type.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.type(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.sequence_id.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.sequence_id.errors %} + {{ form_acl.sequence_id(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.sequence_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.sequence_id(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.forwarding_action.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.forwarding_action.errors %} + {{ form_acl.forwarding_action(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.forwarding_action.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.forwarding_action(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.log_action.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.log_action.errors %} + {{ form_acl.log_action(class="form-control is-invalid") }} +
+ {% for error in form_acl.log_action.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.log_action(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.traffic_flow.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.traffic_flow.errors %} + {{ form_acl.traffic_flow(class="form-control is-invalid") }} +
+ {% for error in form_acl.traffic_flow.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.traffic_flow(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.interface.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.interface.errors %} + {{ form_acl.interface(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.interface.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.interface(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.subinterface.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.subinterface.errors %} + {{ form_acl.subinterface(class="form-control is-invalid") }} +
+ {% for error in form_acl.subinterface.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.subinterface(class="form-control") }} + {% endif %} +
+
+
+

Specific ACL_IPV6 Parameters

+
+ {{ form_acl.source_address.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.source_address.errors %} + {{ form_acl.source_address(class="form-control is-invalid") }} +
+ {% for error in form_acl.source_address.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.source_address(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.destination_address.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.destination_address.errors %} + {{ form_acl.destination_address(class="form-control is-invalid") }} +
+ {% for error in form_acl.destination_address.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.destination_address(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.protocol.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.protocol.errors %} + {{ form_acl.protocol(class="form-control is-invalid") }} +
+ {% for error in form_acl.protocol.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.protocol(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.hop_limit.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.hop_limit.errors %} + {{ form_acl.hop_limit(class="form-control is-invalid") }} +
+ {% for error in form_acl.hop_limit.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.hop_limit(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.dscp.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.dscp.errors %} + {{ form_acl.dscp(class="form-control is-invalid") }} +
+ {% for error in form_acl.dscp.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.dscp(class="form-control") }} + {% endif %} +
+
+ {% endif %} + + +
+
+ {% endblock %} diff --git a/src/webui/service/templates/service/configure_ACL_L2.html b/src/webui/service/templates/service/configure_ACL_L2.html new file mode 100644 index 000000000..41cd70547 --- /dev/null +++ b/src/webui/service/templates/service/configure_ACL_L2.html @@ -0,0 +1,343 @@ + + +{% extends 'base.html' %} + +{% block content %} +

Add New Service [ACL-L2]

+
+
+
+ {{ form_acl.hidden_tag() }} +
+

Generic Service Parameters

+ {% if form_acl.acl_params is not none %} +
+ {{ form_acl.service_name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_name.errors %} + {{ form_acl.service_name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.service_type.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_type.errors %} + {{ form_acl.service_type(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_type.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_type(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.service_device_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_device_1.errors %} + {{ form_acl.service_device_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_device_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_device_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_acl.service_device_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_device_2.errors %} + {{ form_acl.service_device_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_device_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_device_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.service_endpoint_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_endpoint_1.errors %} + {{ form_acl.service_endpoint_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_endpoint_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_endpoint_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_acl.service_endpoint_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_endpoint_2.errors %} + {{ form_acl.service_endpoint_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.service_endpoint_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_endpoint_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+

Generic Service Constraints

+
+ {{ form_acl.service_capacity.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_capacity.errors %} + {{ form_acl.service_capacity(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_capacity.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_capacity(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.service_latency.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_latency.errors %} + {{ form_acl.service_latency(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_latency.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_latency(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.service_availability.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_availability.errors %} + {{ form_acl.service_availability(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_availability.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_availability(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.service_isolation.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.service_isolation.errors %} + {{ form_acl.service_isolation(class="form-control is-invalid") }} +
+ {% for error in form_acl.service_isolation.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.service_isolation(class="form-control") }} + {% endif %} +
+
+
+

Specific Service Parameters

+
+

Generic ACL Parameters

+
+ {{ form_acl.name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.name.errors %} + {{ form_acl.name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.type.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.type.errors %} + {{ form_acl.type(class="form-control is-invalid") }} +
+ {% for error in form_acl.type.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.type(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.sequence_id.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.sequence_id.errors %} + {{ form_acl.sequence_id(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.sequence_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.sequence_id(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.forwarding_action.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.forwarding_action.errors %} + {{ form_acl.forwarding_action(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.forwarding_action.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.forwarding_action(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.log_action.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.log_action.errors %} + {{ form_acl.log_action(class="form-control is-invalid") }} +
+ {% for error in form_acl.log_action.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.log_action(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.traffic_flow.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.traffic_flow.errors %} + {{ form_acl.traffic_flow(class="form-control is-invalid") }} +
+ {% for error in form_acl.traffic_flow.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.traffic_flow(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.interface.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.interface.errors %} + {{ form_acl.interface(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_acl.interface.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.interface(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_acl.subinterface.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.subinterface.errors %} + {{ form_acl.subinterface(class="form-control is-invalid") }} +
+ {% for error in form_acl.subinterface.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.subinterface(class="form-control") }} + {% endif %} +
+
+
+

Specific ACL_L2 Parameters

+
+ {{ form_acl.source_mac.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.source_mac.errors %} + {{ form_acl.source_mac(class="form-control is-invalid") }} +
+ {% for error in form_acl.source_mac.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.source_mac(class="form-control") }} + {% endif %} +
+
+
+ {{ form_acl.destination_mac.label(class="col-sm-2 col-form-label") }} +
+ {% if form_acl.destination_mac.errors %} + {{ form_acl.destination_mac(class="form-control is-invalid") }} +
+ {% for error in form_acl.destination_mac.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_acl.destination_mac(class="form-control") }} + {% endif %} +
+
+ {% endif %} + + +
+
+ {% endblock %} diff --git a/src/webui/service/templates/service/configure_L2VPN.html b/src/webui/service/templates/service/configure_L2VPN.html new file mode 100644 index 000000000..c443a024d --- /dev/null +++ b/src/webui/service/templates/service/configure_L2VPN.html @@ -0,0 +1,434 @@ + + +{% extends 'base.html' %} + +{% block content %} +

Add New Service [L2VPN]

+
+
+
+ {{ form_l2vpn.hidden_tag() }} +
+ {% if form_l2vpn.l2vpn_params is not none %} +

Generic Service Parameters

+
+ {{ form_l2vpn.service_name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_name.errors %} + {{ form_l2vpn.service_name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.service_name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l2vpn.service_type.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_type.errors %} + {{ form_l2vpn.service_type(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.service_type.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_type(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l2vpn.service_device_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_device_1.errors %} + {{ form_l2vpn.service_device_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.service_device_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_device_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l2vpn.service_device_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_device_2.errors %} + {{ form_l2vpn.service_device_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.service_device_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_device_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l2vpn.service_endpoint_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_endpoint_1.errors %} + {{ form_l2vpn.service_endpoint_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.service_endpoint_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_endpoint_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l2vpn.service_endpoint_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_endpoint_2.errors %} + {{ form_l2vpn.service_endpoint_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.service_endpoint_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_endpoint_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+

Generic Service Constraints

+
+ {{ form_l2vpn.service_capacity.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_capacity.errors %} + {{ form_l2vpn.service_capacity(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.service_capacity.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_capacity(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l2vpn.service_latency.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_latency.errors %} + {{ form_l2vpn.service_latency(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.service_latency.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_latency(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l2vpn.service_availability.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_availability.errors %} + {{ form_l2vpn.service_availability(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.service_availability.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_availability(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l2vpn.service_isolation.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.service_isolation.errors %} + {{ form_l2vpn.service_isolation(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.service_isolation.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.service_isolation(class="form-control") }} + {% endif %} +
+
+
+

Specific Service Parameters

+
+

Network Instance (NI) Parameters

+
+ {{ form_l2vpn.NI_name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.NI_name.errors %} + {{ form_l2vpn.NI_name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.NI_name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.NI_name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l2vpn.NI_mtu.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.NI_mtu.errors %} + {{ form_l2vpn.NI_mtu(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.NI_mtu.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.NI_mtu(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l2vpn.NI_description.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.NI_description.errors %} + {{ form_l2vpn.NI_description(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.NI_description.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.NI_description(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l2vpn.Device_1_NI_remote_system.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_1_NI_remote_system.errors %} + {{ form_l2vpn.Device_1_NI_remote_system(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_1_NI_remote_system.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_1_NI_remote_system(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l2vpn.Device_2_NI_remote_system.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_2_NI_remote_system.errors %} + {{ form_l2vpn.Device_2_NI_remote_system(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_2_NI_remote_system.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_2_NI_remote_system(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l2vpn.Device_1_NI_VC_ID.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_1_NI_VC_ID.errors %} + {{ form_l2vpn.Device_1_NI_VC_ID(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_1_NI_VC_ID.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_1_NI_VC_ID(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l2vpn.Device_2_NI_VC_ID.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_2_NI_VC_ID.errors %} + {{ form_l2vpn.Device_2_NI_VC_ID(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_2_NI_VC_ID.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_2_NI_VC_ID(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l2vpn.Device_1_NI_connection_point.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_1_NI_connection_point.errors %} + {{ form_l2vpn.Device_1_NI_connection_point(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_1_NI_connection_point.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_1_NI_connection_point(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l2vpn.Device_2_NI_connection_point.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_2_NI_connection_point.errors %} + {{ form_l2vpn.Device_2_NI_connection_point(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_2_NI_connection_point.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_2_NI_connection_point(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+ +

Interface Parameters

+
+ {{ form_l2vpn.Device_1_IF_index.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_1_IF_index.errors %} + {{ form_l2vpn.Device_1_IF_index(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_1_IF_index.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_1_IF_index(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l2vpn.Device_2_IF_index.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_2_IF_index.errors %} + {{ form_l2vpn.Device_2_IF_index(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_2_IF_index.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_2_IF_index(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l2vpn.Device_1_IF_vlan_id.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_1_IF_vlan_id.errors %} + {{ form_l2vpn.Device_1_IF_vlan_id(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_1_IF_vlan_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_1_IF_vlan_id(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l2vpn.Device_2_IF_vlan_id.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_2_IF_vlan_id.errors %} + {{ form_l2vpn.Device_2_IF_vlan_id(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l2vpn.Device_2_IF_vlan_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_2_IF_vlan_id(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l2vpn.Device_1_IF_mtu.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_1_IF_mtu.errors %} + {{ form_l2vpn.Device_1_IF_mtu(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.Device_1_IF_mtu.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_1_IF_mtu(class="form-control") }} + {% endif %} +
+ {{ form_l2vpn.Device_2_IF_mtu.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_2_IF_mtu.errors %} + {{ form_l2vpn.Device_2_IF_mtu(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.Device_2_IF_mtu.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_2_IF_mtu(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l2vpn.Device_1_IF_description.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_1_IF_description.errors %} + {{ form_l2vpn.Device_1_IF_description(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.Device_1_IF_description.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_1_IF_description(class="form-control") }} + {% endif %} +
+ {{ form_l2vpn.Device_2_IF_description.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l2vpn.Device_2_IF_description.errors %} + {{ form_l2vpn.Device_2_IF_description(class="form-control is-invalid") }} +
+ {% for error in form_l2vpn.Device_2_IF_description.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l2vpn.Device_2_IF_description(class="form-control") }} + {% endif %} +
+
+ {% endif %} + + + +
+
+{% endblock %} \ No newline at end of file diff --git a/src/webui/service/templates/service/configure_L3VPN.html b/src/webui/service/templates/service/configure_L3VPN.html new file mode 100644 index 000000000..575eec10a --- /dev/null +++ b/src/webui/service/templates/service/configure_L3VPN.html @@ -0,0 +1,510 @@ + + +{% extends 'base.html' %} + +{% block content %} +

Add New Service [L3VPN]

+
+
+
+ {{ form_l3vpn.hidden_tag() }} +
+ {% if form_l3vpn.l3vpn_params is not none %} +

Generic Service Parameters

+
+ {{ form_l3vpn.service_name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_name.errors %} + {{ form_l3vpn.service_name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.service_name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.service_type.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_type.errors %} + {{ form_l3vpn.service_type(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.service_type.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_type(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.service_device_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_device_1.errors %} + {{ form_l3vpn.service_device_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.service_device_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_device_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l3vpn.service_device_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_device_2.errors %} + {{ form_l3vpn.service_device_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.service_device_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_device_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.service_endpoint_1.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_endpoint_1.errors %} + {{ form_l3vpn.service_endpoint_1(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.service_endpoint_1.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_endpoint_1(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l3vpn.service_endpoint_2.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_endpoint_2.errors %} + {{ form_l3vpn.service_endpoint_2(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.service_endpoint_2.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_endpoint_2(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+

Generic Service Constraints

+
+ {{ form_l3vpn.service_capacity.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_capacity.errors %} + {{ form_l3vpn.service_capacity(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.service_capacity.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_capacity(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l3vpn.service_latency.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_latency.errors %} + {{ form_l3vpn.service_latency(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.service_latency.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_latency(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l3vpn.service_availability.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_availability.errors %} + {{ form_l3vpn.service_availability(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.service_availability.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_availability(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l3vpn.service_isolation.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.service_isolation.errors %} + {{ form_l3vpn.service_isolation(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.service_isolation.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.service_isolation(class="form-control") }} + {% endif %} +
+
+
+

Specific Service Parameters

+
+

Network Instance Parameters

+
+ {{ form_l3vpn.NI_name.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_name.errors %} + {{ form_l3vpn.NI_name(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.NI_name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_name(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.NI_route_distinguisher.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_route_distinguisher.errors %} + {{ form_l3vpn.NI_route_distinguisher(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.NI_route_distinguisher.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_route_distinguisher(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.NI_protocol.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_protocol.errors %} + {{ form_l3vpn.NI_protocol(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.NI_protocol.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_protocol(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.NI_as.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_as.errors %} + {{ form_l3vpn.NI_as(class="form-control is-invalid", placeholder="Mandatory if BGP protocol is selected") }} +
+ {% for error in form_l3vpn.NI_as.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_as(class="form-control", placeholder="Mandatory if BGP protocol is selected") }} + {% endif %} +
+
+
+ {{ form_l3vpn.NI_address_family.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_address_family.errors %} + {{ form_l3vpn.NI_address_family(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.NI_address_family.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_address_family(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.NI_default_import_policy.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_default_import_policy.errors %} + {{ form_l3vpn.NI_default_import_policy(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.NI_default_import_policy.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_default_import_policy(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l3vpn.NI_import_policy.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_import_policy.errors %} + {{ form_l3vpn.NI_import_policy(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.NI_import_policy.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_import_policy(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.NI_export_policy.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_export_policy.errors %} + {{ form_l3vpn.NI_export_policy(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.NI_export_policy.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_export_policy(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.NI_router_id.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_router_id.errors %} + {{ form_l3vpn.NI_router_id(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.NI_router_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_router_id(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l3vpn.NI_description.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.NI_description.errors %} + {{ form_l3vpn.NI_description(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.NI_description.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.NI_description(class="form-control") }} + {% endif %} +
+
+

Interface Parameters

+
+ {{ form_l3vpn.Device_1_IF_index.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_1_IF_index.errors %} + {{ form_l3vpn.Device_1_IF_index(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.Device_1_IF_index.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_1_IF_index(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l3vpn.Device_2_IF_index.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_2_IF_index.errors %} + {{ form_l3vpn.Device_2_IF_index(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.Device_2_IF_index.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_2_IF_index(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.Device_1_IF_vlan_id.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_1_IF_vlan_id.errors %} + {{ form_l3vpn.Device_1_IF_vlan_id(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.Device_1_IF_vlan_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_1_IF_vlan_id(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l3vpn.Device_2_IF_vlan_id.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_2_IF_vlan_id.errors %} + {{ form_l3vpn.Device_2_IF_vlan_id(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.Device_2_IF_vlan_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_2_IF_vlan_id(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.Device_1_IF_address_ip.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_1_IF_address_ip.errors %} + {{ form_l3vpn.Device_1_IF_address_ip(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.Device_1_IF_address_ip.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_1_IF_address_ip(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l3vpn.Device_2_IF_address_ip.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_2_IF_address_ip.errors %} + {{ form_l3vpn.Device_2_IF_address_ip(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.Device_2_IF_address_ip.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_2_IF_address_ip(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.Device_1_IF_address_prefix.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_1_IF_address_prefix.errors %} + {{ form_l3vpn.Device_1_IF_address_prefix(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.Device_1_IF_address_prefix.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_1_IF_address_prefix(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+ {{ form_l3vpn.Device_2_IF_address_prefix.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_2_IF_address_prefix.errors %} + {{ form_l3vpn.Device_2_IF_address_prefix(class="form-control is-invalid", placeholder="Mandatory") }} +
+ {% for error in form_l3vpn.Device_2_IF_address_prefix.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_2_IF_address_prefix(class="form-control", placeholder="Mandatory") }} + {% endif %} +
+
+
+ {{ form_l3vpn.Device_1_IF_mtu.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_1_IF_mtu.errors %} + {{ form_l3vpn.Device_1_IF_mtu(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.Device_1_IF_mtu.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_1_IF_mtu(class="form-control") }} + {% endif %} +
+ {{ form_l3vpn.Device_2_IF_mtu.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_2_IF_mtu.errors %} + {{ form_l3vpn.Device_2_IF_mtu(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.Device_2_IF_mtu.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_2_IF_mtu(class="form-control") }} + {% endif %} +
+
+
+ {{ form_l3vpn.Device_1_IF_description.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_1_IF_description.errors %} + {{ form_l3vpn.Device_1_IF_description(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.Device_1_IF_description.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_1_IF_description(class="form-control") }} + {% endif %} +
+ {{ form_l3vpn.Device_2_IF_description.label(class="col-sm-2 col-form-label") }} +
+ {% if form_l3vpn.Device_2_IF_description.errors %} + {{ form_l3vpn.Device_2_IF_description(class="form-control is-invalid") }} +
+ {% for error in form_l3vpn.Device_2_IF_description.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form_l3vpn.Device_2_IF_description(class="form-control") }} + {% endif %} +
+
+ {% endif %} + + + +
+
+{% endblock %} \ No newline at end of file diff --git a/src/webui/service/templates/service/detail.html b/src/webui/service/templates/service/detail.html index 414aa19d0..9e83f05c4 100644 --- a/src/webui/service/templates/service/detail.html +++ b/src/webui/service/templates/service/detail.html @@ -215,6 +215,69 @@ {% endif %} + {% if config.WhichOneof('config_rule') == 'acl' %} + + + {% if config.acl %} + {% set endpoint_id = config.acl.endpoint_id %} + {% set rule_set_name = config.acl.rule_set.name %} + /device[{{ endpoint_id.device_id.device_uuid.uuid }}]/endpoint[{{ endpoint_id.endpoint_uuid.uuid }}]/acl_ruleset[{{ rule_set_name }}] + {% endif %} + + +
    + {% if config.acl.rule_set.name %} +
  • name: {{ config.acl.rule_set.name }}
  • + {% endif %} + {% if config.acl.rule_set.type %} +
  • type: {{ type[config.acl.rule_set.type] }}
  • + {% endif %} + {% if config.acl.rule_set.description %} +
  • description: {{ config.acl.rule_set.description }}
  • + {% endif %} + {% if config.acl.rule_set.user_id %} +
  • user_id: {{ config.acl.rule_set.user_id }}
  • + {% endif %} + {% for entry in config.acl.rule_set.entries %} + {% if entry.description %} +
  • entry {{ entry.sequence_id }} description: {{ entry.description }}
  • + {% endif %} + {% if entry.match.protocol %} +
  • entry {{ entry.sequence_id }} protocol: {{ entry.match.protocol }}
  • + {% endif %} + {% if entry.match.dscp %} +
  • entry {{ entry.sequence_id }} dscp:{{ entry.match.dscp }}
  • + {% endif %} + {% if entry.match.src_address %} +
  • entry {{ entry.sequence_id }} src_address: {{ entry.match.src_address }}
  • + {% endif %} + {% if entry.match.dst_address %} +
  • entry {{ entry.sequence_id }} dst_address: {{ entry.match.dst_address }}
  • + {% endif %} + {% if entry.match.src_port %} +
  • entry {{ entry.sequence_id }} src_port: {{ entry.match.src_port }}
  • + {% endif %} + {% if entry.match.dst_port %} +
  • entry {{ entry.sequence_id }} dst_port: {{ entry.match.dst_port }}
  • + {% endif %} + {% if entry.match.start_mpls_label %} +
  • entry {{ entry.sequence_id }} start mpls label: {{ entry.match.start_mpls_label }}
  • + {% endif %} + {% if entry.match.end_mpls_label %} +
  • entry {{ entry.sequence_id }} end mpls label: {{ entry.match.end_mpls_label }}
  • + {% endif %} + {% if entry.action.forward_action %} +
  • entry {{ entry.sequence_id }} forward_action: {{ f_action[entry.action.forward_action] }}
  • + {% endif %} + {% if entry.action.log_action %} +
  • entry {{ entry.sequence_id }} log_action: {{l_action[entry.action.log_action] }}
  • + {% endif %} + {% endfor %} + +
+ + + {% endif %} {% endfor %} diff --git a/src/webui/service/templates/service/home.html b/src/webui/service/templates/service/home.html index 00feaff59..a079dbd28 100644 --- a/src/webui/service/templates/service/home.html +++ b/src/webui/service/templates/service/home.html @@ -19,13 +19,13 @@ {% block content %}

Services

-
- + --> +
@@ -41,7 +41,7 @@
{{ services | length }} services found in context {{ session['context_uuid'] }}
- - -- GitLab From 045c52a3e9f1369044c5e74506b34cafd39ad941 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Mon, 15 Jan 2024 15:23:36 +0000 Subject: [PATCH 2/4] WebUI - Service Management form - Pre-merge clean-up --- deploy/webui.sh | 181 ----------------------------- src/webui/service/service/forms.py | 21 ++-- 2 files changed, 9 insertions(+), 193 deletions(-) delete mode 100755 deploy/webui.sh diff --git a/deploy/webui.sh b/deploy/webui.sh deleted file mode 100755 index 94cc12122..000000000 --- a/deploy/webui.sh +++ /dev/null @@ -1,181 +0,0 @@ -#!/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. - - -######################################################################################################################## -# Read deployment settings -######################################################################################################################## - - -# ----- TeraFlowSDN ------------------------------------------------------------ - -# If not already set, set the URL of the Docker registry where the images will be uploaded to. -# By default, assume internal MicroK8s registry is used. -export TFS_REGISTRY_IMAGES=${TFS_REGISTRY_IMAGES:-"http://localhost:32000/tfs/"} - -# If not already set, set the list of components, separated by spaces, you want to build images for, and deploy. -# By default, only basic components are deployed -export TFS_COMPONENTS=${TFS_COMPONENTS:-"context device service compute webui"} - -# If not already set, set the tag you want to use for your images. -export TFS_IMAGE_TAG=${TFS_IMAGE_TAG:-"dev"} - -# If not already set, set the name of the Kubernetes namespace to deploy TFS to. -export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"} - -# If not already set, set additional manifest files to be applied after the deployment -export TFS_EXTRA_MANIFESTS=${TFS_EXTRA_MANIFESTS:-""} - -# If not already set, set the new Grafana admin password -export TFS_GRAFANA_PASSWORD=${TFS_GRAFANA_PASSWORD:-"admin123+"} - -# If not already set, disable skip-build flag to rebuild the Docker images. -# If TFS_SKIP_BUILD is "YES", the containers are not rebuilt-retagged-repushed and existing ones are used. -export TFS_SKIP_BUILD=${TFS_SKIP_BUILD:-""} - - -# ----- CockroachDB ------------------------------------------------------------ - -# If not already set, set the namespace where CockroackDB will be deployed. -export CRDB_NAMESPACE=${CRDB_NAMESPACE:-"crdb"} - -# If not already set, set the external port CockroackDB Postgre SQL interface will be exposed to. -export CRDB_EXT_PORT_SQL=${CRDB_EXT_PORT_SQL:-"26257"} - -# If not already set, set the external port CockroackDB HTTP Mgmt GUI interface will be exposed to. -export CRDB_EXT_PORT_HTTP=${CRDB_EXT_PORT_HTTP:-"8081"} - -# If not already set, set the database username to be used by Context. -export CRDB_USERNAME=${CRDB_USERNAME:-"tfs"} - -# If not already set, set the database user's password to be used by Context. -export CRDB_PASSWORD=${CRDB_PASSWORD:-"tfs123"} - -# If not already set, set the database name to be used by Context. -export CRDB_DATABASE=${CRDB_DATABASE:-"tfs"} - -# If not already set, set CockroachDB installation mode. Accepted values are: 'single' and 'cluster'. -# "YES", the database pointed by variable CRDB_NAMESPACE will be dropped while -# checking/deploying CockroachDB. -# - If CRDB_DEPLOY_MODE is "single", CockroachDB is deployed in single node mode. It is convenient for -# development and testing purposes and should fit in a VM. IT SHOULD NOT BE USED IN PRODUCTION ENVIRONMENTS. -# - If CRDB_DEPLOY_MODE is "cluster", CockroachDB is deployed in cluster mode, and an entire CockroachDB cluster -# with 3 replicas and version v22.2 (set by default) will be deployed. It is convenient for production and -# provides scalability features. If you are deploying for production, also read the following link providing -# details on deploying CockroachDB for production environments: -# Ref: https://www.cockroachlabs.com/docs/stable/recommended-production-settings.html -export CRDB_DEPLOY_MODE=${CRDB_DEPLOY_MODE:-"single"} - -# If not already set, disable flag for dropping database, if it exists. -# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE DATABASE INFORMATION! -# If CRDB_DROP_DATABASE_IF_EXISTS is "YES", the database pointed by variable CRDB_NAMESPACE will be dropped while -# checking/deploying CockroachDB. -export CRDB_DROP_DATABASE_IF_EXISTS=${CRDB_DROP_DATABASE_IF_EXISTS:-""} - -# If not already set, disable flag for re-deploying CockroachDB from scratch. -# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE DATABASE INFORMATION! -# WARNING: THE REDEPLOY MIGHT TAKE FEW MINUTES TO COMPLETE GRACEFULLY IN CLUSTER MODE -# If CRDB_REDEPLOY is "YES", the database will be dropped while checking/deploying CockroachDB. -export CRDB_REDEPLOY=${CRDB_REDEPLOY:-""} - - -# ----- NATS ------------------------------------------------------------------- - -# If not already set, set the namespace where NATS will be deployed. -export NATS_NAMESPACE=${NATS_NAMESPACE:-"nats"} - -# If not already set, set the external port NATS Client interface will be exposed to. -export NATS_EXT_PORT_CLIENT=${NATS_EXT_PORT_CLIENT:-"4222"} - -# If not already set, set the external port NATS HTTP Mgmt GUI interface will be exposed to. -export NATS_EXT_PORT_HTTP=${NATS_EXT_PORT_HTTP:-"8222"} - -# If not already set, disable flag for re-deploying NATS from scratch. -# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE MESSAGE BROKER INFORMATION! -# If NATS_REDEPLOY is "YES", the message broker will be dropped while checking/deploying NATS. -export NATS_REDEPLOY=${NATS_REDEPLOY:-""} - - -# ----- QuestDB ---------------------------------------------------------------- - -# If not already set, set the namespace where QuestDB will be deployed. -export QDB_NAMESPACE=${QDB_NAMESPACE:-"qdb"} - -# If not already set, set the external port QuestDB Postgre SQL interface will be exposed to. -export QDB_EXT_PORT_SQL=${QDB_EXT_PORT_SQL:-"8812"} - -# If not already set, set the external port QuestDB Influx Line Protocol interface will be exposed to. -export QDB_EXT_PORT_ILP=${QDB_EXT_PORT_ILP:-"9009"} - -# If not already set, set the external port QuestDB HTTP Mgmt GUI interface will be exposed to. -export QDB_EXT_PORT_HTTP=${QDB_EXT_PORT_HTTP:-"9000"} - -# If not already set, set the database username to be used for QuestDB. -export QDB_USERNAME=${QDB_USERNAME:-"admin"} - -# If not already set, set the database user's password to be used for QuestDB. -export QDB_PASSWORD=${QDB_PASSWORD:-"quest"} - -# If not already set, set the table name to be used by Monitoring for KPIs. -export QDB_TABLE_MONITORING_KPIS=${QDB_TABLE_MONITORING_KPIS:-"tfs_monitoring_kpis"} - -# If not already set, set the table name to be used by Slice for plotting groups. -export QDB_TABLE_SLICE_GROUPS=${QDB_TABLE_SLICE_GROUPS:-"tfs_slice_groups"} - -# If not already set, disable flag for dropping tables if they exist. -# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE TABLE INFORMATION! -# If QDB_DROP_TABLES_IF_EXIST is "YES", the tables pointed by variables -# QDB_TABLE_MONITORING_KPIS and QDB_TABLE_SLICE_GROUPS will be dropped while -# checking/deploying QuestDB. -export QDB_DROP_TABLES_IF_EXIST=${QDB_DROP_TABLES_IF_EXIST:-""} - -# If not already set, disable flag for re-deploying QuestDB from scratch. -# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE DATABASE INFORMATION! -# If QDB_REDEPLOY is "YES", the database will be dropped while checking/deploying QuestDB. -export QDB_REDEPLOY=${QDB_REDEPLOY:-""} - - -# ----- K8s Observability ------------------------------------------------------ - -# If not already set, set the external port Prometheus Mgmt HTTP GUI interface will be exposed to. -export PROM_EXT_PORT_HTTP=${PROM_EXT_PORT_HTTP:-"9090"} - -# If not already set, set the external port Grafana HTTP Dashboards will be exposed to. -export GRAF_EXT_PORT_HTTP=${GRAF_EXT_PORT_HTTP:-"3000"} - - -######################################################################################################################## -# Automated steps start here -######################################################################################################################## - -# Deploy CockroachDB -./deploy/crdb.sh - -# Deploy NATS -./deploy/nats.sh - -# Deploy QuestDB -./deploy/qdb.sh - -# Expose Dashboard -./deploy/expose_dashboard.sh - -# Deploy TeraFlowSDN -./deploy/tfs.sh - -# Show deploy summary -./deploy/show.sh - -echo "Done!" diff --git a/src/webui/service/service/forms.py b/src/webui/service/service/forms.py index 52fc68302..5105df79e 100644 --- a/src/webui/service/service/forms.py +++ b/src/webui/service/service/forms.py @@ -12,17 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -import re +import ipaddress, re from flask import flash, Flask from flask_wtf import FlaskForm from wtforms import StringField, SelectField, IntegerField, DecimalField from wtforms.validators import InputRequired, Optional, NumberRange, ValidationError, StopValidation -#from common.proto.context_pb2 import DeviceOperationalStatusEnum -import ipaddress -def validate_ipv4_address(form, field): #Custom validator for ensuring a valid IPv4 address is submitted - # Check for a valid IPv4 address - # print(field.data) +# Custom IPv4 address validator +def validate_ipv4_address(form, field): try: ipaddress.IPv4Address(field.data) except ipaddress.AddressValueError: @@ -53,12 +50,12 @@ def validate_NI_as(form, field): #Custom validator that check if form.NI_protocol.data == 'BGP' and field.data == None: raise StopValidation('AS field is required if the BGP protocol is selected.') -def validator_ADVA(form, field): - if field.name == 'Device_1_NI_VC_ID' and form.Device_1_IF_vendor.data == 'ADVA' and form.Device_1_NI_VC_ID.data != form.Device_1_IF_vlan_id.data: - raise StopValidation('For the ADVA vendor, it is mandatory that the VC_ID is the same as the Vlan_ID.') - - if field.name == 'Device_2_NI_VC_ID' and form.Device_2_IF_vendor.data == 'ADVA' and form.Device_2_NI_VC_ID.data != form.Device_2_IF_vlan_id.data: - raise StopValidation('For the ADVA vendor, it is mandatory that the VC_ID is the same as the Vlan_ID.') +#def validator_ADVA(form, field): +# if field.name == 'Device_1_NI_VC_ID' and form.Device_1_IF_vendor.data == 'ADVA' and form.Device_1_NI_VC_ID.data != form.Device_1_IF_vlan_id.data: +# raise StopValidation('For the ADVA vendor, it is mandatory that the VC_ID is the same as the Vlan_ID.') +# +# if field.name == 'Device_2_NI_VC_ID' and form.Device_2_IF_vendor.data == 'ADVA' and form.Device_2_NI_VC_ID.data != form.Device_2_IF_vlan_id.data: +# raise StopValidation('For the ADVA vendor, it is mandatory that the VC_ID is the same as the Vlan_ID.') -- GitLab From 14bb71634a6f3a7a29cff9d5a3a7a4d88b43491c Mon Sep 17 00:00:00 2001 From: armingol Date: Mon, 15 Jan 2024 15:48:13 +0000 Subject: [PATCH 3/4] Pre Merge -Code cleanup --- src/webui/service/service/forms.py | 334 ++++++++---------- src/webui/service/service/routes.py | 263 +++++++------- .../service/templates/service/detail.html | 9 +- src/webui/service/templates/service/home.html | 14 +- 4 files changed, 276 insertions(+), 344 deletions(-) diff --git a/src/webui/service/service/forms.py b/src/webui/service/service/forms.py index 5105df79e..80476870a 100644 --- a/src/webui/service/service/forms.py +++ b/src/webui/service/service/forms.py @@ -13,7 +13,6 @@ # limitations under the License. import ipaddress, re -from flask import flash, Flask from flask_wtf import FlaskForm from wtforms import StringField, SelectField, IntegerField, DecimalField from wtforms.validators import InputRequired, Optional, NumberRange, ValidationError, StopValidation @@ -25,75 +24,71 @@ def validate_ipv4_address(form, field): except ipaddress.AddressValueError: raise ValidationError('Invalid IPv4 address format') -def validate_ipv6_address(form, field): #Custom validator for ensuring a valid IPv6 address is submitted - # Check for a valid IPv6 address +# Custom IPv6 address validator +def validate_ipv6_address(form, field): try: ipaddress.IPv6Address(field.data) except ipaddress.AddressValueError: raise ValidationError('Invalid IPv6 address format') - -def validate_mac_address(form, field): #Custom validator for ensuring a valid MAC address is submitted - # Check for a valid MAC [L2] address + +# Custom Mac address validator +def validate_mac_address(form, field): if not re.match(r'^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$', field.data): raise ValidationError('Invalid MAC address format') -def validate_route_distinguisher(form,field): #Custom validator for the input of Route Distinguisher value +# Custom route distinguisher validator +def validate_route_distinguisher(form,field): pattern = r'^([0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]):([0-9]|[1-9][0-9]{1,8}|[1-3][0-9]{9}|4[01][0-9]{8}|42[0-8][0-9]{7}|429[0-3][0-9]{6}|4294[0-8][0-9]{5}|42949[0-5][0-9]{4}|429496[0-6][0-9]{3}|4294967[01][0-9]{2}|42949672[0-8][0-9]|429496729[0-5])$' if not re.match(pattern, field.data): raise ValidationError('Invalid Route Distinguisher') -def validate_uint32(form, field): #Custom validator for ensuring uint32 integers +# Custom integer validator +def validate_uint32(form, field): if not 0 <= field.data <= 2**32-1: raise ValidationError('Value must be a positive integer within the range of uint32') -def validate_NI_as(form, field): #Custom validator that checks if NI_protocol_name is BGP and NI_as is not provided +# Custom BGP AS validator +def validate_NI_as(form, field): if form.NI_protocol.data == 'BGP' and field.data == None: raise StopValidation('AS field is required if the BGP protocol is selected.') - -#def validator_ADVA(form, field): -# if field.name == 'Device_1_NI_VC_ID' and form.Device_1_IF_vendor.data == 'ADVA' and form.Device_1_NI_VC_ID.data != form.Device_1_IF_vlan_id.data: -# raise StopValidation('For the ADVA vendor, it is mandatory that the VC_ID is the same as the Vlan_ID.') -# -# if field.name == 'Device_2_NI_VC_ID' and form.Device_2_IF_vendor.data == 'ADVA' and form.Device_2_NI_VC_ID.data != form.Device_2_IF_vlan_id.data: -# raise StopValidation('For the ADVA vendor, it is mandatory that the VC_ID is the same as the Vlan_ID.') - - -class CustomInputRequired(): #Custom validator that ensures that the required data is provided - def __init__(self, message=None): #Define a constructor that takes an optional message parameter - self.message = message or "This field is required." #If message is provided, use it. Otherwise, set a default message. - - def __call__(self, form, field): #Define a __call__ method that takes in the form and field to be validated - if field.data is None or field.data == '': #Check if the field data is empty or None - raise StopValidation(self.message) #If the data is empty or None, raise a StopValidation exception with the provided message +class CustomInputRequired(): + def __init__(self, message=None): + self.message = message or "This field is required." + def __call__(self, form, field): + if field.data is None or field.data == '': + raise StopValidation(self.message) -class AddServiceForm_1(FlaskForm): #Form-1 - Formulary Fields -> Select the type of new service to add +class AddServiceForm_1(FlaskForm): service_type = SelectField('Type of service', choices=[('', 'Select a type of service to add'), ('ACL_L2', 'ACL_L2'), ('ACL_IPV4', 'ACL_IPV4'), ('ACL_IPV6', 'ACL_IPV6'), ('L2VPN', 'L2VPN'), ('L3VPN', 'L3VPN')], validators=[InputRequired()]) -class AddServiceForm_ACL_L2(FlaskForm): #ACL_L2 - Formulary Fields +class AddServiceForm_ACL_L2(FlaskForm): #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) - service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - service_type = SelectField('Service Type', choices=[(2, '2 (L2NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L3NM - service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + service_name = StringField('Service Name', validators=[CustomInputRequired()]) + service_type = SelectField('Service Type', choices=[(2, '2 (L2NM)')], validators=[CustomInputRequired()]) + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) - service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), + ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), + ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), + ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) #MANDATORY_PARAMETERS - name = StringField('ACL Name', validators=[CustomInputRequired("The name of the ACL is a mandatory parameter")]) #MANDATORY PARAMETER - type = SelectField('ACL Type', choices=[('ACL_L2', 'ACL_L2')], validators=[CustomInputRequired("The type of the ACL is a mandatory parameter")]) #MANDATORY PARAMETER - sequence_id = IntegerField('ACL Sequence ID', validators=[CustomInputRequired("The name of the Sequence ID of the ACL is a mandatory parameter"), validate_uint32]) #MANDATORY PARAMETER + name = StringField('ACL Name', validators=[CustomInputRequired("The name of the ACL is a mandatory parameter")]) + type = SelectField('ACL Type', choices=[('ACL_L2', 'ACL_L2')], validators=[CustomInputRequired("The type of the ACL is a mandatory parameter")]) + sequence_id = IntegerField('ACL Sequence ID', validators=[CustomInputRequired("The name of the Sequence ID of the ACL is a mandatory parameter"), validate_uint32]) forwarding_action = SelectField('ACL Fowarding Action', choices=[('', 'Select an action (Mandatory)'), ('ACCEPT', 'Accept'), ('DROP','Drop'),('REJECT','Reject')], validators=[CustomInputRequired("The Forwarding Action of the ACL is a mandatory parameter")]) log_action = SelectField('ACL Log Action', choices=[(None, 'Select a log action (Optional)'), ('LOG_SYSLOG', 'Syslog'), ('LOG_NONE','None')], validators=[Optional()]) #PARAMETERS FOR Associating ACL to IF - interface = StringField('Interface Name', validators=[CustomInputRequired("The name of the Interface is a mandatory parameter")]) #MANDATORY PARAMETER + interface = StringField('Interface Name', validators=[CustomInputRequired("The name of the Interface is a mandatory parameter")]) subinterface = StringField('Subinterface Index', validators=[Optional()]) traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[CustomInputRequired("The direction of the traffic flow is a mandatory parameter")]) #MANDATORY PARAMETER @@ -101,192 +96,167 @@ class AddServiceForm_ACL_L2(FlaskForm): #ACL_L2 - Formulary Field source_mac = StringField('Source MAC Address', validators=[Optional(), validate_mac_address]) destination_mac = StringField('Destination MAC Address', validators=[Optional(), validate_mac_address]) -class AddServiceForm_ACL_IPV4(FlaskForm): #ACL_IPV4 - Formulary Fields +class AddServiceForm_ACL_IPV4(FlaskForm): #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) - service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - service_type = SelectField('Service Type', choices=[(1, '1 (L3NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L3NM - service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + service_name = StringField('Service Name', validators=[CustomInputRequired()]) + service_type = SelectField('Service Type', choices=[(1, '1 (L3NM)')], validators=[CustomInputRequired()]) + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) - service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), + ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), + ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), + ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) #MANDATORY_PARAMETERS - name = StringField('ACL Name', validators=[CustomInputRequired("The name of the ACL is a mandatory parameter")]) #MANDATORY PARAMETER - type = SelectField('ACL Type', choices=[('ACL_IPV4', 'ACL_IPV4')], validators=[CustomInputRequired("The type of the ACL is a mandatory parameter")]) #MANDATORY PARAMETER - sequence_id = IntegerField('ACL Sequence ID', validators=[InputRequired(), NumberRange(min=1, message="Sequence ID must be greater than 0")]) #MANDATORY PARAMETER #MANDATORY PARAMETER + name = StringField('ACL Name', validators=[CustomInputRequired("The name of the ACL is a mandatory parameter")]) + type = SelectField('ACL Type', choices=[('ACL_IPV4', 'ACL_IPV4')], validators=[CustomInputRequired("The type of the ACL is a mandatory parameter")]) + sequence_id = IntegerField('ACL Sequence ID', validators=[InputRequired(), NumberRange(min=1, message="Sequence ID must be greater than 0")]) forwarding_action = SelectField('ACL Fowarding Action', choices=[(None, 'Select an action (Mandatory)'), ('ACCEPT', 'Accept'), ('DROP','Drop'),('REJECT','Reject')], validators=[InputRequired()]) log_action = SelectField('ACL Log Action', choices=[(None, 'Select a log action (Optional)'), ('LOG_SYSLOG', 'Syslog'), ('LOG_NONE','None')], validators=[Optional()]) #PARAMETERS FOR Associating ACL to IF - interface = StringField('Interface Name', validators=[InputRequired()]) #MANDATORY PARAMETER + interface = StringField('Interface Name', validators=[InputRequired()]) subinterface = StringField('Subinterface Index', validators=[Optional()]) - traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[InputRequired()]) #MANDATORY PARAMETER + traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[InputRequired()]) #OPTIONAL_PARAMETERS - Creating ACL Entry [ACL_IPV4] source_address = StringField('Source Address', validators=[Optional(), validate_ipv4_address]) destination_address = StringField('Destination Address', validators=[Optional(), validate_ipv4_address]) - protocol = IntegerField('Protocol', validators=[Optional(),NumberRange(min=1, max=255, message="Protocol number is between 1 and 255 as defined by IANA")]) #Protocols are defined from 1 - 255 as defined in IANA (https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) - hop_limit = IntegerField('Hop Limit', validators=[Optional(),NumberRange(min=1, max=255, message="The Hop limit value has to be between 0 and 255")]) #Max. value of Hop Limit = 255 - dscp = IntegerField('DSCP', validators=[Optional(),NumberRange(min=1, max=255, message="The DSCP value has to be between 0 and 63")]) #Max. value of DSCP = 63 - source_port = IntegerField('Source Port', validators=[Optional(),NumberRange(min=0, max=65535, message="The Port value has to be between 0 and 655535")]) #Range of existing ports in a PC - destination_port = IntegerField('Destination Port', validators=[Optional(),NumberRange(min=0, max=65535, message="The Port value has to be between 0 and 655535")]) #Range of existing ports in a PC - tcp_flags = SelectField('TCP Flags', choices=[(None, 'Select a TCP Flag (Optional)'),('TCP_SYN', 'TCP_SYN'),('TCP_ACK', 'TCP_ACK'),('TCP_RST', 'TCP_RST'),('TCP_FIN', 'TCP_FIN'),('TCP_PSH', 'TCP_PSH'),('TCP_URG', 'TCP_URG') ,('TCP_ECE', 'TCP_ECE'),('TCP_CWR', 'TCP_CWR')], validators=[Optional()]) + protocol = IntegerField('Protocol', validators=[Optional(),NumberRange(min=1, max=255, message="Protocol number is between 1 and 255 as defined by IANA")]) + hop_limit = IntegerField('Hop Limit', validators=[Optional(),NumberRange(min=1, max=255, message="The Hop limit value has to be between 0 and 255")]) + dscp = IntegerField('DSCP', validators=[Optional(),NumberRange(min=1, max=255, message="The DSCP value has to be between 0 and 63")]) + source_port = IntegerField('Source Port', validators=[Optional(),NumberRange(min=0, max=65535, message="The Port value has to be between 0 and 655535")]) + destination_port = IntegerField('Destination Port', validators=[Optional(),NumberRange(min=0, max=65535, message="The Port value has to be between 0 and 655535")]) + tcp_flags = SelectField('TCP Flags', choices=[(None, 'Select a TCP Flag (Optional)'),('TCP_SYN', 'TCP_SYN'),('TCP_ACK', 'TCP_ACK'),('TCP_RST', 'TCP_RST'),('TCP_FIN', 'TCP_FIN'), + ('TCP_PSH', 'TCP_PSH'),('TCP_URG', 'TCP_URG') ,('TCP_ECE', 'TCP_ECE'),('TCP_CWR', 'TCP_CWR')], validators=[Optional()]) -class AddServiceForm_ACL_IPV6(FlaskForm): #ACL_IPV6 - Formulary Fields +class AddServiceForm_ACL_IPV6(FlaskForm): #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) - service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - service_type = SelectField('Service Type', choices=[(1, '1 (L3NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L2NM - service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 + service_name = StringField('Service Name', validators=[CustomInputRequired()]) + service_type = SelectField('Service Type', choices=[(1, '1 (L3NM)')], validators=[CustomInputRequired()]) + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) - service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), + ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), + ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), + ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) #MANDATORY_PARAMETERS - name = StringField('ACL Name', validators=[InputRequired()]) #MANDATORY PARAMETER - type = SelectField('ACL Type', choices=[('ACL_IPV6', 'ACL_IPV6')], validators=[InputRequired()]) #MANDATORY PARAMETER - sequence_id = IntegerField('ACL Sequence ID', validators=[InputRequired(), NumberRange(min=1, message="Sequence ID must be greater than 0")]) #MANDATORY PARAMETER]) #MANDATORY PARAMETER + name = StringField('ACL Name', validators=[InputRequired()]) + type = SelectField('ACL Type', choices=[('ACL_IPV6', 'ACL_IPV6')], validators=[InputRequired()]) + sequence_id = IntegerField('ACL Sequence ID', validators=[InputRequired(), NumberRange(min=1, message="Sequence ID must be greater than 0")]) forwarding_action = SelectField('ACL Fowarding Action', choices=[(None, 'Select an action (Mandatory)'), ('ACCEPT', 'Accept'), ('DROP','Drop'),('REJECT','Reject')], validators=[InputRequired()]) log_action = SelectField('ACL Log Action', choices=[(None, 'Select a log action (Optional)'), ('LOG_SYSLOG', 'Syslog'), ('LOG_NONE','None')], validators=[Optional()]) #PARAMETERS FOR Associating ACL to IF - interface = StringField('Interface Name', validators=[InputRequired()]) #MANDATORY PARAMETER + interface = StringField('Interface Name', validators=[InputRequired()]) subinterface = StringField('Subinterface Index', validators=[Optional()]) - traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[InputRequired()]) #MANDATORY PARAMETER + traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[InputRequired()]) #SPECIFIC PARAMETERS - Creating ACL Entry [ACL_IPV6] source_address = StringField('Source Address', validators=[Optional(), validate_ipv6_address]) destination_address = StringField('Destination Address', validators=[Optional(), validate_ipv6_address]) - protocol = IntegerField('Protocol', validators=[Optional(),NumberRange(min=1, max=255, message="Protocol number is between 1 and 255 as defined by IANA")]) #Protocols are defined from 1 - 255 as defined in IANA (https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) - hop_limit = IntegerField('Hop Limit', validators=[Optional(),NumberRange(min=1, max=255, message="The Hop limit value has to be between 0 and 255")]) #Max. value of Hop Limit = 255 - dscp = IntegerField('DSCP', validators=[Optional(),NumberRange(min=1, max=255, message="The DSCP value has to be between 0 and 63")]) #Max. value of DSCP = 63 + protocol = IntegerField('Protocol', validators=[Optional(),NumberRange(min=1, max=255, message="Protocol number is between 1 and 255 as defined by IANA")]) + hop_limit = IntegerField('Hop Limit', validators=[Optional(),NumberRange(min=1, max=255, message="The Hop limit value has to be between 0 and 255")]) + dscp = IntegerField('DSCP', validators=[Optional(),NumberRange(min=1, max=255, message="The DSCP value has to be between 0 and 63")]) -class AddServiceForm_L2VPN(FlaskForm): #L2VPN - Formulary Fields +class AddServiceForm_L2VPN(FlaskForm): #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) - service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - service_type = SelectField('Service Type', choices=[(2, '2 (L2NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L2NM - service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - #Device_1_IF_vendor = SelectField ('Device_1 Vendor', choices=[('', 'Select a vendor (Mandatory)'),('ADVA', 'ADVA'), ('CISCO','CISCO'), ('Huawei', 'Huawei'),('Juniper', 'Juniper'),('Nokia', 'Nokia')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - #Device_2_IF_vendor = SelectField ('Device_2 Vendor', choices=[('', 'Select a vendor (Mandatory)'),('ADVA', 'ADVA'), ('CISCO','CISCO'), ('Huawei', 'Huawei'),('Juniper', 'Juniper'),('Nokia', 'Nokia')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - #Device_1_Template = SelectField ('Device_1 Template', choices=[('', 'Select a type of template (Mandatory)'),('Jinja', 'Jinja'), ('Pyangbind','Pyangbind')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - #Device_2_Template = SelectField ('Device_2 Template', choices=[('', 'Select a type of template (Mandatory)'),('Jinja', 'Jinja'), ('Pyangbind','Pyangbind')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - - + service_name = StringField('Service Name', validators=[CustomInputRequired()]) + service_type = SelectField('Service Type', choices=[(2, '2 (L2NM)')], validators=[CustomInputRequired()]) + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) + #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) - service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), + ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), + ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), + ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) - #NI parameters - #Common for the service - NI_name = StringField('NI Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - #NI_type = SelectField('NI Type', choices=[('L2VSI', 'L2VSI')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L2VSI - NI_mtu = IntegerField('NI MTU', default=1500, validators=[CustomInputRequired(), NumberRange(min=0, message="MTU value can't be negative")]) #MANDATORY PARAMETER - FIXED VALUE -> 1500 - NI_description = StringField('NI Description', validators=[Optional()]) #OPTIONAL PARAMETER + + NI_name = StringField('NI Name', validators=[CustomInputRequired()]) + NI_mtu = IntegerField('NI MTU', default=1500, validators=[CustomInputRequired(), NumberRange(min=0, message="MTU value can't be negative")]) + NI_description = StringField('NI Description', validators=[Optional()]) #Device_1 specific - #Device_1_NI_VC_ID = IntegerField('Device_1 NI VC_ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative"), validator_ADVA]) #MANDATORY PARAMETER - Device_1_NI_remote_system = StringField('Device_1 NI Remote System', validators=[CustomInputRequired(),validate_ipv4_address]) #MANDATORY PARAMETER - Device_1_NI_VC_ID = IntegerField('Device_1 NI VC ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative")]) #MANDATORY PARAMETER - Device_1_NI_connection_point = StringField('Device_1 NI Conection Point', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + Device_1_NI_remote_system = StringField('Device_1 NI Remote System', validators=[CustomInputRequired(),validate_ipv4_address]) + Device_1_NI_VC_ID = IntegerField('Device_1 NI VC ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative")]) + Device_1_NI_connection_point = StringField('Device_1 NI Conection Point', validators=[CustomInputRequired()]) #Device_2 specific - #Device_2_NI_VC_ID = IntegerField('Device_2 NI VC_ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative"), validator_ADVA]) #MANDATORY PARAMETER - Device_2_NI_remote_system = StringField ('Device_2 NI Remote System', validators=[CustomInputRequired(),validate_ipv4_address]) #MANDATORY PARAMETER - Device_2_NI_VC_ID = IntegerField('Device_2 NI VC ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative")]) #MANDATORY PARAMETER - Device_2_NI_connection_point = StringField ('Device_2 NI Conection Point', validators=[CustomInputRequired()]) #MANDATORY PARAMETER + Device_2_NI_remote_system = StringField ('Device_2 NI Remote System', validators=[CustomInputRequired(),validate_ipv4_address]) + Device_2_NI_VC_ID = IntegerField('Device_2 NI VC ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VC can't be negative")]) + Device_2_NI_connection_point = StringField ('Device_2 NI Conection Point', validators=[CustomInputRequired()]) #Interface parameters (DEVICE SPECIFIC) - #Device-1 - #Device_1_IF_name = StringField ('Device_1 Interface Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - #Device_1_IF_type = StringField ('Device_1 Interface Type', default="l2vlan", validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> l2vlan? - Device_1_IF_index = IntegerField('Device_1 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) #MANDATORY PARAMETER - Device_1_IF_vlan_id = IntegerField('Device_1 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) #MANDATORY PARAMETER - Device_1_IF_mtu = IntegerField('Device_1 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) #OPTIONAL PARAMETER - FIXED VALUE -> 3000? - Device_1_IF_description = StringField ('Device_1 SubIF Description', validators=[Optional()]) #OPTIONAL PARAMETER - #Device-2 - #Device_2_IF_name = StringField ('Device_2 Interface Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - #Device_2_IF_type = StringField ('Device_2 Interface Type', default="l2vlan", validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> l2vlan? - Device_2_IF_index = IntegerField('Device_2 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) #MANDATORY PARAMETER - Device_2_IF_vlan_id = IntegerField('Device_2 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) #MANDATORY PARAMETER - Device_2_IF_mtu = IntegerField('Device_2 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) #OPTIONAL PARAMETER - FIXED VALUE -> 3000? - Device_2_IF_description = StringField ('Device_2 SubIF Description', validators=[Optional()]) #OPTIONAL PARAMETER + Device_1_IF_index = IntegerField('Device_1 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) + Device_1_IF_vlan_id = IntegerField('Device_1 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) + Device_1_IF_mtu = IntegerField('Device_1 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) + Device_1_IF_description = StringField ('Device_1 SubIF Description', validators=[Optional()]) + + Device_2_IF_index = IntegerField('Device_2 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) + Device_2_IF_vlan_id = IntegerField('Device_2 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) + Device_2_IF_mtu = IntegerField('Device_2 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) + Device_2_IF_description = StringField ('Device_2 SubIF Description', validators=[Optional()]) -class AddServiceForm_L3VPN(FlaskForm): #L3VPN - Formulary Fields +class AddServiceForm_L3VPN(FlaskForm): #GENERIC SERVICE PARAMETERS (COMMON & MANDATORY) - service_name = StringField('Service Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - service_type = SelectField('Service Type', choices=[(1, '1 (L3NM)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L3NM - service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - #Device_1_IF_vendor = SelectField ('Device_1 Vendor', choices=[('', 'Select a vendor (Mandatory)'),('ADVA', 'ADVA'), ('CISCO','CISCO'), ('Huawei', 'Huawei'),('Juniper', 'Juniper'),('Nokia', 'Nokia')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - #Device_2_IF_vendor = SelectField ('Device_2 Vendor', choices=[('', 'Select a vendor (Mandatory)'),('ADVA', 'ADVA'), ('CISCO','CISCO'), ('Huawei', 'Huawei'),('Juniper', 'Juniper'),('Nokia', 'Nokia')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - #Device_1_Template = SelectField ('Device_1 Template', choices=[('', 'Select a type of template (Mandatory)'),('Jinja', 'Jinja'), ('Pyangbind','Pyangbind')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-1 - #Device_2_Template = SelectField ('Device_2 Template', choices=[('', 'Select a type of template (Mandatory)'),('Jinja', 'Jinja'), ('Pyangbind','Pyangbind')], validators=[CustomInputRequired()]) #MANDATORY PARAMETER - DEVICE-2 - + service_name = StringField('Service Name', validators=[CustomInputRequired()]) + service_type = SelectField('Service Type', choices=[(1, '1 (L3NM)')], validators=[CustomInputRequired()]) + service_device_1 = SelectField('Device_1', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_device_2 = SelectField('Device_2', choices=[('', 'Select a device (Mandatory)')], validators=[CustomInputRequired()]) + service_endpoint_1 = StringField('Device_1 Endpoint', validators=[CustomInputRequired()]) + service_endpoint_2 = StringField('Device_2 Endpoint', validators=[CustomInputRequired()]) + #GENERIC SERVICE CONSTRAINT PARAMETERS (ALL OPTIONAL) - service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) #OPTIONAL PARAMETER - service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) + service_capacity = DecimalField('Service Capacity', places=2, default=10.00, validators=[Optional(), NumberRange(min=0)]) + service_latency = DecimalField('Service Latency', places=2, default=15.20, validators=[Optional(), NumberRange(min=0)]) + service_availability= DecimalField('Service Availability', places=2, validators=[Optional(), NumberRange(min=0)]) + service_isolation = SelectField('Service Isolation', choices=[('', 'Select (Optional)'), ('NO_ISOLATION', 'NO_ISOLATION'), ('PHYSICAL_ISOLATION', 'PHYSICAL_ISOLATION'), + ('LOGICAL_ISOLATION', 'LOGICAL_ISOLATION'), ('PROCESS_ISOLATION', 'PROCESS_ISOLATION'), ('PHYSICAL_MEMORY_ISOLATION', 'PHYSICAL_MEMORY_ISOLATION'), + ('PHYSICAL_NETWORK_ISOLATION', 'PHYSICAL_NETWORK_ISOLATION'), ('VIRTUAL_RESOURCE_ISOLATION', 'VIRTUAL_RESOURCE_ISOLATION'), + ('NETWORK_FUNCTIONS_ISOLATION', 'NETWORK_FUNCTIONS_ISOLATION'), ('SERVICE_ISOLATION', 'SERVICE_ISOLATION')], validators=[Optional()]) - ## Network Instance (NI) PARAMS - #Create a NI - NI_name = StringField('Name', validators=[InputRequired()]) #MANDATORY PARAMETER - #NI_type = SelectField('Type', choices=[('L3VRF', 'L3VRF')], validators=[InputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> L3VRF - NI_route_distinguisher = StringField('Route Distinguisher', validators=[InputRequired(),validate_route_distinguisher]) #MANDATORY PARAMETER - NI_router_id = StringField('Router ID', validators=[Optional(), validate_ipv4_address]) #OPTIONAL PARAMETER - NI_description = StringField('Description', validators=[Optional()]) #OPTIONAL PARAMETER - #Add a protocol to NI + NI_name = StringField('Name', validators=[InputRequired()]) + NI_route_distinguisher = StringField('Route Distinguisher', validators=[InputRequired(),validate_route_distinguisher]) + NI_router_id = StringField('Router ID', validators=[Optional(), validate_ipv4_address]) + NI_description = StringField('Description', validators=[Optional()]) NI_protocol = SelectField('Protocol', choices=[('', 'Select a type (Mandatory)'),('STATIC', 'STATIC'),('DIRECTLY_CONNECTED', 'DIRECTLY_CONNECTED'),('BGP', 'BGP')], validators=[InputRequired()]) NI_as = IntegerField('AS', default=None, validators=[validate_NI_as, Optional(), validate_uint32]) - #Create Connections Table - #NI_src_protocol = SelectField('Source Protocol', choices=[('', 'Select a type'),('STATIC', 'STATIC'),('DIRECTLY_CONNECTED', 'DIRECTLY_CONNECTED'),('BGP', 'BGP')], validators=[InputRequired()]) - #NI_dst_protocol = SelectField('Destination Protocol', choices=[('', 'Select a type'),('STATIC', 'STATIC'),('DIRECTLY_CONNECTED', 'DIRECTLY_CONNECTED'),('BGP', 'BGP')], validators=[InputRequired()]) NI_address_family = SelectField('Protocol Address Family', choices=[('', 'Select a type (Mandatory)'),('IPV4', 'IPV4'),('IPV6', 'IPV6')], validators=[InputRequired()]) NI_default_import_policy = SelectField('Default Network Instance Import Policy', choices=[('', 'Select a policy (Mandatory)'),('ACCEPT_ROUTE', 'ACCEPT_ROUTE'),('REJECT_ROUTE', 'REJECT_ROUTE')], validators=[Optional()]) - #Associate RP to NI - NI_import_policy = StringField('Name of the Network Instance Import Policy', validators=[Optional()]) #OPTIONAL PARAMETER - NI_export_policy = StringField('Name of the Network Instance Export Policy', validators=[Optional()]) #OPTIONAL PARAMETER + NI_import_policy = StringField('Name of the Network Instance Import Policy', validators=[Optional()]) + NI_export_policy = StringField('Name of the Network Instance Export Policy', validators=[Optional()]) ## Interface (IF) PARAMS - #Device-1 - #Device_1_IF_name = StringField ('Device_1 Interface Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - #Device_1_IF_type = StringField ('Device_1 Interface Type', default="l3ipvlan", validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> l3ipvlan? - Device_1_IF_index = IntegerField('Device_1 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) #MANDATORY PARAMETER - Device_1_IF_vlan_id = IntegerField('Device_1 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) #MANDATORY PARAMETER - Device_1_IF_mtu = IntegerField('Device_1 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) #OPTIONAL PARAMETER - FIXED VALUE -> 3000? - Device_1_IF_address_ip = StringField('Device_1 IP Address', validators=[CustomInputRequired(), validate_ipv4_address]) #MANDATORY PARAMETER - Device_1_IF_address_prefix = IntegerField('Device_1 IP Prefix length', validators=[CustomInputRequired(), validate_uint32]) #MANDATORY PARAMETER - Device_1_IF_description = StringField ('Device_1 SubIF Description', validators=[Optional()]) #OPTIONAL PARAMETER - #Device-2 - #Device_2_IF_name = StringField ('Device_2 Interface Name', validators=[CustomInputRequired()]) #MANDATORY PARAMETER - #Device_2_IF_type = StringField ('Device_1 Interface Type', default="l3ipvlan", validators=[CustomInputRequired()]) #MANDATORY PARAMETER - FIXED VALUE -> l3ipvlan? - Device_2_IF_index = IntegerField('Device_2 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) #MANDATORY PARAMETER - Device_2_IF_vlan_id = IntegerField('Device_2 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) #MANDATORY PARAMETER - Device_2_IF_mtu = IntegerField('Device_2 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) #MANDATORY PARAMETER - FIXED VALUE -> 3000? - Device_2_IF_address_ip = StringField('Device_2 IP Address', validators=[CustomInputRequired(), validate_ipv4_address]) #MANDATORY PARAMETER - Device_2_IF_address_prefix = IntegerField('Device_2 IP Prefix length', validators=[CustomInputRequired(), validate_uint32]) #MANDATORY PARAMETER - Device_2_IF_description = StringField ('Device_2 SubIF Description', validators=[Optional()]) #OPTIONAL PARAMETER + Device_1_IF_index = IntegerField('Device_1 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) + Device_1_IF_vlan_id = IntegerField('Device_1 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) + Device_1_IF_mtu = IntegerField('Device_1 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) + Device_1_IF_address_ip = StringField('Device_1 IP Address', validators=[CustomInputRequired(), validate_ipv4_address]) + Device_1_IF_address_prefix = IntegerField('Device_1 IP Prefix length', validators=[CustomInputRequired(), validate_uint32]) + Device_1_IF_description = StringField ('Device_1 SubIF Description', validators=[Optional()]) - ## Routing Policy (RP) parameters - #RP_policy_name = StringField('Policy Name', validators=[InputRequired()]) #MANDATORY PARAMETER - #RP_statement_name = StringField('Statement Name', validators=[InputRequired()]) #MANDATORY PARAMETER - #RP_policy_result = SelectField('Policy Result', choices=[(None, 'Not Defined'), ('ACCEPT_ROUTE', 'ACCEPT_ROUTE'),('REJECT_ROUTE', 'REJECT_ROUTE')], validators=[Optional()]) - #RP_ext_community_set_name = StringField('Ext Community Set Name', validators=[InputRequired()]) #MANDATORY PARAMETER - #RP_ext_community_member = StringField('Ext Community Member', validators=[InputRequired()]) #MANDATORY PARAMETER - + Device_2_IF_index = IntegerField('Device_2 SubIF Index', validators=[CustomInputRequired(), NumberRange(min=0, message="SubIf index can't be negative")]) + Device_2_IF_vlan_id = IntegerField('Device_2 VLAN ID', validators=[CustomInputRequired(), NumberRange(min=0, message="VlanID can't be negative")]) + Device_2_IF_mtu = IntegerField('Device_2 Interface MTU', validators=[Optional(), NumberRange(min=0, message="MTU value can't be negative")]) + Device_2_IF_address_ip = StringField('Device_2 IP Address', validators=[CustomInputRequired(), validate_ipv4_address]) + Device_2_IF_address_prefix = IntegerField('Device_2 IP Prefix length', validators=[CustomInputRequired(), validate_uint32]) + Device_2_IF_description = StringField ('Device_2 SubIF Description', validators=[Optional()]) + \ No newline at end of file diff --git a/src/webui/service/service/routes.py b/src/webui/service/service/routes.py index 9aff0ad79..1d3e25490 100644 --- a/src/webui/service/service/routes.py +++ b/src/webui/service/service/routes.py @@ -13,8 +13,7 @@ # limitations under the License. -import base64, json, logging #, re -from contextlib import contextmanager +import json, logging #, re import json import grpc from collections import defaultdict @@ -38,7 +37,6 @@ from common.tools.descriptor.Loader import DescriptorLoader, compose_notificatio from common.tools.object_factory.ConfigRule import json_config_rule_set from common.tools.object_factory.Device import json_device_id from common.tools.object_factory.EndPoint import json_endpoint_id -#from src.common.tools.grpc.Tools import grpc_message_to_json_string from webui.service.service.forms import AddServiceForm_1, AddServiceForm_ACL_L2, AddServiceForm_ACL_IPV4, AddServiceForm_ACL_IPV6, AddServiceForm_L2VPN, AddServiceForm_L3VPN from common.tools.context_queries.Service import get_service_by_uuid from common.tools.object_factory.Context import json_context_id @@ -46,10 +44,10 @@ from common.tools.object_factory.Topology import json_topology_id from typing import Optional, Set LOGGER = logging.getLogger(__name__) -service = Blueprint('service', __name__, url_prefix='/service') #Define a flask Blueprint called "service" behind the url "/service" +service = Blueprint('service', __name__, url_prefix='/service') -context_client = ContextClient() #Create an instance of ContextClient class as defined in /src/service/client/ContextClient.py -service_client = ServiceClient() #Create an instance of ServiceClient class as defined in /src/service/client/ServiceClient.py +context_client = ContextClient() +service_client = ServiceClient() device_client = DeviceClient() type = ["ACL_UNDEFINED", "ACL_IPV4","ACL_IPV6","ACL_L2","ACL_MPLS","ACL_MIXED"] @@ -66,7 +64,7 @@ def connected_client(c): finally: c.close() ''' -# Context client must be in connected state when calling this function + def get_device_drivers_in_use(topology_uuid: str, context_uuid: str) -> Set[str]: active_drivers = set() grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) @@ -80,15 +78,15 @@ def get_device_drivers_in_use(topology_uuid: str, context_uuid: str) -> Set[str] @service.get('/') def home(): - if 'context_uuid' not in session or 'topology_uuid' not in session: #Check if context_uuid and topology_uuid are defined in the current seession - flash("Please select a context!", "warning") #If they are not defined in the current session [Return to main page - STOP] + 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() #Creates a connection, as specified in the connect method of the ContextClient() class + context_client.connect() - context_obj = get_context(context_client, context_uuid, rw_copy=False) #Using the get_context function, defined in /src/common/ + context_obj = get_context(context_client, context_uuid, rw_copy=False) if context_obj is None: flash('Context({:s}) not found'.format(str(context_uuid)), 'danger') services, device_names, endpoints_data = list(), list(), list() @@ -113,13 +111,10 @@ def home(): 'service/home.html', services=services, device_names=device_names, endpoints_data=endpoints_data, ste=ServiceTypeEnum, sse=ServiceStatusEnum, active_drivers=active_drivers) - @service.route('add', methods=['GET', 'POST']) def add(): flash('Add service route called', 'danger') raise NotImplementedError() - #return render_template('service/home.html') - def get_hub_module_name(dev: Device) -> Optional[str]: for cr in dev.device_config.config_rules: @@ -176,8 +171,6 @@ def add_xr(): hub_interfaces_by_device[d.name].sort() leaf_interfaces_by_device[d.name].sort() - # Find out what endpoints are already used so that they can be disabled - # in the create screen context_obj = get_context(context_client, context_uuid, rw_copy=False) if context_obj is None: flash('Context({:s}) not found'.format(str(context_uuid)), 'danger') @@ -300,7 +293,7 @@ def detail(service_uuid: str): current_app.logger.exception(e) return redirect(url_for('service.home')) -@service.get('/delete') #Route for deleting a specific service +@service.get('/delete') def delete(service_uuid: str): if 'context_uuid' not in session or 'topology_uuid' not in session: flash("Please select a context!", "warning") @@ -321,14 +314,10 @@ def delete(service_uuid: str): current_app.logger.exception(e) return redirect(url_for('service.home')) -#Added routes for creating a new Service -@service.route('add/configure', methods=['GET', 'POST']) #Route for adding a new service [Selecting the type of operation to be performed - First Form] +@service.route('add/configure', methods=['GET', 'POST']) def add_configure(): form_1 = AddServiceForm_1() if form_1.validate_on_submit(): - #store the selected service type in session - #session['service_type'] = form_1.service_type.data - #redirect to the same page to display the second form if form_1.service_type.data == 'ACL_L2': return redirect(url_for('service.add_configure_ACL_L2')) elif form_1.service_type.data == 'ACL_IPV4': @@ -339,21 +328,19 @@ def add_configure(): return redirect(url_for('service.add_configure_L2VPN')) elif form_1.service_type.data == 'L3VPN': return redirect(url_for('service.add_configure_L3VPN')) - # display the first form return render_template('service/add.html', form_1=form_1, submit_text='Continue to configuraton') -@service.route('add/configure/ACL_L2', methods=['GET', 'POST']) #Route for adding a new ACL_L2 service [Setting the parameters for defining the service] +@service.route('add/configure/ACL_L2', methods=['GET', 'POST']) def add_configure_ACL_L2(): form_acl = AddServiceForm_ACL_L2() service_obj = Service() - context_uuid, topology_uuid = get_context_and_topology_uuids() #Get the topology and context UUIDS - if context_uuid and topology_uuid: #If the UUIDs exist - context_client.connect() #Connects to the context service using the context_client object - grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) #Call the get_topology() function to retrieve the topology information for the given context and topology UUIDs - if grpc_topology: #If the topology is defined + context_uuid, topology_uuid = get_context_and_topology_uuids() + if context_uuid and topology_uuid: + context_client.connect() + grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) + if grpc_topology: topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids} - #devices = get_filtered_devices(context_client, topo_device_uuids) #Calls the fucntion that returns a list of devices that have UUIDs in the set of topology device UUIDs. context_obj = get_context(context_client, context_uuid, rw_copy=False) if context_obj is None: flash('Context({:s}) not found'.format(str(context_uuid)), 'danger') @@ -375,20 +362,20 @@ def add_configure_ACL_L2(): if device.device_id.device_uuid.uuid in devices_services: devices.append(device) - choices = get_device_choices(devices) #Returns a list of tuples, where each tuple contains the index of the device in the list and the name of the device - add_device_choices_to_form(choices, form_acl.service_device_1) #Adds the device choices to the select options for the form (Device1) - add_device_choices_to_form(choices, form_acl.service_device_2) #Adds the device choices to the select options for the form (Device2) + choices = get_device_choices(devices) + add_device_choices_to_form(choices, form_acl.service_device_1) + add_device_choices_to_form(choices, form_acl.service_device_2) else: - flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') #If the topology is not found, display an error message and set the devices list to an empty list + flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') else: - flash('Missing context or topology UUID', 'danger') #If the topology or context UUID is not found, display an error message + flash('Missing context or topology UUID', 'danger') if form_acl.validate_on_submit(): flash(f'New configuration was created', 'success') return redirect(url_for('service.home')) return render_template('service/configure_ACL_L2.html', form_acl=form_acl, submit_text='Add New Service') -@service.route('add/configure/ACL_IPV4', methods=['GET', 'POST']) #Route for adding a new ACL_IPV4 service [Setting the parameters for defining the service] +@service.route('add/configure/ACL_IPV4', methods=['GET', 'POST']) def add_configure_ACL_IPV4(): form_acl = AddServiceForm_ACL_IPV4() if form_acl.validate_on_submit(): @@ -397,7 +384,7 @@ def add_configure_ACL_IPV4(): print(form_acl.errors) return render_template('service/configure_ACL_IPV4.html', form_acl=form_acl, submit_text='Add New Service') -@service.route('add/configure/ACL_IPV6', methods=['GET', 'POST']) #Route for adding a new ACL_IPV6 service [Setting the parameters for defining the service] +@service.route('add/configure/ACL_IPV6', methods=['GET', 'POST']) def add_configure_ACL_IPV6(): form_acl = AddServiceForm_ACL_IPV6() if form_acl.validate_on_submit(): @@ -406,35 +393,34 @@ def add_configure_ACL_IPV6(): print(form_acl.errors) return render_template('service/configure_ACL_IPV6.html', form_acl=form_acl, submit_text='Add New Service') -@service.route('add/configure/L2VPN', methods=['GET', 'POST']) #Route for adding a new L2VPN service [Setting the parameters for defining the service] +@service.route('add/configure/L2VPN', methods=['GET', 'POST']) def add_configure_L2VPN(): - form_l2vpn = AddServiceForm_L2VPN() #Load the AddServiceForm_L3VPN form defined in forms.py - service_obj = Service() #Create a new instance of the Service class - - context_uuid, topology_uuid = get_context_and_topology_uuids() #Get the topology and context UUIDS - if context_uuid and topology_uuid: #If the UUIDs exist - context_client.connect() #Connects to the context service using the context_client object - grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) #Call the get_topology() function to retrieve the topology information for the given context and topology UUIDs - if grpc_topology: #If the topology is defined + form_l2vpn = AddServiceForm_L2VPN() + service_obj = Service() + + context_uuid, topology_uuid = get_context_and_topology_uuids() + if context_uuid and topology_uuid: + context_client.connect() + grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) + if grpc_topology: topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids} - devices = get_filtered_devices(context_client, topo_device_uuids) #Calls the fucntion that returns a list of devices that have UUIDs in the set of topology device UUIDs. - choices = get_device_choices(devices) #Returns a list of tuples, where each tuple contains the index of the device in the list and the name of the device - add_device_choices_to_form(choices, form_l2vpn.service_device_1) #Adds the device choices to the select options for the form (Device1) - add_device_choices_to_form(choices, form_l2vpn.service_device_2) #Adds the device choices to the select options for the form (Device2) + devices = get_filtered_devices(context_client, topo_device_uuids) + choices = get_device_choices(devices) + add_device_choices_to_form(choices, form_l2vpn.service_device_1) + add_device_choices_to_form(choices, form_l2vpn.service_device_2) else: - flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') #If the topology is not found, display an error message and set the devices list to an empty list + flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') else: - flash('Missing context or topology UUID', 'danger') #If the topology or context UUID is not found, display an error message + flash('Missing context or topology UUID', 'danger') - if form_l2vpn.validate_on_submit(): #Check if the form has been submitted and is valid - try: #Calls a function that validates the selected devices and endpoints exists and are correct + if form_l2vpn.validate_on_submit(): + try: [selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2] = validate_selected_devices_and_endpoints(form_l2vpn, devices) - except Exception as e: #Catch any exception raised during the validation process + except Exception as e: flash('{:s}'.format(str(e.args[0])), 'danger') current_app.logger.exception(e) - return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service') #Render the L2VPN configuration form with the previously entered data and an error message + return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service') - #Check the specific values of the parameters dependent by the vendor of the device [vendor_1, vendor_2] = get_device_vendor(form_l2vpn, devices) try: validate_params_vendor(form_l2vpn, vendor_1, 1) @@ -442,17 +428,16 @@ def add_configure_L2VPN(): except Exception as e: flash('{:s}'.format(str(e.args[0])), 'danger') current_app.logger.exception(e) - return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service') #Render the L2VPN configuration form with the previously entered data and an error message + return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service') - #Create definition of the Service: - service_uuid, service_type, endpoint_ids = set_service_parameters(service_obj, form_l2vpn, selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2) #Calls the function to set the Service - Endpoint UUIDS - constraints = add_constraints(form_l2vpn) #Calls the function to add the constraint parameters for defining a service - params_device_1_with_data = get_device_params(form_l2vpn, 1, service_type) #Calls the function that getst the parameters that will configure the service in the device-1 - params_device_2_with_data = get_device_params(form_l2vpn, 2, service_type) #Calls the function that getst the parameters that will configure the service in the device-2 + service_uuid, service_type, endpoint_ids = set_service_parameters(service_obj, form_l2vpn, selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2) + constraints = add_constraints(form_l2vpn) + params_device_1_with_data = get_device_params(form_l2vpn, 1, service_type) + params_device_2_with_data = get_device_params(form_l2vpn, 2, service_type) print(params_device_1_with_data) print(params_device_2_with_data) - params_settings = {} #Param settings (Defined despite it has no value) -> Avoid error - config_rules = [ #Create the configuration rules from the params_with_data + params_settings = {} + config_rules = [ json_config_rule_set( '/settings', params_settings ), @@ -467,54 +452,54 @@ def add_configure_L2VPN(): context_client.connect() device_client.connect() descriptor_json = json_service_l2nm_planned(service_uuid = service_uuid, endpoint_ids = endpoint_ids, constraints = constraints, config_rules = config_rules, context_uuid= context_uuid) - descriptor_json = {"services": [descriptor_json]} #Wrap the descriptor between the tag: "services": []" + descriptor_json = {"services": [descriptor_json]} try: process_descriptors(descriptor_json) - flash('Service "{:s}" added successfully!'.format(service_obj.service_id.service_uuid.uuid), 'success') #If the service was added succesfully -> Flash success message with newly added service UUID. - return redirect(url_for('service.home', service_uuid=service_obj.service_id.service_uuid.uuid)) #If the service was added succesfully -> Redirect to the service.home URL #Call the process_descriptors function to add the new service defined in the descriptor_json variable + flash('Service "{:s}" added successfully!'.format(service_obj.service_id.service_uuid.uuid), 'success') + return redirect(url_for('service.home', service_uuid=service_obj.service_id.service_uuid.uuid)) except Exception as e: - flash('Problem adding service: {:s}'.format((str(e.args[0]))), 'danger') #If the service was NOT added succesfully -> Include the exception message in a flashed message - current_app.logger.exception(e) #If the service was NOT added succesfully -> Log the exception using Flask's logger + flash('Problem adding service: {:s}'.format((str(e.args[0]))), 'danger') + current_app.logger.exception(e) finally: context_client.close() device_client.close() service_client.close() return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service') -@service.route('add/configure/L3VPN', methods=['GET', 'POST']) #Route for adding a new L3VPN service [Setting the parameters for defining the service] +@service.route('add/configure/L3VPN', methods=['GET', 'POST']) def add_configure_L3VPN(): - form_l3vpn = AddServiceForm_L3VPN() #Load the AddServiceForm_L3VPN form defined in forms.py - service_obj = Service() #Create a new instance of the Service class - - context_uuid, topology_uuid = get_context_and_topology_uuids() #Get the topology and context UUIDS - if context_uuid and topology_uuid: #If the UUIDs exist - context_client.connect() #Connects to the context service using the context_client object - grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) #Call the get_topology() function to retrieve the topology information for the given context and topology UUIDs - if grpc_topology: #If the topology is defined + form_l3vpn = AddServiceForm_L3VPN() + service_obj = Service() + + context_uuid, topology_uuid = get_context_and_topology_uuids() + if context_uuid and topology_uuid: + context_client.connect() + grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) + if grpc_topology: topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids} - devices = get_filtered_devices(context_client, topo_device_uuids) #Calls the fucntion that returns a list of devices that have UUIDs in the set of topology device UUIDs. - choices = get_device_choices(devices) #Returns a list of tuples, where each tuple contains the index of the device in the list and the name of the device - add_device_choices_to_form(choices, form_l3vpn.service_device_1) #Adds the device choices to the select options for the form (Device1) - add_device_choices_to_form(choices, form_l3vpn.service_device_2) #Adds the device choices to the select options for the form (Device2) + devices = get_filtered_devices(context_client, topo_device_uuids) + choices = get_device_choices(devices) + add_device_choices_to_form(choices, form_l3vpn.service_device_1) + add_device_choices_to_form(choices, form_l3vpn.service_device_2) else: - flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') #If the topology is not found, display an error message and set the devices list to an empty list + flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger') else: - flash('Missing context or topology UUID', 'danger') #If the topology or context UUID is not found, display an error message + flash('Missing context or topology UUID', 'danger') if form_l3vpn.validate_on_submit(): try: - [selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2] = validate_selected_devices_and_endpoints(form_l3vpn, devices) #Calls a function that validates the selected devices and endpoints exists and are correct - except Exception as e: # Catch any exception raised during the validation process + [selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2] = validate_selected_devices_and_endpoints(form_l3vpn, devices) + except Exception as e: flash('{:s}'.format(str(e.args[0])), 'danger') current_app.logger.exception(e) - return render_template('service/configure_L3VPN.html', form_l3vpn=form_l3vpn, submit_text='Add New Service') #Render the L3VPN configuration form with the previously entered data and an error message - #Create definition of the Service: - service_uuid, service_type, endpoint_ids = set_service_parameters(service_obj, form_l3vpn, selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2) #Calls the function to set the Service - Endpoint UUIDS - constraints = add_constraints(form_l3vpn) #Calls the function to add the constraint parameters for defining a service + return render_template('service/configure_L3VPN.html', form_l3vpn=form_l3vpn, submit_text='Add New Service') + + service_uuid, service_type, endpoint_ids = set_service_parameters(service_obj, form_l3vpn, selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2) + constraints = add_constraints(form_l3vpn) params_device_1_with_data = get_device_params(form_l3vpn, 1, service_type) params_device_2_with_data = get_device_params(form_l3vpn, 2, service_type) params_settings = {} - config_rules = [ #Create the configuration rules from the params_with_data + config_rules = [ json_config_rule_set( '/settings', params_settings ), @@ -529,14 +514,14 @@ def add_configure_L3VPN(): context_client.connect() device_client.connect() descriptor_json = json_service_l3nm_planned(service_uuid = service_uuid, endpoint_ids = endpoint_ids, constraints = constraints, config_rules = config_rules, context_uuid= context_uuid) - descriptor_json = {"services": [descriptor_json]} #Wrap the descriptor between the tag: "services": []" + descriptor_json = {"services": [descriptor_json]} try: process_descriptors(descriptor_json) - flash('Service "{:s}" added successfully!'.format(service_obj.service_id.service_uuid.uuid), 'success') #If the service was added succesfully -> Flash success message with newly added service UUID. - return redirect(url_for('service.home', service_uuid=service_obj.service_id.service_uuid.uuid)) #If the service was added succesfully -> Redirect to the service.home URL #Call the process_descriptors function to add the new service defined in the descriptor_json variable + flash('Service "{:s}" added successfully!'.format(service_obj.service_id.service_uuid.uuid), 'success') + return redirect(url_for('service.home', service_uuid=service_obj.service_id.service_uuid.uuid)) except Exception as e: - flash('Problem adding service: {:s}'.format((str(e.args[0]))), 'danger') #If the service was NOT added succesfully -> Include the exception message in a flashed message - current_app.logger.exception(e) #If the service was NOT added succesfully -> Log the exception using Flask's logger + flash('Problem adding service: {:s}'.format((str(e.args[0]))), 'danger') + current_app.logger.exception(e) finally: context_client.close() device_client.close() @@ -544,51 +529,49 @@ def add_configure_L3VPN(): return render_template('service/configure_L3VPN.html', form_l3vpn=form_l3vpn, submit_text='Add New Service') -##Function for creating the service DESCRIPTOR_LOADER_NUM_WORKERS = 10 -def process_descriptors(descriptors): #The function receives a "descriptors" parameter which has to be a JSON descriptor object - descriptor_loader = DescriptorLoader(descriptors, num_workers=DESCRIPTOR_LOADER_NUM_WORKERS) #Creates a descriptor_loader object - results = descriptor_loader.process() #Calls the descriptor_loader.process method and saves the result in the results variable - for message,level in compose_notifications(results): #Retrieve the notifications that are obtained in the proccess +def process_descriptors(descriptors): + descriptor_loader = DescriptorLoader(descriptors, num_workers=DESCRIPTOR_LOADER_NUM_WORKERS) + results = descriptor_loader.process() + for message,level in compose_notifications(results): if level == 'error': - LOGGER.warning('ERROR message={:s}'.format(str(message))) #Display any error message in the LOG - flash(message, level) #Show any notification message to the user in the webUI by using flash() + LOGGER.warning('ERROR message={:s}'.format(str(message))) + flash(message, level) -##Functions for having a higher leaver of abstraction and understanding in the code: -def get_context_and_topology_uuids(): #Retrieve the context and topology UUIDs from the session, if they exist +def get_context_and_topology_uuids(): context_uuid = session.get('context_uuid') topology_uuid = session.get('topology_uuid') - return context_uuid, topology_uuid #Return the UUIDs as a tuple, or None if either is missing + return context_uuid, topology_uuid -def get_filtered_devices(context_client, topo_device_uuids): #Call the ListDevices() method on the context client to retrieve a list of all devices +def get_filtered_devices(context_client, topo_device_uuids): grpc_devices = context_client.ListDevices(Empty()) - return [device for device in grpc_devices.devices if device.device_id.device_uuid.uuid in topo_device_uuids] #Filter the list of devices to only include those with UUIDs that appear in the topology + return [device for device in grpc_devices.devices if device.device_id.device_uuid.uuid in topo_device_uuids] -def get_device_choices(devices): #Create the tuple (Number, Device) that will be added to the form +def get_device_choices(devices): return [(i, str(device.name)) for i, device in enumerate(devices)] -def add_device_choices_to_form(choices, form): #Add the device choices (tuple) to the select options of the correspondent form +def add_device_choices_to_form(choices, form): form.choices += choices -def validate_selected_devices_and_endpoints(form, devices): #Validates that the 2 selected devices and 2 endpoints exist and are valid. Then it returns them - selected_device_1 = devices[int(form.service_device_1.data)] #Selected_Device1 will be the one selected by the user in the previously defined form field - selected_device_2 = devices[int(form.service_device_2.data)] #Selected_Device2 will be the one selected by the user in the previously defined form field +def validate_selected_devices_and_endpoints(form, devices): + selected_device_1 = devices[int(form.service_device_1.data)] + selected_device_2 = devices[int(form.service_device_2.data)] if selected_device_1 == selected_device_2: - raise ValidationError('The devices must be different!. Please select two valid and different devices') # If it is not a valid endpoint -> Raise a Validation Error - elif form.service_endpoint_1.data not in [endpoint.name for endpoint in selected_device_1.device_endpoints]: # Check if the endpoint submitted by the user is a valid endpoint of the selected device + raise ValidationError('The devices must be different!. Please select two valid and different devices') + elif form.service_endpoint_1.data not in [endpoint.name for endpoint in selected_device_1.device_endpoints]: raise ValidationError('The selected endpoint: ' + form.service_endpoint_1.data + ' is not a valid endpoint for: '+ selected_device_1.name + '. Please select an endpoint that is available for this device') - elif form.service_endpoint_2.data not in [endpoint.name for endpoint in selected_device_2.device_endpoints]: # Check if the endpoint submitted by the user is a valid endpoint of the selected device + elif form.service_endpoint_2.data not in [endpoint.name for endpoint in selected_device_2.device_endpoints]: raise ValidationError('The selected endpoint: ' + form.service_endpoint_2.data + ' is not a valid endpoint for: '+ selected_device_2.name + '. Please select an endpoint that is available for this device') else: - selected_endpoint_1 = form.service_endpoint_1.data #If the selected endpoint is valid, save it in a variable - selected_endpoint_2 = form.service_endpoint_2.data #If the selected endpoint is valid, save it in a variable - return selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2 #Return the devices and endpoints + selected_endpoint_1 = form.service_endpoint_1.data + selected_endpoint_2 = form.service_endpoint_2.data + return selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2 def get_device_vendor(form, devices): - selected_device_1 = devices[int(form.service_device_1.data)] #Selected_Device1 will be the one selected by the user in the previously defined form field - selected_device_2 = devices[int(form.service_device_2.data)] #Selected_Device2 will be the one selected by the user in the previously defined form field + selected_device_1 = devices[int(form.service_device_1.data)] + selected_device_2 = devices[int(form.service_device_2.data)] vendor_value_1 = None vendor_value_2 = None @@ -611,7 +594,7 @@ def get_device_vendor(form, devices): return vendor_value_1, vendor_value_2 -def validate_params_vendor(form, vendor, device_num): #num is an auxiliar variable that can be 1 or 2 for knowing if it corresponds to the first or second device +def validate_params_vendor(form, vendor, device_num): if vendor == "ADVA": if form.NI_name.data != f"ELAN-AC:{getattr(form, f'Device_{device_num}_IF_vlan_id').data}": raise ValidationError('For an ADVA device, the name of the Network Instance should have this name: "ELAN-AC:vlanID"') @@ -622,35 +605,33 @@ def validate_params_vendor(form, vendor, device_num): #num is an auxiliar varia None return None -def set_service_parameters(service_obj, form, selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2): #Function to retrieve and set the service parameters for defining the service - #Service UUID: - service_obj.service_id.service_uuid.uuid = str(form.service_name.data) #Create the Service UUID (Unique Identifier of the service) from the service name +def set_service_parameters(service_obj, form, selected_device_1, selected_device_2, selected_endpoint_1, selected_endpoint_2): + service_obj.service_id.service_uuid.uuid = str(form.service_name.data) service_uuid = service_obj.service_id.service_uuid.uuid - #Service type [OPTIONS Defined in Context.proto]: 0(Unknown), 1(L3NM), 2(L2NM), 3(TAPI_CONNECTIVITY_SERVICE), 4(ACL) - service_obj.service_type = int(form.service_type.data) #Set the Service type as selected by the user in the form + service_obj.service_type = int(form.service_type.data) service_type = service_obj.service_type - # Set the endpoint IDs - endpoint_ids = [ #Create a list containing a element that represents the Selected Device ID and the Selected Endpoint + + endpoint_ids = [ json_endpoint_id(json_device_id(selected_device_1.name), str(selected_endpoint_1)), json_endpoint_id(json_device_id(selected_device_2.name), str(selected_endpoint_2)) ] return service_uuid, service_type, endpoint_ids -def add_constraints(form): #Function to add the constraints for a definition of a service - constraints = [] #Constraints -> Creates a list in which the constraints for the service will be added +def add_constraints(form): + constraints = [] if form.service_capacity.data: - constraints.append(json_constraint_sla_capacity(float(form.service_capacity.data))) #Capacity [Gbps] + constraints.append(json_constraint_sla_capacity(float(form.service_capacity.data))) if form.service_latency.data: - constraints.append(json_constraint_sla_latency(float(form.service_latency.data))) #Latency [ms] + constraints.append(json_constraint_sla_latency(float(form.service_latency.data))) if form.service_availability.data: - constraints.append(json_constraint_sla_availability(1, True, float(form.service_availability.data))) #Availability [%] + constraints.append(json_constraint_sla_availability(1, True, float(form.service_availability.data))) if form.service_isolation.data is not None and form.service_isolation.data != '': - constraints.append(json_constraint_sla_isolation([getattr(IsolationLevelEnum, str(form.service_isolation.data))])) #Isolation (Predefined values) + constraints.append(json_constraint_sla_isolation([getattr(IsolationLevelEnum, str(form.service_isolation.data))])) - return constraints #Returns a list with the constraints and values + return constraints -def get_device_params(form, device_num, form_type): #Function to retrieve and set the device parameters for defining the service - if form_type == 2: #Type2 = L2NM +def get_device_params(form, device_num, form_type): + if form_type == 2: device_params = { 'ni_name': str(getattr(form, 'NI_name').data), 'sub_interface_index': str(getattr(form, f'Device_{device_num}_IF_index').data), @@ -662,7 +643,7 @@ def get_device_params(form, device_num, form_type): 'ni_description': str(getattr(form, 'NI_description').data), 'subif_description': str(getattr(form, f'Device_{device_num}_IF_description').data), } - elif form_type == 1: #Type1 = L3NM + elif form_type == 1: if device_num == 1: policy_az_field = 'NI_import_policy' policy_za_field = 'NI_export_policy' @@ -687,5 +668,5 @@ def get_device_params(form, device_num, form_type): else: raise ValueError(f'Unsupported form type: {form_type}') - params_with_data = {k: v for k, v in device_params.items() if v is not None and str(v) != 'None' and v != ''} #Retrieve the params that do not have value (None or ' ') + params_with_data = {k: v for k, v in device_params.items() if v is not None and str(v) != 'None' and v != ''} return params_with_data diff --git a/src/webui/service/templates/service/detail.html b/src/webui/service/templates/service/detail.html index 64f56f254..ff2de8a3c 100644 --- a/src/webui/service/templates/service/detail.html +++ b/src/webui/service/templates/service/detail.html @@ -26,15 +26,8 @@ Back to service list - -
-
@@ -67,9 +57,7 @@ {% for service in services %}
- {{ service.service_id.service_uuid.uuid }} - {{ service.name }} -- GitLab From a1e32d0af543bc6a13aa2ad31d9c3f5456118470 Mon Sep 17 00:00:00 2001 From: armingol Date: Mon, 15 Jan 2024 15:56:59 +0000 Subject: [PATCH 4/4] code cleanup --- src/webui/service/service/forms.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/webui/service/service/forms.py b/src/webui/service/service/forms.py index 80476870a..b3fffcc89 100644 --- a/src/webui/service/service/forms.py +++ b/src/webui/service/service/forms.py @@ -90,7 +90,7 @@ class AddServiceForm_ACL_L2(FlaskForm): #PARAMETERS FOR Associating ACL to IF interface = StringField('Interface Name', validators=[CustomInputRequired("The name of the Interface is a mandatory parameter")]) subinterface = StringField('Subinterface Index', validators=[Optional()]) - traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[CustomInputRequired("The direction of the traffic flow is a mandatory parameter")]) #MANDATORY PARAMETER + traffic_flow = SelectField('ACL Traffic Flow Direction', choices=[('', 'Select a direction (Mandatory)'), ('Ingress', 'Ingress'), ('Egress','Egress')], validators=[CustomInputRequired("The direction of the traffic flow is a mandatory parameter")]) #SPECIFIC PARAMETERS - Creating ACL Entry [ACL_L2] source_mac = StringField('Source MAC Address', validators=[Optional(), validate_mac_address]) @@ -259,4 +259,3 @@ class AddServiceForm_L3VPN(FlaskForm): Device_2_IF_address_ip = StringField('Device_2 IP Address', validators=[CustomInputRequired(), validate_ipv4_address]) Device_2_IF_address_prefix = IntegerField('Device_2 IP Prefix length', validators=[CustomInputRequired(), validate_uint32]) Device_2_IF_description = StringField ('Device_2 SubIF Description', validators=[Optional()]) - \ No newline at end of file -- GitLab