diff --git a/src/webui/service/slice/routes.py b/src/webui/service/slice/routes.py index 922f8af96dc916f0ca5658e120cdf3dfa4ec9b21..11ed8dad743694cd0736397e0030c79c48f1aede 100644 --- a/src/webui/service/slice/routes.py +++ b/src/webui/service/slice/routes.py @@ -14,10 +14,11 @@ import grpc from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for -from common.proto.context_pb2 import IsolationLevelEnum, Slice, SliceId, SliceStatusEnum +from common.proto.context_pb2 import IsolationLevelEnum, Slice, SliceId, SliceStatusEnum, EndPointId from common.tools.context_queries.Context import get_context from common.tools.context_queries.EndPoint import get_endpoint_names from common.tools.context_queries.Slice import get_slice_by_uuid +from common.Constants import DEFAULT_CONTEXT_NAME from context.client.ContextClient import ContextClient from slice.client.SliceClient import SliceClient @@ -26,6 +27,67 @@ slice = Blueprint('slice', __name__, url_prefix='/slice') context_client = ContextClient() slice_client = SliceClient() + +RUNNING_RESOURCE_KEY = "running_ietf_slice" +CANDIDATE_RESOURCE_KEY = "candidate_ietf_slice" + + +class ConfigRuleNotFoundError(Exception): + ... + +def get_custom_config_rule( + service_config: ServiceConfig, resource_key: str +) -> Optional[ConfigRule]: + """ + Retrieve the custom config rule with the given resource_key from a ServiceConfig. + """ + for cr in service_config.config_rules: + if ( + cr.WhichOneof("config_rule") == "custom" + and cr.custom.resource_key == resource_key + ): + return cr + return None + + +def get_ietf_data_from_config(slice_request: Slice, resource_key: str) -> Dict: + """ + Retrieve the IETF data (as a Python dict) from a slice's config rule for the specified resource_key. + Raises an exception if not found. + """ + config_rule = get_custom_config_rule(slice_request.slice_config, resource_key) + if not config_rule: + raise ConfigRuleNotFoundError(f"IETF data not found for resource_key: {resource_key}") + return json.loads(config_rule.custom.resource_value) + + +def get_slice_endpoints(slice_obj: Slice) -> list[EndPointId]: + ''' + Get the list of endpoint ids for a slice. + If the slice has a `running_ietf_slice` config rule, return the list of endpoint ids from the config rule, + otherwise return the slice's list of endpoint ids. + ''' + try: + running_ietf_data = get_ietf_data_from_config(slice_obj, RUNNING_RESOURCE_KEY) + slice_service = running_ietf_data["network-slice-services"]["slice-service"][0] + slice_sdps = slice_service["sdps"]["sdp"] + list_endpoint_ids = [] + for sdp in slice_sdps: + endpoint = EndPointId() + endpoint.topology_id.context_id.context_uuid.uuid = DEFAULT_CONTEXT_NAME + device_uuid = sdp["node-id"] + endpoint.device_id.device_uuid.uuid = device_uuid + attachment_circuits = sdp["attachment-circuits"]["attachment-circuit"] + endpoint_uuid = attachment_circuits[0]["ac-tp-id"] + endpoint.endpoint_uuid.uuid = endpoint_uuid + list_endpoint_ids.append(endpoint) + + except ConfigRuleNotFoundError: + # The slice does not have `running_ietf_slice` config rule, return slice's list of endpoint ids + list_endpoint_ids = slice_obj.slice_endpoint_ids + + return list_endpoint_ids + @slice.get('/') def home(): if 'context_uuid' not in session or 'topology_uuid' not in session: @@ -50,7 +112,8 @@ def home(): else: endpoint_ids = list() for slice_ in slices: - endpoint_ids.extend(slice_.slice_endpoint_ids) + slice_endpoint_ids = get_slice_endpoints(slice_) + endpoint_ids.extend(slice_endpoint_ids) device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids) context_client.close() @@ -81,7 +144,8 @@ def detail(slice_uuid: str): 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) + slice_endpoint_ids = get_slice_endpoints(slice_obj) + device_names, endpoints_data = get_endpoint_names(context_client, slice_endpoint_ids) context_client.close() @@ -111,5 +175,5 @@ def delete(slice_uuid: str): flash('Slice "{:s}" deleted successfully!'.format(slice_uuid), 'success') except Exception as e: flash('Problem deleting slice "{:s}": {:s}'.format(slice_uuid, str(e.details())), 'danger') - current_app.logger.exception(e) + current_app.logger.exception(e) return redirect(url_for('slice.home'))