diff --git a/proto/context.proto b/proto/context.proto index 7570a4596a0abd254d93c77131f03fa432cf09c7..d5022ac292f04cd2e9b80f690be3077e7aedd868 100644 --- a/proto/context.proto +++ b/proto/context.proto @@ -202,6 +202,7 @@ enum DeviceDriverEnum { DEVICEDRIVER_IETF_L2VPN = 7; DEVICEDRIVER_GNMI_OPENCONFIG = 8; DEVICEDRIVER_FLEXSCALE = 9; + DEVICEDRIVER_IETF_ACTN = 10; } enum DeviceOperationalStatusEnum { diff --git a/src/common/type_checkers/Assertions.py b/src/common/type_checkers/Assertions.py index 286ae179d325b6e70d6ebf509de92e354ba42bc8..8b7d5ff03cab348e89206a5e47d3d6e88e66b32f 100644 --- a/src/common/type_checkers/Assertions.py +++ b/src/common/type_checkers/Assertions.py @@ -35,6 +35,8 @@ def validate_device_driver_enum(message): 'DEVICEDRIVER_XR', 'DEVICEDRIVER_IETF_L2VPN', 'DEVICEDRIVER_GNMI_OPENCONFIG', + 'DEVICEDRIVER_FLEXSCALE', + 'DEVICEDRIVER_IETF_ACTN', ] def validate_device_operational_status_enum(message): diff --git a/src/context/service/database/models/enums/DeviceDriver.py b/src/context/service/database/models/enums/DeviceDriver.py index f8483360191dcea1a56cdc372b681ae2d03c9ef1..8e15bf058599eeed0629fc1249af0d052183db28 100644 --- a/src/context/service/database/models/enums/DeviceDriver.py +++ b/src/context/service/database/models/enums/DeviceDriver.py @@ -32,6 +32,7 @@ class ORM_DeviceDriverEnum(enum.Enum): IETF_L2VPN = DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN GNMI_OPENCONFIG = DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG FLEXSCALE = DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE + IETF_ACTN = DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN grpc_to_enum__device_driver = functools.partial( grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum) diff --git a/src/device/service/drivers/ietf_actn/IetfActnDriver.py b/src/device/service/drivers/ietf_actn/IetfActnDriver.py new file mode 100644 index 0000000000000000000000000000000000000000..34362c0b09bfa154f4634529189c2707bcffa9d0 --- /dev/null +++ b/src/device/service/drivers/ietf_actn/IetfActnDriver.py @@ -0,0 +1,131 @@ +# 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 logging, requests, threading +from requests.auth import HTTPBasicAuth +from typing import Any, Iterator, List, Optional, Tuple, Union +from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method +from common.type_checkers.Checkers import chk_string, chk_type +from device.service.driver_api._Driver import _Driver +from . import ALL_RESOURCE_KEYS +#from .Tools import create_connectivity_service, find_key, config_getter, delete_connectivity_service + +LOGGER = logging.getLogger(__name__) + +DRIVER_NAME = 'ietf_actn' +METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME}) + +class IetfActnDriver(_Driver): + def __init__(self, address: str, port: int, **settings) -> None: + super().__init__(DRIVER_NAME, address, port, **settings) + self.__lock = threading.Lock() + self.__started = threading.Event() + self.__terminate = threading.Event() + username = self.settings.get('username') + password = self.settings.get('password') + self.__auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None + scheme = self.settings.get('scheme', 'http') + self.__base_url = '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port)) + self.__timeout = int(self.settings.get('timeout', 120)) + + def Connect(self) -> bool: + #url = self.__base_url + '/restconf/data/tapi-common:context' + #with self.__lock: + # if self.__started.is_set(): return True + # try: + # requests.get(url, timeout=self.__timeout, verify=False, auth=self.__auth) + # except requests.exceptions.Timeout: + # LOGGER.exception('Timeout connecting {:s}'.format(str(self.__base_url))) + # return False + # except Exception: # pylint: disable=broad-except + # LOGGER.exception('Exception connecting {:s}'.format(str(self.__base_url))) + # return False + # else: + # self.__started.set() + return True + + def Disconnect(self) -> bool: + with self.__lock: + self.__terminate.set() + return True + + @metered_subclass_method(METRICS_POOL) + def GetInitialConfig(self) -> List[Tuple[str, Any]]: + with self.__lock: + return [] + + @metered_subclass_method(METRICS_POOL) + def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]: + chk_type('resources', resource_keys, list) + results = [] + #with self.__lock: + # if len(resource_keys) == 0: resource_keys = ALL_RESOURCE_KEYS + # for i, resource_key in enumerate(resource_keys): + # str_resource_name = 'resource_key[#{:d}]'.format(i) + # chk_string(str_resource_name, resource_key, allow_empty=False) + # results.extend(config_getter( + # self.__base_url, resource_key, timeout=self.__timeout, auth=self.__auth)) + return results + + @metered_subclass_method(METRICS_POOL) + def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + results = [] + if len(resources) == 0: + return results + #with self.__lock: + # for resource in resources: + # LOGGER.info('resource = {:s}'.format(str(resource))) + # + # uuid = find_key(resource, 'uuid') + # input_sip = find_key(resource, 'input_sip_uuid') + # output_sip = find_key(resource, 'output_sip_uuid') + # capacity_value = find_key(resource, 'capacity_value') + # capacity_unit = find_key(resource, 'capacity_unit') + # layer_protocol_name = find_key(resource, 'layer_protocol_name') + # layer_protocol_qualifier = find_key(resource, 'layer_protocol_qualifier') + # direction = find_key(resource, 'direction') + # + # data = create_connectivity_service( + # self.__base_url, uuid, input_sip, output_sip, direction, capacity_value, capacity_unit, + # layer_protocol_name, layer_protocol_qualifier, timeout=self.__timeout, auth=self.__auth) + # results.extend(data) + return results + + @metered_subclass_method(METRICS_POOL) + def DeleteConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]: + results = [] + if len(resources) == 0: return results + #with self.__lock: + # for resource in resources: + # LOGGER.info('resource = {:s}'.format(str(resource))) + # uuid = find_key(resource, 'uuid') + # results.extend(delete_connectivity_service( + # self.__base_url, uuid, timeout=self.__timeout, auth=self.__auth)) + return results + + @metered_subclass_method(METRICS_POOL) + def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: + # TODO: IETF ACTN does not support monitoring by now + return [False for _ in subscriptions] + + @metered_subclass_method(METRICS_POOL) + def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]: + # TODO: IETF ACTN does not support monitoring by now + return [False for _ in subscriptions] + + def GetState( + self, blocking=False, terminate : Optional[threading.Event] = None + ) -> Iterator[Tuple[float, str, Any]]: + # TODO: IETF ACTN does not support monitoring by now + return [] diff --git a/src/device/service/drivers/ietf_actn/Tools.py b/src/device/service/drivers/ietf_actn/Tools.py new file mode 100644 index 0000000000000000000000000000000000000000..bbd4247f0debdd17885c5aadccafc32607e4cbe5 --- /dev/null +++ b/src/device/service/drivers/ietf_actn/Tools.py @@ -0,0 +1,198 @@ +# 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, logging, operator, requests +from requests.auth import HTTPBasicAuth +from typing import Optional +from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_SERVICES + +LOGGER = logging.getLogger(__name__) + +HTTP_OK_CODES = { + 200, # OK + 201, # Created + 202, # Accepted + 204, # No Content +} + +def find_key(resource, key): + return json.loads(resource[1])[key] + + +def config_getter( + root_url : str, resource_key : str, auth : Optional[HTTPBasicAuth] = None, timeout : Optional[int] = None +): + url = '{:s}/restconf/data/tapi-common:context'.format(root_url) + result = [] + try: + response = requests.get(url, timeout=timeout, verify=False, auth=auth) + except requests.exceptions.Timeout: + LOGGER.exception('Timeout connecting {:s}'.format(url)) + return result + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception retrieving {:s}'.format(resource_key)) + result.append((resource_key, e)) + return result + + try: + context = json.loads(response.content) + except Exception as e: # pylint: disable=broad-except + LOGGER.warning('Unable to decode reply: {:s}'.format(str(response.content))) + result.append((resource_key, e)) + return result + + if resource_key == RESOURCE_ENDPOINTS: + if 'tapi-common:context' in context: + context = context['tapi-common:context'] + elif 'context' in context: + context = context['context'] + + for sip in context['service-interface-point']: + layer_protocol_name = sip.get('layer-protocol-name', '?') + supportable_spectrum = sip.get('tapi-photonic-media:media-channel-service-interface-point-spec', {}) + supportable_spectrum = supportable_spectrum.get('mc-pool', {}) + supportable_spectrum = supportable_spectrum.get('supportable-spectrum', []) + supportable_spectrum = supportable_spectrum[0] if len(supportable_spectrum) == 1 else {} + grid_type = supportable_spectrum.get('frequency-constraint', {}).get('grid-type') + granularity = supportable_spectrum.get('frequency-constraint', {}).get('adjustment-granularity') + direction = sip.get('direction', '?') + + endpoint_type = [layer_protocol_name, grid_type, granularity, direction] + str_endpoint_type = ':'.join(filter(lambda i: operator.is_not(i, None), endpoint_type)) + sip_uuid = sip['uuid'] + + sip_names = sip.get('name', []) + sip_name = next(iter([ + sip_name['value'] + for sip_name in sip_names + if sip_name['value-name'] == 'local-name' + ]), sip_uuid) + + endpoint_url = '/endpoints/endpoint[{:s}]'.format(sip_uuid) + endpoint_data = {'uuid': sip_uuid, 'name': sip_name, 'type': str_endpoint_type} + result.append((endpoint_url, endpoint_data)) + + elif resource_key == RESOURCE_SERVICES: + if 'tapi-common:context' in context: + context = context['tapi-common:context'] + elif 'context' in context: + context = context['context'] + + if 'tapi-connectivity:connectivity-context' in context: + context = context['tapi-connectivity:connectivity-context'] + elif 'connectivity-context' in context: + context = context['connectivity-context'] + + for conn_svc in context['connectivity-service']: + service_uuid = conn_svc['uuid'] + constraints = conn_svc.get('connectivity-constraint', {}) + total_req_cap = constraints.get('requested-capacity', {}).get('total-size', {}) + + service_url = '/services/service[{:s}]'.format(service_uuid) + service_data = { + 'uuid': service_uuid, + 'direction': constraints.get('connectivity-direction', 'UNIDIRECTIONAL'), + 'capacity_unit': total_req_cap.get('unit', '<UNDEFINED>'), + 'capacity_value': total_req_cap.get('value', '<UNDEFINED>'), + } + + for i,endpoint in enumerate(conn_svc.get('end-point', [])): + layer_protocol_name = endpoint.get('layer-protocol-name') + if layer_protocol_name is not None: + service_data['layer_protocol_name'] = layer_protocol_name + + layer_protocol_qualifier = endpoint.get('layer-protocol-qualifier') + if layer_protocol_qualifier is not None: + service_data['layer_protocol_qualifier'] = layer_protocol_qualifier + + sip = endpoint['service-interface-point']['service-interface-point-uuid'] + service_data['input_sip' if i == 0 else 'output_sip'] = sip + + result.append((service_url, service_data)) + + return result + +def create_connectivity_service( + root_url, uuid, input_sip, output_sip, direction, capacity_value, capacity_unit, layer_protocol_name, + layer_protocol_qualifier, + auth : Optional[HTTPBasicAuth] = None, timeout : Optional[int] = None +): + + url = '{:s}/restconf/data/tapi-common:context/tapi-connectivity:connectivity-context'.format(root_url) + headers = {'content-type': 'application/json'} + data = { + 'tapi-connectivity:connectivity-service': [ + { + 'uuid': uuid, + 'connectivity-constraint': { + 'requested-capacity': { + 'total-size': { + 'value': capacity_value, + 'unit': capacity_unit + } + }, + 'connectivity-direction': direction + }, + 'end-point': [ + { + 'service-interface-point': { + 'service-interface-point-uuid': input_sip + }, + 'layer-protocol-name': layer_protocol_name, + 'layer-protocol-qualifier': layer_protocol_qualifier, + 'local-id': input_sip + }, + { + 'service-interface-point': { + 'service-interface-point-uuid': output_sip + }, + 'layer-protocol-name': layer_protocol_name, + 'layer-protocol-qualifier': layer_protocol_qualifier, + 'local-id': output_sip + } + ] + } + ] + } + results = [] + try: + LOGGER.info('Connectivity service {:s}: {:s}'.format(str(uuid), str(data))) + response = requests.post( + url=url, data=json.dumps(data), timeout=timeout, headers=headers, verify=False, auth=auth) + LOGGER.info('TAPI response: {:s}'.format(str(response))) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception creating ConnectivityService(uuid={:s}, data={:s})'.format(str(uuid), str(data))) + results.append(e) + else: + if response.status_code not in HTTP_OK_CODES: + msg = 'Could not create ConnectivityService(uuid={:s}, data={:s}). status_code={:s} reply={:s}' + LOGGER.error(msg.format(str(uuid), str(data), str(response.status_code), str(response))) + results.append(response.status_code in HTTP_OK_CODES) + return results + +def delete_connectivity_service(root_url, uuid, auth : Optional[HTTPBasicAuth] = None, timeout : Optional[int] = None): + url = '{:s}/restconf/data/tapi-common:context/tapi-connectivity:connectivity-context/connectivity-service={:s}' + url = url.format(root_url, uuid) + results = [] + try: + response = requests.delete(url=url, timeout=timeout, verify=False, auth=auth) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Exception deleting ConnectivityService(uuid={:s})'.format(str(uuid))) + results.append(e) + else: + if response.status_code not in HTTP_OK_CODES: + msg = 'Could not delete ConnectivityService(uuid={:s}). status_code={:s} reply={:s}' + LOGGER.error(msg.format(str(uuid), str(response.status_code), str(response))) + results.append(response.status_code in HTTP_OK_CODES) + return results diff --git a/src/device/service/drivers/ietf_actn/__init__.py b/src/device/service/drivers/ietf_actn/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d5073c330b89bed63f08b0da86c4a7649c87b3dd --- /dev/null +++ b/src/device/service/drivers/ietf_actn/__init__.py @@ -0,0 +1,20 @@ +# 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 device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_SERVICES + +ALL_RESOURCE_KEYS = [ + RESOURCE_ENDPOINTS, + RESOURCE_SERVICES, +] diff --git a/src/policy/src/main/java/org/etsi/tfs/policy/Serializer.java b/src/policy/src/main/java/org/etsi/tfs/policy/Serializer.java index b7de8ff99fe820ad80a555c97a42accfe21b1d7b..f777c77209b0d023da5a30270ab472de6117bb59 100644 --- a/src/policy/src/main/java/org/etsi/tfs/policy/Serializer.java +++ b/src/policy/src/main/java/org/etsi/tfs/policy/Serializer.java @@ -2284,6 +2284,12 @@ public class Serializer { return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_XR; case IETF_L2VPN: return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN; + case GNMI_OPENCONFIG: + return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG; + case FLEXSCALE: + return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE; + case IETF_ACTN: + return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN; case UNDEFINED: default: return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_UNDEFINED; @@ -2307,6 +2313,12 @@ public class Serializer { return DeviceDriverEnum.XR; case DEVICEDRIVER_IETF_L2VPN: return DeviceDriverEnum.IETF_L2VPN; + case DEVICEDRIVER_GNMI_OPENCONFIG: + return DeviceDriverEnum.GNMI_OPENCONFIG; + case DEVICEDRIVER_FLEXSCALE: + return DeviceDriverEnum.FLEXSCALE; + case DEVICEDRIVER_IETF_ACTN: + return DeviceDriverEnum.IETF_ACTN; case DEVICEDRIVER_UNDEFINED: case UNRECOGNIZED: default: diff --git a/src/policy/src/test/java/org/etsi/tfs/policy/SerializerTest.java b/src/policy/src/test/java/org/etsi/tfs/policy/SerializerTest.java index f29ae3697a8842c14dc28716e325adc85a5c45af..df2ae46cf718dfd0178c0e658a40972855e16879 100644 --- a/src/policy/src/test/java/org/etsi/tfs/policy/SerializerTest.java +++ b/src/policy/src/test/java/org/etsi/tfs/policy/SerializerTest.java @@ -3614,6 +3614,15 @@ class SerializerTest { Arguments.of( DeviceDriverEnum.IETF_L2VPN, ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN), + Arguments.of( + DeviceDriverEnum.GNMI_OPENCONFIG, + ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG), + Arguments.of( + DeviceDriverEnum.FLEXSCALE, + ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE), + Arguments.of( + DeviceDriverEnum.IETF_ACTN, + ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN), Arguments.of( DeviceDriverEnum.UNDEFINED, ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_UNDEFINED)); } diff --git a/src/service/service/service_handler_api/FilterFields.py b/src/service/service/service_handler_api/FilterFields.py index 35c45c99699b5bc640639cde3054ef72bbb6de50..e771e24f17b2ea97c61158b65cb62c87ee9f37c5 100644 --- a/src/service/service/service_handler_api/FilterFields.py +++ b/src/service/service/service_handler_api/FilterFields.py @@ -39,6 +39,7 @@ DEVICE_DRIVER_VALUES = { DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN, DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE, + DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN, } # Map allowed filter fields to allowed values per Filter field. If no restriction (free text) None is specified diff --git a/src/webui/service/device/forms.py b/src/webui/service/device/forms.py index bcd5804d32927763344d08371320fdde5f2fcab7..4c04bbfe12d8d39e51bd8275021064a5a7ad4fc3 100644 --- a/src/webui/service/device/forms.py +++ b/src/webui/service/device/forms.py @@ -31,6 +31,8 @@ class AddDeviceForm(FlaskForm): device_drivers_xr = BooleanField('XR') device_drivers_ietf_l2vpn = BooleanField('IETF L2VPN') device_drivers_gnmi_openconfig = BooleanField('GNMI OPENCONFIG') + device_drivers_flexscale = BooleanField('FLEXSCALE') + device_drivers_ietf_actn = BooleanField('IETF ACTN') 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)]) diff --git a/src/webui/service/device/routes.py b/src/webui/service/device/routes.py index 4459deeebd000642cfe235f4f46ebf65670ae2ee..b75e9fb9f09bddcb9f321995465fd8cca5263277 100644 --- a/src/webui/service/device/routes.py +++ b/src/webui/service/device/routes.py @@ -125,6 +125,10 @@ def add(): device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN) if form.device_drivers_gnmi_openconfig.data: device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG) + if form.device_drivers_flexscale.data: + device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE) + if form.device_drivers_ietf_actn.data: + device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN) device_obj.device_drivers.extend(device_drivers) # pylint: disable=no-member try: diff --git a/src/webui/service/templates/device/add.html b/src/webui/service/templates/device/add.html index c115657aa08828849172345ca50caaeb4150fe0f..c4d7f16858b7c63bd87e730cff6d586dc702e0c9 100644 --- a/src/webui/service/templates/device/add.html +++ b/src/webui/service/templates/device/add.html @@ -92,6 +92,9 @@ {{ form.device_drivers_xr }} {{ form.device_drivers_xr.label(class="col-sm-3 col-form-label") }} {{ form.device_drivers_ietf_l2vpn }} {{ form.device_drivers_ietf_l2vpn.label(class="col-sm-3 col-form-label") }} {{ form.device_drivers_gnmi_openconfig }} {{ form.device_drivers_gnmi_openconfig.label(class="col-sm-3 col-form-label") }} + <br /> + {{ form.device_drivers_flexscale }} {{ form.device_drivers_flexscale.label(class="col-sm-3 col-form-label") }} + {{ form.device_drivers_ietf_actn }} {{ form.device_drivers_ietf_actn.label(class="col-sm-3 col-form-label") }} {% endif %} </div> </div> diff --git a/src/ztp/src/main/java/org/etsi/tfs/ztp/Serializer.java b/src/ztp/src/main/java/org/etsi/tfs/ztp/Serializer.java index cf49280a856e5fb7f4afaef394b565b02e44a8c2..feb65b77c9f45c760474f5e25a82b68eac8a7a01 100644 --- a/src/ztp/src/main/java/org/etsi/tfs/ztp/Serializer.java +++ b/src/ztp/src/main/java/org/etsi/tfs/ztp/Serializer.java @@ -863,6 +863,12 @@ public class Serializer { return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_XR; case IETF_L2VPN: return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN; + case GNMI_OPENCONFIG: + return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG; + case FLEXSCALE: + return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE; + case IETF_ACTN: + return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN; case UNDEFINED: default: return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_UNDEFINED; @@ -886,6 +892,12 @@ public class Serializer { return DeviceDriverEnum.XR; case DEVICEDRIVER_IETF_L2VPN: return DeviceDriverEnum.IETF_L2VPN; + case DEVICEDRIVER_GNMI_OPENCONFIG: + return DeviceDriverEnum.GNMI_OPENCONFIG; + case DEVICEDRIVER_FLEXSCALE: + return DeviceDriverEnum.FLEXSCALE; + case DEVICEDRIVER_IETF_ACTN: + return DeviceDriverEnum.IETF_ACTN; case DEVICEDRIVER_UNDEFINED: case UNRECOGNIZED: default: diff --git a/src/ztp/src/test/java/org/etsi/tfs/ztp/SerializerTest.java b/src/ztp/src/test/java/org/etsi/tfs/ztp/SerializerTest.java index 5a7887a049526e530874a597b2b0f96e2646a4f9..37c6df36d01140f947378493da8f4c568b15650b 100644 --- a/src/ztp/src/test/java/org/etsi/tfs/ztp/SerializerTest.java +++ b/src/ztp/src/test/java/org/etsi/tfs/ztp/SerializerTest.java @@ -1223,6 +1223,15 @@ class SerializerTest { Arguments.of( DeviceDriverEnum.IETF_L2VPN, ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN), + Arguments.of( + DeviceDriverEnum.GNMI_OPENCONFIG, + ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG), + Arguments.of( + DeviceDriverEnum.FLEXSCALE, + ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE), + Arguments.of( + DeviceDriverEnum.IETF_ACTN, + ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN), Arguments.of( DeviceDriverEnum.UNDEFINED, ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_UNDEFINED)); }