diff --git a/my_deploy.sh b/my_deploy.sh index 8fe133477e95e4a3d595edf59878330cc1e600bb..7e8abb1282655dd300d48457f655ac932cbb6e68 100755 --- a/my_deploy.sh +++ b/my_deploy.sh @@ -20,19 +20,18 @@ export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/" # Set the list of components, separated by spaces, you want to build images for, and deploy. -#export TFS_COMPONENTS="context device pathcomp service slice compute webui load_generator" -export TFS_COMPONENTS="context device pathcomp service slice webui" +export TFS_COMPONENTS="context device pathcomp service slice compute webui load_generator" -# Uncoment to activate Monitoring -export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" +# Uncomment to activate Monitoring +#export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" -# Uncoment to activate Automation and Policy Manager +# Uncomment to activate Automation and Policy Manager #export TFS_COMPONENTS="${TFS_COMPONENTS} automation policy" -# Uncoment to activate Optical CyberSecurity +# Uncomment to activate Optical CyberSecurity #export TFS_COMPONENTS="${TFS_COMPONENTS} dbscanserving opticalattackmitigator opticalattackdetector opticalattackmanager" -# Uncoment to activate L3 CyberSecurity +# Uncomment to activate L3 CyberSecurity #export TFS_COMPONENTS="${TFS_COMPONENTS} l3_attackmitigator l3_centralizedattackdetector" # Set the tag you want to use for your images. @@ -42,10 +41,12 @@ export TFS_IMAGE_TAG="dev" export TFS_K8S_NAMESPACE="tfs" # Set additional manifest files to be applied after the deployment -#export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml manifests/servicemonitors.yaml" export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml" -# Uncoment when deploying Optical CyberSecurity +# Uncomment to monitor performance of components +export TFS_EXTRA_MANIFESTS="${TFS_EXTRA_MANIFESTS} manifests/servicemonitors.yaml" + +# Uncomment when deploying Optical CyberSecurity #export TFS_EXTRA_MANIFESTS="${TFS_EXTRA_MANIFESTS} manifests/cachingservice.yaml" # Set the new Grafana admin password diff --git a/src/service/service/service_handlers/l2nm_emulated/ConfigRules.py b/src/service/service/service_handlers/l2nm_emulated/ConfigRules.py index ab5807a9fa5b2f9d0031851ba2cd8069dece44f0..e68a62030fba242d40e6b1c9bf0c2c65e66639f2 100644 --- a/src/service/service/service_handlers/l2nm_emulated/ConfigRules.py +++ b/src/service/service/service_handlers/l2nm_emulated/ConfigRules.py @@ -21,6 +21,12 @@ def setup_config_rules( service_settings : TreeNode, endpoint_settings : TreeNode, endpoint_acls : List [Tuple] ) -> List[Dict]: + if service_settings is None: return [] + if endpoint_settings is None: return [] + + json_settings : Dict = service_settings.value + json_endpoint_settings : Dict = endpoint_settings.value + #mtu = json_settings.get('mtu', 1450 ) # 1512 #address_families = json_settings.get('address_families', [] ) # ['IPV4'] #bgp_as = json_settings.get('bgp_as', 0 ) # 65000 @@ -80,6 +86,9 @@ def teardown_config_rules( service_settings : TreeNode, endpoint_settings : TreeNode ) -> List[Dict]: + if service_settings is None: return [] + if endpoint_settings is None: return [] + #json_settings : Dict = service_settings.value json_endpoint_settings : Dict = endpoint_settings.value diff --git a/src/webui/service/device/forms.py b/src/webui/service/device/forms.py index a6e07fe3cee6889163d5f22670326ef62320bd9d..e884e96a511ab90625bda257075c80adce4406cd 100644 --- a/src/webui/service/device/forms.py +++ b/src/webui/service/device/forms.py @@ -18,10 +18,10 @@ from wtforms.validators import DataRequired, Length, NumberRange, ValidationErro from common.proto.context_pb2 import DeviceOperationalStatusEnum class AddDeviceForm(FlaskForm): - device_id = StringField('ID', - validators=[DataRequired(), Length(min=5)]) + device_id = StringField('ID', validators=[DataRequired(), Length(min=5)]) device_type = SelectField('Type') operational_status = SelectField('Operational Status', coerce=int, validators=[NumberRange(min=0)]) + device_drivers_undefined = BooleanField('UNDEFINED / EMULATED') device_drivers_openconfig = BooleanField('OPENCONFIG') device_drivers_transport_api = BooleanField('TRANSPORT_API') @@ -31,9 +31,11 @@ class AddDeviceForm(FlaskForm): device_drivers_xr = BooleanField('XR') device_drivers_ietf_l2vpn = BooleanField('IETF L2VPN') device_drivers_gnmi_openconfig = BooleanField('GNMI OPENCONFIG') + device_config_address = StringField('connect/address',default='127.0.0.1',validators=[DataRequired(), Length(min=5)]) device_config_port = StringField('connect/port',default='0',validators=[DataRequired(), Length(min=1)]) device_config_settings = TextAreaField('connect/settings',default='{}',validators=[DataRequired(), Length(min=2)]) + submit = SubmitField('Add') def validate_operational_status(form, field): diff --git a/src/webui/service/service/routes.py b/src/webui/service/service/routes.py index 3d3d47ab59500a8cf3d330407d9311ad17ece94b..fa3d3b164bd8d470db92fc1041cc972e5e01f19f 100644 --- a/src/webui/service/service/routes.py +++ b/src/webui/service/service/routes.py @@ -92,6 +92,12 @@ def home(): 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: if cr.action == ConfigActionEnum.CONFIGACTION_SET and cr.custom and cr.custom.resource_key == "_connect/settings": @@ -103,139 +109,139 @@ def get_hub_module_name(dev: Device) -> Optional[str]: pass return None -#@service.route('add-xr', methods=['GET', 'POST']) -#def add_xr(): -# ### FIXME: copypaste -# 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() -# grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) -# 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() -# -# # 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') -# 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 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) -# -# 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) -# -# return redirect(url_for('service.home')) +@service.route('add-xr', methods=['GET', 'POST']) +def add_xr(): + ### FIXME: copypaste + 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() + grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False) + 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() + + # 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') + 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 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) + + 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) + + return redirect(url_for('service.home')) @service.get('<path:service_uuid>/detail') def detail(service_uuid: str):