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

Merge branch 'release/2.0.1' of https://labs.etsi.org/rep/tfs/controller into feat/slice-grouping

parents e2cc0054 0beaad33
No related branches found
No related tags found
2 merge requests!142Release TeraFlowSDN 2.1,!64Slice Grouping
...@@ -85,7 +85,7 @@ TMP_LOGS_FOLDER="$TMP_FOLDER/logs" ...@@ -85,7 +85,7 @@ TMP_LOGS_FOLDER="$TMP_FOLDER/logs"
mkdir -p $TMP_LOGS_FOLDER mkdir -p $TMP_LOGS_FOLDER
echo "Deleting and Creating a new namespace..." echo "Deleting and Creating a new namespace..."
kubectl delete namespace $TFS_K8S_NAMESPACE kubectl delete namespace $TFS_K8S_NAMESPACE --ignore-not-found
kubectl create namespace $TFS_K8S_NAMESPACE kubectl create namespace $TFS_K8S_NAMESPACE
printf "\n" printf "\n"
......
...@@ -51,7 +51,7 @@ class SyntheticSamplingParameters: ...@@ -51,7 +51,7 @@ class SyntheticSamplingParameters:
metric = match.group(2) metric = match.group(2)
metric_sense = metric.lower().replace('packets_', '').replace('bytes_', '') metric_sense = metric.lower().replace('packets_', '').replace('bytes_', '')
LOGGER.info(MSG_INFO.format(monitoring_resource_key, endpoint_uuid, metric, metric_sense)) LOGGER.debug(MSG_INFO.format(monitoring_resource_key, endpoint_uuid, metric, metric_sense))
parameters_key = '{:s}-{:s}'.format(endpoint_uuid, metric_sense) parameters_key = '{:s}-{:s}'.format(endpoint_uuid, metric_sense)
parameters = self.__data.get(parameters_key) parameters = self.__data.get(parameters_key)
......
...@@ -96,6 +96,7 @@ def create_app(use_config=None, web_app_root=None): ...@@ -96,6 +96,7 @@ def create_app(use_config=None, web_app_root=None):
app.register_blueprint(link) app.register_blueprint(link)
app.jinja_env.globals.update({ # pylint: disable=no-member app.jinja_env.globals.update({ # pylint: disable=no-member
'enumerate' : enumerate,
'json_to_list' : json_to_list, 'json_to_list' : json_to_list,
'get_working_context' : get_working_context, 'get_working_context' : get_working_context,
'get_working_topology': get_working_topology, 'get_working_topology': get_working_topology,
......
...@@ -12,21 +12,16 @@ ...@@ -12,21 +12,16 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# external imports
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import StringField, SelectField, TextAreaField, SubmitField, BooleanField, Form from wtforms import StringField, SelectField, TextAreaField, SubmitField, BooleanField
from wtforms.validators import DataRequired, Length, NumberRange, Regexp, ValidationError from wtforms.validators import DataRequired, Length, NumberRange, ValidationError
from common.proto.context_pb2 import DeviceOperationalStatusEnum from common.proto.context_pb2 import DeviceOperationalStatusEnum
from webui.utils.form_validators import key_value_validator
class AddDeviceForm(FlaskForm): class AddDeviceForm(FlaskForm):
device_id = StringField('ID', device_id = StringField('ID',
validators=[DataRequired(), Length(min=5)]) validators=[DataRequired(), Length(min=5)])
device_type = SelectField('Type', choices = []) device_type = SelectField('Type')
operational_status = SelectField('Operational Status', operational_status = SelectField('Operational Status', coerce=int, validators=[NumberRange(min=0)])
# choices=[(-1, 'Select...'), (0, 'Undefined'), (1, 'Disabled'), (2, 'Enabled')],
coerce=int,
validators=[NumberRange(min=0)])
device_drivers_undefined = BooleanField('UNDEFINED / EMULATED') device_drivers_undefined = BooleanField('UNDEFINED / EMULATED')
device_drivers_openconfig = BooleanField('OPENCONFIG') device_drivers_openconfig = BooleanField('OPENCONFIG')
device_drivers_transport_api = BooleanField('TRANSPORT_API') device_drivers_transport_api = BooleanField('TRANSPORT_API')
......
...@@ -14,16 +14,14 @@ ...@@ -14,16 +14,14 @@
import json import json
from flask import current_app, render_template, Blueprint, flash, session, redirect, url_for from flask import current_app, render_template, Blueprint, flash, session, redirect, url_for
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import ( from common.proto.context_pb2 import (
ConfigActionEnum, Device, DeviceDriverEnum, DeviceId, DeviceList, DeviceOperationalStatusEnum, Empty, TopologyId) ConfigActionEnum, Device, DeviceDriverEnum, DeviceId, DeviceList, DeviceOperationalStatusEnum, Empty)
from common.tools.object_factory.Context import json_context_id from common.tools.context_queries.Device import get_device
from common.tools.object_factory.Topology import json_topology_id from common.tools.context_queries.Topology import get_topology
from context.client.ContextClient import ContextClient from context.client.ContextClient import ContextClient
from device.client.DeviceClient import DeviceClient from device.client.DeviceClient import DeviceClient
from webui.service.device.forms import AddDeviceForm from webui.service.device.forms import AddDeviceForm, ConfigForm, UpdateDeviceForm
from common.DeviceTypes import DeviceTypeEnum
from webui.service.device.forms import ConfigForm
from webui.service.device.forms import UpdateDeviceForm
device = Blueprint('device', __name__, url_prefix='/device') device = Blueprint('device', __name__, url_prefix='/device')
context_client = ContextClient() context_client = ContextClient()
...@@ -39,17 +37,19 @@ def home(): ...@@ -39,17 +37,19 @@ def home():
topology_uuid = session['topology_uuid'] topology_uuid = session['topology_uuid']
context_client.connect() context_client.connect()
json_topo_id = json_topology_id(topology_uuid, context_id=json_context_id(context_uuid)) grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False)
grpc_topology = context_client.GetTopology(TopologyId(**json_topo_id)) if grpc_topology is None:
topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids} flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger')
grpc_devices: DeviceList = context_client.ListDevices(Empty()) devices = []
else:
topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids}
grpc_devices: DeviceList = context_client.ListDevices(Empty())
devices = [
device for device in grpc_devices.devices
if device.device_id.device_uuid.uuid in topo_device_uuids
]
context_client.close() context_client.close()
devices = [
device for device in grpc_devices.devices
if device.device_id.device_uuid.uuid in topo_device_uuids
]
return render_template( return render_template(
'device/home.html', devices=devices, dde=DeviceDriverEnum, 'device/home.html', devices=devices, dde=DeviceDriverEnum,
dose=DeviceOperationalStatusEnum) dose=DeviceOperationalStatusEnum)
...@@ -71,23 +71,23 @@ def add(): ...@@ -71,23 +71,23 @@ def add():
if form.validate_on_submit(): if form.validate_on_submit():
device_obj = Device() device_obj = Device()
# Device UUID: # Device UUID:
device_obj.device_id.device_uuid.uuid = form.device_id.data device_obj.device_id.device_uuid.uuid = form.device_id.data # pylint: disable=no-member
# Device type: # Device type:
device_obj.device_type = str(form.device_type.data) device_obj.device_type = str(form.device_type.data)
# Device configurations: # Device configurations:
config_rule = device_obj.device_config.config_rules.add() config_rule = device_obj.device_config.config_rules.add() # pylint: disable=no-member
config_rule.action = ConfigActionEnum.CONFIGACTION_SET config_rule.action = ConfigActionEnum.CONFIGACTION_SET
config_rule.custom.resource_key = '_connect/address' config_rule.custom.resource_key = '_connect/address'
config_rule.custom.resource_value = form.device_config_address.data config_rule.custom.resource_value = form.device_config_address.data
config_rule = device_obj.device_config.config_rules.add() config_rule = device_obj.device_config.config_rules.add() # pylint: disable=no-member
config_rule.action = ConfigActionEnum.CONFIGACTION_SET config_rule.action = ConfigActionEnum.CONFIGACTION_SET
config_rule.custom.resource_key = '_connect/port' config_rule.custom.resource_key = '_connect/port'
config_rule.custom.resource_value = form.device_config_port.data config_rule.custom.resource_value = form.device_config_port.data
config_rule = device_obj.device_config.config_rules.add() config_rule = device_obj.device_config.config_rules.add() # pylint: disable=no-member
config_rule.action = ConfigActionEnum.CONFIGACTION_SET config_rule.action = ConfigActionEnum.CONFIGACTION_SET
config_rule.custom.resource_key = '_connect/settings' config_rule.custom.resource_key = '_connect/settings'
...@@ -105,20 +105,22 @@ def add(): ...@@ -105,20 +105,22 @@ def add():
device_obj.device_operational_status = form.operational_status.data device_obj.device_operational_status = form.operational_status.data
# Device drivers: # Device drivers:
device_drivers = list()
if form.device_drivers_undefined.data: if form.device_drivers_undefined.data:
device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_UNDEFINED) device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_UNDEFINED)
if form.device_drivers_openconfig.data: if form.device_drivers_openconfig.data:
device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG) device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG)
if form.device_drivers_transport_api.data: if form.device_drivers_transport_api.data:
device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API) device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API)
if form.device_drivers_p4.data: if form.device_drivers_p4.data:
device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_P4) device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_P4)
if form.device_drivers_ietf_network_topology.data: if form.device_drivers_ietf_network_topology.data:
device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY) device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY)
if form.device_drivers_onf_tr_352.data: if form.device_drivers_onf_tr_352.data:
device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352) device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352)
if form.device_drivers_xr.data: if form.device_drivers_xr.data:
device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_XR) device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_XR)
device_obj.device_drivers.extend(device_drivers) # pylint: disable=no-member
try: try:
device_client.connect() device_client.connect()
...@@ -126,7 +128,7 @@ def add(): ...@@ -126,7 +128,7 @@ def add():
device_client.close() device_client.close()
flash(f'New device was created with ID "{response.device_uuid.uuid}".', 'success') flash(f'New device was created with ID "{response.device_uuid.uuid}".', 'success')
return redirect(url_for('device.home')) return redirect(url_for('device.home'))
except Exception as e: except Exception as e: # pylint: disable=broad-except
flash(f'Problem adding the device. {e.details()}', 'danger') flash(f'Problem adding the device. {e.details()}', 'danger')
return render_template('device/add.html', form=form, return render_template('device/add.html', form=form,
...@@ -134,14 +136,15 @@ def add(): ...@@ -134,14 +136,15 @@ def add():
@device.route('detail/<path:device_uuid>', methods=['GET', 'POST']) @device.route('detail/<path:device_uuid>', methods=['GET', 'POST'])
def detail(device_uuid: str): def detail(device_uuid: str):
request = DeviceId()
request.device_uuid.uuid = device_uuid
context_client.connect() context_client.connect()
response = context_client.GetDevice(request) device_obj = get_device(context_client, device_uuid, rw_copy=False)
if device_obj is None:
flash('Device({:s}) not found'.format(str(device_uuid)), 'danger')
device_obj = Device()
context_client.close() context_client.close()
return render_template('device/detail.html', device=response,
dde=DeviceDriverEnum, return render_template(
dose=DeviceOperationalStatusEnum) 'device/detail.html', device=device_obj, dde=DeviceDriverEnum, dose=DeviceOperationalStatusEnum)
@device.get('<path:device_uuid>/delete') @device.get('<path:device_uuid>/delete')
def delete(device_uuid): def delete(device_uuid):
...@@ -154,13 +157,13 @@ def delete(device_uuid): ...@@ -154,13 +157,13 @@ def delete(device_uuid):
# TODO: finalize implementation # TODO: finalize implementation
request = DeviceId() request = DeviceId()
request.device_uuid.uuid = device_uuid request.device_uuid.uuid = device_uuid # pylint: disable=no-member
device_client.connect() device_client.connect()
response = device_client.DeleteDevice(request) device_client.DeleteDevice(request)
device_client.close() device_client.close()
flash(f'Device "{device_uuid}" deleted successfully!', 'success') flash(f'Device "{device_uuid}" deleted successfully!', 'success')
except Exception as e: except Exception as e: # pylint: disable=broad-except
flash(f'Problem deleting device "{device_uuid}": {e.details()}', 'danger') flash(f'Problem deleting device "{device_uuid}": {e.details()}', 'danger')
current_app.logger.exception(e) current_app.logger.exception(e)
return redirect(url_for('device.home')) return redirect(url_for('device.home'))
...@@ -169,25 +172,25 @@ def delete(device_uuid): ...@@ -169,25 +172,25 @@ def delete(device_uuid):
def addconfig(device_uuid): def addconfig(device_uuid):
form = ConfigForm() form = ConfigForm()
request = DeviceId() request = DeviceId()
request.device_uuid.uuid = device_uuid request.device_uuid.uuid = device_uuid # pylint: disable=no-member
context_client.connect() context_client.connect()
response = context_client.GetDevice(request) response = context_client.GetDevice(request)
context_client.close() context_client.close()
if form.validate_on_submit(): if form.validate_on_submit():
device = Device() device_obj = Device()
device.CopyFrom(response) device_obj.CopyFrom(response)
config_rule = device.device_config.config_rules.add() config_rule = device_obj.device_config.config_rules.add() # pylint: disable=no-member
config_rule.action = ConfigActionEnum.CONFIGACTION_SET config_rule.action = ConfigActionEnum.CONFIGACTION_SET
config_rule.custom.resource_key = form.device_key_config.data config_rule.custom.resource_key = form.device_key_config.data
config_rule.custom.resource_value = form.device_value_config.data config_rule.custom.resource_value = form.device_value_config.data
try: try:
device_client.connect() device_client.connect()
response: DeviceId = device_client.ConfigureDevice(device) response: DeviceId = device_client.ConfigureDevice(device_obj)
device_client.close() device_client.close()
flash(f'New configuration was created with ID "{response.device_uuid.uuid}".', 'success') flash(f'New configuration was created with ID "{response.device_uuid.uuid}".', 'success')
return redirect(url_for('device.home')) return redirect(url_for('device.home'))
except Exception as e: except Exception as e: # pylint: disable=broad-except
flash(f'Problem adding the device. {e.details()}', 'danger') flash(f'Problem adding the device. {e.details()}', 'danger')
return render_template('device/addconfig.html', form=form, submit_text='Add New Configuration') return render_template('device/addconfig.html', form=form, submit_text='Add New Configuration')
...@@ -203,28 +206,29 @@ def updateconfig(): ...@@ -203,28 +206,29 @@ def updateconfig():
def update(device_uuid): def update(device_uuid):
form = UpdateDeviceForm() form = UpdateDeviceForm()
request = DeviceId() request = DeviceId()
request.device_uuid.uuid = device_uuid request.device_uuid.uuid = device_uuid # pylint: disable=no-member
context_client.connect() context_client.connect()
response = context_client.GetDevice(request) response = context_client.GetDevice(request)
context_client.close() context_client.close()
# listing enum values # listing enum values
form.update_operational_status.choices = [] form.update_operational_status.choices = []
for key, value in DeviceOperationalStatusEnum.DESCRIPTOR.values_by_name.items(): for key, _ in DeviceOperationalStatusEnum.DESCRIPTOR.values_by_name.items():
form.update_operational_status.choices.append((DeviceOperationalStatusEnum.Value(key), key.replace('DEVICEOPERATIONALSTATUS_', ''))) item = (DeviceOperationalStatusEnum.Value(key), key.replace('DEVICEOPERATIONALSTATUS_', ''))
form.update_operational_status.choices.append(item)
form.update_operational_status.default = response.device_operational_status form.update_operational_status.default = response.device_operational_status
if form.validate_on_submit(): if form.validate_on_submit():
device = Device() device_obj = Device()
device.CopyFrom(response) device_obj.CopyFrom(response)
device.device_operational_status = form.update_operational_status.data device_obj.device_operational_status = form.update_operational_status.data
try: try:
device_client.connect() device_client.connect()
response: DeviceId = device_client.ConfigureDevice(device) response: DeviceId = device_client.ConfigureDevice(device_obj)
device_client.close() device_client.close()
flash(f'Status of device with ID "{response.device_uuid.uuid}" was updated.', 'success') flash(f'Status of device with ID "{response.device_uuid.uuid}" was updated.', 'success')
return redirect(url_for('device.home')) return redirect(url_for('device.home'))
except Exception as e: except Exception as e: # pylint: disable=broad-except
flash(f'Problem updating the device. {e.details()}', 'danger') flash(f'Problem updating the device. {e.details()}', 'danger')
return render_template('device/update.html', device=response, form=form, submit_text='Update Device') return render_template('device/update.html', device=response, form=form, submit_text='Update Device')
...@@ -14,10 +14,10 @@ ...@@ -14,10 +14,10 @@
from flask import render_template, Blueprint, flash, session, redirect, url_for from flask import render_template, Blueprint, flash, session, redirect, url_for
from common.proto.context_pb2 import Empty, LinkId, LinkList, TopologyId from common.proto.context_pb2 import Empty, Link, LinkList
from common.tools.context_queries.EndPoint import get_endpoint_names from common.tools.context_queries.EndPoint import get_endpoint_names
from common.tools.object_factory.Context import json_context_id from common.tools.context_queries.Link import get_link
from common.tools.object_factory.Topology import json_topology_id from common.tools.context_queries.Topology import get_topology
from context.client.ContextClient import ContextClient from context.client.ContextClient import ContextClient
...@@ -33,20 +33,21 @@ def home(): ...@@ -33,20 +33,21 @@ def home():
context_uuid = session['context_uuid'] context_uuid = session['context_uuid']
topology_uuid = session['topology_uuid'] topology_uuid = session['topology_uuid']
links, endpoint_ids = list(), list()
device_names, endpoints_data = dict(), dict()
context_client.connect() context_client.connect()
json_topo_id = json_topology_id(topology_uuid, context_id=json_context_id(context_uuid)) grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False)
grpc_topology = context_client.GetTopology(TopologyId(**json_topo_id)) if grpc_topology is None:
topo_link_uuids = {link_id.link_uuid.uuid for link_id in grpc_topology.link_ids} flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger')
grpc_links: LinkList = context_client.ListLinks(Empty()) else:
topo_link_uuids = {link_id.link_uuid.uuid for link_id in grpc_topology.link_ids}
endpoint_ids = [] grpc_links: LinkList = context_client.ListLinks(Empty())
links = [] for link_ in grpc_links.links:
for link_ in grpc_links.links: if link_.link_id.link_uuid.uuid not in topo_link_uuids: continue
if link_.link_id.link_uuid.uuid not in topo_link_uuids: continue links.append(link_)
links.append(link_) endpoint_ids.extend(link_.link_endpoint_ids)
endpoint_ids.extend(link_.link_endpoint_ids) device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids)
device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids)
context_client.close() context_client.close()
return render_template('link/home.html', links=links, device_names=device_names, endpoints_data=endpoints_data) return render_template('link/home.html', links=links, device_names=device_names, endpoints_data=endpoints_data)
...@@ -54,10 +55,13 @@ def home(): ...@@ -54,10 +55,13 @@ def home():
@link.route('detail/<path:link_uuid>', methods=('GET', 'POST')) @link.route('detail/<path:link_uuid>', methods=('GET', 'POST'))
def detail(link_uuid: str): def detail(link_uuid: str):
request = LinkId()
request.link_uuid.uuid = link_uuid # pylint: disable=no-member
context_client.connect() context_client.connect()
response = context_client.GetLink(request) link_obj = get_link(context_client, link_uuid, rw_copy=False)
device_names, endpoints_data = get_endpoint_names(context_client, response.link_endpoint_ids) if link_obj is None:
flash('Link({:s}) not found'.format(str(link_uuid)), 'danger')
link_obj = Link()
device_names, endpoints_data = dict(), dict()
else:
device_names, endpoints_data = get_endpoint_names(context_client, link_obj.link_endpoint_ids)
context_client.close() context_client.close()
return render_template('link/detail.html',link=response, device_names=device_names, endpoints_data=endpoints_data) return render_template('link/detail.html',link=link_obj, device_names=device_names, endpoints_data=endpoints_data)
...@@ -14,8 +14,11 @@ ...@@ -14,8 +14,11 @@
import grpc import grpc
from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for
from common.proto.context_pb2 import ContextId, Service, ServiceId, ServiceTypeEnum, ServiceStatusEnum, Connection from common.proto.context_pb2 import (
IsolationLevelEnum, Service, ServiceId, ServiceTypeEnum, ServiceStatusEnum, Connection)
from common.tools.context_queries.Context import get_context
from common.tools.context_queries.EndPoint import get_endpoint_names from common.tools.context_queries.EndPoint import get_endpoint_names
from common.tools.context_queries.Service import get_service
from context.client.ContextClient import ContextClient from context.client.ContextClient import ContextClient
from service.client.ServiceClient import ServiceClient from service.client.ServiceClient import ServiceClient
...@@ -26,93 +29,94 @@ service_client = ServiceClient() ...@@ -26,93 +29,94 @@ service_client = ServiceClient()
@service.get('/') @service.get('/')
def home(): def home():
# flash('This is an info message', 'info') if 'context_uuid' not in session or 'topology_uuid' not in session:
# flash('This is a danger message', 'danger')
context_uuid = session.get('context_uuid', '-')
if context_uuid == "-":
flash("Please select a context!", "warning") flash("Please select a context!", "warning")
return redirect(url_for("main.home")) return redirect(url_for("main.home"))
request = ContextId() context_uuid = session['context_uuid']
request.context_uuid.uuid = context_uuid
context_client.connect() context_client.connect()
try:
service_list = context_client.ListServices(request) context_obj = get_context(context_client, context_uuid, rw_copy=False)
# print(service_list) if context_obj is None:
services = service_list.services flash('Context({:s}) not found'.format(str(context_uuid)), 'danger')
context_found = True services, device_names, endpoints_data = list(), list(), list()
except grpc.RpcError as e:
if e.code() != grpc.StatusCode.NOT_FOUND: raise
if e.details() != 'Context({:s}) not found'.format(context_uuid): raise
services = []
context_found = False
if context_found:
endpoint_ids = []
for service_ in services:
endpoint_ids.extend(service_.service_endpoint_ids)
device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids)
else: else:
device_names, endpoints_data = [],[] try:
services = context_client.ListServices(context_obj.context_id)
services = services.services
except grpc.RpcError as e:
if e.code() != grpc.StatusCode.NOT_FOUND: raise
if e.details() != 'Context({:s}) not found'.format(context_uuid): raise
services, device_names, endpoints_data = list(), dict(), dict()
else:
endpoint_ids = list()
for service_ in services:
endpoint_ids.extend(service_.service_endpoint_ids)
device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids)
context_client.close() context_client.close()
return render_template( return render_template(
'service/home.html', services=services, device_names=device_names, endpoints_data=endpoints_data, 'service/home.html', services=services, device_names=device_names, endpoints_data=endpoints_data,
context_not_found=not context_found, ste=ServiceTypeEnum, sse=ServiceStatusEnum) ste=ServiceTypeEnum, sse=ServiceStatusEnum)
@service.route('add', methods=['GET', 'POST']) @service.route('add', methods=['GET', 'POST'])
def add(): def add():
flash('Add service route called', 'danger') flash('Add service route called', 'danger')
raise NotImplementedError() raise NotImplementedError()
return render_template('service/home.html') #return render_template('service/home.html')
@service.get('<path:service_uuid>/detail') @service.get('<path:service_uuid>/detail')
def detail(service_uuid: str): def detail(service_uuid: str):
context_uuid = session.get('context_uuid', '-') if 'context_uuid' not in session or 'topology_uuid' not in session:
if context_uuid == "-":
flash("Please select a context!", "warning") flash("Please select a context!", "warning")
return redirect(url_for("main.home")) return redirect(url_for("main.home"))
context_uuid = session['context_uuid']
request: ServiceId = ServiceId()
request.service_uuid.uuid = service_uuid
request.context_id.context_uuid.uuid = context_uuid
try: try:
context_client.connect() context_client.connect()
response: Service = context_client.GetService(request)
connections: Connection = context_client.ListConnections(request)
connections = connections.connections
endpoint_ids = [] endpoint_ids = list()
endpoint_ids.extend(response.service_endpoint_ids) service_obj = get_service(context_client, service_uuid, rw_copy=False)
for connection in connections: if service_obj is None:
endpoint_ids.extend(connection.path_hops_endpoint_ids) flash('Context({:s})/Service({:s}) not found'.format(str(context_uuid), str(service_uuid)), 'danger')
device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids) service_obj = Service()
else:
endpoint_ids.extend(service_obj.service_endpoint_ids)
connections: Connection = context_client.ListConnections(service_obj.service_id)
connections = connections.connections
for connection in connections: endpoint_ids.extend(connection.path_hops_endpoint_ids)
if len(endpoint_ids) > 0:
device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids)
else:
device_names, endpoints_data = dict(), dict()
context_client.close() 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)
except Exception as e: except Exception as e:
flash('The system encountered an error and cannot show the details of this service.', 'warning') flash('The system encountered an error and cannot show the details of this service.', 'warning')
current_app.logger.exception(e) current_app.logger.exception(e)
return redirect(url_for('service.home')) return redirect(url_for('service.home'))
return render_template(
'service/detail.html', service=response, connections=connections, device_names=device_names,
endpoints_data=endpoints_data, ste=ServiceTypeEnum, sse=ServiceStatusEnum)
@service.get('<path:service_uuid>/delete') @service.get('<path:service_uuid>/delete')
def delete(service_uuid: str): def delete(service_uuid: str):
context_uuid = session.get('context_uuid', '-') if 'context_uuid' not in session or 'topology_uuid' not in session:
if context_uuid == "-":
flash("Please select a context!", "warning") flash("Please select a context!", "warning")
return redirect(url_for("main.home")) return redirect(url_for("main.home"))
context_uuid = session['context_uuid']
try: try:
request = ServiceId() request = ServiceId()
request.service_uuid.uuid = service_uuid request.service_uuid.uuid = service_uuid
request.context_id.context_uuid.uuid = context_uuid request.context_id.context_uuid.uuid = context_uuid
service_client.connect() service_client.connect()
response = service_client.DeleteService(request) service_client.DeleteService(request)
service_client.close() service_client.close()
flash('Service "{:s}" deleted successfully!'.format(service_uuid), 'success') flash('Service "{:s}" deleted successfully!'.format(service_uuid), 'success')
......
...@@ -11,11 +11,13 @@ ...@@ -11,11 +11,13 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
#
import grpc import grpc
from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for
from common.proto.context_pb2 import ContextId, Slice, SliceId, SliceStatusEnum from common.proto.context_pb2 import IsolationLevelEnum, Slice, SliceId, SliceStatusEnum
from common.tools.context_queries.Context import get_context
from common.tools.context_queries.EndPoint import get_endpoint_names from common.tools.context_queries.EndPoint import get_endpoint_names
from common.tools.context_queries.Slice import get_slice
from context.client.ContextClient import ContextClient from context.client.ContextClient import ContextClient
from slice.client.SliceClient import SliceClient from slice.client.SliceClient import SliceClient
...@@ -26,92 +28,88 @@ slice_client = SliceClient() ...@@ -26,92 +28,88 @@ slice_client = SliceClient()
@slice.get('/') @slice.get('/')
def home(): def home():
context_uuid = session.get('context_uuid', '-') if 'context_uuid' not in session or 'topology_uuid' not in session:
if context_uuid == "-":
flash("Please select a context!", "warning") flash("Please select a context!", "warning")
return redirect(url_for("main.home")) return redirect(url_for("main.home"))
request = ContextId() context_uuid = session['context_uuid']
request.context_uuid.uuid = context_uuid
context_client.connect() context_client.connect()
try:
slice_list = context_client.ListSlices(request) context_obj = get_context(context_client, context_uuid, rw_copy=False)
slices = slice_list.slices if context_obj is None:
context_found = True flash('Context({:s}) not found'.format(str(context_uuid)), 'danger')
except grpc.RpcError as e: device_names, endpoints_data = list(), list()
if e.code() != grpc.StatusCode.NOT_FOUND: raise
if e.details() != 'Context({:s}) not found'.format(context_uuid): raise
slices = []
context_found = False
if context_found:
endpoint_ids = []
for slice_ in slices:
endpoint_ids.extend(slice_.slice_endpoint_ids)
device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids)
else: else:
device_names, endpoints_data = [],[] try:
slices = context_client.ListSlices(context_obj.context_id)
slices = slices.slices
except grpc.RpcError as e:
if e.code() != grpc.StatusCode.NOT_FOUND: raise
if e.details() != 'Context({:s}) not found'.format(context_uuid): raise
slices, device_names, endpoints_data = list(), dict(), dict()
else:
endpoint_ids = list()
for slice_ in slices:
endpoint_ids.extend(slice_.slice_endpoint_ids)
device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids)
context_client.close() context_client.close()
return render_template( return render_template(
'slice/home.html', slices=slices, device_names=device_names, endpoints_data=endpoints_data, 'slice/home.html', slices=slices, device_names=device_names, endpoints_data=endpoints_data,
context_not_found=not context_found, sse=SliceStatusEnum) sse=SliceStatusEnum)
@slice.route('add', methods=['GET', 'POST']) @slice.route('add', methods=['GET', 'POST'])
def add(): def add():
flash('Add slice route called', 'danger') flash('Add slice route called', 'danger')
raise NotImplementedError() raise NotImplementedError()
return render_template('slice/home.html') #return render_template('slice/home.html')
@slice.get('<path:slice_uuid>/detail') @slice.get('<path:slice_uuid>/detail')
def detail(slice_uuid: str): def detail(slice_uuid: str):
context_uuid = session.get('context_uuid', '-') if 'context_uuid' not in session or 'topology_uuid' not in session:
if context_uuid == "-":
flash("Please select a context!", "warning") flash("Please select a context!", "warning")
return redirect(url_for("main.home")) return redirect(url_for("main.home"))
context_uuid = session['context_uuid']
request: SliceId = SliceId()
request.slice_uuid.uuid = slice_uuid
request.context_id.context_uuid.uuid = context_uuid
req = ContextId()
req.context_uuid.uuid = context_uuid
try: try:
context_client.connect() context_client.connect()
response: Slice = context_client.GetSlice(request)
services = context_client.ListServices(req)
endpoint_ids = [] slice_obj = get_slice(context_client, slice_uuid, rw_copy=False)
endpoint_ids.extend(response.slice_endpoint_ids) if slice_obj is None:
device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids) flash('Context({:s})/Slice({:s}) not found'.format(str(context_uuid), str(slice_uuid)), 'danger')
slice_obj = Slice()
else:
device_names, endpoints_data = get_endpoint_names(context_client, slice_obj.slice_endpoint_ids)
context_client.close() context_client.close()
return render_template(
'slice/detail.html', slice=slice_obj, device_names=device_names, endpoints_data=endpoints_data,
sse=SliceStatusEnum, ile=IsolationLevelEnum)
except Exception as e: except Exception as e:
flash('The system encountered an error and cannot show the details of this slice.', 'warning') flash('The system encountered an error and cannot show the details of this slice.', 'warning')
current_app.logger.exception(e) current_app.logger.exception(e)
return redirect(url_for('slice.home')) return redirect(url_for('slice.home'))
return render_template(
'slice/detail.html', slice=response, device_names=device_names, endpoints_data=endpoints_data, @slice.get('<path:slice_uuid>/delete')
sse=SliceStatusEnum, services=services) def delete(slice_uuid: str):
if 'context_uuid' not in session or 'topology_uuid' not in session:
#@slice.get('<path:slice_uuid>/delete') flash("Please select a context!", "warning")
#def delete(slice_uuid: str): return redirect(url_for("main.home"))
# context_uuid = session.get('context_uuid', '-') context_uuid = session['context_uuid']
# if context_uuid == "-":
# flash("Please select a context!", "warning") try:
# return redirect(url_for("main.home")) request = SliceId()
# request.slice_uuid.uuid = slice_uuid
# try: request.context_id.context_uuid.uuid = context_uuid
# request = SliceId() slice_client.connect()
# request.slice_uuid.uuid = slice_uuid slice_client.DeleteSlice(request)
# request.context_id.context_uuid.uuid = context_uuid slice_client.close()
# slice_client.connect()
# response = slice_client.DeleteSlice(request) flash('Slice "{:s}" deleted successfully!'.format(slice_uuid), 'success')
# slice_client.close() except Exception as e:
# flash('Problem deleting slice "{:s}": {:s}'.format(slice_uuid, str(e.details())), 'danger')
# flash('Slice "{:s}" deleted successfully!'.format(slice_uuid), 'success') current_app.logger.exception(e)
# except Exception as e: return redirect(url_for('slice.home'))
# flash('Problem deleting slice "{:s}": {:s}'.format(slice_uuid, str(e.details())), 'danger')
# current_app.logger.exception(e)
# return redirect(url_for('slice.home'))
...@@ -103,7 +103,7 @@ ...@@ -103,7 +103,7 @@
</li> </li>
</ul> </ul>
<span class="navbar-text" style="color: #fff;"> <span class="navbar-text" style="color: #fff;">
Current Context(<b>{{ get_working_context() }}</b>)/Topology(<b>{{ get_working_topology() }}</b>) Selected Context(<b>{{ get_working_context() }}</b>)/Topology(<b>{{ get_working_topology() }}</b>)
</span> </span>
</div> </div>
</div> </div>
......
...@@ -29,13 +29,14 @@ ...@@ -29,13 +29,14 @@
<div class="col-sm-3"> <div class="col-sm-3">
<a id="update" class="btn btn-secondary" href="{{ url_for('device.update',device_uuid=device.device_id.device_uuid.uuid) }}"> <a id="update" class="btn btn-secondary" href="{{ url_for('device.update',device_uuid=device.device_id.device_uuid.uuid) }}">
<i class="bi bi-pencil-square"></i> <i class="bi bi-pencil-square"></i>
Update Update device
</a> </a>
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">
<!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete device</button> --> <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete device</button> -->
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal"> <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
<i class="bi bi-x-square"></i>Delete device <i class="bi bi-x-square"></i>
Delete device
</button> </button>
</div> </div>
</div> </div>
......
...@@ -36,7 +36,8 @@ ...@@ -36,7 +36,8 @@
<div class="col-sm-3"> <div class="col-sm-3">
<!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete service</button> --> <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete service</button> -->
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal"> <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
<i class="bi bi-x-square"></i>Delete service <i class="bi bi-x-square"></i>
Delete service
</button> </button>
</div> </div>
</div> </div>
...@@ -87,7 +88,7 @@ ...@@ -87,7 +88,7 @@
<thead> <thead>
<tr> <tr>
<th scope="col">Kind</th> <th scope="col">Kind</th>
<th scope="col">Type</th> <th scope="col">Key/Type</th>
<th scope="col">Value</th> <th scope="col">Value</th>
</tr> </tr>
</thead> </thead>
...@@ -135,15 +136,43 @@ ...@@ -135,15 +136,43 @@
</td> </td>
<td>{{ constraint.endpoint_priority.priority }}</td> <td>{{ constraint.endpoint_priority.priority }}</td>
</tr> </tr>
{% elif constraint.WhichOneof('constraint')=='sla_capacity' %}
<tr>
<td>SLA Capacity</td>
<td>-</td>
<td>
{{ constraint.sla_capacity.capacity_gbps }} Gbps
</td>
</tr>
{% elif constraint.WhichOneof('constraint')=='sla_latency' %}
<tr>
<td>SLA E2E Latency</td>
<td>-</td>
<td>
{{ constraint.sla_latency.e2e_latency_ms }} ms
</td>
</tr>
{% elif constraint.WhichOneof('constraint')=='sla_availability' %} {% elif constraint.WhichOneof('constraint')=='sla_availability' %}
<tr> <tr>
<td>SLA Availability</td> <td>SLA Availability</td>
<td>-</td> <td>-</td>
<td> <td>
{{ constraint.sla_availability.availability }} %;
{{ constraint.sla_availability.num_disjoint_paths }} disjoint paths; {{ constraint.sla_availability.num_disjoint_paths }} disjoint paths;
{% if constraint.sla_availability.all_active %}all{% else %}single{% endif %}-active {% if constraint.sla_availability.all_active %}all{% else %}single{% endif %}-active
</td> </td>
</tr> </tr>
{% elif constraint.WhichOneof('constraint')=='sla_isolation' %}
<tr>
<td>SLA Isolation</td>
<td>-</td>
<td>
{% for i,isolation_level in enumerate(constraint.sla_isolation.isolation_level) %}
{% if i > 0 %}, {% endif %}
{{ ile.Name(isolation_level) }}
{% endfor %}
</td>
</tr>
{% else %} {% else %}
<tr> <tr>
<td>-</td> <td>-</td>
...@@ -185,34 +214,12 @@ ...@@ -185,34 +214,12 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
<!-- Modal -->
<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Delete service?</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Are you sure you want to delete the service "{{ service.service_id.service_uuid.uuid }}"?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button>
<a type="button" class="btn btn-danger"
href="{{ url_for('service.delete', service_uuid=service.service_id.service_uuid.uuid) }}"><i
class="bi bi-exclamation-diamond"></i>Yes</a>
</div>
</div>
</div>
</div>
<table class="table table-striped table-hover"> <table class="table table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th scope="col">Connection Id</th> <th scope="col">Connection Id</th>
<th scope="col">Sub-service</th> <th scope="col">Sub-Service</th>
<th scope="col">Path</th> <th scope="col">Path</th>
</tr> </tr>
</thead> </thead>
...@@ -258,8 +265,26 @@ ...@@ -258,8 +265,26 @@
</tbody> </tbody>
</table> </table>
<!-- Modal -->
<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Delete service?</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Are you sure you want to delete the service "{{ service.service_id.service_uuid.uuid }}"?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button>
<a type="button" class="btn btn-danger"
href="{{ url_for('service.delete', service_uuid=service.service_id.service_uuid.uuid) }}"><i
class="bi bi-exclamation-diamond"></i>Yes</a>
</div>
</div>
</div>
</div>
{% endblock %}
{% endblock %}
\ No newline at end of file
...@@ -32,14 +32,14 @@ ...@@ -32,14 +32,14 @@
<i class="bi bi-pencil-square"></i> <i class="bi bi-pencil-square"></i>
Update Update
</a> </a>
</div> </div>-->
<div class="col-sm-3">--> <div class="col-sm-3">
<!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete slice</button> --> <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete slice</button> -->
<!--<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal"> <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
<i class="bi bi-x-square"></i>Delete slice <i class="bi bi-x-square"></i>
Delete slice
</button> </button>
</div> </div>
-->
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
<thead> <thead>
<tr> <tr>
<th scope="col">Kind</th> <th scope="col">Kind</th>
<th scope="col">Type</th> <th scope="col">Key/Type</th>
<th scope="col">Value</th> <th scope="col">Value</th>
</tr> </tr>
</thead> </thead>
...@@ -136,15 +136,43 @@ ...@@ -136,15 +136,43 @@
</td> </td>
<td>{{ constraint.endpoint_priority.priority }}</td> <td>{{ constraint.endpoint_priority.priority }}</td>
</tr> </tr>
{% elif constraint.WhichOneof('constraint')=='sla_capacity' %}
<tr>
<td>SLA Capacity</td>
<td>-</td>
<td>
{{ constraint.sla_capacity.capacity_gbps }} Gbps
</td>
</tr>
{% elif constraint.WhichOneof('constraint')=='sla_latency' %}
<tr>
<td>SLA E2E Latency</td>
<td>-</td>
<td>
{{ constraint.sla_latency.e2e_latency_ms }} ms
</td>
</tr>
{% elif constraint.WhichOneof('constraint')=='sla_availability' %} {% elif constraint.WhichOneof('constraint')=='sla_availability' %}
<tr> <tr>
<td>SLA Availability</td> <td>SLA Availability</td>
<td>-</td> <td>-</td>
<td> <td>
{{ constraint.sla_availability.availability }} %;
{{ constraint.sla_availability.num_disjoint_paths }} disjoint paths; {{ constraint.sla_availability.num_disjoint_paths }} disjoint paths;
{% if constraint.sla_availability.all_active %}all{% else %}single{% endif %}-active {% if constraint.sla_availability.all_active %}all{% else %}single{% endif %}-active
</td> </td>
</tr> </tr>
{% elif constraint.WhichOneof('constraint')=='sla_isolation' %}
<tr>
<td>SLA Isolation</td>
<td>-</td>
<td>
{% for i,isolation_level in enumerate(constraint.sla_isolation.isolation_level) %}
{% if i > 0 %}, {% endif %}
{{ ile.Name(isolation_level) }}
{% endfor %}
</td>
</tr>
{% else %} {% else %}
<tr> <tr>
<td>-</td> <td>-</td>
...@@ -191,7 +219,7 @@ ...@@ -191,7 +219,7 @@
<table class="table table-striped table-hover"> <table class="table table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th scope="col">Service Id</th> <th scope="col">Sub-Services</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -219,7 +247,7 @@ ...@@ -219,7 +247,7 @@
<table class="table table-striped table-hover"> <table class="table table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th scope="col">Sub-slices</th> <th scope="col">Sub-Slices</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -244,4 +272,27 @@ ...@@ -244,4 +272,27 @@
</table> </table>
</div> </div>
</div> </div>
{% endblock %}
\ No newline at end of file <!-- Modal -->
<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Delete slice?</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Are you sure you want to delete the slice "{{ slice.slice_id.slice_uuid.uuid }}"?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button>
<a type="button" class="btn btn-danger"
href="{{ url_for('slice.delete', slice_uuid=slice.slice_id.slice_uuid.uuid) }}"><i
class="bi bi-exclamation-diamond"></i>Yes</a>
</div>
</div>
</div>
</div>
{% endblock %}
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