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/proto/generate_code_java.sh b/proto/generate_code_java.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4a3dbcf128b28e9feb1f96f95b7541b0f32cc664
--- /dev/null
+++ b/proto/generate_code_java.sh
@@ -0,0 +1,32 @@
+#!/bin/bash -eu    
+# 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.
+    
+    
+export JAVA_COMPONENTS="ztp policy"
+
+export TFS_ROOT_DIR=$(dirname $(dirname $(realpath $0)))
+    
+for COMPONENT in $JAVA_COMPONENTS; do
+  echo "\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/"
+  echo
+  echo "[TFS] Now building" $COMPONENT
+  echo
+  echo "\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/"
+  cd $TFS_ROOT_DIR/src/$COMPONENT
+    
+  ./mvnw spotless:apply
+  ./mvnw install -DskipUTs
+done
+
diff --git a/scripts/run_tests_locally-device-ietf-actn.sh b/scripts/run_tests_locally-device-ietf-actn.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8e602b31d9465821dfd798e8038de9b78f7dedc6
--- /dev/null
+++ b/scripts/run_tests_locally-device-ietf-actn.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# 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.
+
+
+PROJECTDIR=`pwd`
+
+cd $PROJECTDIR/src
+RCFILE=$PROJECTDIR/coverage/.coveragerc
+
+# Run unitary tests and analyze coverage of code at same time
+# helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    device/tests/test_unitary_ietf_actn.py
diff --git a/scripts/run_tests_locally-nbi-debug-api.sh b/scripts/run_tests_locally-nbi-debug-api.sh
new file mode 100755
index 0000000000000000000000000000000000000000..218bad8c57b508cee4fc5cfe40f0f6d484dff32e
--- /dev/null
+++ b/scripts/run_tests_locally-nbi-debug-api.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# 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.
+
+
+PROJECTDIR=`pwd`
+
+cd $PROJECTDIR/src
+RCFILE=$PROJECTDIR/coverage/.coveragerc
+
+# Run unitary tests and analyze coverage of code at same time
+# helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    nbi/tests/test_debug_api.py
diff --git a/src/common/tests/MockServicerImpl_Context.py b/src/common/tests/MockServicerImpl_Context.py
index 98a216850a757e0c21c44d2e295cb4b93c538e05..464517a767f31d95277dc8205cf49f527fe96a48 100644
--- a/src/common/tests/MockServicerImpl_Context.py
+++ b/src/common/tests/MockServicerImpl_Context.py
@@ -25,12 +25,13 @@ from common.proto.context_pb2 import (
     Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList,
     Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList)
 from common.proto.context_pb2_grpc import ContextServiceServicer
+from common.proto.policy_pb2 import PolicyRule, PolicyRuleId, PolicyRuleIdList, PolicyRuleList
 from common.tools.grpc.Tools import grpc_message_to_json, grpc_message_to_json_string
 from common.tools.object_factory.Device import json_device_id
 from common.tools.object_factory.Link import json_link_id
 from .InMemoryObjectDatabase import InMemoryObjectDatabase
 from .MockMessageBroker import (
-    TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, TOPIC_SERVICE, TOPIC_SLICE, TOPIC_TOPOLOGY,
+    TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, TOPIC_SERVICE, TOPIC_SLICE, TOPIC_TOPOLOGY, TOPIC_POLICY,
     MockMessageBroker, notify_event)
 
 LOGGER = logging.getLogger(__name__)
@@ -62,58 +63,58 @@ class MockServicerImpl_Context(ContextServiceServicer):
 
     # ----- Context ----------------------------------------------------------------------------------------------------
 
-    def ListContextIds(self, request: Empty, context : grpc.ServicerContext) -> ContextIdList:
+    def ListContextIds(self, request : Empty, context : grpc.ServicerContext) -> ContextIdList:
         LOGGER.debug('[ListContextIds] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = ContextIdList(context_ids=[context.context_id for context in self.obj_db.get_entries('context')])
         LOGGER.debug('[ListContextIds] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def ListContexts(self, request: Empty, context : grpc.ServicerContext) -> ContextList:
+    def ListContexts(self, request : Empty, context : grpc.ServicerContext) -> ContextList:
         LOGGER.debug('[ListContexts] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = ContextList(contexts=self.obj_db.get_entries('context'))
         LOGGER.debug('[ListContexts] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetContext(self, request: ContextId, context : grpc.ServicerContext) -> Context:
+    def GetContext(self, request : ContextId, context : grpc.ServicerContext) -> Context:
         LOGGER.debug('[GetContext] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = self.obj_db.get_entry('context', request.context_uuid.uuid, context)
         LOGGER.debug('[GetContext] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def SetContext(self, request: Context, context : grpc.ServicerContext) -> ContextId:
+    def SetContext(self, request : Context, context : grpc.ServicerContext) -> ContextId:
         LOGGER.debug('[SetContext] request={:s}'.format(grpc_message_to_json_string(request)))
         reply,_ = self._set(request, 'context', request.context_id.context_uuid.uuid, 'context_id', TOPIC_CONTEXT)
         LOGGER.debug('[SetContext] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def RemoveContext(self, request: ContextId, context : grpc.ServicerContext) -> Empty:
+    def RemoveContext(self, request : ContextId, context : grpc.ServicerContext) -> Empty:
         LOGGER.debug('[RemoveContext] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = self._del(request, 'context', request.context_uuid.uuid, 'context_id', TOPIC_CONTEXT, context)
         LOGGER.debug('[RemoveContext] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetContextEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[ContextEvent]:
+    def GetContextEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ContextEvent]:
         LOGGER.debug('[GetContextEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_CONTEXT}): yield ContextEvent(**json.loads(message.content))
 
 
     # ----- Topology ---------------------------------------------------------------------------------------------------
 
-    def ListTopologyIds(self, request: ContextId, context : grpc.ServicerContext) -> TopologyIdList:
+    def ListTopologyIds(self, request : ContextId, context : grpc.ServicerContext) -> TopologyIdList:
         LOGGER.debug('[ListTopologyIds] request={:s}'.format(grpc_message_to_json_string(request)))
         topologies = self.obj_db.get_entries('topology[{:s}]'.format(str(request.context_uuid.uuid)))
         reply = TopologyIdList(topology_ids=[topology.topology_id for topology in topologies])
         LOGGER.debug('[ListTopologyIds] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def ListTopologies(self, request: ContextId, context : grpc.ServicerContext) -> TopologyList:
+    def ListTopologies(self, request : ContextId, context : grpc.ServicerContext) -> TopologyList:
         LOGGER.debug('[ListTopologies] request={:s}'.format(grpc_message_to_json_string(request)))
         topologies = self.obj_db.get_entries('topology[{:s}]'.format(str(request.context_uuid.uuid)))
         reply = TopologyList(topologies=[topology for topology in topologies])
         LOGGER.debug('[ListTopologies] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetTopology(self, request: TopologyId, context : grpc.ServicerContext) -> Topology:
+    def GetTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Topology:
         LOGGER.debug('[GetTopology] request={:s}'.format(grpc_message_to_json_string(request)))
         container_name = 'topology[{:s}]'.format(str(request.context_id.context_uuid.uuid))
         reply = self.obj_db.get_entry(container_name, request.topology_uuid.uuid, context)
@@ -143,7 +144,7 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.debug('[GetTopologyDetails] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def SetTopology(self, request: Topology, context : grpc.ServicerContext) -> TopologyId:
+    def SetTopology(self, request : Topology, context : grpc.ServicerContext) -> TopologyId:
         LOGGER.debug('[SetTopology] request={:s}'.format(grpc_message_to_json_string(request)))
         context_uuid = str(request.topology_id.context_id.context_uuid.uuid)
         container_name = 'topology[{:s}]'.format(context_uuid)
@@ -164,10 +165,12 @@ class MockServicerImpl_Context(ContextServiceServicer):
             rw_request = Topology()
             rw_request.CopyFrom(request)
 
+            # pylint: disable=no-member
             del rw_request.device_ids[:]
             for device_uuid in sorted(device_uuids):
                 rw_request.device_ids.append(DeviceId(**json_device_id(device_uuid)))
 
+            # pylint: disable=no-member
             del rw_request.link_ids[:]
             for link_uuid in sorted(link_uuids):
                 rw_request.link_ids.append(LinkId(**json_link_id(link_uuid)))
@@ -181,12 +184,14 @@ class MockServicerImpl_Context(ContextServiceServicer):
             if _topology_id.topology_uuid.uuid == topology_uuid: break
         else:
             # topology not found, add it
-            context_.topology_ids.add().topology_uuid.uuid = topology_uuid
+            topology_id = context_.topology_ids.add()
+            topology_id.context_id.context_uuid.uuid = context_uuid
+            topology_id.topology_uuid.uuid = topology_uuid
 
         LOGGER.debug('[SetTopology] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def RemoveTopology(self, request: TopologyId, context : grpc.ServicerContext) -> Empty:
+    def RemoveTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Empty:
         LOGGER.debug('[RemoveTopology] request={:s}'.format(grpc_message_to_json_string(request)))
         context_uuid = str(request.context_id.context_uuid.uuid)
         container_name = 'topology[{:s}]'.format(context_uuid)
@@ -195,39 +200,40 @@ class MockServicerImpl_Context(ContextServiceServicer):
 
         context_ = self.obj_db.get_entry('context', context_uuid, context)
         for _topology_id in context_.topology_ids:
-            if _topology_id.topology_uuid.uuid == topology_uuid:
-                context_.topology_ids.remove(_topology_id)
-                break
+            if _topology_id.context_id.context_uuid.uuid != context_uuid: continue
+            if _topology_id.topology_uuid.uuid != topology_uuid: continue
+            context_.topology_ids.remove(_topology_id)
+            break
 
         LOGGER.debug('[RemoveTopology] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetTopologyEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[TopologyEvent]:
+    def GetTopologyEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[TopologyEvent]:
         LOGGER.debug('[GetTopologyEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_TOPOLOGY}): yield TopologyEvent(**json.loads(message.content))
 
 
     # ----- Device -----------------------------------------------------------------------------------------------------
 
-    def ListDeviceIds(self, request: Empty, context : grpc.ServicerContext) -> DeviceIdList:
+    def ListDeviceIds(self, request : Empty, context : grpc.ServicerContext) -> DeviceIdList:
         LOGGER.debug('[ListDeviceIds] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = DeviceIdList(device_ids=[device.device_id for device in self.obj_db.get_entries('device')])
         LOGGER.debug('[ListDeviceIds] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def ListDevices(self, request: Empty, context : grpc.ServicerContext) -> DeviceList:
+    def ListDevices(self, request : Empty, context : grpc.ServicerContext) -> DeviceList:
         LOGGER.debug('[ListDevices] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = DeviceList(devices=self.obj_db.get_entries('device'))
         LOGGER.debug('[ListDevices] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetDevice(self, request: DeviceId, context : grpc.ServicerContext) -> Device:
+    def GetDevice(self, request : DeviceId, context : grpc.ServicerContext) -> Device:
         LOGGER.debug('[GetDevice] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = self.obj_db.get_entry('device', request.device_uuid.uuid, context)
         LOGGER.debug('[GetDevice] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def SetDevice(self, request: Context, context : grpc.ServicerContext) -> DeviceId:
+    def SetDevice(self, request : Context, context : grpc.ServicerContext) -> DeviceId:
         LOGGER.debug('[SetDevice] request={:s}'.format(grpc_message_to_json_string(request)))
         device_uuid = request.device_id.device_uuid.uuid
         reply, device = self._set(request, 'device', device_uuid, 'device_id', TOPIC_DEVICE)
@@ -253,7 +259,7 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.debug('[SetDevice] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def RemoveDevice(self, request: DeviceId, context : grpc.ServicerContext) -> Empty:
+    def RemoveDevice(self, request : DeviceId, context : grpc.ServicerContext) -> Empty:
         LOGGER.debug('[RemoveDevice] request={:s}'.format(grpc_message_to_json_string(request)))
         device_uuid = request.device_uuid.uuid
         device = self.obj_db.get_entry('device', device_uuid, context)
@@ -279,7 +285,7 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.debug('[RemoveDevice] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetDeviceEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[DeviceEvent]:
+    def GetDeviceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[DeviceEvent]:
         LOGGER.debug('[GetDeviceEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_DEVICE}): yield DeviceEvent(**json.loads(message.content))
 
@@ -313,25 +319,25 @@ class MockServicerImpl_Context(ContextServiceServicer):
 
     # ----- Link -------------------------------------------------------------------------------------------------------
 
-    def ListLinkIds(self, request: Empty, context : grpc.ServicerContext) -> LinkIdList:
+    def ListLinkIds(self, request : Empty, context : grpc.ServicerContext) -> LinkIdList:
         LOGGER.debug('[ListLinkIds] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = LinkIdList(link_ids=[link.link_id for link in self.obj_db.get_entries('link')])
         LOGGER.debug('[ListLinkIds] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def ListLinks(self, request: Empty, context : grpc.ServicerContext) -> LinkList:
+    def ListLinks(self, request : Empty, context : grpc.ServicerContext) -> LinkList:
         LOGGER.debug('[ListLinks] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = LinkList(links=self.obj_db.get_entries('link'))
         LOGGER.debug('[ListLinks] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetLink(self, request: LinkId, context : grpc.ServicerContext) -> Link:
+    def GetLink(self, request : LinkId, context : grpc.ServicerContext) -> Link:
         LOGGER.debug('[GetLink] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = self.obj_db.get_entry('link', request.link_uuid.uuid, context)
         LOGGER.debug('[GetLink] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def SetLink(self, request: Context, context : grpc.ServicerContext) -> LinkId:
+    def SetLink(self, request : Context, context : grpc.ServicerContext) -> LinkId:
         LOGGER.debug('[SetLink] request={:s}'.format(grpc_message_to_json_string(request)))
         link_uuid = request.link_id.link_uuid.uuid
         reply, link = self._set(request, 'link', link_uuid, 'link_id', TOPIC_LINK)
@@ -357,7 +363,7 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.debug('[SetLink] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def RemoveLink(self, request: LinkId, context : grpc.ServicerContext) -> Empty:
+    def RemoveLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty:
         LOGGER.debug('[RemoveLink] request={:s}'.format(grpc_message_to_json_string(request)))
         link_uuid = request.link_uuid.uuid
         link = self.obj_db.get_entry('link', link_uuid, context)
@@ -383,35 +389,35 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.debug('[RemoveLink] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetLinkEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[LinkEvent]:
+    def GetLinkEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[LinkEvent]:
         LOGGER.debug('[GetLinkEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_LINK}): yield LinkEvent(**json.loads(message.content))
 
 
     # ----- Slice ------------------------------------------------------------------------------------------------------
 
-    def ListSliceIds(self, request: ContextId, context : grpc.ServicerContext) -> SliceIdList:
+    def ListSliceIds(self, request : ContextId, context : grpc.ServicerContext) -> SliceIdList:
         LOGGER.debug('[ListSliceIds] request={:s}'.format(grpc_message_to_json_string(request)))
         slices = self.obj_db.get_entries('slice[{:s}]'.format(str(request.context_uuid.uuid)))
         reply = SliceIdList(slice_ids=[slice.slice_id for slice in slices])
         LOGGER.debug('[ListSliceIds] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def ListSlices(self, request: ContextId, context : grpc.ServicerContext) -> SliceList:
+    def ListSlices(self, request : ContextId, context : grpc.ServicerContext) -> SliceList:
         LOGGER.debug('[ListSlices] request={:s}'.format(grpc_message_to_json_string(request)))
         slices = self.obj_db.get_entries('slice[{:s}]'.format(str(request.context_uuid.uuid)))
         reply = SliceList(slices=[slice for slice in slices])
         LOGGER.debug('[ListSlices] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetSlice(self, request: SliceId, context : grpc.ServicerContext) -> Slice:
+    def GetSlice(self, request : SliceId, context : grpc.ServicerContext) -> Slice:
         LOGGER.debug('[GetSlice] request={:s}'.format(grpc_message_to_json_string(request)))
         container_name = 'slice[{:s}]'.format(str(request.context_id.context_uuid.uuid))
         reply = self.obj_db.get_entry(container_name, request.slice_uuid.uuid, context)
         LOGGER.debug('[GetSlice] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def SetSlice(self, request: Slice, context : grpc.ServicerContext) -> SliceId:
+    def SetSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId:
         LOGGER.debug('[SetSlice] request={:s}'.format(grpc_message_to_json_string(request)))
         context_uuid = str(request.slice_id.context_id.context_uuid.uuid)
         container_name = 'slice[{:s}]'.format(context_uuid)
@@ -423,12 +429,14 @@ class MockServicerImpl_Context(ContextServiceServicer):
             if _slice_id.slice_uuid.uuid == slice_uuid: break
         else:
             # slice not found, add it
-            context_.slice_ids.add().slice_uuid.uuid = slice_uuid
+            slice_id = context_.slice_ids.add()
+            slice_id.context_id.context_uuid.uuid = context_uuid
+            slice_id.slice_uuid.uuid = slice_uuid
 
         LOGGER.debug('[SetSlice] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def RemoveSlice(self, request: SliceId, context : grpc.ServicerContext) -> Empty:
+    def RemoveSlice(self, request : SliceId, context : grpc.ServicerContext) -> Empty:
         LOGGER.debug('[RemoveSlice] request={:s}'.format(grpc_message_to_json_string(request)))
         context_uuid = str(request.context_id.context_uuid.uuid)
         container_name = 'slice[{:s}]'.format(context_uuid)
@@ -437,14 +445,15 @@ class MockServicerImpl_Context(ContextServiceServicer):
 
         context_ = self.obj_db.get_entry('context', context_uuid, context)
         for _slice_id in context_.slice_ids:
-            if _slice_id.slice_uuid.uuid == slice_uuid:
-                context_.slice_ids.remove(_slice_id)
-                break
+            if _slice_id.context_id.context_uuid.uuid != context_uuid: continue
+            if _slice_id.slice_uuid.uuid != slice_uuid: continue
+            context_.slice_ids.remove(_slice_id)
+            break
 
         LOGGER.debug('[RemoveSlice] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetSliceEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[SliceEvent]:
+    def GetSliceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[SliceEvent]:
         LOGGER.debug('[GetSliceEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_SLICE}): yield SliceEvent(**json.loads(message.content))
 
@@ -482,28 +491,28 @@ class MockServicerImpl_Context(ContextServiceServicer):
 
     # ----- Service ----------------------------------------------------------------------------------------------------
 
-    def ListServiceIds(self, request: ContextId, context : grpc.ServicerContext) -> ServiceIdList:
+    def ListServiceIds(self, request : ContextId, context : grpc.ServicerContext) -> ServiceIdList:
         LOGGER.debug('[ListServiceIds] request={:s}'.format(grpc_message_to_json_string(request)))
         services = self.obj_db.get_entries('service[{:s}]'.format(str(request.context_uuid.uuid)))
         reply = ServiceIdList(service_ids=[service.service_id for service in services])
         LOGGER.debug('[ListServiceIds] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def ListServices(self, request: ContextId, context : grpc.ServicerContext) -> ServiceList:
+    def ListServices(self, request : ContextId, context : grpc.ServicerContext) -> ServiceList:
         LOGGER.debug('[ListServices] request={:s}'.format(grpc_message_to_json_string(request)))
         services = self.obj_db.get_entries('service[{:s}]'.format(str(request.context_uuid.uuid)))
         reply = ServiceList(services=[service for service in services])
         LOGGER.debug('[ListServices] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetService(self, request: ServiceId, context : grpc.ServicerContext) -> Service:
+    def GetService(self, request : ServiceId, context : grpc.ServicerContext) -> Service:
         LOGGER.debug('[GetService] request={:s}'.format(grpc_message_to_json_string(request)))
         container_name = 'service[{:s}]'.format(str(request.context_id.context_uuid.uuid))
         reply = self.obj_db.get_entry(container_name, request.service_uuid.uuid, context)
         LOGGER.debug('[GetService] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def SetService(self, request: Service, context : grpc.ServicerContext) -> ServiceId:
+    def SetService(self, request : Service, context : grpc.ServicerContext) -> ServiceId:
         LOGGER.debug('[SetService] request={:s}'.format(grpc_message_to_json_string(request)))
         context_uuid = str(request.service_id.context_id.context_uuid.uuid)
         container_name = 'service[{:s}]'.format(context_uuid)
@@ -515,12 +524,14 @@ class MockServicerImpl_Context(ContextServiceServicer):
             if _service_id.service_uuid.uuid == service_uuid: break
         else:
             # service not found, add it
-            context_.service_ids.add().service_uuid.uuid = service_uuid
+            service_id = context_.service_ids.add()
+            service_id.context_id.context_uuid.uuid = context_uuid
+            service_id.service_uuid.uuid = service_uuid
 
         LOGGER.debug('[SetService] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def RemoveService(self, request: ServiceId, context : grpc.ServicerContext) -> Empty:
+    def RemoveService(self, request : ServiceId, context : grpc.ServicerContext) -> Empty:
         LOGGER.debug('[RemoveService] request={:s}'.format(grpc_message_to_json_string(request)))
         context_uuid = str(request.context_id.context_uuid.uuid)
         container_name = 'service[{:s}]'.format(context_uuid)
@@ -529,14 +540,15 @@ class MockServicerImpl_Context(ContextServiceServicer):
 
         context_ = self.obj_db.get_entry('context', context_uuid, context)
         for _service_id in context_.service_ids:
-            if _service_id.service_uuid.uuid == service_uuid:
-                context_.service_ids.remove(_service_id)
-                break
+            if _service_id.context_id.context_uuid.uuid != context_uuid: continue
+            if _service_id.service_uuid.uuid != service_uuid: continue
+            context_.service_ids.remove(_service_id)
+            break
 
         LOGGER.debug('[RemoveService] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetServiceEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[ServiceEvent]:
+    def GetServiceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ServiceEvent]:
         LOGGER.debug('[GetServiceEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_SERVICE}): yield ServiceEvent(**json.loads(message.content))
 
@@ -569,7 +581,7 @@ class MockServicerImpl_Context(ContextServiceServicer):
 
     # ----- Connection -------------------------------------------------------------------------------------------------
 
-    def ListConnectionIds(self, request: ServiceId, context : grpc.ServicerContext) -> ConnectionIdList:
+    def ListConnectionIds(self, request : ServiceId, context : grpc.ServicerContext) -> ConnectionIdList:
         LOGGER.debug('[ListConnectionIds] request={:s}'.format(grpc_message_to_json_string(request)))
         container_name = 'service_connections[{:s}/{:s}]'.format(
             str(request.context_id.context_uuid.uuid), str(request.service_uuid.uuid))
@@ -577,7 +589,7 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.debug('[ListConnectionIds] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def ListConnections(self, request: ServiceId, context : grpc.ServicerContext) -> ConnectionList:
+    def ListConnections(self, request : ServiceId, context : grpc.ServicerContext) -> ConnectionList:
         LOGGER.debug('[ListConnections] request={:s}'.format(grpc_message_to_json_string(request)))
         container_name = 'service_connections[{:s}/{:s}]'.format(
             str(request.context_id.context_uuid.uuid), str(request.service_uuid.uuid))
@@ -585,13 +597,13 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.debug('[ListConnections] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetConnection(self, request: ConnectionId, context : grpc.ServicerContext) -> Connection:
+    def GetConnection(self, request : ConnectionId, context : grpc.ServicerContext) -> Connection:
         LOGGER.debug('[GetConnection] request={:s}'.format(grpc_message_to_json_string(request)))
         reply = self.obj_db.get_entry('connection', request.connection_uuid.uuid, context)
         LOGGER.debug('[GetConnection] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def SetConnection(self, request: Connection, context : grpc.ServicerContext) -> ConnectionId:
+    def SetConnection(self, request : Connection, context : grpc.ServicerContext) -> ConnectionId:
         LOGGER.debug('[SetConnection] request={:s}'.format(grpc_message_to_json_string(request)))
         container_name = 'service_connection[{:s}/{:s}]'.format(
             str(request.service_id.context_id.context_uuid.uuid), str(request.service_id.service_uuid.uuid))
@@ -601,7 +613,7 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.debug('[SetConnection] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def RemoveConnection(self, request: ConnectionId, context : grpc.ServicerContext) -> Empty:
+    def RemoveConnection(self, request : ConnectionId, context : grpc.ServicerContext) -> Empty:
         LOGGER.debug('[RemoveConnection] request={:s}'.format(grpc_message_to_json_string(request)))
         connection = self.obj_db.get_entry('connection', request.connection_uuid.uuid, context)
         container_name = 'service_connection[{:s}/{:s}]'.format(
@@ -612,6 +624,45 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.debug('[RemoveConnection] reply={:s}'.format(grpc_message_to_json_string(reply)))
         return reply
 
-    def GetConnectionEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[ConnectionEvent]:
+    def GetConnectionEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ConnectionEvent]:
         LOGGER.debug('[GetConnectionEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_CONNECTION}): yield ConnectionEvent(**json.loads(message.content))
+
+    def ListPolicyRuleIds(self, request : Empty, context : grpc.ServicerContext):   # pylint: disable=unused-argument
+        LOGGER.debug('[ListPolicyRuleIds] request={:s}'.format(grpc_message_to_json_string(request)))
+        reply = PolicyRuleIdList(policyRuleIdList=[
+            getattr(policy_rule, policy_rule.WhichOneof('policy_rule')).policyRuleBasic.policyRuleId
+            for policy_rule in self.obj_db.get_entries('policy')
+        ])
+        LOGGER.debug('[ListPolicyRuleIds] reply={:s}'.format(grpc_message_to_json_string(reply)))
+        return reply
+
+    def ListPolicyRules(self, request : Empty, context : grpc.ServicerContext):     # pylint: disable=unused-argument
+        LOGGER.debug('[ListPolicyRules] request={:s}'.format(grpc_message_to_json_string(request)))
+        reply = PolicyRuleList(policyRules=self.obj_db.get_entries('policy'))
+        LOGGER.debug('[ListPolicyRules] reply={:s}'.format(grpc_message_to_json_string(reply)))
+        return reply
+
+    def GetPolicyRule(self, request : PolicyRuleId, context : grpc.ServicerContext):
+        LOGGER.debug('[GetPolicyRule] request={:s}'.format(grpc_message_to_json_string(request)))
+        reply = self.obj_db.get_entry('policy_rule', request.uuid.uuid, context)
+        LOGGER.debug('[GetPolicyRule] reply={:s}'.format(grpc_message_to_json_string(reply)))
+        return reply
+
+    def SetPolicyRule(self, request : PolicyRule, context : grpc.ServicerContext):  # pylint: disable=unused-argument
+        LOGGER.debug('[SetPolicyRule] request={:s}'.format(grpc_message_to_json_string(request)))
+        policy_type = request.WhichOneof('policy_rule')
+        policy_uuid = getattr(request, policy_type).policyRuleBasic.policyRuleId.uuid.uuid
+        rule_id_field = '{:s}.policyRuleBasic.policyRuleId'.format(policy_type)
+        reply, _ = self._set(request, 'policy', policy_uuid, rule_id_field, TOPIC_POLICY)
+        LOGGER.debug('[SetPolicyRule] reply={:s}'.format(grpc_message_to_json_string(reply)))
+        return reply
+
+    def RemovePolicyRule(self, request : PolicyRuleId, context : grpc.ServicerContext):
+        LOGGER.debug('[RemovePolicyRule] request={:s}'.format(grpc_message_to_json_string(request)))
+        policy_type = request.WhichOneof('policy_rule')
+        policy_uuid = getattr(request, policy_type).policyRuleBasic.policyRuleId.uuid.uuid
+        rule_id_field = '{:s}.policyRuleBasic.policyRuleId'.format(policy_type)
+        reply = self._del(request, 'policy', policy_uuid, rule_id_field, TOPIC_CONTEXT, context)
+        LOGGER.debug('[RemovePolicyRule] reply={:s}'.format(grpc_message_to_json_string(reply)))
+        return reply
diff --git a/src/common/tools/object_factory/Device.py b/src/common/tools/object_factory/Device.py
index bc5c28740d5635df99c26ef56124c471d2c77d91..76959232a947ec50918afbc77a992d8af0d0723f 100644
--- a/src/common/tools/object_factory/Device.py
+++ b/src/common/tools/object_factory/Device.py
@@ -46,6 +46,10 @@ DEVICE_P4_DRIVERS   = [DeviceDriverEnum.DEVICEDRIVER_P4]
 DEVICE_TFS_TYPE    = DeviceTypeEnum.TERAFLOWSDN_CONTROLLER.value
 DEVICE_TFS_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN]
 
+DEVICE_IETF_ACTN_TYPE    = DeviceTypeEnum.OPEN_LINE_SYSTEM.value
+DEVICE_IETF_ACTN_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN]
+
+
 def json_device_id(device_uuid : str):
     return {'device_uuid': {'uuid': device_uuid}}
 
@@ -136,6 +140,14 @@ def json_device_tfs_disabled(
         device_uuid, DEVICE_TFS_TYPE, DEVICE_DISABLED, name=name, endpoints=endpoints, config_rules=config_rules,
         drivers=drivers)
 
+def json_device_ietf_actn_disabled(
+        device_uuid : str, name : Optional[str] = None, endpoints : List[Dict] = [], config_rules : List[Dict] = [],
+        drivers : List[Dict] = DEVICE_IETF_ACTN_DRIVERS
+    ):
+    return json_device(
+        device_uuid, DEVICE_IETF_ACTN_TYPE, DEVICE_DISABLED, name=name, endpoints=endpoints, config_rules=config_rules,
+        drivers=drivers)
+
 def json_device_connect_rules(address : str, port : int, settings : Dict = {}) -> List[Dict]:
     return [
         json_config_rule_set('_connect/address',  address),
diff --git a/src/common/type_checkers/Assertions.py b/src/common/type_checkers/Assertions.py
index 286ae179d325b6e70d6ebf509de92e354ba42bc8..87d8e54ee390fb1f56266317be5317731bb755b6 100644
--- a/src/common/type_checkers/Assertions.py
+++ b/src/common/type_checkers/Assertions.py
@@ -12,7 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from typing import Dict
+import logging
+from typing import Callable, Dict
+
+LOGGER = logging.getLogger(__name__)
 
 # ----- Enumerations ---------------------------------------------------------------------------------------------------
 def validate_config_action_enum(message):
@@ -23,6 +26,14 @@ def validate_config_action_enum(message):
         'CONFIGACTION_DELETE',
     ]
 
+def validate_constraint_action_enum(message):
+    assert isinstance(message, str)
+    assert message in [
+        'CONSTRAINTACTION_UNDEFINED',
+        'CONSTRAINTACTION_SET',
+        'CONSTRAINTACTION_DELETE',
+    ]
+
 def validate_device_driver_enum(message):
     assert isinstance(message, str)
     assert message in [
@@ -35,6 +46,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):
@@ -64,6 +77,8 @@ def validate_service_type_enum(message):
         'SERVICETYPE_L3NM',
         'SERVICETYPE_L2NM',
         'SERVICETYPE_TAPI_CONNECTIVITY_SERVICE',
+        'SERVICETYPE_TE',
+        'SERVICETYPE_E2E',
     ]
 
 def validate_service_state_enum(message):
@@ -77,6 +92,17 @@ def validate_service_state_enum(message):
         'SERVICESTATUS_SLA_VIOLATED',
     ]
 
+def validate_slice_status_enum(message):
+    assert isinstance(message, str)
+    assert message in [
+        'SLICESTATUS_UNDEFINED',
+        'SLICESTATUS_PLANNED',
+        'SLICESTATUS_INIT',
+        'SLICESTATUS_ACTIVE',
+        'SLICESTATUS_DEINIT',
+        'SLICESTATUS_SLA_VIOLATED',
+    ]
+
 
 # ----- Common ---------------------------------------------------------------------------------------------------------
 def validate_uuid(message, allow_empty=False):
@@ -114,28 +140,61 @@ def validate_config_rules(message):
     assert 'config_rules' in message
     for config_rule in message['config_rules']: validate_config_rule(config_rule)
 
-CONSTRAINT_TYPES = {
-    'custom',
-    'schedule',
-    'endpoint_location',
-    'sla_capacity',
-    'sla_latency',
-    'sla_availability',
-    'sla_isolation',
+def validate_constraint_custom(message):
+    assert isinstance(message, dict)
+    assert len(message.keys()) == 2
+    assert 'constraint_type' in message
+    assert isinstance(message['constraint_type'], str)
+    assert 'constraint_value' in message
+    assert isinstance(message['constraint_value'], str)
+
+def validate_constraint_sla_capacity(message):
+    assert isinstance(message, dict)
+    assert len(message.keys()) == 1
+    assert 'capacity_gbps' in message
+    assert isinstance(message['capacity_gbps'], (int, float))
+
+def validate_constraint_sla_latency(message):
+    assert isinstance(message, dict)
+    assert len(message.keys()) == 1
+    assert 'e2e_latency_ms' in message
+    assert isinstance(message['e2e_latency_ms'], (int, float))
+
+def validate_constraint_sla_availability(message):
+    assert isinstance(message, dict)
+    assert len(message.keys()) == 3
+    assert 'num_disjoint_paths' in message
+    assert isinstance(message['num_disjoint_paths'], int)
+    assert message['num_disjoint_paths'] >= 0
+    assert 'all_active' in message
+    assert isinstance(message['all_active'], bool)
+    assert 'availability' in message
+    assert isinstance(message['availability'], (int, float))
+    assert message['availability'] >= 0 and message['availability'] <= 100
+
+CONSTRAINT_TYPE_TO_VALIDATOR = {
+    'custom'            : validate_constraint_custom,
+    #'schedule'          : validate_constraint_schedule,
+    #'endpoint_location' : validate_constraint_endpoint_location,
+    #'endpoint_priority' : validate_constraint_endpoint_priority,
+    'sla_capacity'      : validate_constraint_sla_capacity,
+    'sla_latency'       : validate_constraint_sla_latency,
+    'sla_availability'  : validate_constraint_sla_availability,
+    #'sla_isolation'     : validate_constraint_sla_isolation,
+    #'exclusions'        : validate_constraint_exclusions,
 }
+
 def validate_constraint(message):
     assert isinstance(message, dict)
-    assert len(message.keys()) == 1
-    other_keys = list(message.keys())
-    constraint_type = other_keys[0]
-    assert constraint_type in CONSTRAINT_TYPES
-    assert constraint_type == 'custom', 'Constraint Type Validator for {:s} not implemented'.format(constraint_type)
-    custom : Dict = message['custom']
-    assert len(custom.keys()) == 2
-    assert 'constraint_type' in custom
-    assert isinstance(custom['constraint_type'], str)
-    assert 'constraint_value' in custom
-    assert isinstance(custom['constraint_value'], str)
+    assert len(message.keys()) == 2
+    assert 'action' in message
+    validate_constraint_action_enum(message['action'])
+    other_keys = set(list(message.keys()))
+    other_keys.discard('action')
+    constraint_type = other_keys.pop()
+    validator : Callable = CONSTRAINT_TYPE_TO_VALIDATOR.get(constraint_type)
+    assert validator is not None, 'Constraint Type Validator for {:s} not implemented'.format(constraint_type)
+    validator(message[constraint_type])
 
 
 # ----- Identifiers ----------------------------------------------------------------------------------------------------
@@ -192,6 +251,15 @@ def validate_connection_id(message):
     assert 'connection_uuid' in message
     validate_uuid(message['connection_uuid'])
 
+def validate_slice_id(message, context_uuid = None):
+    assert isinstance(message, dict)
+    assert len(message.keys()) == 2
+    assert 'context_id' in message
+    validate_context_id(message['context_id'])
+    if context_uuid is not None: assert message['context_id']['context_uuid']['uuid'] == context_uuid
+    assert 'slice_uuid' in message
+    validate_uuid(message['slice_uuid'])
+
 
 # ----- Lists of Identifiers -------------------------------------------------------------------------------------------
 
@@ -209,6 +277,13 @@ def validate_service_ids(message, context_uuid=None):
     assert isinstance(message['service_ids'], list)
     for service_id in message['service_ids']: validate_service_id(service_id, context_uuid=context_uuid)
 
+def validate_slice_ids(message, context_uuid=None):
+    assert isinstance(message, dict)
+    assert len(message.keys()) == 1
+    assert 'slice_ids' in message
+    assert isinstance(message['slice_ids'], list)
+    for slice_id in message['slice_ids']: validate_slice_id(slice_id, context_uuid=context_uuid)
+
 def validate_topology_ids(message, context_uuid=None):
     assert isinstance(message, dict)
     assert len(message.keys()) == 1
@@ -242,16 +317,21 @@ def validate_connection_ids(message):
 
 def validate_context(message):
     assert isinstance(message, dict)
-    assert len(message.keys()) == 3
+    assert len(message.keys()) == 5
     assert 'context_id' in message
     validate_context_id(message['context_id'])
     context_uuid = message['context_id']['context_uuid']['uuid']
-    assert 'service_ids' in message
-    assert isinstance(message['service_ids'], list)
-    for service_id in message['service_ids']: validate_service_id(service_id, context_uuid=context_uuid)
+    assert 'name' in message
+    assert isinstance(message['name'], str)
     assert 'topology_ids' in message
     assert isinstance(message['topology_ids'], list)
     for topology_id in message['topology_ids']: validate_topology_id(topology_id, context_uuid=context_uuid)
+    assert 'service_ids' in message
+    assert isinstance(message['service_ids'], list)
+    for service_id in message['service_ids']: validate_service_id(service_id, context_uuid=context_uuid)
+    assert 'slice_ids' in message
+    assert isinstance(message['slice_ids'], list)
+    for slice_id in message['slice_ids']: validate_slice_id(slice_id, context_uuid=context_uuid)
 
 def validate_service_state(message):
     assert isinstance(message, dict)
@@ -259,11 +339,19 @@ def validate_service_state(message):
     assert 'service_status' in message
     validate_service_state_enum(message['service_status'])
 
+def validate_slice_status(message):
+    assert isinstance(message, dict)
+    assert len(message.keys()) == 1
+    assert 'slice_status' in message
+    validate_slice_status_enum(message['slice_status'])
+
 def validate_service(message):
     assert isinstance(message, dict)
-    assert len(message.keys()) == 6
+    assert len(message.keys()) == 7
     assert 'service_id' in message
     validate_service_id(message['service_id'])
+    assert 'name' in message
+    assert isinstance(message['name'], str)
     assert 'service_type' in message
     validate_service_type_enum(message['service_type'])
     assert 'service_endpoint_ids' in message
@@ -277,11 +365,44 @@ def validate_service(message):
     assert 'service_config' in message
     validate_config_rules(message['service_config'])
 
+def validate_slice(message):
+    assert isinstance(message, dict)
+    assert len(message.keys()) in {8, 9}
+    assert 'slice_id' in message
+    validate_slice_id(message['slice_id'])
+    assert 'name' in message
+    assert isinstance(message['name'], str)
+    assert 'slice_endpoint_ids' in message
+    assert isinstance(message['slice_endpoint_ids'], list)
+    for endpoint_id in message['slice_endpoint_ids']: validate_endpoint_id(endpoint_id)
+    assert 'slice_constraints' in message
+    assert isinstance(message['slice_constraints'], list)
+    for constraint in message['slice_constraints']: validate_constraint(constraint)
+    assert 'slice_service_ids' in message
+    assert isinstance(message['slice_service_ids'], list)
+    for service_id in message['slice_service_ids']: validate_service_id(service_id)
+    assert 'slice_subslice_ids' in message
+    assert isinstance(message['slice_subslice_ids'], list)
+    for slice_id in message['slice_subslice_ids']: validate_slice_id(slice_id)
+    assert 'slice_status' in message
+    validate_slice_status(message['slice_status'])
+    assert 'slice_config' in message
+    validate_config_rules(message['slice_config'])
+    if len(message.keys()) == 9:
+        assert 'slice_owner' in message
+        assert isinstance(message['slice_owner'], dict)
+        assert 'owner_uuid' in message['slice_owner']
+        validate_uuid(message['slice_owner']['owner_uuid'])
+        assert 'owner_string' in message['slice_owner']
+        assert isinstance(message['slice_owner']['owner_string'], str)
+
 def validate_topology(message, num_devices=None, num_links=None):
     assert isinstance(message, dict)
-    assert len(message.keys()) == 3
+    assert len(message.keys()) == 4
     assert 'topology_id' in message
     validate_topology_id(message['topology_id'])
+    assert 'name' in message
+    assert isinstance(message['name'], str)
     assert 'device_ids' in message
     assert isinstance(message['device_ids'], list)
     if num_devices is not None: assert len(message['device_ids']) == num_devices
@@ -293,20 +414,49 @@ def validate_topology(message, num_devices=None, num_links=None):
 
 def validate_endpoint(message):
     assert isinstance(message, dict)
-    assert len(message.keys()) == 3
+    assert len(message.keys()) == 4
     assert 'endpoint_id' in message
     validate_endpoint_id(message['endpoint_id'])
+    assert 'name' in message
+    assert isinstance(message['name'], str)
     assert 'endpoint_type' in message
     assert isinstance(message['endpoint_type'], str)
     assert 'kpi_sample_types' in message
     assert isinstance(message['kpi_sample_types'], list)
     for kpi_sample_type in message['kpi_sample_types']: validate_kpi_sample_types_enum(kpi_sample_type)
 
+def validate_component(component):
+    assert isinstance(component, dict)
+    assert len(component.keys()) == 5
+    assert 'component_uuid' in component
+    validate_uuid(component['component_uuid'])
+    assert 'name' in component
+    assert isinstance(component['name'], str)
+    assert 'type' in component
+    assert isinstance(component['type'], str)
+    assert 'attributes' in component
+    assert isinstance(component['attributes'], dict)
+    for k,v in component['attributes'].items():
+        assert isinstance(k, str)
+        assert isinstance(v, str)
+    assert 'parent' in component
+    assert isinstance(component['parent'], str)
+
+def validate_link_attributes(link_attributes):
+    assert isinstance(link_attributes, dict)
+    assert len(link_attributes.keys()) == 2
+    assert 'total_capacity_gbps' in link_attributes
+    assert isinstance(link_attributes['total_capacity_gbps'], (int, float))
+    assert 'used_capacity_gbps' in link_attributes
+    assert isinstance(link_attributes['used_capacity_gbps'], (int, float))
+
 def validate_device(message):
     assert isinstance(message, dict)
-    assert len(message.keys()) == 6
+    assert len(message.keys()) in {8, 9}
     assert 'device_id' in message
     validate_device_id(message['device_id'])
+    assert 'name' in message
+    assert isinstance(message['name'], str)
     assert 'device_type' in message
     assert isinstance(message['device_type'], str)
     assert 'device_config' in message
@@ -319,19 +469,30 @@ def validate_device(message):
     assert 'device_endpoints' in message
     assert isinstance(message['device_endpoints'], list)
     for endpoint in message['device_endpoints']: validate_endpoint(endpoint)
+    assert 'components' in message
+    assert isinstance(message['components'], list)
+    for component in message['components']: validate_component(component)
+    if len(message.keys()) == 9:
+        assert 'controller_id' in message
+        if len(message['controller_id']) > 0:
+            validate_device_id(message['controller_id'])
 
 def validate_link(message):
     assert isinstance(message, dict)
-    assert len(message.keys()) == 2
+    assert len(message.keys()) == 4
     assert 'link_id' in message
     validate_link_id(message['link_id'])
+    assert 'name' in message
+    assert isinstance(message['name'], str)
     assert 'link_endpoint_ids' in message
     assert isinstance(message['link_endpoint_ids'], list)
     for endpoint_id in message['link_endpoint_ids']: validate_endpoint_id(endpoint_id)
+    assert 'attributes' in message
+    validate_link_attributes(message['attributes'])
 
 def validate_connection(message):
     assert isinstance(message, dict)
-    assert len(message.keys()) == 4
+    assert len(message.keys()) in {4, 5}
     assert 'connection_id' in message
     validate_connection_id(message['connection_id'])
     assert 'service_id' in message
@@ -342,6 +503,50 @@ def validate_connection(message):
     assert 'sub_service_ids' in message
     assert isinstance(message['sub_service_ids'], list)
     for sub_service_id in message['sub_service_ids']: validate_service_id(sub_service_id)
+    if len(message.keys()) == 5:
+        assert 'settings' in message
+        assert isinstance(message['settings'], dict)
+        # TODO: improve validation of data types, especially for uint values, IP/MAC addresses, TCP/UDP ports, etc.
+        if 'l0' in message['settings']:
+            assert isinstance(message['settings']['l0'], dict)
+            if 'lsp_symbolic_name' in message['settings']['l0']:
+                assert isinstance(message['settings']['l0']['lsp_symbolic_name'], str)
+        if 'l2' in message['settings']:
+            assert isinstance(message['settings']['l2'], dict)
+            if 'src_mac_address' in message['settings']['l2']:
+                assert isinstance(message['settings']['l2']['src_mac_address'], str)
+            if 'dst_mac_address' in message['settings']['l2']:
+                assert isinstance(message['settings']['l2']['dst_mac_address'], str)
+            if 'ether_type' in message['settings']['l2']:
+                assert isinstance(message['settings']['l2']['ether_type'], int)
+            if 'vlan_id' in message['settings']['l2']:
+                assert isinstance(message['settings']['l2']['vlan_id'], int)
+            if 'mpls_label' in message['settings']['l2']:
+                assert isinstance(message['settings']['l2']['mpls_label'], int)
+            if 'mpls_traffic_class' in message['settings']['l2']:
+                assert isinstance(message['settings']['l2']['mpls_traffic_class'], int)
+        if 'l3' in message['settings']:
+            assert isinstance(message['settings']['l3'], dict)
+            if 'src_ip_address' in message['settings']['l3']:
+                assert isinstance(message['settings']['l3']['src_ip_address'], str)
+            if 'dst_ip_address' in message['settings']['l3']:
+                assert isinstance(message['settings']['l3']['dst_ip_address'], str)
+            if 'dscp' in message['settings']['l3']:
+                assert isinstance(message['settings']['l3']['dscp'], int)
+            if 'protocol' in message['settings']['l3']:
+                assert isinstance(message['settings']['l3']['protocol'], int)
+            if 'ttl' in message['settings']['l3']:
+                assert isinstance(message['settings']['l3']['ttl'], int)
+        if 'l4' in message['settings']:
+            assert isinstance(message['settings']['l4'], dict)
+            if 'src_port' in message['settings']['l4']:
+                assert isinstance(message['settings']['l4']['src_port'], int)
+            if 'dst_port' in message['settings']['l4']:
+                assert isinstance(message['settings']['l4']['dst_port'], int)
+            if 'tcp_flags' in message['settings']['l4']:
+                assert isinstance(message['settings']['l4']['tcp_flags'], int)
+            if 'ttl' in message['settings']['l4']:
+                assert isinstance(message['settings']['l4']['ttl'], int)
 
 
 # ----- Lists of Objects -----------------------------------------------------------------------------------------------
@@ -360,6 +565,13 @@ def validate_services(message):
     assert isinstance(message['services'], list)
     for service in message['services']: validate_service(service)
 
+def validate_slices(message):
+    assert isinstance(message, dict)
+    assert len(message.keys()) == 1
+    assert 'slices' in message
+    assert isinstance(message['slices'], list)
+    for slice_ in message['slices']: validate_slice(slice_)
+
 def validate_topologies(message):
     assert isinstance(message, dict)
     assert len(message.keys()) == 1
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/.gitlab-ci.yml b/src/device/.gitlab-ci.yml
index 5fed57be6b7963f776425c2196e232aacddee04f..bcc2e05e50f63fd6552bb53b4d23c0ae0e2e7302 100644
--- a/src/device/.gitlab-ci.yml
+++ b/src/device/.gitlab-ci.yml
@@ -48,15 +48,26 @@ unit_test device:
     - build device
   before_script:
     - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
-    - if docker network list | grep teraflowbridge; then echo "teraflowbridge is already created"; else docker network create -d bridge teraflowbridge; fi
-    - if docker container ls | grep $IMAGE_NAME; then docker rm -f $IMAGE_NAME; else echo "$IMAGE_NAME image is not in the system"; fi
+    - >
+      if docker network list | grep teraflowbridge; then
+        echo "teraflowbridge is already created";
+      else
+        docker network create -d bridge teraflowbridge;
+      fi
+    - >
+      if docker container ls | grep $IMAGE_NAME; then
+        docker rm -f $IMAGE_NAME;
+      else
+        echo "$IMAGE_NAME image is not in the system";
+      fi
   script:
     - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
     - docker run --name $IMAGE_NAME -d -p 2020:2020 -v "$PWD/src/$IMAGE_NAME/tests:/opt/results" --network=teraflowbridge $CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG
     - sleep 5
     - docker ps -a
     - docker logs $IMAGE_NAME
-    - docker exec -i $IMAGE_NAME bash -c "coverage run -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_emulated.py --junitxml=/opt/results/${IMAGE_NAME}_report.xml"
+    - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_emulated.py --junitxml=/opt/results/${IMAGE_NAME}_report_emulated.xml"
+    - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary_ietf_actn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_actn.xml"
     - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing"
   coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
   after_script:
@@ -77,7 +88,7 @@ unit_test device:
   artifacts:
       when: always
       reports:
-        junit: src/$IMAGE_NAME/tests/${IMAGE_NAME}_report.xml
+        junit: src/$IMAGE_NAME/tests/${IMAGE_NAME}_report_*.xml
 
 ## Deployment of the service in Kubernetes Cluster
 #deploy device:
diff --git a/src/device/Dockerfile b/src/device/Dockerfile
index 6566625527f8ceaa8de4639d558c92572c4835cb..909ae3bd31817401412629cbc04b5c0577b40355 100644
--- a/src/device/Dockerfile
+++ b/src/device/Dockerfile
@@ -66,5 +66,11 @@ COPY src/context/. context/
 COPY src/device/. device/
 COPY src/monitoring/. monitoring/
 
+RUN mkdir -p tests/tools/mock_ietf_actn_sdn_ctrl
+RUN touch tests/__init__.py
+RUN touch tests/tools/__init__.py
+RUN touch tests/tools/mock_ietf_actn_sdn_ctrl/__init__.py
+COPY src/tests/tools/mock_ietf_actn_sdn_ctrl/. tests/tools/mock_ietf_actn_sdn_ctrl/
+
 # Start the service
 ENTRYPOINT ["python", "-m", "device.service"]
diff --git a/src/device/requirements.in b/src/device/requirements.in
index ece761571ec2ff9c3376b1062787d76047d71e7c..1a09542a3854e10fedc5be91b76546c341113d67 100644
--- a/src/device/requirements.in
+++ b/src/device/requirements.in
@@ -16,7 +16,12 @@
 anytree==2.8.0
 APScheduler==3.10.1
 cryptography==36.0.2
+deepdiff==6.7.*
+deepmerge==1.1.*
 #fastcache==1.1.0
+Flask==2.1.3
+Flask-HTTPAuth==4.5.0
+Flask-RESTful==0.3.9
 Jinja2==3.0.3
 ncclient==0.6.13
 p4runtime==1.3.0
@@ -32,9 +37,10 @@ tabulate
 ipaddress
 macaddress
 yattag
-pyang
+pyang==2.6.0
 git+https://github.com/robshakir/pyangbind.git
 websockets==10.4
+werkzeug==2.3.7
 
 # pip's dependency resolver does not take into account installed packages.
 # p4runtime does not specify the version of grpcio/protobuf it needs, so it tries to install latest one
diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py
index 442acf839c8e4615237d338d7b485be297d1a4ff..27c61f89f15c735b44ad2724df01e08a51dda6ba 100644
--- a/src/device/service/drivers/__init__.py
+++ b/src/device/service/drivers/__init__.py
@@ -84,6 +84,15 @@ DRIVERS.append(
         }
     ]))
 
+from .ietf_actn.IetfActnDriver import IetfActnDriver # pylint: disable=wrong-import-position
+DRIVERS.append(
+    (IetfActnDriver, [
+        {
+            FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.OPEN_LINE_SYSTEM,
+            FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN,
+        }
+    ]))
+
 if LOAD_ALL_DEVICE_DRIVERS:
     from .openconfig.OpenConfigDriver import OpenConfigDriver # pylint: disable=wrong-import-position
     DRIVERS.append(
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..a33c403f3202ca5ee3025a7b7808ad53a89ede4a
--- /dev/null
+++ b/src/device/service/drivers/ietf_actn/IetfActnDriver.py
@@ -0,0 +1,166 @@
+# 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, requests, threading
+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, RESOURCE_SERVICES
+from .handlers.EthtServiceHandler import EthtServiceHandler
+from .handlers.OsuTunnelHandler import OsuTunnelHandler
+from .handlers.RestApiClient import RestApiClient
+from .Tools import get_etht_services, get_osu_tunnels, parse_resource_key
+
+LOGGER = logging.getLogger(__name__)
+
+ALL_RESOURCE_KEYS = [
+    RESOURCE_SERVICES,
+]
+
+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()
+        self._rest_api_client = RestApiClient(address, port, settings=settings)
+        self._handler_osu_tunnel = OsuTunnelHandler(self._rest_api_client)
+        self._handler_etht_service = EthtServiceHandler(self._rest_api_client)
+
+    def Connect(self) -> bool:
+        with self.__lock:
+            if self.__started.is_set(): return True
+            try:
+                self._rest_api_client.get('Check Credentials', '')
+            except requests.exceptions.Timeout:
+                LOGGER.exception('Timeout exception checking connectivity')
+                return False
+            except Exception:  # pylint: disable=broad-except
+                LOGGER.exception('Unhandled exception checking connectivity')
+                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):
+                chk_string('resource_key[#{:d}]'.format(i), resource_key, allow_empty=False)
+
+                try:
+                    _results = list()
+
+                    if resource_key == RESOURCE_SERVICES:
+                        get_osu_tunnels(self._handler_osu_tunnel, _results)
+                        get_etht_services(self._handler_etht_service, _results)
+                    else:
+                        # check if resource key is for a specific OSU tunnel or ETHT service, and get them accordingly
+                        osu_tunnel_name, etht_service_name = parse_resource_key(resource_key)
+                        if osu_tunnel_name is not None:
+                            get_osu_tunnels(self._handler_osu_tunnel, _results, osu_tunnel_name=osu_tunnel_name)
+                        if etht_service_name is not None:
+                            get_etht_services(self._handler_etht_service, _results, etht_service_name=etht_service_name)
+
+                    results.extend(_results)
+                except Exception as e:
+                    results.append((resource_key, e))
+
+        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_key, resource_value in resources:
+                LOGGER.info('resource: key({:s}) => value({:s})'.format(str(resource_key), str(resource_value)))
+                try:
+                    _results = list()
+
+                    if isinstance(resource_value, str): resource_value = json.loads(resource_value)
+                    osu_tunnel_name, etht_service_name = parse_resource_key(resource_key)
+
+                    if osu_tunnel_name is not None:
+                        succeeded = self._handler_osu_tunnel.update(resource_value)
+                        _results.append(succeeded)
+
+                    if etht_service_name is not None:
+                        succeeded = self._handler_etht_service.update(resource_value)
+                        _results.append(succeeded)
+
+                    results.extend(_results)
+                except Exception as e:
+                    results.append(e)
+
+        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_key, resource_value in resources:
+                LOGGER.info('resource: key({:s}) => value({:s})'.format(str(resource_key), str(resource_value)))
+                try:
+                    _results = list()
+
+                    if isinstance(resource_value, str): resource_value = json.loads(resource_value)
+                    osu_tunnel_name, etht_service_name = parse_resource_key(resource_key)
+
+                    if osu_tunnel_name is not None:
+                        succeeded = self._handler_osu_tunnel.delete(osu_tunnel_name)
+                        _results.append(succeeded)
+
+                    if etht_service_name is not None:
+                        succeeded = self._handler_etht_service.delete(etht_service_name)
+                        _results.append(succeeded)
+
+                    results.extend(_results)
+                except Exception as e:
+                    results.append(e)
+
+        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..52f5b15c4d9f0c723b7e4eeeea4537d23c5bf758
--- /dev/null
+++ b/src/device/service/drivers/ietf_actn/Tools.py
@@ -0,0 +1,52 @@
+# 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, re
+from typing import Any, List, Optional, Tuple, Union
+from .handlers.EthtServiceHandler import EthtServiceHandler
+from .handlers.OsuTunnelHandler import OsuTunnelHandler
+
+LOGGER = logging.getLogger(__name__)
+
+RE_OSU_TUNNEL   = re.compile(r'^\/osu\_tunnels\/osu\_tunnel\[([^\]]+)\]$')
+RE_ETHT_SERVICE = re.compile(r'^\/etht\_services\/etht\_service\[([^\]]+)\]$')
+
+def parse_resource_key(resource_key : str) -> Tuple[Optional[str], Optional[str]]:
+    re_match_osu_tunnel   = RE_OSU_TUNNEL.match(resource_key)
+    osu_tunnel_name = None if re_match_osu_tunnel is None else re_match_osu_tunnel.group(1)
+
+    re_match_etht_service = RE_ETHT_SERVICE.match(resource_key)
+    etht_service_name = None if re_match_etht_service is None else re_match_etht_service.group(1)
+
+    return osu_tunnel_name, etht_service_name
+
+def get_osu_tunnels(
+    handler_osu_tunnel : OsuTunnelHandler, results : List[Tuple[str, Union[Any, None, Exception]]],
+    osu_tunnel_name : Optional[str] = None
+) -> None:
+    osu_tunnels = handler_osu_tunnel.get(osu_tunnel_name=osu_tunnel_name)
+    for osu_tunnel in osu_tunnels:
+        osu_tunnel_name = osu_tunnel['name']
+        resource_key = '/osu_tunnels/osu_tunnel[{:s}]'.format(osu_tunnel_name)
+        results.append((resource_key, osu_tunnel))
+
+def get_etht_services(
+    handler_etht_service : EthtServiceHandler, results : List[Tuple[str, Union[Any, None, Exception]]],
+    etht_service_name : Optional[str] = None
+) -> None:
+    etht_services = handler_etht_service.get(etht_service_name=etht_service_name)
+    for etht_service in etht_services:
+        etht_service_name = etht_service['name']
+        resource_key = '/etht_services/etht_service[{:s}]'.format(etht_service_name)
+        results.append((resource_key, etht_service))
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..38d04994fb0fa1951fb465bc127eb72659dc2eaf
--- /dev/null
+++ b/src/device/service/drivers/ietf_actn/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/src/device/service/drivers/ietf_actn/handlers/EthtServiceHandler.py b/src/device/service/drivers/ietf_actn/handlers/EthtServiceHandler.py
new file mode 100644
index 0000000000000000000000000000000000000000..230d13797f224931f657aa32c83091f4eb1c1d63
--- /dev/null
+++ b/src/device/service/drivers/ietf_actn/handlers/EthtServiceHandler.py
@@ -0,0 +1,221 @@
+# 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 enum, logging
+from typing import Dict, List, Optional, Tuple, Union
+from .RestApiClient import HTTP_STATUS_CREATED, HTTP_STATUS_NO_CONTENT, HTTP_STATUS_OK, RestApiClient
+
+LOGGER = logging.getLogger(__name__)
+
+class BandwidthProfileTypeEnum(enum.Enum):
+    MEF_10_BWP = 'ietf-eth-tran-types:mef-10-bwp'
+
+class EndpointLayerSpecificAccessTypeEnum(enum.Enum):
+    PORT = 'port'
+
+class EndpointProtectionRoleEnum(enum.Enum):
+    WORK = 'work'
+
+class OptimizationMetricRole(enum.Enum):
+    WORK = 'work'
+
+class OptimizationMetricType(enum.Enum):
+    PATH_METRIC_TE = 'ietf-te-types:path-metric-te'
+
+class OuterTagTypeEnum(enum.Enum):
+    CLASSIFY_C_VLAN = 'ietf-eth-tran-types:classify-c-vlan'
+
+class ServiceClassificationTypeEnum(enum.Enum):
+    VLAN_CLASSIFICATION = 'ietf-eth-tran-type:vlan-classification'
+
+class ServiceTypeEnum(enum.Enum):
+    MP2MP = 'op-mp2mp-svc'
+    P2MP  = 'op-p2mp-svc'
+
+def compose_outer_tag(tag_type : OuterTagTypeEnum, vlan_value : int) -> Dict:
+    return {'tag-type': tag_type.value, 'vlan-value': vlan_value}
+
+def compose_ingress_egress_bandwidth_profile() -> Dict:
+    return {
+        'bandwidth-profile-type': BandwidthProfileTypeEnum.MEF_10_BWP.value,
+        'CIR': 10_000_000,
+        'EIR': 10_000_000,
+    }
+
+def compose_layer_specific_access_type() -> Dict:
+    return {'access-type': EndpointLayerSpecificAccessTypeEnum.PORT.value}
+
+def compose_static_route(prefix : str, mask : int, next_hop : str) -> Dict:
+    return {'destination': prefix, 'destination-mask': mask, 'next-hop': next_hop}
+
+def compose_static_route_list(static_routes : List[Tuple[str, int, str]]) -> List[Dict]:
+    return [
+        compose_static_route(prefix, mask, next_hop)
+        for prefix, mask, next_hop in static_routes
+    ]
+
+def compose_etht_service_endpoint(
+    node_id : str, tp_id : str, vlan_value : int, static_routes : List[Tuple[str, int, str]] = list()
+) -> Dict:
+    return {
+        'node-id'           : node_id,
+        'tp-id'             : tp_id,
+        'protection-role'   : EndpointProtectionRoleEnum.WORK.value,
+        'layer-specific'    : compose_layer_specific_access_type(),
+        'is-extendable'     : False,
+        'is-terminal'       : True,
+        'static-route-list' : compose_static_route_list(static_routes),
+        'outer-tag'         : compose_outer_tag(OuterTagTypeEnum.CLASSIFY_C_VLAN, vlan_value),
+        'service-classification-type'     : ServiceClassificationTypeEnum.VLAN_CLASSIFICATION.value,
+        'ingress-egress-bandwidth-profile': compose_ingress_egress_bandwidth_profile(),
+    }
+
+def compose_optimizations() -> Dict:
+    return {'optimization-metric': [{
+        'metric-role': OptimizationMetricRole.WORK.value,
+        'metric-type': OptimizationMetricType.PATH_METRIC_TE.value,
+    }]}
+
+def compose_etht_service(
+    name : str, service_type : ServiceTypeEnum, osu_tunnel_name : str,
+    src_node_id : str, src_tp_id : str, src_vlan_tag : int, dst_node_id : str, dst_tp_id : str, dst_vlan_tag : int,
+    src_static_routes : List[Tuple[str, int, str]] = list(), dst_static_routes : List[Tuple[str, int, str]] = list()
+) -> Dict:
+    return {'ietf-eth-tran-service:etht-svc': {'etht-svc-instances': [{
+        'etht-svc-name' : name,
+        'etht-svc-title': name.upper(),
+        'etht-svc-type' : service_type.value,
+        'source-endpoints': {'source-endpoint': [
+            compose_etht_service_endpoint(src_node_id, src_tp_id, src_vlan_tag, src_static_routes),
+        ]},
+        'destination-endpoints': {'destination-endpoint': [
+            compose_etht_service_endpoint(dst_node_id, dst_tp_id, dst_vlan_tag, dst_static_routes),
+        ]},
+        'svc-tunnel': [{'tunnel-name': osu_tunnel_name}],
+        'optimizations': compose_optimizations(),
+    }]}}
+
+class EthtServiceHandler:
+    def __init__(self, rest_api_client : RestApiClient) -> None:
+        self._rest_api_client = rest_api_client
+        self._object_name  = 'EthtService'
+        self._subpath_root = '/ietf-eth-tran-service:etht-svc'
+        self._subpath_item = self._subpath_root + '/etht-svc-instances="{etht_service_name:s}"'
+
+    def _rest_api_get(self, etht_service_name : Optional[str] = None) -> Union[Dict, List]:
+        if etht_service_name is None:
+            subpath_url = self._subpath_root
+        else:
+            subpath_url = self._subpath_item.format(etht_service_name=etht_service_name)
+        return self._rest_api_client.get(
+            self._object_name, subpath_url, expected_http_status={HTTP_STATUS_OK}
+        )
+
+    def _rest_api_update(self, data : Dict) -> bool:
+        return self._rest_api_client.update(
+            self._object_name, self._subpath_root, data, expected_http_status={HTTP_STATUS_CREATED}
+        )
+
+    def _rest_api_delete(self, etht_service_name : str) -> bool:
+        if etht_service_name is None: raise Exception('etht_service_name is None')
+        subpath_url = self._subpath_item.format(etht_service_name=etht_service_name)
+        return self._rest_api_client.delete(
+            self._object_name, subpath_url, expected_http_status={HTTP_STATUS_NO_CONTENT}
+        )
+
+    def get(self, etht_service_name : Optional[str] = None) -> Union[Dict, List]:
+        data = self._rest_api_get(etht_service_name=etht_service_name)
+
+        if not isinstance(data, dict): raise ValueError('data should be a dict')
+        if 'ietf-eth-tran-service:etht-svc' not in data:
+            raise ValueError('data does not contain key "ietf-eth-tran-service:etht-svc"')
+        data = data['ietf-eth-tran-service:etht-svc']
+        if 'etht-svc-instances' not in data:
+            raise ValueError('data["ietf-eth-tran-service:etht-svc"] does not contain key "etht-svc-instances"')
+        data = data['etht-svc-instances']
+        if not isinstance(data, list):
+            raise ValueError('data["ietf-eth-tran-service:etht-svc"]["etht-svc-instances"] should be a list')
+
+        etht_services : List[Dict] = list()
+        for item in data:
+            src_endpoints = item['source-endpoints']['source-endpoint']
+            if len(src_endpoints) != 1:
+                MSG = 'EthtService({:s}) has zero/multiple source endpoints'
+                raise Exception(MSG.format(str(item)))
+            src_endpoint = src_endpoints[0]
+
+            dst_endpoints = item['destination-endpoints']['destination-endpoint']
+            if len(dst_endpoints) != 1:
+                MSG = 'EthtService({:s}) has zero/multiple destination endpoints'
+                raise Exception(MSG.format(str(item)))
+            dst_endpoint = dst_endpoints[0]
+
+            svc_tunnels = item['svc-tunnel']
+            if len(svc_tunnels) != 1:
+                MSG = 'EthtService({:s}) has zero/multiple service tunnels'
+                raise Exception(MSG.format(str(item)))
+            svc_tunnel = svc_tunnels[0]
+
+            etht_service = {
+                'name'             : item['etht-svc-name'],
+                'service_type'     : item['etht-svc-type'],
+                'osu_tunnel_name'  : svc_tunnel['tunnel-name'],
+
+                'src_node_id'      : src_endpoint['node-id'],
+                'src_tp_id'        : src_endpoint['tp-id'],
+                'src_vlan_tag'     : src_endpoint['outer-tag']['vlan-value'],
+                'src_static_routes': [
+                    [static_route['destination'], static_route['destination-mask'], static_route['next-hop']]
+                    for static_route in src_endpoint.get('static-route-list', list())
+                ],
+
+                'dst_node_id'      : dst_endpoint['node-id'],
+                'dst_tp_id'        : dst_endpoint['tp-id'],
+                'dst_vlan_tag'     : dst_endpoint['outer-tag']['vlan-value'],
+                'dst_static_routes': [
+                    [static_route['destination'], static_route['destination-mask'], static_route['next-hop']]
+                    for static_route in dst_endpoint.get('static-route-list', list())
+                ],
+            }
+            etht_services.append(etht_service)
+
+        return etht_services
+
+    def update(self, parameters : Dict) -> bool:
+        name              = parameters['name'           ]
+        service_type      = parameters['service_type'   ]
+        osu_tunnel_name   = parameters['osu_tunnel_name']
+
+        src_node_id       = parameters['src_node_id'    ]
+        src_tp_id         = parameters['src_tp_id'      ]
+        src_vlan_tag      = parameters['src_vlan_tag'   ]
+        src_static_routes = parameters.get('src_static_routes', [])
+
+        dst_node_id       = parameters['dst_node_id'    ]
+        dst_tp_id         = parameters['dst_tp_id'      ]
+        dst_vlan_tag      = parameters['dst_vlan_tag'   ]
+        dst_static_routes = parameters.get('dst_static_routes', [])
+
+        service_type = ServiceTypeEnum._value2member_map_[service_type]
+
+        data = compose_etht_service(
+            name, service_type, osu_tunnel_name,
+            src_node_id, src_tp_id, src_vlan_tag, dst_node_id, dst_tp_id, dst_vlan_tag,
+            src_static_routes=src_static_routes, dst_static_routes=dst_static_routes
+        )
+
+        return self._rest_api_update(data)
+
+    def delete(self, etht_service_name : str) -> bool:
+        return self._rest_api_delete(etht_service_name)
diff --git a/src/device/service/drivers/ietf_actn/handlers/OsuTunnelHandler.py b/src/device/service/drivers/ietf_actn/handlers/OsuTunnelHandler.py
new file mode 100644
index 0000000000000000000000000000000000000000..bcecdf89e41c1cbb7284dbc6f7f08e1f03329c91
--- /dev/null
+++ b/src/device/service/drivers/ietf_actn/handlers/OsuTunnelHandler.py
@@ -0,0 +1,176 @@
+# 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 enum, logging
+from typing import Dict, List, Optional, Union
+from .RestApiClient import HTTP_STATUS_CREATED, HTTP_STATUS_NO_CONTENT, HTTP_STATUS_OK, RestApiClient
+
+LOGGER = logging.getLogger(__name__)
+
+class EndpointProtectionRoleEnum(enum.Enum):
+    WORK = 'work'
+
+class LspProtectionTypeEnum(enum.Enum):
+    UNPROTECTED = 'ietf-te-types:lsp-protection-unprotected'
+
+class LspRestorationTypeEnum(enum.Enum):
+    NOT_APPLICABLE = 'ietf-te-types:lsp-restoration-not-applicable'
+
+class TunnelAdminStateEnum(enum.Enum):
+    UP = 'ietf-te-types:tunnel-admin-state-up'
+
+class OduTypeEnum(enum.Enum):
+    OSUFLEX = 'osuflex'
+
+def compose_osu_tunnel_endpoint(
+    node_id : str, tp_id : str, ttp_channel_name : str,
+    protection_role : EndpointProtectionRoleEnum = EndpointProtectionRoleEnum.WORK
+) -> Dict:
+    return {
+        'node-id': node_id, 'tp-id': tp_id, 'ttp-channel-name': ttp_channel_name,
+        'protection-role': protection_role.value
+    }
+
+def compose_osu_tunnel_te_bandwidth_odu(odu_type : OduTypeEnum, number : int) -> Dict:
+    return {'layer': 'odu', 'odu-type': odu_type.value, 'number': number}
+
+def compose_osu_tunnel_protection(
+    type_ : LspProtectionTypeEnum = LspProtectionTypeEnum.UNPROTECTED, reversion_disable : bool = True
+) -> Dict:
+    return {'protection-type': type_.value, 'protection-reversion-disable': reversion_disable}
+
+def compose_osu_tunnel_restoration(
+    type_ : LspRestorationTypeEnum = LspRestorationTypeEnum.NOT_APPLICABLE, restoration_lock : bool = False
+) -> Dict:
+    return {'restoration-type': type_.value, 'restoration-lock': restoration_lock}
+
+def compose_osu_tunnel(
+    name : str,
+    src_node_id : str, src_tp_id : str, src_ttp_channel_name : str,
+    dst_node_id : str, dst_tp_id : str, dst_ttp_channel_name : str,
+    odu_type : OduTypeEnum, osuflex_number : int,
+    delay : int, bidirectional : bool = True,
+    admin_state : TunnelAdminStateEnum = TunnelAdminStateEnum.UP
+) -> Dict:
+    return {'ietf-te:tunnel': [{
+        'name': name,
+        'title': name.upper(),
+        'admin-state': admin_state.value,
+        'delay': delay,
+        'te-bandwidth': compose_osu_tunnel_te_bandwidth_odu(odu_type, osuflex_number),
+        'bidirectional': bidirectional,
+        'source-endpoints': {'source-endpoint': [
+            compose_osu_tunnel_endpoint(src_node_id, src_tp_id, src_ttp_channel_name),
+        ]},
+        'destination-endpoints': {'destination-endpoint': [
+            compose_osu_tunnel_endpoint(dst_node_id, dst_tp_id, dst_ttp_channel_name),
+        ]},
+        'restoration': compose_osu_tunnel_restoration(),
+        'protection': compose_osu_tunnel_protection(),
+    }]}
+
+class OsuTunnelHandler:
+    def __init__(self, rest_api_client : RestApiClient) -> None:
+        self._rest_api_client = rest_api_client
+        self._object_name  = 'OsuTunnel'
+        self._subpath_root = '/ietf-te:te/tunnels'
+        self._subpath_item = self._subpath_root + '/tunnel="{osu_tunnel_name:s}"'
+
+    def _rest_api_get(self, osu_tunnel_name : Optional[str] = None) -> Union[Dict, List]:
+        if osu_tunnel_name is None:
+            subpath_url = self._subpath_root
+        else:
+            subpath_url = self._subpath_item.format(osu_tunnel_name=osu_tunnel_name)
+        return self._rest_api_client.get(
+            self._object_name, subpath_url, expected_http_status={HTTP_STATUS_OK}
+        )
+
+    def _rest_api_update(self, data : Dict) -> bool:
+        return self._rest_api_client.update(
+            self._object_name, self._subpath_root, data, expected_http_status={HTTP_STATUS_CREATED}
+        )
+
+    def _rest_api_delete(self, osu_tunnel_name : str) -> bool:
+        if osu_tunnel_name is None: raise Exception('osu_tunnel_name is None')
+        subpath_url = self._subpath_item.format(osu_tunnel_name=osu_tunnel_name)
+        return self._rest_api_client.delete(
+            self._object_name, subpath_url, expected_http_status={HTTP_STATUS_NO_CONTENT}
+        )
+
+    def get(self, osu_tunnel_name : Optional[str] = None) -> Union[Dict, List]:
+        data = self._rest_api_get(osu_tunnel_name=osu_tunnel_name)
+
+        if not isinstance(data, dict): raise ValueError('data should be a dict')
+        if 'ietf-te:tunnel' not in data: raise ValueError('data does not contain key "ietf-te:tunnel"')
+        data = data['ietf-te:tunnel']
+        if not isinstance(data, list): raise ValueError('data[ietf-te:tunnel] should be a list')
+
+        osu_tunnels : List[Dict] = list()
+        for item in data:
+            src_endpoints = item['source-endpoints']['source-endpoint']
+            if len(src_endpoints) != 1:
+                MSG = 'OsuTunnel({:s}) has zero/multiple source endpoints'
+                raise Exception(MSG.format(str(item)))
+            src_endpoint = src_endpoints[0]
+
+            dst_endpoints = item['destination-endpoints']['destination-endpoint']
+            if len(dst_endpoints) != 1:
+                MSG = 'OsuTunnel({:s}) has zero/multiple destination endpoints'
+                raise Exception(MSG.format(str(item)))
+            dst_endpoint = dst_endpoints[0]
+
+            osu_tunnel = {
+                'name'                : item['name'],
+                'src_node_id'         : src_endpoint['node-id'],
+                'src_tp_id'           : src_endpoint['tp-id'],
+                'src_ttp_channel_name': src_endpoint['ttp-channel-name'],
+                'dst_node_id'         : dst_endpoint['node-id'],
+                'dst_tp_id'           : dst_endpoint['tp-id'],
+                'dst_ttp_channel_name': dst_endpoint['ttp-channel-name'],
+                'odu_type'            : item['te-bandwidth']['odu-type'],
+                'osuflex_number'      : item['te-bandwidth']['number'],
+                'delay'               : item['delay'],
+                'bidirectional'       : item['bidirectional'],
+            }
+            osu_tunnels.append(osu_tunnel)
+
+        return osu_tunnels
+
+    def update(self, parameters : Dict) -> bool:
+        name                 = parameters['name'                ]
+
+        src_node_id          = parameters['src_node_id'         ]
+        src_tp_id            = parameters['src_tp_id'           ]
+        src_ttp_channel_name = parameters['src_ttp_channel_name']
+
+        dst_node_id          = parameters['dst_node_id'         ]
+        dst_tp_id            = parameters['dst_tp_id'           ]
+        dst_ttp_channel_name = parameters['dst_ttp_channel_name']
+
+        odu_type             = parameters.get('odu_type',       OduTypeEnum.OSUFLEX.value)
+        osuflex_number       = parameters.get('osuflex_number', 1                        )
+        delay                = parameters.get('delay',          20                       )
+        bidirectional        = parameters.get('bidirectional',  True                     )
+
+        odu_type = OduTypeEnum._value2member_map_[odu_type]
+
+        data = compose_osu_tunnel(
+            name, src_node_id, src_tp_id, src_ttp_channel_name, dst_node_id, dst_tp_id, dst_ttp_channel_name,
+            odu_type, osuflex_number, delay, bidirectional=bidirectional
+        )
+
+        return self._rest_api_update(data)
+
+    def delete(self, osu_tunnel_name : str) -> bool:
+        return self._rest_api_delete(osu_tunnel_name)
diff --git a/src/device/service/drivers/ietf_actn/handlers/RestApiClient.py b/src/device/service/drivers/ietf_actn/handlers/RestApiClient.py
new file mode 100644
index 0000000000000000000000000000000000000000..1eed066b90c90c7509674c92f8b13e8feefa3513
--- /dev/null
+++ b/src/device/service/drivers/ietf_actn/handlers/RestApiClient.py
@@ -0,0 +1,104 @@
+# 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, json, logging, requests
+from requests.auth import HTTPBasicAuth
+from typing import Any, Dict, List, Set, Union
+
+LOGGER = logging.getLogger(__name__)
+
+DEFAULT_BASE_URL = '/restconf/v2/data'
+DEFAULT_SCHEME   = 'https'
+DEFAULT_TIMEOUT  = 120
+DEFAULT_VERIFY   = False
+
+HTTP_STATUS_OK         = 200
+HTTP_STATUS_CREATED    = 201
+HTTP_STATUS_ACCEPTED   = 202
+HTTP_STATUS_NO_CONTENT = 204
+
+HTTP_OK_CODES = {
+    HTTP_STATUS_OK,
+    HTTP_STATUS_CREATED,
+    HTTP_STATUS_ACCEPTED,
+    HTTP_STATUS_NO_CONTENT,
+}
+
+class RestApiClient:
+    def __init__(self, address : str, port : int, settings : Dict[str, Any] = dict()) -> None:
+        username = settings.get('username')
+        password = settings.get('password')
+        self._auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None
+
+        scheme   = settings.get('scheme',   DEFAULT_SCHEME  )
+        base_url = settings.get('base_url', DEFAULT_BASE_URL)
+        self._base_url = '{:s}://{:s}:{:d}{:s}'.format(scheme, address, int(port), base_url)
+
+        self._timeout = int(settings.get('timeout', DEFAULT_TIMEOUT))
+        self._verify  = bool(settings.get('verify', DEFAULT_VERIFY))
+
+    def get(
+        self, object_name : str, url : str,
+        expected_http_status : Set[int] = {HTTP_STATUS_OK}
+    ) -> Union[Dict, List]:
+        MSG = 'Get {:s}({:s})'
+        LOGGER.info(MSG.format(str(object_name), str(url)))
+        response = requests.get(
+            self._base_url + url,
+            timeout=self._timeout, verify=self._verify, auth=self._auth
+        )
+        LOGGER.info('  Response[{:s}]: {:s}'.format(str(response.status_code), str(response.content)))
+
+        if response.status_code in expected_http_status: return json.loads(response.content)
+
+        MSG = 'Could not get {:s}({:s}): status_code={:s} reply={:s}'
+        raise Exception(MSG.format(str(object_name), str(url), str(response.status_code), str(response)))
+
+    def update(
+        self, object_name : str, url : str, data : Dict, headers : Dict[str, Any] = dict(),
+        expected_http_status : Set[int] = HTTP_OK_CODES
+    ) -> None:
+        headers = copy.deepcopy(headers)
+        if 'content-type' not in {header_name.lower() for header_name in headers.keys()}:
+            headers.update({'content-type': 'application/json'})
+
+        MSG = 'Create/Update {:s}({:s}, {:s})'
+        LOGGER.info(MSG.format(str(object_name), str(url), str(data)))
+        response = requests.post(
+            self._base_url + url, data=json.dumps(data), headers=headers,
+            timeout=self._timeout, verify=self._verify, auth=self._auth
+        )
+        LOGGER.info('  Response[{:s}]: {:s}'.format(str(response.status_code), str(response.content)))
+
+        if response.status_code in expected_http_status: return
+
+        MSG = 'Could not create/update {:s}({:s}, {:s}): status_code={:s} reply={:s}'
+        raise Exception(MSG.format(str(object_name), str(url), str(data), str(response.status_code), str(response)))
+
+    def delete(
+        self, object_name : str, url : str,
+        expected_http_status : Set[int] = HTTP_OK_CODES
+    ) -> None:
+        MSG = 'Delete {:s}({:s})'
+        LOGGER.info(MSG.format(str(object_name), str(url)))
+        response = requests.delete(
+            self._base_url + url,
+            timeout=self._timeout, verify=self._verify, auth=self._auth
+        )
+        LOGGER.info('  Response[{:s}]: {:s}'.format(str(response.status_code), str(response.content)))
+
+        if response.status_code in expected_http_status: return
+
+        MSG = 'Could not delete {:s}({:s}): status_code={:s} reply={:s}'
+        raise Exception(MSG.format(str(object_name), str(url), str(response.status_code), str(response)))
diff --git a/src/device/service/drivers/ietf_actn/handlers/__init__.py b/src/device/service/drivers/ietf_actn/handlers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..38d04994fb0fa1951fb465bc127eb72659dc2eaf
--- /dev/null
+++ b/src/device/service/drivers/ietf_actn/handlers/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/src/device/tests/data/ietf_actn/config_rules.json b/src/device/tests/data/ietf_actn/config_rules.json
new file mode 100644
index 0000000000000000000000000000000000000000..d73a68674731cf4af7321044d345470c03d68134
--- /dev/null
+++ b/src/device/tests/data/ietf_actn/config_rules.json
@@ -0,0 +1,32 @@
+[
+    {"action": 1, "custom": {"resource_key": "/osu_tunnels/osu_tunnel[osu_tunnel_1]", "resource_value": {
+        "name": "osu_tunnel_1", "odu_type": "osuflex", "osuflex_number": 40, "bidirectional": true, "delay": 20,
+        "src_node_id": "10.0.10.1", "src_tp_id": "200", "src_ttp_channel_name": "och:1-odu2:1-oduflex:1-osuflex:2",
+        "dst_node_id": "10.0.30.1", "dst_tp_id": "200", "dst_ttp_channel_name": "och:1-odu2:1-oduflex:3-osuflex:1"
+    }}},
+    {"action": 1, "custom": {"resource_key": "/osu_tunnels/osu_tunnel[osu_tunnel_2]", "resource_value": {
+        "name": "osu_tunnel_2", "odu_type": "osuflex", "osuflex_number": 40, "bidirectional": true, "delay": 20,
+        "src_node_id": "10.0.10.1", "src_tp_id": "200", "src_ttp_channel_name": "och:1-odu2:1-oduflex:1-osuflex:2",
+        "dst_node_id": "10.0.30.1", "dst_tp_id": "200", "dst_ttp_channel_name": "och:1-odu2:1-oduflex:3-osuflex:1"
+    }}},
+    {"action": 1, "custom": {"resource_key": "/etht_services/etht_service[etht_service_1]", "resource_value": {
+        "name": "etht_service_1", "osu_tunnel_name": "osu_tunnel_1", "service_type": "op-mp2mp-svc",
+        "src_node_id": "10.0.10.1", "src_tp_id": "200", "src_vlan_tag": 21, "src_static_routes": [
+            ["128.32.10.5", 24, "128.32.33.5"],
+            ["128.32.20.5", 24, "128.32.33.5"]
+        ],
+        "dst_node_id": "10.0.30.1", "dst_tp_id": "200", "dst_vlan_tag": 101, "dst_static_routes": [
+            ["172.1.101.22", 24, "172.10.33.5"]
+        ]
+    }}},
+    {"action": 1, "custom": {"resource_key": "/etht_services/etht_service[etht_service_2]", "resource_value": {
+        "name": "etht_service_2", "osu_tunnel_name": "osu_tunnel_2", "service_type": "op-mp2mp-svc",
+        "src_node_id": "10.0.10.1", "src_tp_id": "200", "src_vlan_tag": 31, "src_static_routes": [
+            ["128.32.10.5", 24, "128.32.33.5"],
+            ["128.32.20.5", 24, "128.32.33.5"]
+        ],
+        "dst_node_id": "10.0.30.1", "dst_tp_id": "200", "dst_vlan_tag": 201, "dst_static_routes": [
+            ["172.1.101.22", 24, "172.10.33.5"]
+        ]
+    }}}
+]
diff --git a/src/device/tests/data/ietf_actn/deconfig_rules.json b/src/device/tests/data/ietf_actn/deconfig_rules.json
new file mode 100644
index 0000000000000000000000000000000000000000..f18e5fb2db8b4d077ea68a499d61577030ce7f48
--- /dev/null
+++ b/src/device/tests/data/ietf_actn/deconfig_rules.json
@@ -0,0 +1,14 @@
+[
+    {"action": 2, "custom": {"resource_key": "/osu_tunnels/osu_tunnel[osu_tunnel_1]", "resource_value": {
+        "name": "osu_tunnel_1"
+    }}},
+    {"action": 2, "custom": {"resource_key": "/osu_tunnels/osu_tunnel[osu_tunnel_2]", "resource_value": {
+        "name": "osu_tunnel_2"
+    }}},
+    {"action": 2, "custom": {"resource_key": "/etht_services/etht_service[etht_service_1]", "resource_value": {
+        "name": "etht_service_1"
+    }}},
+    {"action": 2, "custom": {"resource_key": "/etht_services/etht_service[etht_service_2]", "resource_value": {
+        "name": "etht_service_2"
+    }}}
+]
diff --git a/src/device/tests/data/ietf_actn/expected_etht_services.json b/src/device/tests/data/ietf_actn/expected_etht_services.json
new file mode 100644
index 0000000000000000000000000000000000000000..d9f41052692936fd5fffd855b1ba3f3e0478a3b6
--- /dev/null
+++ b/src/device/tests/data/ietf_actn/expected_etht_services.json
@@ -0,0 +1,176 @@
+{
+    "ietf-eth-tran-service:etht-svc": {
+        "etht-svc-instances": [
+            {
+                "etht-svc-name": "etht_service_1",
+                "etht-svc-title": "ETHT_SERVICE_1",
+                "etht-svc-type": "op-mp2mp-svc",
+                "source-endpoints": {
+                    "source-endpoint": [
+                        {
+                            "node-id": "10.0.10.1",
+                            "tp-id": "200",
+                            "protection-role": "work",
+                            "layer-specific": {
+                                "access-type": "port"
+                            },
+                            "is-extendable": false,
+                            "is-terminal": true,
+                            "static-route-list": [
+                                {
+                                    "destination": "128.32.10.5",
+                                    "destination-mask": 24,
+                                    "next-hop": "128.32.33.5"
+                                },
+                                {
+                                    "destination": "128.32.20.5",
+                                    "destination-mask": 24,
+                                    "next-hop": "128.32.33.5"
+                                }
+                            ],
+                            "outer-tag": {
+                                "tag-type": "ietf-eth-tran-types:classify-c-vlan",
+                                "vlan-value": 21
+                            },
+                            "service-classification-type": "ietf-eth-tran-type:vlan-classification",
+                            "ingress-egress-bandwidth-profile" : {
+                                "bandwidth-profile-type": "ietf-eth-tran-types:mef-10-bwp",
+                                "CIR": 10000000,
+                                "EIR": 10000000
+                            }
+                        }
+                    ]
+                },
+                "destination-endpoints": {
+                    "destination-endpoint": [
+                        {
+                            "node-id": "10.0.30.1",
+                            "tp-id": "200",
+                            "protection-role": "work",
+                            "layer-specific": {
+                                "access-type": "port"
+                            },
+                            "is-extendable": false,
+                            "is-terminal": true,
+                            "static-route-list": [
+                                {
+                                    "destination": "172.1.101.22",
+                                    "destination-mask": 24,
+                                    "next-hop": "172.10.33.5"
+                                }
+                            ],
+                            "outer-tag": {
+                                "tag-type": "ietf-eth-tran-types:classify-c-vlan",
+                                "vlan-value": 101
+                            },
+                            "service-classification-type": "ietf-eth-tran-type:vlan-classification",
+                            "ingress-egress-bandwidth-profile" : {
+                                "bandwidth-profile-type": "ietf-eth-tran-types:mef-10-bwp",
+                                "CIR": 10000000,
+                                "EIR": 10000000
+                            }
+                        }
+                    ]
+                },
+                "svc-tunnel": [
+                    {
+                        "tunnel-name": "osu_tunnel_1"
+                    }
+                ],
+                "optimizations": {
+                    "optimization-metric": [
+                        {
+                            "metric-role": "work",
+                            "metric-type": "ietf-te-types:path-metric-te"
+                        }
+                    ]
+                }
+            },
+            {
+                "etht-svc-name": "etht_service_2",
+                "etht-svc-title": "ETHT_SERVICE_2",
+                "etht-svc-type": "op-mp2mp-svc",
+                "source-endpoints": {
+                    "source-endpoint": [
+                        {
+                            "node-id": "10.0.10.1",
+                            "tp-id": "200",
+                            "protection-role": "work",
+                            "layer-specific": {
+                                "access-type": "port"
+                            },
+                            "is-extendable": false,
+                            "is-terminal": true,
+                            "static-route-list": [
+                                {
+                                    "destination": "128.32.10.5",
+                                    "destination-mask": 24,
+                                    "next-hop": "128.32.33.5"
+                                },
+                                {
+                                    "destination": "128.32.20.5",
+                                    "destination-mask": 24,
+                                    "next-hop": "128.32.33.5"
+                                }
+                            ],
+                            "outer-tag": {
+                                "tag-type": "ietf-eth-tran-types:classify-c-vlan",
+                                "vlan-value": 31
+                            },
+                            "service-classification-type": "ietf-eth-tran-type:vlan-classification",
+                            "ingress-egress-bandwidth-profile" : {
+                                "bandwidth-profile-type": "ietf-eth-tran-types:mef-10-bwp",
+                                "CIR": 10000000,
+                                "EIR": 10000000
+                            }
+                        }
+                    ]
+                },
+                "destination-endpoints": {
+                    "destination-endpoint": [
+                        {
+                            "node-id": "10.0.30.1",
+                            "tp-id": "200",
+                            "protection-role": "work",
+                            "layer-specific": {
+                                "access-type": "port"
+                            },
+                            "is-extendable": false,
+                            "is-terminal": true,
+                            "static-route-list": [
+                                {
+                                    "destination": "172.1.101.22",
+                                    "destination-mask": 24,
+                                    "next-hop": "172.10.33.5"
+                                }
+                            ],
+                            "outer-tag": {
+                                "tag-type": "ietf-eth-tran-types:classify-c-vlan",
+                                "vlan-value": 201
+                            },
+                            "service-classification-type": "ietf-eth-tran-type:vlan-classification",
+                            "ingress-egress-bandwidth-profile" : {
+                                "bandwidth-profile-type": "ietf-eth-tran-types:mef-10-bwp",
+                                "CIR": 10000000,
+                                "EIR": 10000000
+                            }
+                        }
+                    ]
+                },
+                "svc-tunnel": [
+                    {
+                        "tunnel-name": "osu_tunnel_2"
+                    }
+                ],
+                "optimizations": {
+                    "optimization-metric": [
+                        {
+                            "metric-role": "work",
+                            "metric-type": "ietf-te-types:path-metric-te"
+                        }
+                    ]
+                }
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/src/device/tests/data/ietf_actn/expected_osu_tunnels.json b/src/device/tests/data/ietf_actn/expected_osu_tunnels.json
new file mode 100644
index 0000000000000000000000000000000000000000..1debf555b7219b1f62c4f04782aeaf0eefca62f9
--- /dev/null
+++ b/src/device/tests/data/ietf_actn/expected_osu_tunnels.json
@@ -0,0 +1,84 @@
+{
+    "ietf-te:tunnel": [
+        {
+            "name": "osu_tunnel_1",
+            "title": "OSU_TUNNEL_1",
+            "admin-state": "ietf-te-types:tunnel-admin-state-up",
+            "delay": 20,
+            "te-bandwidth": {
+                "layer": "odu",
+                "odu-type": "osuflex",
+                "number": 40
+            },
+            "bidirectional": true,
+            "destination-endpoints": {
+                "destination-endpoint": [
+                    {
+                        "node-id": "10.0.30.1",
+                        "tp-id": "200",
+                        "ttp-channel-name": "och:1-odu2:1-oduflex:3-osuflex:1",
+                        "protection-role": "work"
+                    }
+                ]
+            },
+            "source-endpoints": {
+                "source-endpoint": [
+                    {
+                        "node-id": "10.0.10.1",
+                        "tp-id": "200",
+                        "ttp-channel-name": "och:1-odu2:1-oduflex:1-osuflex:2",
+                        "protection-role": "work"
+                    }
+                ]
+            },
+            "restoration": {
+                "restoration-type": "ietf-te-types:lsp-restoration-not-applicable",
+                "restoration-lock": false
+            },
+            "protection": {
+                "protection-type": "ietf-te-types:lsp-protection-unprotected",
+                "protection-reversion-disable": true
+            }
+        },
+        {
+            "name": "osu_tunnel_2",
+            "title": "OSU_TUNNEL_2",
+            "admin-state": "ietf-te-types:tunnel-admin-state-up",
+            "delay": 20,
+            "te-bandwidth": {
+                "layer": "odu",
+                "odu-type": "osuflex",
+                "number": 40
+            },
+            "bidirectional": true,
+            "destination-endpoints": {
+                "destination-endpoint": [
+                    {
+                        "node-id": "10.0.30.1",
+                        "tp-id": "200",
+                        "ttp-channel-name": "och:1-odu2:1-oduflex:3-osuflex:1",
+                        "protection-role": "work"
+                    }
+                ]
+            },
+            "source-endpoints": {
+                "source-endpoint": [
+                    {
+                        "node-id": "10.0.10.1",
+                        "tp-id": "200",
+                        "ttp-channel-name": "och:1-odu2:1-oduflex:1-osuflex:2",
+                        "protection-role": "work"
+                    }
+                ]
+            },
+            "restoration": {
+                "restoration-type": "ietf-te-types:lsp-restoration-not-applicable",
+                "restoration-lock": false
+            },
+            "protection": {
+                "protection-type": "ietf-te-types:lsp-protection-unprotected",
+                "protection-reversion-disable": true
+            }
+        }
+    ]
+}
diff --git a/src/device/tests/test_unitary_ietf_actn.py b/src/device/tests/test_unitary_ietf_actn.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f01a412d88bca142d2bd96ce238947844bc9087
--- /dev/null
+++ b/src/device/tests/test_unitary_ietf_actn.py
@@ -0,0 +1,282 @@
+# 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, deepdiff, json, logging, operator, os, pytest, time
+from flask import Flask, jsonify, make_response
+from flask_restful import Resource
+from common.proto.context_pb2 import ConfigActionEnum, Device, DeviceId
+from common.tools.descriptor.Tools import format_custom_config_rules
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.tools.object_factory.Device import (
+    json_device_connect_rules, json_device_id, json_device_ietf_actn_disabled
+)
+from common.tools.service.GenericRestServer import GenericRestServer
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from device.service.DeviceService import DeviceService
+from device.service.driver_api._Driver import _Driver
+from tests.tools.mock_ietf_actn_sdn_ctrl.ResourceEthServices import EthService, EthServices
+from tests.tools.mock_ietf_actn_sdn_ctrl.ResourceOsuTunnels import OsuTunnel, OsuTunnels
+
+os.environ['DEVICE_EMULATED_ONLY'] = 'TRUE'
+from .PrepareTestScenario import ( # pylint: disable=unused-import
+    # be careful, order of symbols is important here!
+    mock_service, device_service, context_client, device_client, monitoring_client, test_prepare_environment
+)
+
+DEVICE_UUID     = 'DEVICE-IETF-ACTN'
+DEVICE_ADDRESS  = '127.0.0.1'
+DEVICE_PORT     = 8080
+DEVICE_USERNAME = 'admin'
+DEVICE_PASSWORD = 'admin'
+DEVICE_SCHEME   = 'http'
+DEVICE_BASE_URL = '/restconf/v2/data'
+DEVICE_TIMEOUT  = 120
+DEVICE_VERIFY   = False
+
+DEVICE_ID = json_device_id(DEVICE_UUID)
+DEVICE    = json_device_ietf_actn_disabled(DEVICE_UUID)
+
+DEVICE_CONNECT_RULES = json_device_connect_rules(DEVICE_ADDRESS, DEVICE_PORT, {
+    'scheme'  : DEVICE_SCHEME,
+    'username': DEVICE_USERNAME,
+    'password': DEVICE_PASSWORD,
+    'base_url': DEVICE_BASE_URL,
+    'timeout' : DEVICE_TIMEOUT,
+    'verify'  : DEVICE_VERIFY,
+})
+
+DATA_FILE_CONFIG_RULES           = 'device/tests/data/ietf_actn/config_rules.json'
+DATA_FILE_DECONFIG_RULES         = 'device/tests/data/ietf_actn/deconfig_rules.json'
+DATA_FILE_EXPECTED_OSU_TUNNELS   = 'device/tests/data/ietf_actn/expected_osu_tunnels.json'
+DATA_FILE_EXPECTED_ETHT_SERVICES = 'device/tests/data/ietf_actn/expected_etht_services.json'
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+@pytest.fixture(scope='session')
+def ietf_actn_sdn_ctrl(
+    device_service : DeviceService,     # pylint: disable=redefined-outer-name
+) -> Flask:
+    _rest_server = GenericRestServer(DEVICE_PORT, DEVICE_BASE_URL, bind_address=DEVICE_ADDRESS)
+    _rest_server.app.config['DEBUG'      ] = True
+    _rest_server.app.config['ENV'        ] = 'development'
+    _rest_server.app.config['SERVER_NAME'] = '{:s}:{:d}'.format(DEVICE_ADDRESS, DEVICE_PORT)
+    _rest_server.app.config['TESTING'    ] = True
+
+    class Root(Resource):
+        def get(self):
+            return make_response(jsonify({}), 200)
+
+    add_rsrc = _rest_server.add_resource
+    add_rsrc(Root,        '/')
+    add_rsrc(OsuTunnels,  '/ietf-te:te/tunnels')
+    add_rsrc(OsuTunnel,   '/ietf-te:te/tunnels/tunnel="<string:osu_tunnel_name>"')
+    add_rsrc(EthServices, '/ietf-eth-tran-service:etht-svc')
+    add_rsrc(EthService,  '/ietf-eth-tran-service:etht-svc/etht-svc-instances="<string:etht_service_name>"')
+
+    _rest_server.start()
+    time.sleep(1) # bring time for the server to start
+    yield _rest_server
+    _rest_server.shutdown()
+    _rest_server.join()
+
+
+def test_device_ietf_actn_add(
+    device_client : DeviceClient,           # pylint: disable=redefined-outer-name
+    device_service : DeviceService,         # pylint: disable=redefined-outer-name
+    ietf_actn_sdn_ctrl : GenericRestServer, # pylint: disable=redefined-outer-name
+) -> None:
+    DEVICE_WITH_CONNECT_RULES = copy.deepcopy(DEVICE)
+    DEVICE_WITH_CONNECT_RULES['device_config']['config_rules'].extend(DEVICE_CONNECT_RULES)
+    device_client.AddDevice(Device(**DEVICE_WITH_CONNECT_RULES))
+    driver_instance_cache = device_service.device_servicer.driver_instance_cache
+    driver: _Driver = driver_instance_cache.get(DEVICE_UUID)
+    assert driver is not None
+
+
+def test_device_ietf_actn_get(
+    context_client : ContextClient,         # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,           # pylint: disable=redefined-outer-name
+    ietf_actn_sdn_ctrl : GenericRestServer, # pylint: disable=redefined-outer-name
+) -> None:
+
+    initial_config = device_client.GetInitialConfig(DeviceId(**DEVICE_ID))
+    LOGGER.info('initial_config = {:s}'.format(grpc_message_to_json_string(initial_config)))
+
+    device_data = context_client.GetDevice(DeviceId(**DEVICE_ID))
+    LOGGER.info('device_data = {:s}'.format(grpc_message_to_json_string(device_data)))
+
+
+def test_device_ietf_actn_configure(
+    device_client : DeviceClient,           # pylint: disable=redefined-outer-name
+    device_service : DeviceService,         # pylint: disable=redefined-outer-name
+    ietf_actn_sdn_ctrl : GenericRestServer, # pylint: disable=redefined-outer-name
+) -> None:
+    ietf_actn_client = ietf_actn_sdn_ctrl.app.test_client()
+
+    driver_instance_cache = device_service.device_servicer.driver_instance_cache
+    driver : _Driver = driver_instance_cache.get(DEVICE_UUID)
+    assert driver is not None
+
+    retrieved_osu_tunnels = ietf_actn_client.get('/restconf/v2/data/ietf-te:te/tunnels')
+    retrieved_osu_tunnels = retrieved_osu_tunnels.json
+    LOGGER.info('osu_tunnels = {:s}'.format(str(retrieved_osu_tunnels)))
+    expected_osu_tunnels = {'ietf-te:tunnel': []}
+    osu_tunnels_diff = deepdiff.DeepDiff(expected_osu_tunnels, retrieved_osu_tunnels)
+    if len(osu_tunnels_diff) > 0:
+        LOGGER.error('PRE OSU TUNNELS - Differences:\n{:s}'.format(str(osu_tunnels_diff.pretty())))
+    assert len(osu_tunnels_diff) == 0
+
+    retrieved_etht_services = ietf_actn_client.get('/restconf/v2/data/ietf-eth-tran-service:etht-svc')
+    retrieved_etht_services = retrieved_etht_services.json
+    LOGGER.info('etht_services = {:s}'.format(str(retrieved_etht_services)))
+    expected_etht_services = {'ietf-eth-tran-service:etht-svc': {'etht-svc-instances': []}}
+    etht_services_diff = deepdiff.DeepDiff(expected_etht_services, retrieved_etht_services)
+    if len(etht_services_diff) > 0:
+        LOGGER.error('PRE ETHT SERVICES - Differences:\n{:s}'.format(str(etht_services_diff.pretty())))
+    assert len(etht_services_diff) == 0
+
+    retrieved_driver_config_rules = sorted(driver.GetConfig(), key=operator.itemgetter(0))
+    LOGGER.info('driver_config = {:s}'.format(str(retrieved_driver_config_rules)))
+    assert isinstance(retrieved_driver_config_rules, list)
+    if len(retrieved_driver_config_rules) > 0:
+        LOGGER.error('PRE DRIVER CONFIG RULES - Differences:\n{:s}'.format(str(retrieved_driver_config_rules)))
+    assert len(retrieved_driver_config_rules) == 0
+
+    DEVICE_WITH_CONFIG_RULES = copy.deepcopy(DEVICE)
+    with open(DATA_FILE_CONFIG_RULES, 'r', encoding='UTF-8') as f:
+        config_rules = format_custom_config_rules(json.load(f))
+        DEVICE_WITH_CONFIG_RULES['device_config']['config_rules'].extend(config_rules)
+    device_client.ConfigureDevice(Device(**DEVICE_WITH_CONFIG_RULES))
+
+    retrieved_osu_tunnels = ietf_actn_client.get('/restconf/v2/data/ietf-te:te/tunnels')
+    retrieved_osu_tunnels = retrieved_osu_tunnels.json
+    LOGGER.info('osu_tunnels = {:s}'.format(str(retrieved_osu_tunnels)))
+    with open(DATA_FILE_EXPECTED_OSU_TUNNELS, 'r', encoding='UTF-8') as f:
+        expected_osu_tunnels = json.load(f)
+    osu_tunnels_diff = deepdiff.DeepDiff(expected_osu_tunnels, retrieved_osu_tunnels)
+    if len(osu_tunnels_diff) > 0:
+        LOGGER.error('POST OSU TUNNELS - Differences:\n{:s}'.format(str(osu_tunnels_diff.pretty())))
+    assert len(osu_tunnels_diff) == 0
+
+    retrieved_etht_services = ietf_actn_client.get('/restconf/v2/data/ietf-eth-tran-service:etht-svc')
+    retrieved_etht_services = retrieved_etht_services.json
+    LOGGER.info('etht_services = {:s}'.format(str(retrieved_etht_services)))
+    with open(DATA_FILE_EXPECTED_ETHT_SERVICES, 'r', encoding='UTF-8') as f:
+        expected_etht_services = json.load(f)
+    etht_services_diff = deepdiff.DeepDiff(expected_etht_services, retrieved_etht_services)
+    if len(etht_services_diff) > 0:
+        LOGGER.error('POST ETHT SERVICES - Differences:\n{:s}'.format(str(etht_services_diff.pretty())))
+    assert len(etht_services_diff) == 0
+
+    retrieved_driver_config_rules = sorted(driver.GetConfig(), key=operator.itemgetter(0))
+    LOGGER.info('driver_config = {:s}'.format(str(retrieved_driver_config_rules)))
+    retrieved_driver_config_rules = [
+        {'action': 1, 'custom': {'resource_key': resource_key, 'resource_value': resource_value}}
+        for resource_key, resource_value in retrieved_driver_config_rules
+    ]
+    with open(DATA_FILE_CONFIG_RULES, 'r', encoding='UTF-8') as f:
+        expected_driver_config_rules = sorted(json.load(f), key=lambda cr: cr['custom']['resource_key'])
+    driver_config_rules_diff = deepdiff.DeepDiff(expected_driver_config_rules, retrieved_driver_config_rules)
+    if len(driver_config_rules_diff) > 0:
+        LOGGER.error('POST DRIVER CONFIG RULES - Differences:\n{:s}'.format(str(driver_config_rules_diff.pretty())))
+    assert len(driver_config_rules_diff) == 0
+
+
+def test_device_ietf_actn_deconfigure(
+    device_client : DeviceClient,           # pylint: disable=redefined-outer-name
+    device_service : DeviceService,         # pylint: disable=redefined-outer-name
+    ietf_actn_sdn_ctrl : GenericRestServer, # pylint: disable=redefined-outer-name
+) -> None:
+    ietf_actn_client = ietf_actn_sdn_ctrl.app.test_client()
+
+    driver_instance_cache = device_service.device_servicer.driver_instance_cache
+    driver : _Driver = driver_instance_cache.get(DEVICE_UUID)
+    assert driver is not None
+
+    retrieved_osu_tunnels = ietf_actn_client.get('/restconf/v2/data/ietf-te:te/tunnels')
+    retrieved_osu_tunnels = retrieved_osu_tunnels.json
+    LOGGER.info('osu_tunnels = {:s}'.format(str(retrieved_osu_tunnels)))
+    with open(DATA_FILE_EXPECTED_OSU_TUNNELS, 'r', encoding='UTF-8') as f:
+        expected_osu_tunnels = json.load(f)
+    osu_tunnels_diff = deepdiff.DeepDiff(expected_osu_tunnels, retrieved_osu_tunnels)
+    if len(osu_tunnels_diff) > 0:
+        LOGGER.error('PRE OSU TUNNELS - Differences:\n{:s}'.format(str(osu_tunnels_diff.pretty())))
+    assert len(osu_tunnels_diff) == 0
+
+    retrieved_etht_services = ietf_actn_client.get('/restconf/v2/data/ietf-eth-tran-service:etht-svc')
+    retrieved_etht_services = retrieved_etht_services.json
+    LOGGER.info('etht_services = {:s}'.format(str(retrieved_etht_services)))
+    with open(DATA_FILE_EXPECTED_ETHT_SERVICES, 'r', encoding='UTF-8') as f:
+        expected_etht_services = json.load(f)
+    etht_services_diff = deepdiff.DeepDiff(expected_etht_services, retrieved_etht_services)
+    if len(etht_services_diff) > 0:
+        LOGGER.error('PRE ETHT SERVICES - Differences:\n{:s}'.format(str(etht_services_diff.pretty())))
+    assert len(etht_services_diff) == 0
+
+    retrieved_driver_config_rules = sorted(driver.GetConfig(), key=operator.itemgetter(0))
+    LOGGER.info('driver_config = {:s}'.format(str(retrieved_driver_config_rules)))
+    retrieved_driver_config_rules = [
+        {'action': 1, 'custom': {'resource_key': resource_key, 'resource_value': resource_value}}
+        for resource_key, resource_value in retrieved_driver_config_rules
+    ]
+    with open(DATA_FILE_CONFIG_RULES, 'r', encoding='UTF-8') as f:
+        expected_driver_config_rules = sorted(json.load(f), key=lambda cr: cr['custom']['resource_key'])
+    driver_config_rules_diff = deepdiff.DeepDiff(expected_driver_config_rules, retrieved_driver_config_rules)
+    if len(driver_config_rules_diff) > 0:
+        LOGGER.error('PRE DRIVER CONFIG RULES - Differences:\n{:s}'.format(str(driver_config_rules_diff.pretty())))
+    assert len(driver_config_rules_diff) == 0
+
+    DEVICE_WITH_DECONFIG_RULES = copy.deepcopy(DEVICE)
+    with open(DATA_FILE_DECONFIG_RULES, 'r', encoding='UTF-8') as f:
+        deconfig_rules = format_custom_config_rules(json.load(f))
+        DEVICE_WITH_DECONFIG_RULES['device_config']['config_rules'].extend(deconfig_rules)
+    device_client.ConfigureDevice(Device(**DEVICE_WITH_DECONFIG_RULES))
+
+    retrieved_osu_tunnels = ietf_actn_client.get('/restconf/v2/data/ietf-te:te/tunnels')
+    retrieved_osu_tunnels = retrieved_osu_tunnels.json
+    LOGGER.info('osu_tunnels = {:s}'.format(str(retrieved_osu_tunnels)))
+    expected_osu_tunnels = {'ietf-te:tunnel': []}
+    osu_tunnels_diff = deepdiff.DeepDiff(expected_osu_tunnels, retrieved_osu_tunnels)
+    if len(osu_tunnels_diff) > 0:
+        LOGGER.error('POST OSU TUNNELS - Differences:\n{:s}'.format(str(osu_tunnels_diff.pretty())))
+    assert len(osu_tunnels_diff) == 0
+
+    retrieved_etht_services = ietf_actn_client.get('/restconf/v2/data/ietf-eth-tran-service:etht-svc')
+    retrieved_etht_services = retrieved_etht_services.json
+    LOGGER.info('etht_services = {:s}'.format(str(retrieved_etht_services)))
+    expected_etht_services = {'ietf-eth-tran-service:etht-svc': {'etht-svc-instances': []}}
+    etht_services_diff = deepdiff.DeepDiff(expected_etht_services, retrieved_etht_services)
+    if len(etht_services_diff) > 0:
+        LOGGER.error('POST ETHT SERVICES - Differences:\n{:s}'.format(str(etht_services_diff.pretty())))
+    assert len(etht_services_diff) == 0
+
+    retrieved_driver_config_rules = sorted(driver.GetConfig(), key=operator.itemgetter(0))
+    LOGGER.info('retrieved_driver_config_rules = {:s}'.format(str(retrieved_driver_config_rules)))
+    assert isinstance(retrieved_driver_config_rules, list)
+    if len(retrieved_driver_config_rules) > 0:
+        LOGGER.error('POST DRIVER CONFIG RULES - Differences:\n{:s}'.format(str(retrieved_driver_config_rules)))
+    assert len(retrieved_driver_config_rules) == 0
+
+
+def test_device_ietf_actn_delete(
+    device_client : DeviceClient,           # pylint: disable=redefined-outer-name
+    device_service : DeviceService,         # pylint: disable=redefined-outer-name
+    ietf_actn_sdn_ctrl : GenericRestServer, # pylint: disable=redefined-outer-name
+) -> None:
+    device_client.DeleteDevice(DeviceId(**DEVICE_ID))
+    driver_instance_cache = device_service.device_servicer.driver_instance_cache
+    driver : _Driver = driver_instance_cache.get(DEVICE_UUID, {})
+    assert driver is None
diff --git a/src/nbi/.gitlab-ci.yml b/src/nbi/.gitlab-ci.yml
index d9d790803a5cb0387d2d3447ef700154879bb615..e0cac446a33b36a4fbe65b3da1ad5767582a77c6 100644
--- a/src/nbi/.gitlab-ci.yml
+++ b/src/nbi/.gitlab-ci.yml
@@ -66,6 +66,7 @@ unit_test nbi:
     - sleep 5
     - docker ps -a
     - docker logs $IMAGE_NAME
+    - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_debug_api.py --junitxml=/opt/results/${IMAGE_NAME}_report_debug_api.xml"
     - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_ietf_l2vpn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_l2vpn.xml"
     - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_ietf_network.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_network.xml"
     - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_ietf_l3vpn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_l3vpn.xml"
diff --git a/src/nbi/tests/data/debug_api_dummy.json b/src/nbi/tests/data/debug_api_dummy.json
new file mode 100644
index 0000000000000000000000000000000000000000..d8f5137578629408556e3758c512f137fc633d6c
--- /dev/null
+++ b/src/nbi/tests/data/debug_api_dummy.json
@@ -0,0 +1,442 @@
+{
+    "dummy_mode": true,
+    "contexts": [
+        {
+            "context_id": {"context_uuid": {"uuid": "admin"}},
+            "name": "admin",
+            "topology_ids": [
+                {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+            ],
+            "service_ids": [
+                {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R2/200"}},
+                {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R3/200"}},
+                {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R2/200==R3/200"}}
+            ],
+            "slice_ids": [
+                {"context_id": {"context_uuid": {"uuid": "admin"}}, "slice_uuid": {"uuid": "SLC:R1-R2-R3"}}
+            ]
+        }
+    ],
+    "topologies": [
+        {
+            "device_ids": [
+                {"device_uuid": {"uuid": "R1"}},
+                {"device_uuid": {"uuid": "R2"}},
+                {"device_uuid": {"uuid": "R3"}}
+            ],
+            "link_ids": [
+                {"link_uuid": {"uuid": "R1/502==R2/501"}},
+                {"link_uuid": {"uuid": "R1/503==R3/501"}},
+                {"link_uuid": {"uuid": "R2/501==R1/502"}},
+                {"link_uuid": {"uuid": "R2/503==R3/502"}},
+                {"link_uuid": {"uuid": "R3/501==R1/503"}},
+                {"link_uuid": {"uuid": "R3/502==R2/503"}}
+            ],
+            "name": "admin",
+            "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+        }
+    ],
+    "devices": [
+        {
+            "device_id": {"device_uuid": {"uuid": "R1"}}, "name": "R1", "device_type": "emu-packet-router",
+            "device_drivers": [0], "device_operational_status": 2,
+            "device_endpoints": [
+                {"name": "200", "endpoint_type": "copper", "endpoint_id": {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }},
+                {"name": "502", "endpoint_type": "optical", "endpoint_id": {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "502"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }},
+                {"name": "503", "endpoint_type": "optical", "endpoint_id": {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "503"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }}
+            ],
+            "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": 0}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"uuid": "200", "name": "200", "type": "copper"},
+                    {"uuid": "502", "name": "502", "type": "optical"},
+                    {"uuid": "503", "name": "503", "type": "optical"}
+                ]}}},
+                {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[200]", "resource_value": {
+                    "uuid": "200", "name": "200", "type": "copper"
+                }}},
+                {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[502]", "resource_value": {
+                    "uuid": "502", "name": "502", "type": "optical"
+                }}},
+                {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[503]", "resource_value": {
+                    "uuid": "503", "name": "503", "type": "optical"
+                }}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "R2"}}, "name": "R2", "device_type": "emu-packet-router",
+            "device_drivers": [0], "device_operational_status": 2,
+            "device_endpoints": [
+                {"name": "200", "endpoint_type": "copper", "endpoint_id": {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }},
+                {"name": "501", "endpoint_type": "optical", "endpoint_id": {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "501"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }},
+                {"name": "503", "endpoint_type": "optical", "endpoint_id": {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "503"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }}
+            ],
+            "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": 0}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"uuid": "200", "name": "200", "type": "copper"},
+                    {"uuid": "501", "name": "501", "type": "optical"},
+                    {"uuid": "503", "name": "503", "type": "optical"}
+                ]}}},
+                {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[200]", "resource_value": {
+                    "uuid": "200", "name": "200", "type": "copper"
+                }}},
+                {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[501]", "resource_value": {
+                    "uuid": "501", "name": "501", "type": "optical"
+                }}},
+                {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[503]", "resource_value": {
+                    "uuid": "503", "name": "503", "type": "optical"
+                }}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "R3"}}, "name": "R3", "device_type": "emu-packet-router",
+            "device_drivers": [0], "device_operational_status": 2,
+            "device_endpoints": [
+                {"name": "200", "endpoint_type": "copper", "endpoint_id": {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }},
+                {"name": "502", "endpoint_type": "optical", "endpoint_id": {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "502"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }},
+                {"name": "503", "endpoint_type": "optical", "endpoint_id": {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "503"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }}
+            ],
+            "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": 0}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"uuid": "200", "name": "200", "type": "copper"},
+                    {"uuid": "502", "name": "502", "type": "optical"},
+                    {"uuid": "503", "name": "503", "type": "optical"}
+                ]}}},
+                {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[200]", "resource_value": {
+                    "uuid": "200", "name": "200", "type": "copper"
+                }}},
+                {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[502]", "resource_value": {
+                    "uuid": "502", "name": "502", "type": "optical"
+                }}},
+                {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[503]", "resource_value": {
+                    "uuid": "503", "name": "503", "type": "optical"
+                }}}
+            ]}
+        }
+    ],
+    "links": [
+        {
+            "link_id": {"link_uuid": {"uuid": "R1/502==R2/501"}}, "name": "R1/502==R2/501",
+            "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0},
+            "link_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "502"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "501"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "R1/503==R3/501"}}, "name": "R1/503==R3/501",
+            "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0},
+            "link_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "503"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "501"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "R2/501==R1/502"}}, "name": "R2/501==R1/502",
+            "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0},
+            "link_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "501"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "502"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "R2/503==R3/502"}}, "name": "R2/503==R3/502",
+            "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0},
+            "link_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "503"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "502"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "R3/501==R1/503"}}, "name": "R3/501==R1/503",
+            "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0},
+            "link_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "501"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "503"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "R3/502==R2/503"}}, "name": "R3/502==R2/503",
+            "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0},
+            "link_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "502"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "503"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ]
+        }
+    ],
+    "services": [
+        {
+            "service_id" : {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R2/200"}},
+            "name": "SVC:R1/200==R2/200", "service_type": 1, "service_status": {"service_status": 1},
+            "service_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ],
+            "service_constraints": [
+                {"action": 1, "sla_capacity": {"capacity_gbps": 40.0}},
+                {"action": 1, "sla_latency": {"e2e_latency_ms": 10.0}},
+                {"action": 1, "sla_availability": {"num_disjoint_paths": 1, "all_active": true, "availability": 99.99}}
+            ],
+            "service_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "/device[R1]/endpoint[200]/settings", "resource_value": {
+                    "ipv4_address": "10.0.1.1", "ipv4_prefix": 24
+                }}},
+                {"action": 1, "custom": {"resource_key": "/device[R2]/endpoint[200]/settings", "resource_value": {
+                    "ipv4_address": "10.0.2.1", "ipv4_prefix": 24
+                }}}
+            ]}
+        },
+        {
+            "service_id" : {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R3/200"}},
+            "name": "SVC:R1/200==R3/200", "service_type": 1, "service_status": {"service_status": 1},
+            "service_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ],
+            "service_constraints": [
+                {"action": 1, "sla_capacity": {"capacity_gbps": 50.0}},
+                {"action": 1, "sla_latency": {"e2e_latency_ms": 8.0}},
+                {"action": 1, "sla_availability": {"num_disjoint_paths": 1, "all_active": true, "availability": 99.9}}
+            ],
+            "service_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "/device[R1]/endpoint[200]/settings", "resource_value": {
+                    "ipv4_address": "10.0.1.1", "ipv4_prefix": 24
+                }}},
+                {"action": 1, "custom": {"resource_key": "/device[R3]/endpoint[200]/settings", "resource_value": {
+                    "ipv4_address": "10.0.3.1", "ipv4_prefix": 24
+                }}}
+            ]}
+        },
+        {
+            "service_id" : {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R2/200==R3/200"}},
+            "name": "SVC:R2/200==R3/200", "service_type": 1, "service_status": {"service_status": 1},
+            "service_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ],
+            "service_constraints": [
+                {"action": 1, "sla_capacity": {"capacity_gbps": 10.0}},
+                {"action": 1, "sla_latency": {"e2e_latency_ms": 3.0}},
+                {"action": 1, "sla_availability": {"num_disjoint_paths": 1, "all_active": true, "availability": 99.9999}}
+            ],
+            "service_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "/device[R2]/endpoint[200]/settings", "resource_value": {
+                    "ipv4_address": "10.0.2.1", "ipv4_prefix": 24
+                }}},
+                {"action": 1, "custom": {"resource_key": "/device[R3]/endpoint[200]/settings", "resource_value": {
+                    "ipv4_address": "10.0.3.1", "ipv4_prefix": 24
+                }}}
+            ]}
+        }
+    ],
+    "slices": [
+        {
+            "slice_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "slice_uuid": {"uuid": "SLC:R1-R2-R3"}},
+            "name": "SLC:R1-R2-R3",
+            "slice_endpoint_ids": [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ],
+            "slice_constraints": [
+                {"action": 1, "sla_capacity": {"capacity_gbps": 40.0}},
+                {"action": 1, "sla_latency": {"e2e_latency_ms": 10.0}},
+                {"action": 1, "sla_availability": {"num_disjoint_paths": 1, "all_active": true, "availability": 99.99}}
+            ],
+            "slice_service_ids": [
+                {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R2/200"}},
+                {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R3/200"}},
+                {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R2/200==R3/200"}}
+            ],
+            "slice_subslice_ids": [],
+            "slice_status": {"slice_status" : 1},
+            "slice_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "/device[R1]/endpoint[200]/settings", "resource_value": {
+                    "ipv4_address": "10.0.1.1", "ipv4_prefix": 24
+                }}},
+                {"action": 1, "custom": {"resource_key": "/device[R2]/endpoint[200]/settings", "resource_value": {
+                    "ipv4_address": "10.0.2.1", "ipv4_prefix": 24
+                }}},
+                {"action": 1, "custom": {"resource_key": "/device[R3]/endpoint[200]/settings", "resource_value": {
+                    "ipv4_address": "10.0.3.1", "ipv4_prefix": 24
+                }}}
+            ]},
+            "slice_owner": {"owner_uuid": {"uuid": "TFS"}, "owner_string": "TFS:SLC:R1-R2-R3"}
+        }
+    ],
+    "connections": [
+        {
+            "connection_id": {"connection_uuid": {"uuid": "CON:R1/200==R2/200:1"}},
+            "service_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R2/200"}},
+            "path_hops_endpoint_ids" : [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "502"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "501"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ],
+            "sub_service_ids": [],
+            "settings": {
+                "l3": {"src_ip_address": "10.0.1.10", "dst_ip_address": "10.0.2.10", "ttl": 20}
+            }
+        },
+        {
+            "connection_id": {"connection_uuid": {"uuid": "CON:R1/200==R3/200:1"}},
+            "service_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R3/200"}},
+            "path_hops_endpoint_ids" : [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "503"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "501"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ],
+            "sub_service_ids": [],
+            "settings": {
+                "l3": {"src_ip_address": "10.0.1.10", "dst_ip_address": "10.0.3.10", "ttl": 20}
+            }
+        },
+        {
+            "connection_id": {"connection_uuid": {"uuid": "CON:R2/200==R3/200:1"}},
+            "service_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R2/200==R3/200"}},
+            "path_hops_endpoint_ids" : [
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "503"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "502"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                },
+                {
+                    "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
+                }
+            ],
+            "sub_service_ids": [],
+            "settings": {
+                "l3": {"src_ip_address": "10.0.2.10", "dst_ip_address": "10.0.3.10", "ttl": 20}
+            }
+        }
+    ]
+}
diff --git a/src/nbi/tests/test_debug_api.py b/src/nbi/tests/test_debug_api.py
index e284992618a96388371b69b7b0c2a8c4fcaaba70..f19531eaed3b106279c2752a55eb00bb1ca30bb7 100644
--- a/src/nbi/tests/test_debug_api.py
+++ b/src/nbi/tests/test_debug_api.py
@@ -12,209 +12,206 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import logging, os, pytest, time, urllib
-from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME, ServiceNameEnum
-from common.proto.context_pb2 import Connection, Context, Device, Link, Service, Slice, Topology
-from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule
-from common.Settings import (
-    ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, ENVVAR_SUFIX_SERVICE_PORT_HTTP, get_env_var_name,
-    get_service_port_grpc, get_service_port_http
+import logging, urllib
+from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
+from common.proto.context_pb2 import ContextId
+from common.tools.descriptor.Loader import (
+    DescriptorLoader, check_descriptor_load_results, validate_empty_scenario
 )
+from common.tools.object_factory.Context import json_context_id
 from common.type_checkers.Assertions import (
-    validate_connection, validate_connection_ids, validate_connections, validate_context, validate_context_ids,
-    validate_contexts, validate_device, validate_device_ids, validate_devices, validate_link, validate_link_ids,
-    validate_links, validate_service, validate_service_ids, validate_services, validate_topologies, validate_topology,
-    validate_topology_ids)
+    validate_connection, validate_connection_ids, validate_connections,
+    validate_context, validate_context_ids, validate_contexts,
+    validate_device, validate_device_ids, validate_devices,
+    validate_link, validate_link_ids, validate_links,
+    validate_service, validate_service_ids, validate_services,
+    validate_slice, validate_slice_ids, validate_slices,
+    validate_topologies, validate_topology, validate_topology_ids
+)
 from context.client.ContextClient import ContextClient
-from nbi.tests.PrepareTestScenario import do_rest_get_request
-from .MockService_Dependencies import MockService_Dependencies
-from .Objects import (
-    CONNECTION_R1_R3, CONNECTION_R1_R3_ID, CONNECTION_R1_R3_UUID, CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID,
-    DEVICE_R1_UUID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R2_UUID, DEVICE_R3, DEVICE_R3_ID, DEVICE_R3_UUID, LINK_R1_R2,
-    LINK_R1_R2_ID, LINK_R1_R2_UUID, SERVICE_R1_R2, SERVICE_R1_R2_ID, SERVICE_R1_R2_UUID, SERVICE_R1_R3,
-    SERVICE_R1_R3_ID, SERVICE_R1_R3_UUID, SERVICE_R2_R3, SERVICE_R2_R3_ID, SERVICE_R2_R3_UUID, SLICE_R1_R3, TOPOLOGY,
-    TOPOLOGY_ID, POLICY_RULE, POLICY_RULE_ID, POLICY_RULE_UUID
+from nbi.service.rest_server.RestServer import RestServer
+from .PrepareTestScenario import ( # pylint: disable=unused-import
+    # be careful, order of symbols is important here!
+    mock_service, nbi_service_rest, context_client,
+    do_rest_get_request
 )
 
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = 'nbi/tests/data/debug_api_dummy.json'
 
-@pytest.fixture(scope='session')
-def mock_service():
-    _service = MockService_Dependencies(MOCKSERVICE_PORT)
-    _service.configure_env_vars()
-    _service.start()
-    yield _service
-    _service.stop()
+JSON_ADMIN_CONTEXT_ID = json_context_id(DEFAULT_CONTEXT_NAME)
+ADMIN_CONTEXT_ID = ContextId(**JSON_ADMIN_CONTEXT_ID)
 
 
+# ----- Prepare Environment --------------------------------------------------------------------------------------------
 
-LOGGER = logging.getLogger(__name__)
-LOGGER.setLevel(logging.DEBUG)
+def test_prepare_environment(context_client : ContextClient) -> None: # pylint: disable=redefined-outer-name
+    validate_empty_scenario(context_client)
+    descriptor_loader = DescriptorLoader(descriptors_file=DESCRIPTOR_FILE, context_client=context_client)
+    results = descriptor_loader.process()
+    check_descriptor_load_results(results, descriptor_loader)
+    descriptor_loader.validate()
 
-LOCAL_HOST = '127.0.0.1'
-GRPC_PORT = 10000 + int(get_service_port_grpc(ServiceNameEnum.CONTEXT))   # avoid privileged ports
-HTTP_PORT = 10000 + int(get_service_port_http(ServiceNameEnum.CONTEXT))   # avoid privileged ports
-
-MOCKSERVICE_PORT = 10000
-DEVICE_SERVICE_PORT = MOCKSERVICE_PORT + get_service_port_grpc(ServiceNameEnum.DEVICE) # avoid privileged ports
-
-os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_HOST     )] = str(LOCAL_HOST)
-os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(GRPC_PORT)
-os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_HTTP)] = str(HTTP_PORT)
-
-@pytest.fixture(scope='session')
-def context_service_grpc():
-    _service = ContextService(context_s_mb[0], context_s_mb[1])
-    _service.start()
-    yield _service
-    _service.stop()
-
-@pytest.fixture(scope='session')
-def context_service_rest():
-    database = context_db_mb[0]
-    _rest_server = RestServer()
-    for endpoint_name, resource_class, resource_url in RESOURCES:
-        _rest_server.add_resource(resource_class, resource_url, endpoint=endpoint_name, resource_class_args=(database,))
-    _rest_server.start()
-    time.sleep(1) # bring time for the server to start
-    yield _rest_server
-    _rest_server.shutdown()
-    _rest_server.join()
-
-@pytest.fixture(scope='session')
-def context_client_grpc(context_service_grpc : ContextService): # pylint: disable=redefined-outer-name
-    _client = ContextClient()
-    yield _client
-    _client.close()
-
-def test_populate_database():
-    client = ContextClient(host=LOCAL_HOST, port=GRPC_PORT)
-    client.SetContext(Context(**CONTEXT))
-    client.SetTopology(Topology(**TOPOLOGY))
-    client.SetDevice(Device(**DEVICE_R1))
-    client.SetDevice(Device(**DEVICE_R2))
-    client.SetDevice(Device(**DEVICE_R3))
-    client.SetLink(Link(**LINK_R1_R2))
-    client.SetLink(Link(**LINK_R1_R3))
-    client.SetLink(Link(**LINK_R2_R3))
-    client.SetService(Service(**SERVICE_R1_R2))
-    client.SetService(Service(**SERVICE_R1_R3))
-    client.SetService(Service(**SERVICE_R2_R3))
-    client.SetSlice(Slice(**SLICE_R1_R3))
-    client.SetConnection(Connection(**CONNECTION_R1_R3))
-
-def test_rest_get_context_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    reply = do_rest_get_request('/context_ids')
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.topology_ids) == 1
+    assert len(response.service_ids ) == 3
+    assert len(response.slice_ids   ) == 1
+
+
+# ----- Context --------------------------------------------------------------------------------------------------------
+
+def test_rest_get_context_ids(nbi_service_rest: RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    reply = do_rest_get_request('/debug-api/context_ids')
     validate_context_ids(reply)
 
-def test_rest_get_contexts(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    reply = do_rest_get_request('/contexts')
+def test_rest_get_contexts(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    reply = do_rest_get_request('/debug-api/contexts')
     validate_contexts(reply)
 
-def test_rest_get_context(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+def test_rest_get_context(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    reply = do_rest_get_request('/context/{:s}'.format(context_uuid))
+    reply = do_rest_get_request('/debug-api/context/{:s}'.format(context_uuid))
     validate_context(reply)
 
-def test_rest_get_topology_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+
+# ----- Topology -------------------------------------------------------------------------------------------------------
+
+def test_rest_get_topology_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    reply = do_rest_get_request('/context/{:s}/topology_ids'.format(context_uuid))
+    reply = do_rest_get_request('/debug-api/context/{:s}/topology_ids'.format(context_uuid))
     validate_topology_ids(reply)
 
-def test_rest_get_topologies(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+def test_rest_get_topologies(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    reply = do_rest_get_request('/context/{:s}/topologies'.format(context_uuid))
+    reply = do_rest_get_request('/debug-api/context/{:s}/topologies'.format(context_uuid))
     validate_topologies(reply)
 
-def test_rest_get_topology(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+def test_rest_get_topology(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
     topology_uuid = urllib.parse.quote(DEFAULT_TOPOLOGY_NAME)
-    reply = do_rest_get_request('/context/{:s}/topology/{:s}'.format(context_uuid, topology_uuid))
-    validate_topology(reply, num_devices=3, num_links=3)
+    reply = do_rest_get_request('/debug-api/context/{:s}/topology/{:s}'.format(context_uuid, topology_uuid))
+    validate_topology(reply, num_devices=3, num_links=6)
+
+
+# ----- Device ---------------------------------------------------------------------------------------------------------
+
+def test_rest_get_device_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    reply = do_rest_get_request('/debug-api/device_ids')
+    validate_device_ids(reply)
+
+def test_rest_get_devices(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    reply = do_rest_get_request('/debug-api/devices')
+    validate_devices(reply)
+
+def test_rest_get_device(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    device_uuid = urllib.parse.quote('R1', safe='')
+    reply = do_rest_get_request('/debug-api/device/{:s}'.format(device_uuid))
+    validate_device(reply)
+
+
+# ----- Link -----------------------------------------------------------------------------------------------------------
+
+def test_rest_get_link_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    reply = do_rest_get_request('/debug-api/link_ids')
+    validate_link_ids(reply)
 
-def test_rest_get_service_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+def test_rest_get_links(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    reply = do_rest_get_request('/debug-api/links')
+    validate_links(reply)
+
+def test_rest_get_link(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    link_uuid = urllib.parse.quote('R1/502==R2/501', safe='')
+    reply = do_rest_get_request('/debug-api/link/{:s}'.format(link_uuid))
+    validate_link(reply)
+
+
+# ----- Service --------------------------------------------------------------------------------------------------------
+
+def test_rest_get_service_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    reply = do_rest_get_request('/context/{:s}/service_ids'.format(context_uuid))
+    reply = do_rest_get_request('/debug-api/context/{:s}/service_ids'.format(context_uuid))
     validate_service_ids(reply)
 
-def test_rest_get_services(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+def test_rest_get_services(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    reply = do_rest_get_request('/context/{:s}/services'.format(context_uuid))
+    reply = do_rest_get_request('/debug-api/context/{:s}/services'.format(context_uuid))
     validate_services(reply)
 
-def test_rest_get_service(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+def test_rest_get_service(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    service_uuid = urllib.parse.quote(SERVICE_R1_R2_UUID, safe='')
-    reply = do_rest_get_request('/context/{:s}/service/{:s}'.format(context_uuid, service_uuid))
+    service_uuid = urllib.parse.quote('SVC:R1/200==R2/200', safe='')
+    reply = do_rest_get_request('/debug-api/context/{:s}/service/{:s}'.format(context_uuid, service_uuid))
     validate_service(reply)
 
-def test_rest_get_slice_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    reply = do_rest_get_request('/context/{:s}/slice_ids'.format(context_uuid))
-    #validate_slice_ids(reply)
 
-def test_rest_get_slices(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    reply = do_rest_get_request('/context/{:s}/slices'.format(context_uuid))
-    #validate_slices(reply)
+# ----- Slice ----------------------------------------------------------------------------------------------------------
 
-def test_rest_get_slice(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+def test_rest_get_slice_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    slice_uuid = urllib.parse.quote(SLICE_R1_R3_UUID, safe='')
-    reply = do_rest_get_request('/context/{:s}/slice/{:s}'.format(context_uuid, slice_uuid))
-    #validate_slice(reply)
-
-def test_rest_get_device_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    reply = do_rest_get_request('/device_ids')
-    validate_device_ids(reply)
-
-def test_rest_get_devices(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    reply = do_rest_get_request('/devices')
-    validate_devices(reply)
+    reply = do_rest_get_request('/debug-api/context/{:s}/slice_ids'.format(context_uuid))
+    validate_slice_ids(reply)
 
-def test_rest_get_device(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    device_uuid = urllib.parse.quote(DEVICE_R1_UUID, safe='')
-    reply = do_rest_get_request('/device/{:s}'.format(device_uuid))
-    validate_device(reply)
+def test_rest_get_slices(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
+    reply = do_rest_get_request('/debug-api/context/{:s}/slices'.format(context_uuid))
+    validate_slices(reply)
 
-def test_rest_get_link_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    reply = do_rest_get_request('/link_ids')
-    validate_link_ids(reply)
+def test_rest_get_slice(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
+    slice_uuid = urllib.parse.quote('SLC:R1-R2-R3', safe='')
+    reply = do_rest_get_request('/debug-api/context/{:s}/slice/{:s}'.format(context_uuid, slice_uuid))
+    validate_slice(reply)
 
-def test_rest_get_links(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    reply = do_rest_get_request('/links')
-    validate_links(reply)
 
-def test_rest_get_link(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    link_uuid = urllib.parse.quote(LINK_R1_R2_UUID, safe='')
-    reply = do_rest_get_request('/link/{:s}'.format(link_uuid))
-    validate_link(reply)
+# ----- Connection -----------------------------------------------------------------------------------------------------
 
-def test_rest_get_connection_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+def test_rest_get_connection_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    service_uuid = urllib.parse.quote(SERVICE_R1_R3_UUID, safe='')
-    reply = do_rest_get_request('/context/{:s}/service/{:s}/connection_ids'.format(context_uuid, service_uuid))
+    service_uuid = urllib.parse.quote('SVC:R1/200==R2/200', safe='')
+    reply = do_rest_get_request('/debug-api/context/{:s}/service/{:s}/connection_ids'.format(context_uuid, service_uuid))
     validate_connection_ids(reply)
 
-def test_rest_get_connections(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
+def test_rest_get_connections(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
     context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME)
-    service_uuid = urllib.parse.quote(SERVICE_R1_R3_UUID, safe='')
-    reply = do_rest_get_request('/context/{:s}/service/{:s}/connections'.format(context_uuid, service_uuid))
+    service_uuid = urllib.parse.quote('SVC:R1/200==R2/200', safe='')
+    reply = do_rest_get_request('/debug-api/context/{:s}/service/{:s}/connections'.format(context_uuid, service_uuid))
     validate_connections(reply)
 
-def test_rest_get_connection(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    connection_uuid = urllib.parse.quote(CONNECTION_R1_R3_UUID, safe='')
-    reply = do_rest_get_request('/connection/{:s}'.format(connection_uuid))
+def test_rest_get_connection(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+    connection_uuid = urllib.parse.quote('CON:R1/200==R2/200:1', safe='')
+    reply = do_rest_get_request('/debug-api/connection/{:s}'.format(connection_uuid))
     validate_connection(reply)
 
-def test_rest_get_policyrule_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    reply = do_rest_get_request('/policyrule_ids')
-    #validate_policyrule_ids(reply)
+# ----- Policy ---------------------------------------------------------------------------------------------------------
+
+#def test_rest_get_policyrule_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+#    reply = do_rest_get_request('/debug-api/policyrule_ids')
+#    validate_policyrule_ids(reply)
+
+#def test_rest_get_policyrules(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+#    reply = do_rest_get_request('/debug-api/policyrules')
+#    validate_policyrules(reply)
+
+#def test_rest_get_policyrule(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument
+#    policyrule_uuid_quoted = urllib.parse.quote(policyrule_uuid, safe='')
+#    reply = do_rest_get_request('/debug-api/policyrule/{:s}'.format(policyrule_uuid_quoted))
+#    validate_policyrule(reply)
+
+
+# ----- Cleanup Environment --------------------------------------------------------------------------------------------
 
-def test_rest_get_policyrules(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    reply = do_rest_get_request('/policyrules')
-    #validate_policyrules(reply)
+def test_cleanup_environment(context_client : ContextClient) -> None: # pylint: disable=redefined-outer-name
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.topology_ids) == 1
+    assert len(response.service_ids ) == 3
+    assert len(response.slice_ids   ) == 1
 
-def test_rest_get_policyrule(context_service_rest : RestServer): # pylint: disable=redefined-outer-name
-    policyrule_uuid = urllib.parse.quote(POLICYRULE_UUID, safe='')
-    reply = do_rest_get_request('/policyrule/{:s}'.format(policyrule_uuid))
-    #validate_policyrule(reply)
+    # Load descriptors and validate the base scenario
+    descriptor_loader = DescriptorLoader(descriptors_file=DESCRIPTOR_FILE, context_client=context_client)
+    descriptor_loader.validate()
+    descriptor_loader.unload()
+    validate_empty_scenario(context_client)
diff --git a/src/nbi/tests/test_ietf_l3vpn.py b/src/nbi/tests/test_ietf_l3vpn.py
index 17f3c3e93c627c41ddc344e55b3478d13077efb3..da9efdffd4dd6f4b3af956988aa3d51d3e855c84 100644
--- a/src/nbi/tests/test_ietf_l3vpn.py
+++ b/src/nbi/tests/test_ietf_l3vpn.py
@@ -21,7 +21,7 @@ from common.tools.descriptor.Loader import (
 )
 from common.tools.object_factory.Context import json_context_id
 from context.client.ContextClient import ContextClient
-from nbi.service.rest_server import RestServer
+from nbi.service.rest_server.RestServer import RestServer
 from .PrepareTestScenario import ( # pylint: disable=unused-import
     # be careful, order of symbols is important here!
     do_rest_delete_request, do_rest_get_request, do_rest_post_request,
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/main/java/org/etsi/tfs/policy/context/model/DeviceDriverEnum.java b/src/policy/src/main/java/org/etsi/tfs/policy/context/model/DeviceDriverEnum.java
index 63e96a4c61769fbb6a009acf208ef7b4c81200ad..72a1d7136c00d2bac93087d7f8b8f3b7626f9803 100644
--- a/src/policy/src/main/java/org/etsi/tfs/policy/context/model/DeviceDriverEnum.java
+++ b/src/policy/src/main/java/org/etsi/tfs/policy/context/model/DeviceDriverEnum.java
@@ -24,5 +24,8 @@ public enum DeviceDriverEnum {
     IETF_NETWORK_TOPOLOGY,
     ONF_TR_532,
     XR,
-    IETF_L2VPN
+    IETF_L2VPN,
+    GNMI_OPENCONFIG,
+    FLEXSCALE,
+    IETF_ACTN
 }
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..63fb1ad7a72d74cf52148027f4fc0e0546b0b58e 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,13 @@ 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/policy/target/generated-sources/grpc/context/ContextOuterClass.java b/src/policy/target/generated-sources/grpc/context/ContextOuterClass.java
index a25798b884d9006f9c1b218c133634784f8bf392..d4873899b0113a7356c1c4d6bc2ea9aae2e8b4e5 100644
--- a/src/policy/target/generated-sources/grpc/context/ContextOuterClass.java
+++ b/src/policy/target/generated-sources/grpc/context/ContextOuterClass.java
@@ -185,6 +185,14 @@ public final class ContextOuterClass {
      * <code>DEVICEDRIVER_GNMI_OPENCONFIG = 8;</code>
      */
     DEVICEDRIVER_GNMI_OPENCONFIG(8),
+    /**
+     * <code>DEVICEDRIVER_FLEXSCALE = 9;</code>
+     */
+    DEVICEDRIVER_FLEXSCALE(9),
+    /**
+     * <code>DEVICEDRIVER_IETF_ACTN = 10;</code>
+     */
+    DEVICEDRIVER_IETF_ACTN(10),
     UNRECOGNIZED(-1),
     ;
 
@@ -228,6 +236,14 @@ public final class ContextOuterClass {
      * <code>DEVICEDRIVER_GNMI_OPENCONFIG = 8;</code>
      */
     public static final int DEVICEDRIVER_GNMI_OPENCONFIG_VALUE = 8;
+    /**
+     * <code>DEVICEDRIVER_FLEXSCALE = 9;</code>
+     */
+    public static final int DEVICEDRIVER_FLEXSCALE_VALUE = 9;
+    /**
+     * <code>DEVICEDRIVER_IETF_ACTN = 10;</code>
+     */
+    public static final int DEVICEDRIVER_IETF_ACTN_VALUE = 10;
 
 
     public final int getNumber() {
@@ -263,6 +279,8 @@ public final class ContextOuterClass {
         case 6: return DEVICEDRIVER_XR;
         case 7: return DEVICEDRIVER_IETF_L2VPN;
         case 8: return DEVICEDRIVER_GNMI_OPENCONFIG;
+        case 9: return DEVICEDRIVER_FLEXSCALE;
+        case 10: return DEVICEDRIVER_IETF_ACTN;
         default: return null;
       }
     }
@@ -461,6 +479,10 @@ public final class ContextOuterClass {
      * <code>SERVICETYPE_TE = 4;</code>
      */
     SERVICETYPE_TE(4),
+    /**
+     * <code>SERVICETYPE_E2E = 5;</code>
+     */
+    SERVICETYPE_E2E(5),
     UNRECOGNIZED(-1),
     ;
 
@@ -484,6 +506,10 @@ public final class ContextOuterClass {
      * <code>SERVICETYPE_TE = 4;</code>
      */
     public static final int SERVICETYPE_TE_VALUE = 4;
+    /**
+     * <code>SERVICETYPE_E2E = 5;</code>
+     */
+    public static final int SERVICETYPE_E2E_VALUE = 5;
 
 
     public final int getNumber() {
@@ -515,6 +541,7 @@ public final class ContextOuterClass {
         case 2: return SERVICETYPE_L2NM;
         case 3: return SERVICETYPE_TAPI_CONNECTIVITY_SERVICE;
         case 4: return SERVICETYPE_TE;
+        case 5: return SERVICETYPE_E2E;
         default: return null;
       }
     }
@@ -75826,114 +75853,116 @@ public final class ContextOuterClass {
       "\0132\022.context.ContextId\022\025\n\rauthenticated\030\002" +
       " \001(\010*j\n\rEventTypeEnum\022\027\n\023EVENTTYPE_UNDEF" +
       "INED\020\000\022\024\n\020EVENTTYPE_CREATE\020\001\022\024\n\020EVENTTYP" +
-      "E_UPDATE\020\002\022\024\n\020EVENTTYPE_REMOVE\020\003*\231\002\n\020Dev" +
+      "E_UPDATE\020\002\022\024\n\020EVENTTYPE_REMOVE\020\003*\321\002\n\020Dev" +
       "iceDriverEnum\022\032\n\026DEVICEDRIVER_UNDEFINED\020" +
       "\000\022\033\n\027DEVICEDRIVER_OPENCONFIG\020\001\022\036\n\032DEVICE" +
       "DRIVER_TRANSPORT_API\020\002\022\023\n\017DEVICEDRIVER_P" +
       "4\020\003\022&\n\"DEVICEDRIVER_IETF_NETWORK_TOPOLOG" +
       "Y\020\004\022\033\n\027DEVICEDRIVER_ONF_TR_532\020\005\022\023\n\017DEVI" +
       "CEDRIVER_XR\020\006\022\033\n\027DEVICEDRIVER_IETF_L2VPN" +
-      "\020\007\022 \n\034DEVICEDRIVER_GNMI_OPENCONFIG\020\010*\217\001\n" +
-      "\033DeviceOperationalStatusEnum\022%\n!DEVICEOP" +
-      "ERATIONALSTATUS_UNDEFINED\020\000\022$\n DEVICEOPE" +
-      "RATIONALSTATUS_DISABLED\020\001\022#\n\037DEVICEOPERA" +
-      "TIONALSTATUS_ENABLED\020\002*\225\001\n\017ServiceTypeEn" +
-      "um\022\027\n\023SERVICETYPE_UNKNOWN\020\000\022\024\n\020SERVICETY" +
-      "PE_L3NM\020\001\022\024\n\020SERVICETYPE_L2NM\020\002\022)\n%SERVI" +
-      "CETYPE_TAPI_CONNECTIVITY_SERVICE\020\003\022\022\n\016SE" +
-      "RVICETYPE_TE\020\004*\304\001\n\021ServiceStatusEnum\022\033\n\027" +
-      "SERVICESTATUS_UNDEFINED\020\000\022\031\n\025SERVICESTAT" +
-      "US_PLANNED\020\001\022\030\n\024SERVICESTATUS_ACTIVE\020\002\022\032" +
-      "\n\026SERVICESTATUS_UPDATING\020\003\022!\n\035SERVICESTA" +
-      "TUS_PENDING_REMOVAL\020\004\022\036\n\032SERVICESTATUS_S" +
-      "LA_VIOLATED\020\005*\251\001\n\017SliceStatusEnum\022\031\n\025SLI" +
-      "CESTATUS_UNDEFINED\020\000\022\027\n\023SLICESTATUS_PLAN" +
-      "NED\020\001\022\024\n\020SLICESTATUS_INIT\020\002\022\026\n\022SLICESTAT" +
-      "US_ACTIVE\020\003\022\026\n\022SLICESTATUS_DEINIT\020\004\022\034\n\030S" +
-      "LICESTATUS_SLA_VIOLATED\020\005*]\n\020ConfigActio" +
-      "nEnum\022\032\n\026CONFIGACTION_UNDEFINED\020\000\022\024\n\020CON" +
-      "FIGACTION_SET\020\001\022\027\n\023CONFIGACTION_DELETE\020\002" +
-      "*m\n\024ConstraintActionEnum\022\036\n\032CONSTRAINTAC" +
-      "TION_UNDEFINED\020\000\022\030\n\024CONSTRAINTACTION_SET" +
-      "\020\001\022\033\n\027CONSTRAINTACTION_DELETE\020\002*\203\002\n\022Isol" +
-      "ationLevelEnum\022\020\n\014NO_ISOLATION\020\000\022\026\n\022PHYS" +
-      "ICAL_ISOLATION\020\001\022\025\n\021LOGICAL_ISOLATION\020\002\022" +
-      "\025\n\021PROCESS_ISOLATION\020\003\022\035\n\031PHYSICAL_MEMOR" +
-      "Y_ISOLATION\020\004\022\036\n\032PHYSICAL_NETWORK_ISOLAT" +
-      "ION\020\005\022\036\n\032VIRTUAL_RESOURCE_ISOLATION\020\006\022\037\n" +
-      "\033NETWORK_FUNCTIONS_ISOLATION\020\007\022\025\n\021SERVIC" +
-      "E_ISOLATION\020\0102\245\026\n\016ContextService\022:\n\016List" +
-      "ContextIds\022\016.context.Empty\032\026.context.Con" +
-      "textIdList\"\000\0226\n\014ListContexts\022\016.context.E" +
-      "mpty\032\024.context.ContextList\"\000\0224\n\nGetConte" +
-      "xt\022\022.context.ContextId\032\020.context.Context" +
-      "\"\000\0224\n\nSetContext\022\020.context.Context\032\022.con" +
-      "text.ContextId\"\000\0225\n\rRemoveContext\022\022.cont" +
-      "ext.ContextId\032\016.context.Empty\"\000\022=\n\020GetCo" +
-      "ntextEvents\022\016.context.Empty\032\025.context.Co" +
-      "ntextEvent\"\0000\001\022@\n\017ListTopologyIds\022\022.cont" +
-      "ext.ContextId\032\027.context.TopologyIdList\"\000" +
-      "\022=\n\016ListTopologies\022\022.context.ContextId\032\025" +
-      ".context.TopologyList\"\000\0227\n\013GetTopology\022\023" +
-      ".context.TopologyId\032\021.context.Topology\"\000" +
-      "\022E\n\022GetTopologyDetails\022\023.context.Topolog" +
-      "yId\032\030.context.TopologyDetails\"\000\0227\n\013SetTo" +
-      "pology\022\021.context.Topology\032\023.context.Topo" +
-      "logyId\"\000\0227\n\016RemoveTopology\022\023.context.Top" +
-      "ologyId\032\016.context.Empty\"\000\022?\n\021GetTopology" +
-      "Events\022\016.context.Empty\032\026.context.Topolog" +
-      "yEvent\"\0000\001\0228\n\rListDeviceIds\022\016.context.Em" +
-      "pty\032\025.context.DeviceIdList\"\000\0224\n\013ListDevi" +
-      "ces\022\016.context.Empty\032\023.context.DeviceList" +
-      "\"\000\0221\n\tGetDevice\022\021.context.DeviceId\032\017.con" +
-      "text.Device\"\000\0221\n\tSetDevice\022\017.context.Dev" +
-      "ice\032\021.context.DeviceId\"\000\0223\n\014RemoveDevice" +
-      "\022\021.context.DeviceId\032\016.context.Empty\"\000\022;\n" +
-      "\017GetDeviceEvents\022\016.context.Empty\032\024.conte" +
-      "xt.DeviceEvent\"\0000\001\022<\n\014SelectDevice\022\025.con" +
-      "text.DeviceFilter\032\023.context.DeviceList\"\000" +
-      "\022I\n\021ListEndPointNames\022\027.context.EndPoint" +
-      "IdList\032\031.context.EndPointNameList\"\000\0224\n\013L" +
-      "istLinkIds\022\016.context.Empty\032\023.context.Lin" +
-      "kIdList\"\000\0220\n\tListLinks\022\016.context.Empty\032\021" +
-      ".context.LinkList\"\000\022+\n\007GetLink\022\017.context" +
-      ".LinkId\032\r.context.Link\"\000\022+\n\007SetLink\022\r.co" +
-      "ntext.Link\032\017.context.LinkId\"\000\022/\n\nRemoveL" +
-      "ink\022\017.context.LinkId\032\016.context.Empty\"\000\0227" +
-      "\n\rGetLinkEvents\022\016.context.Empty\032\022.contex" +
-      "t.LinkEvent\"\0000\001\022>\n\016ListServiceIds\022\022.cont" +
-      "ext.ContextId\032\026.context.ServiceIdList\"\000\022" +
-      ":\n\014ListServices\022\022.context.ContextId\032\024.co" +
-      "ntext.ServiceList\"\000\0224\n\nGetService\022\022.cont" +
-      "ext.ServiceId\032\020.context.Service\"\000\0224\n\nSet" +
-      "Service\022\020.context.Service\032\022.context.Serv" +
-      "iceId\"\000\0226\n\014UnsetService\022\020.context.Servic" +
-      "e\032\022.context.ServiceId\"\000\0225\n\rRemoveService" +
-      "\022\022.context.ServiceId\032\016.context.Empty\"\000\022=" +
-      "\n\020GetServiceEvents\022\016.context.Empty\032\025.con" +
-      "text.ServiceEvent\"\0000\001\022?\n\rSelectService\022\026" +
-      ".context.ServiceFilter\032\024.context.Service" +
-      "List\"\000\022:\n\014ListSliceIds\022\022.context.Context" +
-      "Id\032\024.context.SliceIdList\"\000\0226\n\nListSlices" +
-      "\022\022.context.ContextId\032\022.context.SliceList" +
-      "\"\000\022.\n\010GetSlice\022\020.context.SliceId\032\016.conte" +
-      "xt.Slice\"\000\022.\n\010SetSlice\022\016.context.Slice\032\020" +
-      ".context.SliceId\"\000\0220\n\nUnsetSlice\022\016.conte" +
-      "xt.Slice\032\020.context.SliceId\"\000\0221\n\013RemoveSl" +
-      "ice\022\020.context.SliceId\032\016.context.Empty\"\000\022" +
-      "9\n\016GetSliceEvents\022\016.context.Empty\032\023.cont" +
-      "ext.SliceEvent\"\0000\001\0229\n\013SelectSlice\022\024.cont" +
-      "ext.SliceFilter\032\022.context.SliceList\"\000\022D\n" +
-      "\021ListConnectionIds\022\022.context.ServiceId\032\031" +
-      ".context.ConnectionIdList\"\000\022@\n\017ListConne" +
-      "ctions\022\022.context.ServiceId\032\027.context.Con" +
-      "nectionList\"\000\022=\n\rGetConnection\022\025.context" +
-      ".ConnectionId\032\023.context.Connection\"\000\022=\n\r" +
-      "SetConnection\022\023.context.Connection\032\025.con" +
-      "text.ConnectionId\"\000\022;\n\020RemoveConnection\022" +
-      "\025.context.ConnectionId\032\016.context.Empty\"\000" +
-      "\022C\n\023GetConnectionEvents\022\016.context.Empty\032" +
-      "\030.context.ConnectionEvent\"\0000\001b\006proto3"
+      "\020\007\022 \n\034DEVICEDRIVER_GNMI_OPENCONFIG\020\010\022\032\n\026" +
+      "DEVICEDRIVER_FLEXSCALE\020\t\022\032\n\026DEVICEDRIVER" +
+      "_IETF_ACTN\020\n*\217\001\n\033DeviceOperationalStatus" +
+      "Enum\022%\n!DEVICEOPERATIONALSTATUS_UNDEFINE" +
+      "D\020\000\022$\n DEVICEOPERATIONALSTATUS_DISABLED\020" +
+      "\001\022#\n\037DEVICEOPERATIONALSTATUS_ENABLED\020\002*\252" +
+      "\001\n\017ServiceTypeEnum\022\027\n\023SERVICETYPE_UNKNOW" +
+      "N\020\000\022\024\n\020SERVICETYPE_L3NM\020\001\022\024\n\020SERVICETYPE" +
+      "_L2NM\020\002\022)\n%SERVICETYPE_TAPI_CONNECTIVITY" +
+      "_SERVICE\020\003\022\022\n\016SERVICETYPE_TE\020\004\022\023\n\017SERVIC" +
+      "ETYPE_E2E\020\005*\304\001\n\021ServiceStatusEnum\022\033\n\027SER" +
+      "VICESTATUS_UNDEFINED\020\000\022\031\n\025SERVICESTATUS_" +
+      "PLANNED\020\001\022\030\n\024SERVICESTATUS_ACTIVE\020\002\022\032\n\026S" +
+      "ERVICESTATUS_UPDATING\020\003\022!\n\035SERVICESTATUS" +
+      "_PENDING_REMOVAL\020\004\022\036\n\032SERVICESTATUS_SLA_" +
+      "VIOLATED\020\005*\251\001\n\017SliceStatusEnum\022\031\n\025SLICES" +
+      "TATUS_UNDEFINED\020\000\022\027\n\023SLICESTATUS_PLANNED" +
+      "\020\001\022\024\n\020SLICESTATUS_INIT\020\002\022\026\n\022SLICESTATUS_" +
+      "ACTIVE\020\003\022\026\n\022SLICESTATUS_DEINIT\020\004\022\034\n\030SLIC" +
+      "ESTATUS_SLA_VIOLATED\020\005*]\n\020ConfigActionEn" +
+      "um\022\032\n\026CONFIGACTION_UNDEFINED\020\000\022\024\n\020CONFIG" +
+      "ACTION_SET\020\001\022\027\n\023CONFIGACTION_DELETE\020\002*m\n" +
+      "\024ConstraintActionEnum\022\036\n\032CONSTRAINTACTIO" +
+      "N_UNDEFINED\020\000\022\030\n\024CONSTRAINTACTION_SET\020\001\022" +
+      "\033\n\027CONSTRAINTACTION_DELETE\020\002*\203\002\n\022Isolati" +
+      "onLevelEnum\022\020\n\014NO_ISOLATION\020\000\022\026\n\022PHYSICA" +
+      "L_ISOLATION\020\001\022\025\n\021LOGICAL_ISOLATION\020\002\022\025\n\021" +
+      "PROCESS_ISOLATION\020\003\022\035\n\031PHYSICAL_MEMORY_I" +
+      "SOLATION\020\004\022\036\n\032PHYSICAL_NETWORK_ISOLATION" +
+      "\020\005\022\036\n\032VIRTUAL_RESOURCE_ISOLATION\020\006\022\037\n\033NE" +
+      "TWORK_FUNCTIONS_ISOLATION\020\007\022\025\n\021SERVICE_I" +
+      "SOLATION\020\0102\245\026\n\016ContextService\022:\n\016ListCon" +
+      "textIds\022\016.context.Empty\032\026.context.Contex" +
+      "tIdList\"\000\0226\n\014ListContexts\022\016.context.Empt" +
+      "y\032\024.context.ContextList\"\000\0224\n\nGetContext\022" +
+      "\022.context.ContextId\032\020.context.Context\"\000\022" +
+      "4\n\nSetContext\022\020.context.Context\032\022.contex" +
+      "t.ContextId\"\000\0225\n\rRemoveContext\022\022.context" +
+      ".ContextId\032\016.context.Empty\"\000\022=\n\020GetConte" +
+      "xtEvents\022\016.context.Empty\032\025.context.Conte" +
+      "xtEvent\"\0000\001\022@\n\017ListTopologyIds\022\022.context" +
+      ".ContextId\032\027.context.TopologyIdList\"\000\022=\n" +
+      "\016ListTopologies\022\022.context.ContextId\032\025.co" +
+      "ntext.TopologyList\"\000\0227\n\013GetTopology\022\023.co" +
+      "ntext.TopologyId\032\021.context.Topology\"\000\022E\n" +
+      "\022GetTopologyDetails\022\023.context.TopologyId" +
+      "\032\030.context.TopologyDetails\"\000\0227\n\013SetTopol" +
+      "ogy\022\021.context.Topology\032\023.context.Topolog" +
+      "yId\"\000\0227\n\016RemoveTopology\022\023.context.Topolo" +
+      "gyId\032\016.context.Empty\"\000\022?\n\021GetTopologyEve" +
+      "nts\022\016.context.Empty\032\026.context.TopologyEv" +
+      "ent\"\0000\001\0228\n\rListDeviceIds\022\016.context.Empty" +
+      "\032\025.context.DeviceIdList\"\000\0224\n\013ListDevices" +
+      "\022\016.context.Empty\032\023.context.DeviceList\"\000\022" +
+      "1\n\tGetDevice\022\021.context.DeviceId\032\017.contex" +
+      "t.Device\"\000\0221\n\tSetDevice\022\017.context.Device" +
+      "\032\021.context.DeviceId\"\000\0223\n\014RemoveDevice\022\021." +
+      "context.DeviceId\032\016.context.Empty\"\000\022;\n\017Ge" +
+      "tDeviceEvents\022\016.context.Empty\032\024.context." +
+      "DeviceEvent\"\0000\001\022<\n\014SelectDevice\022\025.contex" +
+      "t.DeviceFilter\032\023.context.DeviceList\"\000\022I\n" +
+      "\021ListEndPointNames\022\027.context.EndPointIdL" +
+      "ist\032\031.context.EndPointNameList\"\000\0224\n\013List" +
+      "LinkIds\022\016.context.Empty\032\023.context.LinkId" +
+      "List\"\000\0220\n\tListLinks\022\016.context.Empty\032\021.co" +
+      "ntext.LinkList\"\000\022+\n\007GetLink\022\017.context.Li" +
+      "nkId\032\r.context.Link\"\000\022+\n\007SetLink\022\r.conte" +
+      "xt.Link\032\017.context.LinkId\"\000\022/\n\nRemoveLink" +
+      "\022\017.context.LinkId\032\016.context.Empty\"\000\0227\n\rG" +
+      "etLinkEvents\022\016.context.Empty\032\022.context.L" +
+      "inkEvent\"\0000\001\022>\n\016ListServiceIds\022\022.context" +
+      ".ContextId\032\026.context.ServiceIdList\"\000\022:\n\014" +
+      "ListServices\022\022.context.ContextId\032\024.conte" +
+      "xt.ServiceList\"\000\0224\n\nGetService\022\022.context" +
+      ".ServiceId\032\020.context.Service\"\000\0224\n\nSetSer" +
+      "vice\022\020.context.Service\032\022.context.Service" +
+      "Id\"\000\0226\n\014UnsetService\022\020.context.Service\032\022" +
+      ".context.ServiceId\"\000\0225\n\rRemoveService\022\022." +
+      "context.ServiceId\032\016.context.Empty\"\000\022=\n\020G" +
+      "etServiceEvents\022\016.context.Empty\032\025.contex" +
+      "t.ServiceEvent\"\0000\001\022?\n\rSelectService\022\026.co" +
+      "ntext.ServiceFilter\032\024.context.ServiceLis" +
+      "t\"\000\022:\n\014ListSliceIds\022\022.context.ContextId\032" +
+      "\024.context.SliceIdList\"\000\0226\n\nListSlices\022\022." +
+      "context.ContextId\032\022.context.SliceList\"\000\022" +
+      ".\n\010GetSlice\022\020.context.SliceId\032\016.context." +
+      "Slice\"\000\022.\n\010SetSlice\022\016.context.Slice\032\020.co" +
+      "ntext.SliceId\"\000\0220\n\nUnsetSlice\022\016.context." +
+      "Slice\032\020.context.SliceId\"\000\0221\n\013RemoveSlice" +
+      "\022\020.context.SliceId\032\016.context.Empty\"\000\0229\n\016" +
+      "GetSliceEvents\022\016.context.Empty\032\023.context" +
+      ".SliceEvent\"\0000\001\0229\n\013SelectSlice\022\024.context" +
+      ".SliceFilter\032\022.context.SliceList\"\000\022D\n\021Li" +
+      "stConnectionIds\022\022.context.ServiceId\032\031.co" +
+      "ntext.ConnectionIdList\"\000\022@\n\017ListConnecti" +
+      "ons\022\022.context.ServiceId\032\027.context.Connec" +
+      "tionList\"\000\022=\n\rGetConnection\022\025.context.Co" +
+      "nnectionId\032\023.context.Connection\"\000\022=\n\rSet" +
+      "Connection\022\023.context.Connection\032\025.contex" +
+      "t.ConnectionId\"\000\022;\n\020RemoveConnection\022\025.c" +
+      "ontext.ConnectionId\032\016.context.Empty\"\000\022C\n" +
+      "\023GetConnectionEvents\022\016.context.Empty\032\030.c" +
+      "ontext.ConnectionEvent\"\0000\001b\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
diff --git a/src/policy/target/kubernetes/kubernetes.yml b/src/policy/target/kubernetes/kubernetes.yml
index 5cd1f1c4c1b4ce437c16707018f83ef6ec60215a..55847f89e7c031de854d1e54336342f7a24e320a 100644
--- a/src/policy/target/kubernetes/kubernetes.yml
+++ b/src/policy/target/kubernetes/kubernetes.yml
@@ -3,8 +3,8 @@ apiVersion: v1
 kind: Service
 metadata:
   annotations:
-    app.quarkus.io/commit-id: 46486023929121fc955e9550fc8fd625ded433d2
-    app.quarkus.io/build-timestamp: 2023-12-15 - 11:56:20 +0000
+    app.quarkus.io/commit-id: 5f8866be9cb91871607627819258b0b375410467
+    app.quarkus.io/build-timestamp: 2024-01-26 - 16:40:15 +0000
     prometheus.io/scrape: "true"
     prometheus.io/path: /q/metrics
     prometheus.io/port: "8080"
@@ -15,12 +15,12 @@ metadata:
   name: policyservice
 spec:
   ports:
-    - name: grpc-server
-      port: 6060
-      targetPort: 6060
     - name: http
       port: 9192
       targetPort: 8080
+    - name: grpc-server
+      port: 6060
+      targetPort: 6060
   selector:
     app.kubernetes.io/name: policyservice
   type: ClusterIP
@@ -29,8 +29,8 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   annotations:
-    app.quarkus.io/commit-id: 46486023929121fc955e9550fc8fd625ded433d2
-    app.quarkus.io/build-timestamp: 2023-12-15 - 11:56:20 +0000
+    app.quarkus.io/commit-id: 5f8866be9cb91871607627819258b0b375410467
+    app.quarkus.io/build-timestamp: 2024-01-26 - 16:40:15 +0000
     prometheus.io/scrape: "true"
     prometheus.io/path: /q/metrics
     prometheus.io/port: "8080"
@@ -47,8 +47,8 @@ spec:
   template:
     metadata:
       annotations:
-        app.quarkus.io/commit-id: 46486023929121fc955e9550fc8fd625ded433d2
-        app.quarkus.io/build-timestamp: 2023-12-15 - 11:56:20 +0000
+        app.quarkus.io/commit-id: 5f8866be9cb91871607627819258b0b375410467
+        app.quarkus.io/build-timestamp: 2024-01-26 - 16:40:15 +0000
         prometheus.io/scrape: "true"
         prometheus.io/path: /q/metrics
         prometheus.io/port: "8080"
@@ -63,12 +63,12 @@ spec:
               valueFrom:
                 fieldRef:
                   fieldPath: metadata.namespace
-            - name: CONTEXT_SERVICE_HOST
-              value: contextservice
-            - name: MONITORING_SERVICE_HOST
-              value: monitoringservice
             - name: SERVICE_SERVICE_HOST
               value: serviceservice
+            - name: MONITORING_SERVICE_HOST
+              value: monitoringservice
+            - name: CONTEXT_SERVICE_HOST
+              value: contextservice
           image: labs.etsi.org:5050/tfs/controller/policy:0.1.0
           imagePullPolicy: Always
           livenessProbe:
@@ -83,12 +83,12 @@ spec:
             timeoutSeconds: 10
           name: policyservice
           ports:
-            - containerPort: 6060
-              name: grpc-server
-              protocol: TCP
             - containerPort: 8080
               name: http
               protocol: TCP
+            - containerPort: 6060
+              name: grpc-server
+              protocol: TCP
           readinessProbe:
             failureThreshold: 3
             httpGet:
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/tests/tools/mock_ietf_actn_sdn_ctrl/Dockerfile b/src/tests/tools/mock_ietf_actn_sdn_ctrl/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..05c785fb1a353db544d58d0953bc1cc99881a693
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/Dockerfile
@@ -0,0 +1,37 @@
+# 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 python:3.9-slim
+
+# Set Python to show logs as they occur
+ENV PYTHONUNBUFFERED=0
+
+# Get generic Python packages
+RUN python3 -m pip install --upgrade pip
+RUN python3 -m pip install --upgrade setuptools wheel
+RUN python3 -m pip install --upgrade pip-tools
+
+# Create component sub-folders, and copy content
+RUN mkdir -p /var/teraflow/mock_ietf_actn_sdn_ctrl
+WORKDIR /var/teraflow/mock_ietf_actn_sdn_ctrl
+COPY . .
+
+# Get specific Python packages
+RUN pip-compile --quiet --output-file=requirements.txt requirements.in
+RUN python3 -m pip install -r requirements.txt
+
+RUN python3 -m pip list
+
+# Start the service
+ENTRYPOINT ["python", "MockIetfActnSdnCtrl.py"]
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py b/src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py
new file mode 100644
index 0000000000000000000000000000000000000000..c459c294ccb1c457c258a4e80018a90244702b8b
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py
@@ -0,0 +1,80 @@
+# 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.
+
+# Mock IETF ACTN SDN controller
+# -----------------------------
+# REST server implementing minimal support for:
+# - IETF YANG Data Model for Transport Network Client Signals
+#       Ref: https://www.ietf.org/archive/id/draft-ietf-ccamp-client-signal-yang-10.html
+# - IETF YANG Data Model for Traffic Engineering Tunnels, Label Switched Paths and Interfaces
+#       Ref: https://www.ietf.org/archive/id/draft-ietf-teas-yang-te-34.html
+
+
+import functools, logging, sys, time
+from flask import Flask, jsonify, make_response, request
+from flask_restful import Api, Resource
+from ResourceEthServices import EthService, EthServices
+from ResourceOsuTunnels import OsuTunnel, OsuTunnels
+
+BIND_ADDRESS = '0.0.0.0'
+BIND_PORT    = 8443
+BASE_URL     = '/restconf/data'
+STR_ENDPOINT = 'https://{:s}:{:s}{:s}'.format(str(BIND_ADDRESS), str(BIND_PORT), str(BASE_URL))
+LOG_LEVEL    = logging.DEBUG
+
+logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s")
+LOGGER = logging.getLogger(__name__)
+
+logging.getLogger('werkzeug').setLevel(logging.WARNING)
+
+def log_request(logger : logging.Logger, response):
+    timestamp = time.strftime('[%Y-%b-%d %H:%M]')
+    logger.info('%s %s %s %s %s', timestamp, request.remote_addr, request.method, request.full_path, response.status)
+    return response
+
+class Health(Resource):
+    def get(self):
+        return make_response(jsonify({}), 200)
+
+def main():
+    LOGGER.info('Starting...')
+    
+    app = Flask(__name__)
+    app.after_request(functools.partial(log_request, LOGGER))
+
+    api = Api(app, prefix=BASE_URL)
+    api.add_resource(
+        Health, '/'
+    )
+    api.add_resource(
+        OsuTunnels, '/ietf-te:te/tunnels'
+    )
+    api.add_resource(
+        OsuTunnel, '/ietf-te:te/tunnels/tunnel="<string:osu_tunnel_name>"'
+    )
+    api.add_resource(
+        EthServices, '/ietf-eth-tran-service:etht-svc'
+    )
+    api.add_resource(
+        EthService, '/ietf-eth-tran-service:etht-svc/etht-svc-instances="<string:etht_service_name>"'
+    )
+
+    LOGGER.info('Listening on {:s}...'.format(str(STR_ENDPOINT)))
+    app.run(debug=True, host=BIND_ADDRESS, port=BIND_PORT, ssl_context='adhoc')
+
+    LOGGER.info('Bye')
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/README.md b/src/tests/tools/mock_ietf_actn_sdn_ctrl/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a12ae907e792f98413903b6637738c392506be4a
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/README.md
@@ -0,0 +1,53 @@
+# Mock IETF ACTN SDN Controller
+
+This REST server implements very basic support for the following YANG data models:
+- IETF YANG Data Model for Transport Network Client Signals (draft-ietf-ccamp-client-signal-yang-10)
+  - Ref: https://datatracker.ietf.org/doc/draft-ietf-ccamp-client-signal-yang/
+- IETF YANG Data Model for Traffic Engineering Tunnels, Label Switched Paths and Interfaces (draft-ietf-teas-yang-te-34)
+  - Ref: https://datatracker.ietf.org/doc/draft-ietf-teas-yang-te/
+
+The aim of this server is to enable testing the IetfActnDeviceDriver and the IetfActnServiceHandler.
+Follow the steps below to perform the test:
+
+## 1. Deploy TeraFlowSDN controller and the scenario
+Deploy the test scenario "ietf_actn_deploy.sh":
+```bash
+source src/tests/tools/mock_ietf_actn_sdn_ctrl/scenario/ietf_actn_deploy.sh
+./deploy/all.sh
+```
+
+## 2. Install requirements and run the Mock IETF ACTN SDN controller
+__NOTE__: if you run the Mock IETF ACTN SDN controller from the PyEnv used for developping on the TeraFlowSDN framework,
+all the requirements are already in place. Install them only if you execute it in a separate/standalone environment.
+
+Install the required dependencies as follows:
+```bash
+pip install Flask==2.1.3 Flask-RESTful==0.3.9
+```
+
+Run the Mock IETF ACTN SDN Controller as follows:
+```bash
+python src/tests/tools/mock_ietf_actn_sdn_ctrl/MockIetfActnSdnCtrl.py
+```
+
+## 3. Deploy the test descriptors
+Edit the descriptors to meet your environment specifications.
+Edit "network_descriptors.json" and change IP address and port of the IETF ACTN SDN controller of the "ACTN" device.
+- Set value of config rule "_connect/address" to the address of the host where the Mock IETF ACTN SDN controller is
+  running (default="192.168.1.1").
+- Set value of config rule "_connect/port" to the port where your Mock IETF ACTN SDN controller is listening on
+  (default="8443").
+
+Upload the "network_descriptors.json" through the TeraFlowSDN WebUI.
+- If not already selected, select Context(admin)/Topology(admin).
+- Check that a network topology with 4 routers + 1 IETF ACTN radio system are loaded. They should form 2 rings.
+
+Upload the "service_descriptor.json" through the TeraFlowSDN WebUI.
+- Check that 2 services have been created.
+- The "actn-svc" should have a connection and be supported by a sub-service.
+- The sub-service should also have a connection.
+- The R1, R3, and MW devices should have configuration rules established.
+
+# 4. Delete the IETF ACTN service
+Find the "mw-svc" on the WebUI, navigate to its details, and delete the service pressing the "Delete Service" button.
+The service, sub-service, and device configuration rules should be removed.
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/ResourceEthServices.py b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ResourceEthServices.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e08bbdaa48df2ae7338a96d727fdc9f876784e6
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ResourceEthServices.py
@@ -0,0 +1,53 @@
+# 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.
+
+# REST-API resource implementing minimal support for "IETF YANG Data Model for Transport Network Client Signals".
+# Ref: https://www.ietf.org/archive/id/draft-ietf-ccamp-client-signal-yang-10.html
+
+from flask import abort, jsonify, make_response, request
+from flask_restful import Resource
+
+ETHT_SERVICES = {}
+
+class EthServices(Resource):
+    def get(self):
+        etht_services = [etht_service for etht_service in ETHT_SERVICES.values()]
+        data = {'ietf-eth-tran-service:etht-svc': {'etht-svc-instances': etht_services}}
+        return make_response(jsonify(data), 200)
+
+    def post(self):
+        json_request = request.get_json()
+        if not json_request: abort(400)
+        if not isinstance(json_request, dict): abort(400)
+        if 'ietf-eth-tran-service:etht-svc' not in json_request: abort(400)
+        json_request = json_request['ietf-eth-tran-service:etht-svc']
+        if 'etht-svc-instances' not in json_request: abort(400)
+        etht_services = json_request['etht-svc-instances']
+        if not isinstance(etht_services, list): abort(400)
+        if len(etht_services) != 1: abort(400)
+        etht_service = etht_services[0]
+        etht_service_name = etht_service['etht-svc-name']
+        ETHT_SERVICES[etht_service_name] = etht_service
+        return make_response(jsonify({}), 201)
+
+class EthService(Resource):
+    def get(self, etht_service_name : str):
+        etht_service = ETHT_SERVICES.get(etht_service_name, None)
+        data,status = ({}, 404) if etht_service is None else (etht_service, 200)
+        return make_response(jsonify(data), status)
+
+    def delete(self, etht_service_name : str):
+        etht_service = ETHT_SERVICES.pop(etht_service_name, None)
+        data,status = ({}, 404) if etht_service is None else (etht_service, 204)
+        return make_response(jsonify(data), status)
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/ResourceOsuTunnels.py b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ResourceOsuTunnels.py
new file mode 100644
index 0000000000000000000000000000000000000000..914f7096da4101a138ac9b0cdd2911dfcf22bb61
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/ResourceOsuTunnels.py
@@ -0,0 +1,53 @@
+# 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.
+
+# REST-API resource implementing minimal support for "IETF YANG Data Model for Traffic Engineering Tunnels,
+# Label Switched Paths and Interfaces".
+# Ref: https://www.ietf.org/archive/id/draft-ietf-teas-yang-te-34.html
+
+
+from flask import abort, jsonify, make_response, request
+from flask_restful import Resource
+
+OSU_TUNNELS = {}
+
+class OsuTunnels(Resource):
+    def get(self):
+        osu_tunnels = [osu_tunnel for osu_tunnel in OSU_TUNNELS.values()]
+        data = {'ietf-te:tunnel': osu_tunnels}
+        return make_response(jsonify(data), 200)
+
+    def post(self):
+        json_request = request.get_json()
+        if not json_request: abort(400)
+        if not isinstance(json_request, dict): abort(400)
+        if 'ietf-te:tunnel' not in json_request: abort(400)
+        osu_tunnels = json_request['ietf-te:tunnel']
+        if not isinstance(osu_tunnels, list): abort(400)
+        if len(osu_tunnels) != 1: abort(400)
+        osu_tunnel = osu_tunnels[0]
+        osu_tunnel_name = osu_tunnel['name']
+        OSU_TUNNELS[osu_tunnel_name] = osu_tunnel
+        return make_response(jsonify({}), 201)
+
+class OsuTunnel(Resource):
+    def get(self, osu_tunnel_name : str):
+        osu_tunnel = OSU_TUNNELS.get(osu_tunnel_name, None)
+        data,status = ({}, 404) if osu_tunnel is None else (osu_tunnel, 200)
+        return make_response(jsonify(data), status)
+
+    def delete(self, osu_tunnel_name : str):
+        osu_tunnel = OSU_TUNNELS.pop(osu_tunnel_name, None)
+        data,status = ({}, 404) if osu_tunnel is None else (osu_tunnel, 204)
+        return make_response(jsonify(data), status)
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/__init__.py b/src/tests/tools/mock_ietf_actn_sdn_ctrl/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/__init__.py
@@ -0,0 +1,14 @@
+# 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.
+
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/build.sh b/src/tests/tools/mock_ietf_actn_sdn_ctrl/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..d9db334cbf1d361cc9cbce42f95fb10bafc609ed
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/build.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+# 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.
+
+docker build -t mock-ietf-actn-sdn-ctrl:test -f Dockerfile .
+docker tag mock-ietf-actn-sdn-ctrl:test localhost:32000/tfs/mock-ietf-actn-sdn-ctrl:test
+docker push localhost:32000/tfs/mock-ietf-actn-sdn-ctrl:test
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/deploy.sh b/src/tests/tools/mock_ietf_actn_sdn_ctrl/deploy.sh
new file mode 100755
index 0000000000000000000000000000000000000000..47270dc4beafc3828b69ca77eed443f2e16528a5
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/deploy.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# 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.
+
+kubectl delete namespace mocks
+kubectl --namespace mocks apply -f mock-ietf-actn-sdn-ctrl.yaml
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/mock-ietf-actn-sdn-ctrl.yaml b/src/tests/tools/mock_ietf_actn_sdn_ctrl/mock-ietf-actn-sdn-ctrl.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..32cfd922896f6e8860ae07049657b97b0da90c3a
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/mock-ietf-actn-sdn-ctrl.yaml
@@ -0,0 +1,64 @@
+# 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.
+
+kind: Namespace
+apiVersion: v1
+metadata:
+  name: mocks
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: mock-ietf-actn-sdn-ctrl
+spec:
+  selector:
+    matchLabels:
+      app: mock-ietf-actn-sdn-ctrl
+  replicas: 1
+  template:
+    metadata:
+      annotations:
+        config.linkerd.io/skip-inbound-ports: "8443"
+      labels:
+        app: mock-ietf-actn-sdn-ctrl
+    spec:
+      terminationGracePeriodSeconds: 5
+      containers:
+      - name: server
+        image: localhost:32000/tfs/mock-ietf-actn-sdn-ctrl:test
+        imagePullPolicy: IfNotPresent
+        ports:
+        - containerPort: 8443
+        resources:
+          requests:
+            cpu: 250m
+            memory: 512Mi
+          limits:
+            cpu: 700m
+            memory: 1024Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: mock-ietf-actn-sdn-ctrl
+  labels:
+    app: mock-ietf-actn-sdn-ctrl
+spec:
+  type: ClusterIP
+  selector:
+    app: mock-ietf-actn-sdn-ctrl
+  ports:
+  - name: https
+    port: 8443
+    targetPort: 8443
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/requirements.in b/src/tests/tools/mock_ietf_actn_sdn_ctrl/requirements.in
new file mode 100644
index 0000000000000000000000000000000000000000..d91775403366e93a4612296faa6a7d5fa527249a
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/requirements.in
@@ -0,0 +1,22 @@
+# 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.
+
+cryptography==39.0.1
+pyopenssl==23.0.0
+Flask==2.1.3
+Flask-HTTPAuth==4.5.0
+Flask-RESTful==0.3.9
+jsonschema==4.4.0
+requests==2.27.1
+werkzeug==2.3.7
diff --git a/src/tests/tools/mock_ietf_actn_sdn_ctrl/run.sh b/src/tests/tools/mock_ietf_actn_sdn_ctrl/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2697e538ec69a99da4c0fae898748ff496b5d28f
--- /dev/null
+++ b/src/tests/tools/mock_ietf_actn_sdn_ctrl/run.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+# 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.
+
+python MockIetfActnSdnCtrl.py
diff --git a/src/tests/tools/mock_mw_sdn_ctrl/ssl_not_working/build.sh b/src/tests/tools/mock_mw_sdn_ctrl/ssl_not_working/build.sh
index 4df315cec178cef13eaa059a739bc22efc011d4d..5501614c4fd5079d98b81e7ec78bf56b581c888a 100755
--- a/src/tests/tools/mock_mw_sdn_ctrl/ssl_not_working/build.sh
+++ b/src/tests/tools/mock_mw_sdn_ctrl/ssl_not_working/build.sh
@@ -1,4 +1,17 @@
 #!/bin/bash
+# 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.
 
 docker build -t mock-mw-sdn-ctrl:test -f Dockerfile .
 docker tag mock-mw-sdn-ctrl:test localhost:32000/tfs/mock-mw-sdn-ctrl:test
diff --git a/src/tests/tools/mock_mw_sdn_ctrl/ssl_not_working/deploy.sh b/src/tests/tools/mock_mw_sdn_ctrl/ssl_not_working/deploy.sh
index ded232e5c50f8cd5ed448ec0193f58c43626f4ad..ed77bcfbc1200609aa6a6effeb13e723d9f9979e 100755
--- a/src/tests/tools/mock_mw_sdn_ctrl/ssl_not_working/deploy.sh
+++ b/src/tests/tools/mock_mw_sdn_ctrl/ssl_not_working/deploy.sh
@@ -1,4 +1,17 @@
 #!/bin/bash
+# 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.
 
 kubectl delete namespace mocks
 kubectl --namespace mocks apply -f mock-mw-sdn-ctrl.yaml
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 2106623870add4693bc8ca7312a6c33a462f1eaf..8353fb8b772900b4197f52ce4b08f5649785de1b 100644
--- a/src/webui/service/device/routes.py
+++ b/src/webui/service/device/routes.py
@@ -126,6 +126,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/main/java/org/etsi/tfs/ztp/context/model/DeviceDriverEnum.java b/src/ztp/src/main/java/org/etsi/tfs/ztp/context/model/DeviceDriverEnum.java
index 7c87b0638272edb58ef3cd57d3aad7aa3365cca8..8e89be8a6ddc993e7d90794c756f406fa72104f2 100644
--- a/src/ztp/src/main/java/org/etsi/tfs/ztp/context/model/DeviceDriverEnum.java
+++ b/src/ztp/src/main/java/org/etsi/tfs/ztp/context/model/DeviceDriverEnum.java
@@ -24,5 +24,8 @@ public enum DeviceDriverEnum {
     IETF_NETWORK_TOPOLOGY,
     ONF_TR_532,
     XR,
-    IETF_L2VPN
+    IETF_L2VPN,
+    GNMI_OPENCONFIG,
+    FLEXSCALE,
+    IETF_ACTN
 }
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..67048119d0b0cdb8d1fb2df2dcb2659b0870efb3 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,13 @@ 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/ztp/target/generated-sources/grpc/context/ContextOuterClass.java b/src/ztp/target/generated-sources/grpc/context/ContextOuterClass.java
index a25798b884d9006f9c1b218c133634784f8bf392..d4873899b0113a7356c1c4d6bc2ea9aae2e8b4e5 100644
--- a/src/ztp/target/generated-sources/grpc/context/ContextOuterClass.java
+++ b/src/ztp/target/generated-sources/grpc/context/ContextOuterClass.java
@@ -185,6 +185,14 @@ public final class ContextOuterClass {
      * <code>DEVICEDRIVER_GNMI_OPENCONFIG = 8;</code>
      */
     DEVICEDRIVER_GNMI_OPENCONFIG(8),
+    /**
+     * <code>DEVICEDRIVER_FLEXSCALE = 9;</code>
+     */
+    DEVICEDRIVER_FLEXSCALE(9),
+    /**
+     * <code>DEVICEDRIVER_IETF_ACTN = 10;</code>
+     */
+    DEVICEDRIVER_IETF_ACTN(10),
     UNRECOGNIZED(-1),
     ;
 
@@ -228,6 +236,14 @@ public final class ContextOuterClass {
      * <code>DEVICEDRIVER_GNMI_OPENCONFIG = 8;</code>
      */
     public static final int DEVICEDRIVER_GNMI_OPENCONFIG_VALUE = 8;
+    /**
+     * <code>DEVICEDRIVER_FLEXSCALE = 9;</code>
+     */
+    public static final int DEVICEDRIVER_FLEXSCALE_VALUE = 9;
+    /**
+     * <code>DEVICEDRIVER_IETF_ACTN = 10;</code>
+     */
+    public static final int DEVICEDRIVER_IETF_ACTN_VALUE = 10;
 
 
     public final int getNumber() {
@@ -263,6 +279,8 @@ public final class ContextOuterClass {
         case 6: return DEVICEDRIVER_XR;
         case 7: return DEVICEDRIVER_IETF_L2VPN;
         case 8: return DEVICEDRIVER_GNMI_OPENCONFIG;
+        case 9: return DEVICEDRIVER_FLEXSCALE;
+        case 10: return DEVICEDRIVER_IETF_ACTN;
         default: return null;
       }
     }
@@ -461,6 +479,10 @@ public final class ContextOuterClass {
      * <code>SERVICETYPE_TE = 4;</code>
      */
     SERVICETYPE_TE(4),
+    /**
+     * <code>SERVICETYPE_E2E = 5;</code>
+     */
+    SERVICETYPE_E2E(5),
     UNRECOGNIZED(-1),
     ;
 
@@ -484,6 +506,10 @@ public final class ContextOuterClass {
      * <code>SERVICETYPE_TE = 4;</code>
      */
     public static final int SERVICETYPE_TE_VALUE = 4;
+    /**
+     * <code>SERVICETYPE_E2E = 5;</code>
+     */
+    public static final int SERVICETYPE_E2E_VALUE = 5;
 
 
     public final int getNumber() {
@@ -515,6 +541,7 @@ public final class ContextOuterClass {
         case 2: return SERVICETYPE_L2NM;
         case 3: return SERVICETYPE_TAPI_CONNECTIVITY_SERVICE;
         case 4: return SERVICETYPE_TE;
+        case 5: return SERVICETYPE_E2E;
         default: return null;
       }
     }
@@ -75826,114 +75853,116 @@ public final class ContextOuterClass {
       "\0132\022.context.ContextId\022\025\n\rauthenticated\030\002" +
       " \001(\010*j\n\rEventTypeEnum\022\027\n\023EVENTTYPE_UNDEF" +
       "INED\020\000\022\024\n\020EVENTTYPE_CREATE\020\001\022\024\n\020EVENTTYP" +
-      "E_UPDATE\020\002\022\024\n\020EVENTTYPE_REMOVE\020\003*\231\002\n\020Dev" +
+      "E_UPDATE\020\002\022\024\n\020EVENTTYPE_REMOVE\020\003*\321\002\n\020Dev" +
       "iceDriverEnum\022\032\n\026DEVICEDRIVER_UNDEFINED\020" +
       "\000\022\033\n\027DEVICEDRIVER_OPENCONFIG\020\001\022\036\n\032DEVICE" +
       "DRIVER_TRANSPORT_API\020\002\022\023\n\017DEVICEDRIVER_P" +
       "4\020\003\022&\n\"DEVICEDRIVER_IETF_NETWORK_TOPOLOG" +
       "Y\020\004\022\033\n\027DEVICEDRIVER_ONF_TR_532\020\005\022\023\n\017DEVI" +
       "CEDRIVER_XR\020\006\022\033\n\027DEVICEDRIVER_IETF_L2VPN" +
-      "\020\007\022 \n\034DEVICEDRIVER_GNMI_OPENCONFIG\020\010*\217\001\n" +
-      "\033DeviceOperationalStatusEnum\022%\n!DEVICEOP" +
-      "ERATIONALSTATUS_UNDEFINED\020\000\022$\n DEVICEOPE" +
-      "RATIONALSTATUS_DISABLED\020\001\022#\n\037DEVICEOPERA" +
-      "TIONALSTATUS_ENABLED\020\002*\225\001\n\017ServiceTypeEn" +
-      "um\022\027\n\023SERVICETYPE_UNKNOWN\020\000\022\024\n\020SERVICETY" +
-      "PE_L3NM\020\001\022\024\n\020SERVICETYPE_L2NM\020\002\022)\n%SERVI" +
-      "CETYPE_TAPI_CONNECTIVITY_SERVICE\020\003\022\022\n\016SE" +
-      "RVICETYPE_TE\020\004*\304\001\n\021ServiceStatusEnum\022\033\n\027" +
-      "SERVICESTATUS_UNDEFINED\020\000\022\031\n\025SERVICESTAT" +
-      "US_PLANNED\020\001\022\030\n\024SERVICESTATUS_ACTIVE\020\002\022\032" +
-      "\n\026SERVICESTATUS_UPDATING\020\003\022!\n\035SERVICESTA" +
-      "TUS_PENDING_REMOVAL\020\004\022\036\n\032SERVICESTATUS_S" +
-      "LA_VIOLATED\020\005*\251\001\n\017SliceStatusEnum\022\031\n\025SLI" +
-      "CESTATUS_UNDEFINED\020\000\022\027\n\023SLICESTATUS_PLAN" +
-      "NED\020\001\022\024\n\020SLICESTATUS_INIT\020\002\022\026\n\022SLICESTAT" +
-      "US_ACTIVE\020\003\022\026\n\022SLICESTATUS_DEINIT\020\004\022\034\n\030S" +
-      "LICESTATUS_SLA_VIOLATED\020\005*]\n\020ConfigActio" +
-      "nEnum\022\032\n\026CONFIGACTION_UNDEFINED\020\000\022\024\n\020CON" +
-      "FIGACTION_SET\020\001\022\027\n\023CONFIGACTION_DELETE\020\002" +
-      "*m\n\024ConstraintActionEnum\022\036\n\032CONSTRAINTAC" +
-      "TION_UNDEFINED\020\000\022\030\n\024CONSTRAINTACTION_SET" +
-      "\020\001\022\033\n\027CONSTRAINTACTION_DELETE\020\002*\203\002\n\022Isol" +
-      "ationLevelEnum\022\020\n\014NO_ISOLATION\020\000\022\026\n\022PHYS" +
-      "ICAL_ISOLATION\020\001\022\025\n\021LOGICAL_ISOLATION\020\002\022" +
-      "\025\n\021PROCESS_ISOLATION\020\003\022\035\n\031PHYSICAL_MEMOR" +
-      "Y_ISOLATION\020\004\022\036\n\032PHYSICAL_NETWORK_ISOLAT" +
-      "ION\020\005\022\036\n\032VIRTUAL_RESOURCE_ISOLATION\020\006\022\037\n" +
-      "\033NETWORK_FUNCTIONS_ISOLATION\020\007\022\025\n\021SERVIC" +
-      "E_ISOLATION\020\0102\245\026\n\016ContextService\022:\n\016List" +
-      "ContextIds\022\016.context.Empty\032\026.context.Con" +
-      "textIdList\"\000\0226\n\014ListContexts\022\016.context.E" +
-      "mpty\032\024.context.ContextList\"\000\0224\n\nGetConte" +
-      "xt\022\022.context.ContextId\032\020.context.Context" +
-      "\"\000\0224\n\nSetContext\022\020.context.Context\032\022.con" +
-      "text.ContextId\"\000\0225\n\rRemoveContext\022\022.cont" +
-      "ext.ContextId\032\016.context.Empty\"\000\022=\n\020GetCo" +
-      "ntextEvents\022\016.context.Empty\032\025.context.Co" +
-      "ntextEvent\"\0000\001\022@\n\017ListTopologyIds\022\022.cont" +
-      "ext.ContextId\032\027.context.TopologyIdList\"\000" +
-      "\022=\n\016ListTopologies\022\022.context.ContextId\032\025" +
-      ".context.TopologyList\"\000\0227\n\013GetTopology\022\023" +
-      ".context.TopologyId\032\021.context.Topology\"\000" +
-      "\022E\n\022GetTopologyDetails\022\023.context.Topolog" +
-      "yId\032\030.context.TopologyDetails\"\000\0227\n\013SetTo" +
-      "pology\022\021.context.Topology\032\023.context.Topo" +
-      "logyId\"\000\0227\n\016RemoveTopology\022\023.context.Top" +
-      "ologyId\032\016.context.Empty\"\000\022?\n\021GetTopology" +
-      "Events\022\016.context.Empty\032\026.context.Topolog" +
-      "yEvent\"\0000\001\0228\n\rListDeviceIds\022\016.context.Em" +
-      "pty\032\025.context.DeviceIdList\"\000\0224\n\013ListDevi" +
-      "ces\022\016.context.Empty\032\023.context.DeviceList" +
-      "\"\000\0221\n\tGetDevice\022\021.context.DeviceId\032\017.con" +
-      "text.Device\"\000\0221\n\tSetDevice\022\017.context.Dev" +
-      "ice\032\021.context.DeviceId\"\000\0223\n\014RemoveDevice" +
-      "\022\021.context.DeviceId\032\016.context.Empty\"\000\022;\n" +
-      "\017GetDeviceEvents\022\016.context.Empty\032\024.conte" +
-      "xt.DeviceEvent\"\0000\001\022<\n\014SelectDevice\022\025.con" +
-      "text.DeviceFilter\032\023.context.DeviceList\"\000" +
-      "\022I\n\021ListEndPointNames\022\027.context.EndPoint" +
-      "IdList\032\031.context.EndPointNameList\"\000\0224\n\013L" +
-      "istLinkIds\022\016.context.Empty\032\023.context.Lin" +
-      "kIdList\"\000\0220\n\tListLinks\022\016.context.Empty\032\021" +
-      ".context.LinkList\"\000\022+\n\007GetLink\022\017.context" +
-      ".LinkId\032\r.context.Link\"\000\022+\n\007SetLink\022\r.co" +
-      "ntext.Link\032\017.context.LinkId\"\000\022/\n\nRemoveL" +
-      "ink\022\017.context.LinkId\032\016.context.Empty\"\000\0227" +
-      "\n\rGetLinkEvents\022\016.context.Empty\032\022.contex" +
-      "t.LinkEvent\"\0000\001\022>\n\016ListServiceIds\022\022.cont" +
-      "ext.ContextId\032\026.context.ServiceIdList\"\000\022" +
-      ":\n\014ListServices\022\022.context.ContextId\032\024.co" +
-      "ntext.ServiceList\"\000\0224\n\nGetService\022\022.cont" +
-      "ext.ServiceId\032\020.context.Service\"\000\0224\n\nSet" +
-      "Service\022\020.context.Service\032\022.context.Serv" +
-      "iceId\"\000\0226\n\014UnsetService\022\020.context.Servic" +
-      "e\032\022.context.ServiceId\"\000\0225\n\rRemoveService" +
-      "\022\022.context.ServiceId\032\016.context.Empty\"\000\022=" +
-      "\n\020GetServiceEvents\022\016.context.Empty\032\025.con" +
-      "text.ServiceEvent\"\0000\001\022?\n\rSelectService\022\026" +
-      ".context.ServiceFilter\032\024.context.Service" +
-      "List\"\000\022:\n\014ListSliceIds\022\022.context.Context" +
-      "Id\032\024.context.SliceIdList\"\000\0226\n\nListSlices" +
-      "\022\022.context.ContextId\032\022.context.SliceList" +
-      "\"\000\022.\n\010GetSlice\022\020.context.SliceId\032\016.conte" +
-      "xt.Slice\"\000\022.\n\010SetSlice\022\016.context.Slice\032\020" +
-      ".context.SliceId\"\000\0220\n\nUnsetSlice\022\016.conte" +
-      "xt.Slice\032\020.context.SliceId\"\000\0221\n\013RemoveSl" +
-      "ice\022\020.context.SliceId\032\016.context.Empty\"\000\022" +
-      "9\n\016GetSliceEvents\022\016.context.Empty\032\023.cont" +
-      "ext.SliceEvent\"\0000\001\0229\n\013SelectSlice\022\024.cont" +
-      "ext.SliceFilter\032\022.context.SliceList\"\000\022D\n" +
-      "\021ListConnectionIds\022\022.context.ServiceId\032\031" +
-      ".context.ConnectionIdList\"\000\022@\n\017ListConne" +
-      "ctions\022\022.context.ServiceId\032\027.context.Con" +
-      "nectionList\"\000\022=\n\rGetConnection\022\025.context" +
-      ".ConnectionId\032\023.context.Connection\"\000\022=\n\r" +
-      "SetConnection\022\023.context.Connection\032\025.con" +
-      "text.ConnectionId\"\000\022;\n\020RemoveConnection\022" +
-      "\025.context.ConnectionId\032\016.context.Empty\"\000" +
-      "\022C\n\023GetConnectionEvents\022\016.context.Empty\032" +
-      "\030.context.ConnectionEvent\"\0000\001b\006proto3"
+      "\020\007\022 \n\034DEVICEDRIVER_GNMI_OPENCONFIG\020\010\022\032\n\026" +
+      "DEVICEDRIVER_FLEXSCALE\020\t\022\032\n\026DEVICEDRIVER" +
+      "_IETF_ACTN\020\n*\217\001\n\033DeviceOperationalStatus" +
+      "Enum\022%\n!DEVICEOPERATIONALSTATUS_UNDEFINE" +
+      "D\020\000\022$\n DEVICEOPERATIONALSTATUS_DISABLED\020" +
+      "\001\022#\n\037DEVICEOPERATIONALSTATUS_ENABLED\020\002*\252" +
+      "\001\n\017ServiceTypeEnum\022\027\n\023SERVICETYPE_UNKNOW" +
+      "N\020\000\022\024\n\020SERVICETYPE_L3NM\020\001\022\024\n\020SERVICETYPE" +
+      "_L2NM\020\002\022)\n%SERVICETYPE_TAPI_CONNECTIVITY" +
+      "_SERVICE\020\003\022\022\n\016SERVICETYPE_TE\020\004\022\023\n\017SERVIC" +
+      "ETYPE_E2E\020\005*\304\001\n\021ServiceStatusEnum\022\033\n\027SER" +
+      "VICESTATUS_UNDEFINED\020\000\022\031\n\025SERVICESTATUS_" +
+      "PLANNED\020\001\022\030\n\024SERVICESTATUS_ACTIVE\020\002\022\032\n\026S" +
+      "ERVICESTATUS_UPDATING\020\003\022!\n\035SERVICESTATUS" +
+      "_PENDING_REMOVAL\020\004\022\036\n\032SERVICESTATUS_SLA_" +
+      "VIOLATED\020\005*\251\001\n\017SliceStatusEnum\022\031\n\025SLICES" +
+      "TATUS_UNDEFINED\020\000\022\027\n\023SLICESTATUS_PLANNED" +
+      "\020\001\022\024\n\020SLICESTATUS_INIT\020\002\022\026\n\022SLICESTATUS_" +
+      "ACTIVE\020\003\022\026\n\022SLICESTATUS_DEINIT\020\004\022\034\n\030SLIC" +
+      "ESTATUS_SLA_VIOLATED\020\005*]\n\020ConfigActionEn" +
+      "um\022\032\n\026CONFIGACTION_UNDEFINED\020\000\022\024\n\020CONFIG" +
+      "ACTION_SET\020\001\022\027\n\023CONFIGACTION_DELETE\020\002*m\n" +
+      "\024ConstraintActionEnum\022\036\n\032CONSTRAINTACTIO" +
+      "N_UNDEFINED\020\000\022\030\n\024CONSTRAINTACTION_SET\020\001\022" +
+      "\033\n\027CONSTRAINTACTION_DELETE\020\002*\203\002\n\022Isolati" +
+      "onLevelEnum\022\020\n\014NO_ISOLATION\020\000\022\026\n\022PHYSICA" +
+      "L_ISOLATION\020\001\022\025\n\021LOGICAL_ISOLATION\020\002\022\025\n\021" +
+      "PROCESS_ISOLATION\020\003\022\035\n\031PHYSICAL_MEMORY_I" +
+      "SOLATION\020\004\022\036\n\032PHYSICAL_NETWORK_ISOLATION" +
+      "\020\005\022\036\n\032VIRTUAL_RESOURCE_ISOLATION\020\006\022\037\n\033NE" +
+      "TWORK_FUNCTIONS_ISOLATION\020\007\022\025\n\021SERVICE_I" +
+      "SOLATION\020\0102\245\026\n\016ContextService\022:\n\016ListCon" +
+      "textIds\022\016.context.Empty\032\026.context.Contex" +
+      "tIdList\"\000\0226\n\014ListContexts\022\016.context.Empt" +
+      "y\032\024.context.ContextList\"\000\0224\n\nGetContext\022" +
+      "\022.context.ContextId\032\020.context.Context\"\000\022" +
+      "4\n\nSetContext\022\020.context.Context\032\022.contex" +
+      "t.ContextId\"\000\0225\n\rRemoveContext\022\022.context" +
+      ".ContextId\032\016.context.Empty\"\000\022=\n\020GetConte" +
+      "xtEvents\022\016.context.Empty\032\025.context.Conte" +
+      "xtEvent\"\0000\001\022@\n\017ListTopologyIds\022\022.context" +
+      ".ContextId\032\027.context.TopologyIdList\"\000\022=\n" +
+      "\016ListTopologies\022\022.context.ContextId\032\025.co" +
+      "ntext.TopologyList\"\000\0227\n\013GetTopology\022\023.co" +
+      "ntext.TopologyId\032\021.context.Topology\"\000\022E\n" +
+      "\022GetTopologyDetails\022\023.context.TopologyId" +
+      "\032\030.context.TopologyDetails\"\000\0227\n\013SetTopol" +
+      "ogy\022\021.context.Topology\032\023.context.Topolog" +
+      "yId\"\000\0227\n\016RemoveTopology\022\023.context.Topolo" +
+      "gyId\032\016.context.Empty\"\000\022?\n\021GetTopologyEve" +
+      "nts\022\016.context.Empty\032\026.context.TopologyEv" +
+      "ent\"\0000\001\0228\n\rListDeviceIds\022\016.context.Empty" +
+      "\032\025.context.DeviceIdList\"\000\0224\n\013ListDevices" +
+      "\022\016.context.Empty\032\023.context.DeviceList\"\000\022" +
+      "1\n\tGetDevice\022\021.context.DeviceId\032\017.contex" +
+      "t.Device\"\000\0221\n\tSetDevice\022\017.context.Device" +
+      "\032\021.context.DeviceId\"\000\0223\n\014RemoveDevice\022\021." +
+      "context.DeviceId\032\016.context.Empty\"\000\022;\n\017Ge" +
+      "tDeviceEvents\022\016.context.Empty\032\024.context." +
+      "DeviceEvent\"\0000\001\022<\n\014SelectDevice\022\025.contex" +
+      "t.DeviceFilter\032\023.context.DeviceList\"\000\022I\n" +
+      "\021ListEndPointNames\022\027.context.EndPointIdL" +
+      "ist\032\031.context.EndPointNameList\"\000\0224\n\013List" +
+      "LinkIds\022\016.context.Empty\032\023.context.LinkId" +
+      "List\"\000\0220\n\tListLinks\022\016.context.Empty\032\021.co" +
+      "ntext.LinkList\"\000\022+\n\007GetLink\022\017.context.Li" +
+      "nkId\032\r.context.Link\"\000\022+\n\007SetLink\022\r.conte" +
+      "xt.Link\032\017.context.LinkId\"\000\022/\n\nRemoveLink" +
+      "\022\017.context.LinkId\032\016.context.Empty\"\000\0227\n\rG" +
+      "etLinkEvents\022\016.context.Empty\032\022.context.L" +
+      "inkEvent\"\0000\001\022>\n\016ListServiceIds\022\022.context" +
+      ".ContextId\032\026.context.ServiceIdList\"\000\022:\n\014" +
+      "ListServices\022\022.context.ContextId\032\024.conte" +
+      "xt.ServiceList\"\000\0224\n\nGetService\022\022.context" +
+      ".ServiceId\032\020.context.Service\"\000\0224\n\nSetSer" +
+      "vice\022\020.context.Service\032\022.context.Service" +
+      "Id\"\000\0226\n\014UnsetService\022\020.context.Service\032\022" +
+      ".context.ServiceId\"\000\0225\n\rRemoveService\022\022." +
+      "context.ServiceId\032\016.context.Empty\"\000\022=\n\020G" +
+      "etServiceEvents\022\016.context.Empty\032\025.contex" +
+      "t.ServiceEvent\"\0000\001\022?\n\rSelectService\022\026.co" +
+      "ntext.ServiceFilter\032\024.context.ServiceLis" +
+      "t\"\000\022:\n\014ListSliceIds\022\022.context.ContextId\032" +
+      "\024.context.SliceIdList\"\000\0226\n\nListSlices\022\022." +
+      "context.ContextId\032\022.context.SliceList\"\000\022" +
+      ".\n\010GetSlice\022\020.context.SliceId\032\016.context." +
+      "Slice\"\000\022.\n\010SetSlice\022\016.context.Slice\032\020.co" +
+      "ntext.SliceId\"\000\0220\n\nUnsetSlice\022\016.context." +
+      "Slice\032\020.context.SliceId\"\000\0221\n\013RemoveSlice" +
+      "\022\020.context.SliceId\032\016.context.Empty\"\000\0229\n\016" +
+      "GetSliceEvents\022\016.context.Empty\032\023.context" +
+      ".SliceEvent\"\0000\001\0229\n\013SelectSlice\022\024.context" +
+      ".SliceFilter\032\022.context.SliceList\"\000\022D\n\021Li" +
+      "stConnectionIds\022\022.context.ServiceId\032\031.co" +
+      "ntext.ConnectionIdList\"\000\022@\n\017ListConnecti" +
+      "ons\022\022.context.ServiceId\032\027.context.Connec" +
+      "tionList\"\000\022=\n\rGetConnection\022\025.context.Co" +
+      "nnectionId\032\023.context.Connection\"\000\022=\n\rSet" +
+      "Connection\022\023.context.Connection\032\025.contex" +
+      "t.ConnectionId\"\000\022;\n\020RemoveConnection\022\025.c" +
+      "ontext.ConnectionId\032\016.context.Empty\"\000\022C\n" +
+      "\023GetConnectionEvents\022\016.context.Empty\032\030.c" +
+      "ontext.ConnectionEvent\"\0000\001b\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
diff --git a/src/ztp/target/kubernetes/kubernetes.yml b/src/ztp/target/kubernetes/kubernetes.yml
index f3e4a6d6dda261c4eac983552b01bb6a4f901e9f..d2a59eb05f056d69f021d897e89f1ab9cbb102ce 100644
--- a/src/ztp/target/kubernetes/kubernetes.yml
+++ b/src/ztp/target/kubernetes/kubernetes.yml
@@ -3,8 +3,8 @@ apiVersion: v1
 kind: Service
 metadata:
   annotations:
-    app.quarkus.io/commit-id: 46486023929121fc955e9550fc8fd625ded433d2
-    app.quarkus.io/build-timestamp: 2023-12-15 - 12:04:12 +0000
+    app.quarkus.io/commit-id: 5f8866be9cb91871607627819258b0b375410467
+    app.quarkus.io/build-timestamp: 2024-01-26 - 16:39:32 +0000
     prometheus.io/scrape: "true"
     prometheus.io/path: /q/metrics
     prometheus.io/port: "8080"
@@ -15,12 +15,12 @@ metadata:
   name: ztpservice
 spec:
   ports:
-    - name: grpc-server
-      port: 5050
-      targetPort: 5050
     - name: http
       port: 9192
       targetPort: 8080
+    - name: grpc-server
+      port: 5050
+      targetPort: 5050
   selector:
     app.kubernetes.io/name: ztpservice
   type: ClusterIP
@@ -29,8 +29,8 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   annotations:
-    app.quarkus.io/commit-id: 46486023929121fc955e9550fc8fd625ded433d2
-    app.quarkus.io/build-timestamp: 2023-12-15 - 12:04:12 +0000
+    app.quarkus.io/commit-id: 5f8866be9cb91871607627819258b0b375410467
+    app.quarkus.io/build-timestamp: 2024-01-26 - 16:39:32 +0000
     prometheus.io/scrape: "true"
     prometheus.io/path: /q/metrics
     prometheus.io/port: "8080"
@@ -47,8 +47,8 @@ spec:
   template:
     metadata:
       annotations:
-        app.quarkus.io/commit-id: 46486023929121fc955e9550fc8fd625ded433d2
-        app.quarkus.io/build-timestamp: 2023-12-15 - 12:04:12 +0000
+        app.quarkus.io/commit-id: 5f8866be9cb91871607627819258b0b375410467
+        app.quarkus.io/build-timestamp: 2024-01-26 - 16:39:32 +0000
         prometheus.io/scrape: "true"
         prometheus.io/path: /q/metrics
         prometheus.io/port: "8080"
@@ -81,12 +81,12 @@ spec:
             timeoutSeconds: 10
           name: ztpservice
           ports:
-            - containerPort: 5050
-              name: grpc-server
-              protocol: TCP
             - containerPort: 8080
               name: http
               protocol: TCP
+            - containerPort: 5050
+              name: grpc-server
+              protocol: TCP
           readinessProbe:
             failureThreshold: 3
             httpGet: