diff --git a/src/nbi/service/__main__.py b/src/nbi/service/__main__.py index 71df0517aa688c106d8d0fe544f5f6b1af5a58f3..1d470f4eac30795e2272c9145baf947f3c982ba5 100644 --- a/src/nbi/service/__main__.py +++ b/src/nbi/service/__main__.py @@ -31,6 +31,7 @@ from .rest_server.nbi_plugins.ietf_network_slice import register_ietf_nss from .rest_server.nbi_plugins.ietf_acl import register_ietf_acl from .rest_server.nbi_plugins.qkd_app import register_qkd_app from .rest_server.nbi_plugins.tfs_api import register_tfs_api +from .rest_server.nbi_plugins import register_restconf from .context_subscription import register_context_subscription terminate = threading.Event() @@ -79,6 +80,7 @@ def main(): register_ietf_acl(rest_server) register_qkd_app(rest_server) register_tfs_api(rest_server) + register_restconf(rest_server) rest_server.start() register_context_subscription() diff --git a/src/nbi/service/rest_server/nbi_plugins/__init__.py b/src/nbi/service/rest_server/nbi_plugins/__init__.py index e7d5584cd2d19b7393f147a647189da9d01c79a9..9b5d7920db49bab6d456aba186e6500142aad5b2 100644 --- a/src/nbi/service/rest_server/nbi_plugins/__init__.py +++ b/src/nbi/service/rest_server/nbi_plugins/__init__.py @@ -34,5 +34,5 @@ def _add_resource(rest_server: RestServer, resource: Resource, *urls, **kwargs): rest_server.add_resource(resource, *urls, **kwargs) -def register_ietf_nss(rest_server: RestServer): +def register_restconf(rest_server: RestServer): _add_resource(rest_server, BaseServer, "") diff --git a/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/NSS_Services.py b/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/NSS_Services.py index 0b4f83fa80739bdf94fdc97de882449251cb8cda..8398917a2c5d8c553efe59551962271d91759e9e 100644 --- a/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/NSS_Services.py +++ b/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/NSS_Services.py @@ -22,7 +22,7 @@ from werkzeug.exceptions import UnsupportedMediaType from context.client.ContextClient import ContextClient from slice.client.SliceClient import SliceClient -from ..tools.HttpStatusCodes import HTTP_CREATED +from ..tools.HttpStatusCodes import HTTP_CREATED, HTTP_OK from .ietf_slice_handler import IETFSliceHandler LOGGER = logging.getLogger(__name__) @@ -31,8 +31,10 @@ LOGGER = logging.getLogger(__name__) class NSS_Services(Resource): # @HTTP_AUTH.login_required def get(self): - response = jsonify({"message": "All went well!"}) - # TODO Return list of current network-slice-services + context_client = ContextClient() + ietf_slices = IETFSliceHandler.get_all_ietf_slices(context_client) + response = jsonify(ietf_slices) + response.status_code = HTTP_OK return response # @HTTP_AUTH.login_required diff --git a/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/__init__.py b/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/__init__.py index 6dcd6c9e9fd01ffb0e4c5c1535e3da37dae2483a..db76b3b911c971df8ab81b1710f4ac80e4ccb3ad 100644 --- a/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/__init__.py +++ b/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/__init__.py @@ -28,7 +28,7 @@ from .NSS_Services_Connection_Groups import NSS_Service_Connection_Groups from .NSS_Services_SDP import NSS_Service_SDP from .NSS_Services_SDPs import NSS_Service_SDPs -URL_PREFIX = "/restconf/data/ietf-network-slice-service:ietf-nss" +URL_PREFIX = "/restconf/data/ietf-network-slice-service" def _add_resource(rest_server: RestServer, resource: Resource, *urls, **kwargs): @@ -37,39 +37,39 @@ def _add_resource(rest_server: RestServer, resource: Resource, *urls, **kwargs): def register_ietf_nss(rest_server: RestServer): - _add_resource(rest_server, NSS_Services, "/network-slice-services") + _add_resource(rest_server, NSS_Services, ":network-slice-services") _add_resource( rest_server, NSS_Service, - "/network-slice-services/slice-service=<string:slice_id>", + ":network-slice-services/slice-service=<string:slice_id>", ) _add_resource( rest_server, NSS_Service_SDPs, - "/network-slice-services/slice-service=<string:slice_id>/sdps", + ":network-slice-services/slice-service=<string:slice_id>/sdps", ) _add_resource( rest_server, NSS_Service_SDP, - "/network-slice-services/slice-service=<string:slice_id>/sdps/sdp=<string:sdp_id>", + ":network-slice-services/slice-service=<string:slice_id>/sdps/sdp=<string:sdp_id>", ) _add_resource( rest_server, NSS_Service_Connection_Groups, - "/network-slice-services/slice-service=<string:slice_id>/connection-groups", + ":network-slice-services/slice-service=<string:slice_id>/connection-groups", ) _add_resource( rest_server, NSS_Service_Connection_Group, - "/network-slice-services/slice-service=<string:slice_id>/connection-groups/connection-group=<string:connection_group_id>", + ":network-slice-services/slice-service=<string:slice_id>/connection-groups/connection-group=<string:connection_group_id>", ) _add_resource( rest_server, NSS_Service_Match_Criteria, - "/network-slice-services/slice-service=<string:slice_id>/sdps/sdp=<string:sdp_id>/service-match-criteria", + ":network-slice-services/slice-service=<string:slice_id>/sdps/sdp=<string:sdp_id>/service-match-criteria", ) _add_resource( rest_server, NSS_Service_Match_Criterion, - "/network-slice-services/slice-service=<string:slice_id>/sdps/sdp=<string:sdp_id>/service-match-criteria/match-criterion=<string:match_criterion_id>", + ":network-slice-services/slice-service=<string:slice_id>/sdps/sdp=<string:sdp_id>/service-match-criteria/match-criterion=<string:match_criterion_id>", ) diff --git a/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/ietf_slice_handler.py b/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/ietf_slice_handler.py index 6b57cb853a4cda4231e7b2d70f110999da130d14..ee1f215f03dfb095f53d465fabb272b141c5bb01 100644 --- a/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/ietf_slice_handler.py +++ b/src/nbi/service/rest_server/nbi_plugins/ietf_network_slice/ietf_slice_handler.py @@ -1,7 +1,7 @@ import json import logging import uuid -from typing import Optional +from typing import Dict, List, Optional from common.Constants import DEFAULT_CONTEXT_NAME from common.proto.context_pb2 import ( @@ -16,7 +16,6 @@ from common.proto.context_pb2 import ( ) from common.tools.context_queries.Slice import get_slice_by_defualt_name from common.tools.grpc.ConfigRules import update_config_rule_custom -from common.tools.grpc.Tools import grpc_message_to_json from context.client import ContextClient from .YangValidator import YangValidator @@ -41,7 +40,7 @@ def get_custom_config_rule( return cr -def sort_endpoints(endpoinst_list: list, sdps: list, connection_group: dict) -> list: +def sort_endpoints(endpoinst_list: List, sdps: List, connection_group: Dict) -> List: src_sdp_id = connection_group["connectivity-construct"][0]["p2p-sender-sdp"] sdp_id_name_mapping = {sdp["id"]: sdp["node-id"] for sdp in sdps} if endpoinst_list[0].device_id.device_uuid.uuid == sdp_id_name_mapping[src_sdp_id]: @@ -50,8 +49,8 @@ def sort_endpoints(endpoinst_list: list, sdps: list, connection_group: dict) -> def replace_ont_endpoint_with_emu_dc( - endpoint_list: list, context_client: ContextClient -) -> list: + endpoint_list: List, context_client: ContextClient +) -> List: link_list = context_client.ListLinks(Empty()) links = list(link_list.links) devices_list = context_client.ListDevices(Empty()) @@ -96,13 +95,28 @@ def replace_ont_endpoint_with_emu_dc( return endpoint_list -def validate_ietf_slice_data(request_data: dict) -> None: +def validate_ietf_slice_data(request_data: Dict) -> None: yang_validator = YangValidator("ietf-network-slice-service") _ = yang_validator.parse_to_dict(request_data) yang_validator.destroy() class IETFSliceHandler: + @staticmethod + def get_all_ietf_slices(context_client: ContextClient) -> Dict: + slices_list = context_client.ListSlices(Empty()) + slices = slices_list.slices + ietf_slices = {"network-slice-services": {"slice-service": []}} + for slice in slices: + candidate_cr = get_custom_config_rule( + slice.slice_config, CANDIDATE_RESOURCE_KEY + ) + candidate_ietf_data = json.loads(candidate_cr.custom.resource_value) + ietf_slices["network-slice-services"]["slice-service"].append( + candidate_ietf_data["network-slice-services"]["slice-service"][0] + ) + return ietf_slices + @staticmethod def create_slice_service( request_data: dict, context_client: ContextClient diff --git a/src/nbi/tests/data/slice/post_connection_group_to_network_slice2.json b/src/nbi/tests/data/slice/post_connection_group_to_network_slice2.json new file mode 100644 index 0000000000000000000000000000000000000000..d39a837bd8c3719463e8ecfd3fbfc2d25111afef --- /dev/null +++ b/src/nbi/tests/data/slice/post_connection_group_to_network_slice2.json @@ -0,0 +1,62 @@ +{ + "connection-group": [ + { + "id": "line2", + "connectivity-type": "point-to-point", + "connectivity-construct": [ + { + "id": 1, + "p2p-sender-sdp": "1", + "p2p-receiver-sdp": "3", + "service-slo-sle-policy": { + "slo-policy": { + "metric-bound": [ + { + "metric-type": "ietf-network-slice-service:one-way-delay-maximum", + "metric-unit": "milliseconds", + "bound": "10" + }, + { + "metric-type": "ietf-network-slice-service:one-way-bandwidth", + "metric-unit": "Mbps", + "bound": "5000" + }, + { + "metric-type": "ietf-network-slice-service:two-way-packet-loss", + "metric-unit": "percentage", + "percentile-value": "0.001" + } + ] + } + } + }, + { + "id": 2, + "p2p-sender-sdp": "3", + "p2p-receiver-sdp": "1", + "service-slo-sle-policy": { + "slo-policy": { + "metric-bound": [ + { + "metric-type": "ietf-network-slice-service:one-way-delay-maximum", + "metric-unit": "milliseconds", + "bound": "20" + }, + { + "metric-type": "ietf-network-slice-service:one-way-bandwidth", + "metric-unit": "Mbps", + "bound": "1000" + }, + { + "metric-type": "ietf-network-slice-service:two-way-packet-loss", + "metric-unit": "percentage", + "percentile-value": "0.001" + } + ] + } + } + } + ] + } + ] +} \ No newline at end of file diff --git a/src/nbi/tests/data/slice/post_match_criteria_to_sdp1_in_slice2.json b/src/nbi/tests/data/slice/post_match_criteria_to_sdp1_in_slice2.json new file mode 100644 index 0000000000000000000000000000000000000000..8ceefdc2f2471af225143e5a1def2d7ba71e2ab1 --- /dev/null +++ b/src/nbi/tests/data/slice/post_match_criteria_to_sdp1_in_slice2.json @@ -0,0 +1,40 @@ +{ + "match-criterion": [ + { + "index": 2, + "match-type": [ + { + "type": "ietf-network-slice-service:vlan", + "value": [ + "201" + ] + }, + { + "type": "ietf-network-slice-service:source-ip-prefix", + "value": [ + "172.1.201.22/24" + ] + }, + { + "type": "ietf-network-slice-service:source-tcp-port", + "value": [ + "10200" + ] + }, + { + "type": "ietf-network-slice-service:destination-ip-prefix", + "value": [ + "172.16.104.222/24" + ] + }, + { + "type": "ietf-network-slice-service:destination-tcp-port", + "value": [ + "10500" + ] + } + ], + "target-connection-group-id": "line2" + } + ] +} \ No newline at end of file diff --git a/src/nbi/tests/data/slice/post_network_slice2.json b/src/nbi/tests/data/slice/post_network_slice2.json new file mode 100644 index 0000000000000000000000000000000000000000..1445846cc46e925c59064a715dcfb5422e221219 --- /dev/null +++ b/src/nbi/tests/data/slice/post_network_slice2.json @@ -0,0 +1,189 @@ +{ + "slice-service": [ + { + "id": "slice2", + "description": "network slice 2, connect to VM2", + "sdps": { + "sdp": [ + { + "id": "1", + "node-id": "172.16.204.220", + "sdp-ip-address": [ + "172.16.204.220" + ], + "service-match-criteria": { + "match-criterion": [ + { + "index": 1, + "match-type": [ + { + "type": "ietf-network-slice-service:vlan", + "value": [ + "201" + ] + }, + { + "type": "ietf-network-slice-service:destination-ip-prefix", + "value": [ + "172.16.104.221/24" + ] + }, + { + "type": "ietf-network-slice-service:destination-tcp-port", + "value": [ + "10500" + ] + }, + { + "type": "ietf-network-slice-service:source-ip-prefix", + "value": [ + "172.1.201.22/24" + ] + }, + { + "type": "ietf-network-slice-service:source-tcp-port", + "value": [ + "10200" + ] + } + ], + "target-connection-group-id": "line1" + } + ] + }, + "attachment-circuits": { + "attachment-circuit": [ + { + "id": "AC POP to VM2", + "description": "AC VM2 connected to POP", + "ac-node-id": "172.16.204.220", + "ac-tp-id": "201" + } + ] + } + }, + { + "id": "2", + "node-id": "172.16.61.10", + "sdp-ip-address": [ + "172.16.61.10" + ], + "service-match-criteria": { + "match-criterion": [ + { + "index": 1, + "match-type": [ + { + "type": "ietf-network-slice-service:vlan", + "value": [ + "31" + ] + }, + { + "type": "ietf-network-slice-service:source-ip-prefix", + "value": [ + "172.16.104.221/24" + ] + }, + { + "type": "ietf-network-slice-service:source-tcp-port", + "value": [ + "10500" + ] + }, + { + "type": "ietf-network-slice-service:destination-ip-prefix", + "value": [ + "172.1.201.22/24" + ] + }, + { + "type": "ietf-network-slice-service:destination-tcp-port", + "value": [ + "10200" + ] + } + ], + "target-connection-group-id": "line1" + } + ] + }, + "attachment-circuits": { + "attachment-circuit": [ + { + "id": "AC ONT", + "description": "AC connected to PC", + "ac-node-id": "172.16.61.10", + "ac-tp-id": "200", + "ac-ipv4-address": "172.16.61.10" + } + ] + } + } + ] + }, + "connection-groups": { + "connection-group": [ + { + "id": "line1", + "connectivity-type": "point-to-point", + "connectivity-construct": [ + { + "id": 1, + "p2p-sender-sdp": "1", + "p2p-receiver-sdp": "2", + "service-slo-sle-policy": { + "slo-policy": { + "metric-bound": [ + { + "metric-type": "ietf-network-slice-service:one-way-delay-maximum", + "metric-unit": "milliseconds", + "bound": "10" + }, + { + "metric-type": "ietf-network-slice-service:one-way-bandwidth", + "metric-unit": "Mbps", + "bound": "5000" + }, + { + "metric-type": "ietf-network-slice-service:two-way-packet-loss", + "metric-unit": "percentage", + "percentile-value": "0.001" + } + ] + } + } + }, + { + "id": 2, + "p2mp-sender-sdp": "2", + "p2mp-receiver-sdp": "1", + "service-slo-sle-policy": { + "slo-policy": { + "metric-bound": [ + { + "metric-type": "ietf-network-slice-service:one-way-delay-maximum", + "metric-unit": "milliseconds", + "bound": "20" + }, + { + "metric-type": "ietf-network-slice-service:one-way-bandwidth", + "metric-unit": "Mbps", + "bound": "1000" + }, + { + "metric-type": "ietf-network-slice-service:two-way-packet-loss", + "metric-unit": "percentage", + "percentile-value": "0.001" + } + ] + } + } + } + ] + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/nbi/tests/data/slice/post_sdp_to_network_slice2.json b/src/nbi/tests/data/slice/post_sdp_to_network_slice2.json new file mode 100644 index 0000000000000000000000000000000000000000..0b147125bd7eb3efc84c87bebab919639782f760 --- /dev/null +++ b/src/nbi/tests/data/slice/post_sdp_to_network_slice2.json @@ -0,0 +1,62 @@ +{ + "sdp": [ + { + "id": "3", + "node-id": "172.16.61.11", + "sdp-ip-address": [ + "172.16.61.11" + ], + "service-match-criteria": { + "match-criterion": [ + { + "index": 1, + "match-type": [ + { + "type": "ietf-network-slice-service:vlan", + "value": [ + "31" + ] + }, + { + "type": "ietf-network-slice-service:source-ip-prefix", + "value": [ + "172.16.104.222/24" + ] + }, + { + "type": "ietf-network-slice-service:source-tcp-port", + "value": [ + "10500" + ] + }, + { + "type": "ietf-network-slice-service:destination-ip-prefix", + "value": [ + "172.1.201.22/24" + ] + }, + { + "type": "ietf-network-slice-service:destination-tcp-port", + "value": [ + "10200" + ] + } + ], + "target-connection-group-id": "line2" + } + ] + }, + "attachment-circuits": { + "attachment-circuit": [ + { + "id": "AC ONT", + "description": "AC connected to PC2", + "ac-node-id": "172.16.61.11", + "ac-tp-id": "200", + "ac-ipv4-address": "172.16.61.11" + } + ] + } + } + ] +} \ No newline at end of file