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

Merge branch 'feat/compute-etsi_mec_015' into 'develop'

Resolve "(CTTC) Implement ETSI MEC Bandwidth Management API in NBI component"

See merge request !120
parents eaab9562 0d3549fe
No related branches found
No related tags found
2 merge requests!235Release TeraFlowSDN 3.0,!120Resolve "(CTTC) Implement ETSI MEC Bandwidth Management API in NBI component"
......@@ -21,6 +21,7 @@ from common.Settings import (
from .ComputeService import ComputeService
from .rest_server.RestServer import RestServer
from .rest_server.nbi_plugins.debug_api import register_debug_api
from .rest_server.nbi_plugins.etsi_bwm import register_etsi_bwm_api
from .rest_server.nbi_plugins.ietf_l2vpn import register_ietf_l2vpn
from .rest_server.nbi_plugins.ietf_network_slice import register_ietf_nss
......@@ -59,9 +60,10 @@ def main():
grpc_service.start()
rest_server = RestServer()
register_debug_api(rest_server)
register_etsi_bwm_api(rest_server)
register_ietf_l2vpn(rest_server) # Registering L2VPN entrypoint
register_ietf_nss(rest_server) # Registering NSS entrypoint
register_debug_api(rest_server)
rest_server.start()
# Wait for Ctrl+C or termination signal
......
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import copy
from common.Constants import DEFAULT_CONTEXT_NAME
from flask_restful import Resource, request
from context.client.ContextClient import ContextClient
from service.client.ServiceClient import ServiceClient
from .Tools import (
format_grpc_to_json, grpc_context_id, grpc_service_id, bwInfo_2_service, service_2_bwInfo)
class _Resource(Resource):
def __init__(self) -> None:
super().__init__()
self.client = ContextClient()
self.service_client = ServiceClient()
class BwInfo(_Resource):
def get(self):
service_list = self.client.ListServices(grpc_context_id(DEFAULT_CONTEXT_NAME))
bw_allocations = [service_2_bwInfo(service) for service in service_list.services]
return bw_allocations
def post(self):
bwinfo = request.get_json()
service = bwInfo_2_service(self.client, bwinfo)
stripped_service = copy.deepcopy(service)
stripped_service.ClearField('service_endpoint_ids')
stripped_service.ClearField('service_constraints')
stripped_service.ClearField('service_config')
response = format_grpc_to_json(self.service_client.CreateService(stripped_service))
response = format_grpc_to_json(self.service_client.UpdateService(service))
return response
class BwInfoId(_Resource):
def get(self, allocationId: str):
service = self.client.GetService(grpc_service_id(DEFAULT_CONTEXT_NAME, allocationId))
return service_2_bwInfo(service)
def put(self, allocationId: str):
json_data = request.get_json()
service = bwInfo_2_service(self.client, json_data)
response = self.service_client.UpdateService(service)
return format_grpc_to_json(response)
def patch(self, allocationId: str):
json_data = request.get_json()
if not 'appInsId' in json_data:
json_data['appInsId'] = allocationId
service = bwInfo_2_service(self.client, json_data)
response = self.service_client.UpdateService(service)
return format_grpc_to_json(response)
def delete(self, allocationId: str):
self.service_client.DeleteService(grpc_service_id(DEFAULT_CONTEXT_NAME, allocationId))
return
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import logging
import time
from flask.json import jsonify
from common.proto.context_pb2 import ContextId, Empty, EndPointId, ServiceId, ServiceTypeEnum, Service, Constraint, Constraint_SLA_Capacity, ConfigRule, ConfigRule_Custom, ConfigActionEnum
from common.tools.grpc.Tools import grpc_message_to_json
from common.tools.object_factory.Context import json_context_id
from common.tools.object_factory.Service import json_service_id
LOGGER = logging.getLogger(__name__)
def service_2_bwInfo(service: Service) -> dict:
response = {}
# allocationDirection = '??' # String: 00 = Downlink (towards the UE); 01 = Uplink (towards the application/session); 10 = Symmetrical
response['appInsId'] = service.service_id.context_id.context_uuid.uuid # String: Application instance identifier
for constraint in service.service_constraints:
if constraint.WhichOneof('constraint') == 'sla_capacity':
response['fixedAllocation'] = str(constraint.sla_capacity.capacity_gbps*1000) # String: Size of requested fixed BW allocation in [bps]
break
for config_rule in service.service_config.config_rules:
for key in ['allocationDirection', 'fixedBWPriority', 'requestType', 'sourceIp', 'sourcePort', 'dstPort', 'protocol', 'sessionFilter']:
if config_rule.custom.resource_key == key:
if key != 'sessionFilter':
response[key] = config_rule.custom.resource_value
else:
response[key] = json.loads(config_rule.custom.resource_value)
unixtime = time.time()
response['timeStamp'] = { # Time stamp to indicate when the corresponding information elements are sent
"seconds": int(unixtime),
"nanoseconds": int(unixtime%1*1e9)
}
return response
def bwInfo_2_service(client, bwInfo: dict) -> Service:
service = Service()
for key in ['allocationDirection', 'fixedBWPriority', 'requestType', 'timeStamp', 'sessionFilter']:
if key not in bwInfo:
continue
config_rule = ConfigRule()
config_rule.action = ConfigActionEnum.CONFIGACTION_SET
config_rule_custom = ConfigRule_Custom()
config_rule_custom.resource_key = key
if key != 'sessionFilter':
config_rule_custom.resource_value = str(bwInfo[key])
else:
config_rule_custom.resource_value = json.dumps(bwInfo[key])
config_rule.custom.CopyFrom(config_rule_custom)
service.service_config.config_rules.append(config_rule)
if 'sessionFilter' in bwInfo:
a_ip = bwInfo['sessionFilter'][0]['sourceIp']
z_ip = bwInfo['sessionFilter'][0]['dstAddress']
devices = client.ListDevices(Empty()).devices
for device in devices:
for cr in device.device_config.config_rules:
if cr.WhichOneof('config_rule') == 'custom' and cr.custom.resource_key == '_connect/settings':
for ep in json.loads(cr.custom.resource_value)['endpoints']:
if 'ip' in ep and (ep['ip'] == a_ip or ep['ip'] == z_ip):
ep_id = EndPointId()
ep_id.endpoint_uuid.uuid = ep['uuid']
ep_id.device_id.device_uuid.uuid = device.device_id.device_uuid.uuid
service.service_endpoint_ids.append(ep_id)
if len(service.service_endpoint_ids) < 2:
LOGGER.error('No endpoints matched')
return None
service.service_type = ServiceTypeEnum.SERVICETYPE_L3NM
if 'appInsId' in bwInfo:
service.service_id.service_uuid.uuid = bwInfo['appInsId']
service.service_id.context_id.context_uuid.uuid = 'admin'
service.name = bwInfo['appInsId']
if 'fixedAllocation' in bwInfo:
capacity = Constraint_SLA_Capacity()
capacity.capacity_gbps = float(bwInfo['fixedAllocation'])
constraint = Constraint()
constraint.sla_capacity.CopyFrom(capacity)
service.service_constraints.append(constraint)
return service
def format_grpc_to_json(grpc_reply):
return jsonify(grpc_message_to_json(grpc_reply))
def grpc_context_id(context_uuid):
return ContextId(**json_context_id(context_uuid))
def grpc_service_id(context_uuid, service_uuid):
return ServiceId(**json_service_id(service_uuid, context_id=json_context_id(context_uuid)))
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from compute.service.rest_server.RestServer import RestServer
from .Resources import BwInfo, BwInfoId
URL_PREFIX = '/bwm/v1'
# Use 'path' type since some identifiers might contain char '/' and Flask is unable to recognize them in 'string' type.
RESOURCES = [
# (endpoint_name, resource_class, resource_url)
('api.bw_info', BwInfo, '/bw_allocations'),
('api.bw_info_id', BwInfoId, '/bw_allocations/<path:allocationId>'),
]
def register_etsi_bwm_api(rest_server : RestServer):
for endpoint_name, resource_class, resource_url in RESOURCES:
rest_server.add_resource(resource_class, URL_PREFIX + resource_url, endpoint=endpoint_name)
-----------------------GET-----------------------
curl --request GET \
--url http://10.1.7.203:80/restconf/bwm/v1/bw_allocations
-----------------------POST-----------------------
curl --request POST \
--url http://10.1.7.203:80/restconf/bwm/v1/bw_allocations \
--header 'Content-Type: application/json' \
--data '{
"allocationDirection": "string",
"appInsId": "service_uuid",
"fixedAllocation": "123",
"fixedBWPriority": "SEE_DESCRIPTION",
"requestType": 0,
"sessionFilter": [
{
"dstAddress": "192.168.3.2",
"dstPort": [
"b"
],
"protocol": "string",
"sourceIp": "192.168.1.2",
"sourcePort": [
"a"
]
}
],
"timeStamp": {
"nanoSeconds": 1,
"seconds": 1
}
}'
-----------------------GET2-----------------------
curl --request GET \
--url http://10.1.7.203:80/restconf/bwm/v1/bw_allocations/service_uuid
-----------------------PUT-----------------------
curl --request PUT \
--url http://10.1.7.203:80/restconf/bwm/v1/bw_allocations/service_uuid \
--header 'Content-Type: application/json' \
--data '{
"allocationDirection": "string",
"appInsId": "service_uuid",
"fixedAllocation": "123",
"fixedBWPriority": "efefe",
"requestType": 0,
"sessionFilter": [
{
"dstAddress": "192.168.3.2",
"dstPort": [
"b"
],
"protocol": "string",
"sourceIp": "192.168.1.2",
"sourcePort": [
"a"
]
}
],
"timeStamp": {
"nanoSeconds": 1,
"seconds": 1
}
}'
-----------------------PATCH-----------------------
curl --request PATCH \
--url http://10.1.7.203:80/restconf/bwm/v1/bw_allocations/service_uuid \
--header 'Content-Type: application/json' \
--data '{
"fixedBWPriority": "uuuuuuuuuuuuuu"
}'
-----------------------DELETE-----------------------
curl --request DELETE \
--url http://10.1.7.203:80/restconf/bwm/v1/bw_allocations/service_uuid
\ No newline at end of file
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