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

WebUI - Service Management form

- Leftover cosmetic changes from merge request
parent b6ba15c1
No related branches found
No related tags found
1 merge request!235Release TeraFlowSDN 3.0
......@@ -12,36 +12,38 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json, logging #, re
import json
import grpc
import grpc, json, logging #, re
from collections import defaultdict
from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for, request
from typing import Optional, Set
from wtforms.validators import ValidationError
from common.proto.context_pb2 import (
ContextId, IsolationLevelEnum, Service, ServiceId, ServiceTypeEnum, ServiceStatusEnum, Connection, Empty, DeviceDriverEnum,
ConfigActionEnum, Device, DeviceList)
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 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.context_queries.Service import get_service_by_uuid
from common.tools.context_queries.Topology import get_topology
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.Constraint import (
json_constraint_sla_availability, json_constraint_sla_capacity, json_constraint_sla_isolation,
json_constraint_sla_latency
)
from common.tools.object_factory.Context import json_context_id
from common.tools.object_factory.Device import json_device_id
from common.tools.object_factory.EndPoint import json_endpoint_id
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.Service import json_service_l2nm_planned, json_service_l3nm_planned
from common.tools.object_factory.Topology import json_topology_id
from typing import Optional, Set
from context.client.ContextClient import ContextClient
from device.client.DeviceClient import DeviceClient
from service.client.ServiceClient import ServiceClient
from webui.service.service.forms import (
AddServiceForm_1, AddServiceForm_ACL_L2, AddServiceForm_ACL_IPV4, AddServiceForm_ACL_IPV6,
AddServiceForm_L2VPN, AddServiceForm_L3VPN
)
LOGGER = logging.getLogger(__name__)
service = Blueprint('service', __name__, url_prefix='/service')
......@@ -50,21 +52,10 @@ context_client = ContextClient()
service_client = ServiceClient()
device_client = DeviceClient()
type = ["ACL_UNDEFINED", "ACL_IPV4","ACL_IPV6","ACL_L2","ACL_MPLS","ACL_MIXED"]
ACL_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:
c.connect()
yield c
finally:
c.close()
'''
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)
......@@ -118,13 +109,15 @@ def add():
def get_hub_module_name(dev: Device) -> Optional[str]:
for cr in dev.device_config.config_rules:
if cr.action == ConfigActionEnum.CONFIGACTION_SET and cr.custom and cr.custom.resource_key == "_connect/settings":
try:
cr_dict = json.loads(cr.custom.resource_value)
if "hub_module_name" in cr_dict:
return cr_dict["hub_module_name"]
except json.JSONDecodeError:
pass
if cr.action != ConfigActionEnum.CONFIGACTION_SET: continue
if not cr.custom: continue
if cr.custom.resource_key != "_connect/settings": continue
try:
cr_dict = json.loads(cr.custom.resource_value)
if "hub_module_name" in cr_dict:
return cr_dict["hub_module_name"]
except json.JSONDecodeError:
pass
return None
@service.route('add-xr', methods=['GET', 'POST'])
......@@ -142,122 +135,137 @@ def add_xr():
if grpc_topology is None:
flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger')
return redirect(url_for("main.home"))
else:
topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids}
grpc_devices= context_client.ListDevices(Empty())
devices = [
device for device in grpc_devices.devices
if device.device_id.device_uuid.uuid in topo_device_uuids and DeviceDriverEnum.DEVICEDRIVER_XR in device.device_drivers
]
devices.sort(key=lambda dev: dev.name)
hub_interfaces_by_device = defaultdict(list)
leaf_interfaces_by_device = defaultdict(list)
constellation_name_to_uuid = {}
dev_ep_to_uuid = {}
ep_uuid_to_name = {}
for d in devices:
constellation_name_to_uuid[d.name] = d.device_id.device_uuid.uuid
hm_name = get_hub_module_name(d)
if hm_name is not None:
hm_if_prefix= hm_name + "|"
for ep in d.device_endpoints:
dev_ep_to_uuid[(d.name, ep.name)] = ep.endpoint_id.endpoint_uuid.uuid
if ep.name.startswith(hm_if_prefix):
hub_interfaces_by_device[d.name].append(ep.name)
else:
leaf_interfaces_by_device[d.name].append(ep.name)
ep_uuid_to_name[ep.endpoint_id.endpoint_uuid.uuid] = (d.name, ep.name)
hub_interfaces_by_device[d.name].sort()
leaf_interfaces_by_device[d.name].sort()
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)
ep_used_by={}
for service in services.services:
if service.service_type == ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE:
for ep in service.service_endpoint_ids:
ep_uuid = ep.endpoint_uuid.uuid
if ep_uuid in ep_uuid_to_name:
dev_name, ep_name = ep_uuid_to_name[ep_uuid]
ep_used_by[f"{ep_name}@{dev_name}"] = service.name
topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids}
grpc_devices= context_client.ListDevices(Empty())
devices = [
device for device in grpc_devices.devices
if device.device_id.device_uuid.uuid in topo_device_uuids and DeviceDriverEnum.DEVICEDRIVER_XR in device.device_drivers
]
devices.sort(key=lambda dev: dev.name)
hub_interfaces_by_device = defaultdict(list)
leaf_interfaces_by_device = defaultdict(list)
constellation_name_to_uuid = {}
dev_ep_to_uuid = {}
ep_uuid_to_name = {}
for d in devices:
constellation_name_to_uuid[d.name] = d.device_id.device_uuid.uuid
hm_name = get_hub_module_name(d)
if hm_name is not None:
hm_if_prefix= hm_name + "|"
for ep in d.device_endpoints:
dev_ep_to_uuid[(d.name, ep.name)] = ep.endpoint_id.endpoint_uuid.uuid
if ep.name.startswith(hm_if_prefix):
hub_interfaces_by_device[d.name].append(ep.name)
else:
leaf_interfaces_by_device[d.name].append(ep.name)
ep_uuid_to_name[ep.endpoint_id.endpoint_uuid.uuid] = (d.name, ep.name)
hub_interfaces_by_device[d.name].sort()
leaf_interfaces_by_device[d.name].sort()
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)
ep_used_by={}
for service in services.services:
if service.service_type == ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE:
for ep in service.service_endpoint_ids:
ep_uuid = ep.endpoint_uuid.uuid
if ep_uuid in ep_uuid_to_name:
dev_name, ep_name = ep_uuid_to_name[ep_uuid]
ep_used_by[f"{ep_name}@{dev_name}"] = service.name
context_client.close()
if request.method != 'POST':
return render_template('service/add-xr.html', devices=devices, hub_if=hub_interfaces_by_device, leaf_if=leaf_interfaces_by_device, ep_used_by=ep_used_by)
else:
service_name = request.form["service_name"]
if service_name == "":
flash(f"Service name must be specified", 'danger')
constellation = request.form["constellation"]
constellation_uuid = constellation_name_to_uuid.get(constellation, None)
if constellation_uuid is None:
flash(f"Invalid constellation \"{constellation}\"", 'danger')
hub_if = request.form["hubif"]
hub_if_uuid = dev_ep_to_uuid.get((constellation, hub_if), None)
if hub_if_uuid is None:
flash(f"Invalid hub interface \"{hub_if}\"", 'danger')
leaf_if = request.form["leafif"]
leaf_if_uuid = dev_ep_to_uuid.get((constellation, leaf_if), None)
if leaf_if_uuid is None:
flash(f"Invalid leaf interface \"{leaf_if}\"", 'danger')
if service_name == "" or constellation_uuid is None or hub_if_uuid is None or leaf_if_uuid is None:
return render_template(
'service/add-xr.html', devices=devices, hub_if=hub_interfaces_by_device,
leaf_if=leaf_interfaces_by_device, ep_used_by=ep_used_by
)
service_name = request.form["service_name"]
if service_name == "":
flash(f"Service name must be specified", 'danger')
constellation = request.form["constellation"]
constellation_uuid = constellation_name_to_uuid.get(constellation, None)
if constellation_uuid is None:
flash(f"Invalid constellation \"{constellation}\"", 'danger')
hub_if = request.form["hubif"]
hub_if_uuid = dev_ep_to_uuid.get((constellation, hub_if), None)
if hub_if_uuid is None:
flash(f"Invalid hub interface \"{hub_if}\"", 'danger')
leaf_if = request.form["leafif"]
leaf_if_uuid = dev_ep_to_uuid.get((constellation, leaf_if), None)
if leaf_if_uuid is None:
flash(f"Invalid leaf interface \"{leaf_if}\"", 'danger')
if service_name == "" or constellation_uuid is None or hub_if_uuid is None or leaf_if_uuid is None:
return redirect(request.url)
json_context_uuid=json_context_id(context_uuid)
sr = {
"name": service_name,
"service_id": {
"context_id": {"context_uuid": {"uuid": context_uuid}},
"service_uuid": {"uuid": service_name}
},
'service_type' : ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE,
"service_endpoint_ids": [
{
'device_id': {'device_uuid': {'uuid': constellation_uuid}},
'endpoint_uuid': {'uuid': hub_if_uuid},
'topology_id': json_topology_id("admin", context_id=json_context_uuid)
},
{
'device_id': {'device_uuid': {'uuid': constellation_uuid}},
'endpoint_uuid': {'uuid': leaf_if_uuid},
'topology_id': json_topology_id("admin", context_id=json_context_uuid)
}
],
'service_status' : {'service_status': ServiceStatusEnum.SERVICESTATUS_PLANNED},
'service_constraints' : [],
}
json_tapi_settings = {
'capacity_value' : 50.0,
'capacity_unit' : 'GHz',
'layer_proto_name': 'PHOTONIC_MEDIA',
'layer_proto_qual': 'tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC',
'direction' : 'UNIDIRECTIONAL',
}
config_rule = json_config_rule_set('/settings', json_tapi_settings)
try:
service_client.connect()
endpoints, sr['service_endpoint_ids'] = sr['service_endpoint_ids'], []
try:
create_response = service_client.CreateService(Service(**sr))
except Exception as e:
flash(f'Failure to update service name {service_name} with endpoints and configuration, exception {str(e)}', 'danger')
return redirect(request.url)
json_context_uuid=json_context_id(context_uuid)
sr = {
"name": service_name,
"service_id": {
"context_id": {"context_uuid": {"uuid": context_uuid}},
"service_uuid": {"uuid": service_name}
},
'service_type' : ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE,
"service_endpoint_ids": [
{'device_id': {'device_uuid': {'uuid': constellation_uuid}}, 'endpoint_uuid': {'uuid': hub_if_uuid}, 'topology_id': json_topology_id("admin", context_id=json_context_uuid)},
{'device_id': {'device_uuid': {'uuid': constellation_uuid}}, 'endpoint_uuid': {'uuid': leaf_if_uuid}, 'topology_id': json_topology_id("admin", context_id=json_context_uuid)}
],
'service_status' : {'service_status': ServiceStatusEnum.SERVICESTATUS_PLANNED},
'service_constraints' : [],
}
sr['service_endpoint_ids'] = endpoints
sr['service_config'] = {'config_rules': [config_rule]}
json_tapi_settings = {
'capacity_value' : 50.0,
'capacity_unit' : 'GHz',
'layer_proto_name': 'PHOTONIC_MEDIA',
'layer_proto_qual': 'tapi-photonic-media:PHOTONIC_LAYER_QUALIFIER_NMC',
'direction' : 'UNIDIRECTIONAL',
}
config_rule = json_config_rule_set('/settings', json_tapi_settings)
with connected_client(service_client) as sc:
endpoints, sr['service_endpoint_ids'] = sr['service_endpoint_ids'], []
try:
create_response = sc.CreateService(Service(**sr))
except Exception as e:
flash(f'Failure to update service name {service_name} with endpoints and configuration, exception {str(e)}', 'danger')
return redirect(request.url)
sr['service_endpoint_ids'] = endpoints
sr['service_config'] = {'config_rules': [config_rule]}
try:
update_response = sc.UpdateService(Service(**sr))
flash(f'Created service {update_response.service_uuid.uuid}', 'success')
except Exception as e:
flash(f'Failure to update service {create_response.service_uuid.uuid} with endpoints and configuration, exception {str(e)}', 'danger')
return redirect(request.url)
try:
update_response = service_client.UpdateService(Service(**sr))
flash(f'Created service {update_response.service_uuid.uuid}', 'success')
except Exception as e:
flash(f'Failure to update service {create_response.service_uuid.uuid} with endpoints and configuration, exception {str(e)}', 'danger')
return redirect(request.url)
return redirect(url_for('service.home'))
return redirect(url_for('service.home'))
finally:
service_client.close()
@service.get('<path:service_uuid>/detail')
def detail(service_uuid: str):
......@@ -287,7 +295,9 @@ def detail(service_uuid: str):
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, type = type, f_action = f_action, l_action = l_action)
endpoints_data=endpoints_data, ste=ServiceTypeEnum, sse=ServiceStatusEnum, ile=IsolationLevelEnum,
type=ACL_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)
......@@ -318,16 +328,9 @@ def delete(service_uuid: str):
def add_configure():
form_1 = AddServiceForm_1()
if form_1.validate_on_submit():
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'))
service_type = str(form_1.service_type.data)
if service_type in {'ACL_L2', 'ACL_IPV4', 'ACL_IPV6', 'L2VPN', 'L3VPN'}:
return redirect(url_for('service.add_configure_{:s}'.format(service_type)))
return render_template('service/add.html', form_1=form_1, submit_text='Continue to configuraton')
@service.route('add/configure/ACL_L2', methods=['GET', 'POST'])
......@@ -595,15 +598,13 @@ def get_device_vendor(form, devices):
return vendor_value_1, vendor_value_2
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"')
if vendor != "ADVA": return
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
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')
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)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment