diff --git a/manifests/serviceservice.yaml b/manifests/serviceservice.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ac549bb2c5aba48088468c7ed99b4b49500558b1
--- /dev/null
+++ b/manifests/serviceservice.yaml
@@ -0,0 +1,53 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: serviceservice
+spec:
+  selector:
+    matchLabels:
+      app: serviceservice
+  template:
+    metadata:
+      labels:
+        app: serviceservice
+    spec:
+      terminationGracePeriodSeconds: 5
+      containers:
+      - name: server
+        image: registry.gitlab.com/teraflow-h2020/controller/device:latest
+        imagePullPolicy: Always
+        ports:
+        - containerPort: 3030
+        env:
+        - name: DB_ENGINE
+          value: "redis"
+        - name: REDIS_DATABASE_ID
+          value: "0"
+        - name: LOG_LEVEL
+          value: "DEBUG"
+        readinessProbe:
+          exec:
+            command: ["/bin/grpc_health_probe", "-addr=:3030"]
+        livenessProbe:
+          exec:
+            command: ["/bin/grpc_health_probe", "-addr=:3030"]
+        resources:
+          requests:
+            cpu: 250m
+            memory: 512Mi
+          limits:
+            cpu: 700m
+            memory: 1024Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: serviceservice
+spec:
+  type: ClusterIP
+  selector:
+    app: serviceservice
+  ports:
+  - name: grpc
+    port: 3030
+    targetPort: 3030
diff --git a/src/common/database/api/Database.py b/src/common/database/api/Database.py
index c3aeaf628339f8ba58e3c616b7eb6a501cad9278..64a49d7f22ad2231447895f4bad7ca0c26450ff1 100644
--- a/src/common/database/api/Database.py
+++ b/src/common/database/api/Database.py
@@ -1,8 +1,10 @@
 import logging
 from typing import List
-from ..engines._DatabaseEngine import _DatabaseEngine
-from .context.Context import Context
-from .Exceptions import WrongDatabaseEngine, MutexException
+from common.database.api.Exceptions import WrongDatabaseEngine, MutexException
+from common.database.api.context.Context import Context
+from common.database.api.context.Keys import KEY_CONTEXTS
+from common.database.api.entity.EntityCollection import EntityCollection
+from common.database.engines._DatabaseEngine import _DatabaseEngine
 
 LOGGER = logging.getLogger(__name__)
 
@@ -13,6 +15,10 @@ class Database:
         self._database_engine = database_engine
         self._acquired = False
         self._owner_key = None
+        self._contexts = EntityCollection(self, KEY_CONTEXTS)
+
+    @property
+    def database_engine(self) -> _DatabaseEngine: return self._database_engine
 
     def __enter__(self) -> '_DatabaseEngine':
         self._acquired, self._owner_key = self._database_engine.lock()
@@ -36,4 +42,7 @@ class Database:
         entries.sort()
         return ['[{:>4s}] {:100s} :: {}'.format(k_type, k_name, k_value) for k_name,k_type,k_value in entries]
 
+    @property
+    def contexts(self) -> EntityCollection: return self._contexts
+
     def context(self, context_uuid : str) -> Context: return Context(context_uuid, self._database_engine)
diff --git a/src/common/database/api/Constants.py b/src/common/database/api/context/Constants.py
similarity index 100%
rename from src/common/database/api/Constants.py
rename to src/common/database/api/context/Constants.py
diff --git a/src/common/database/api/context/Context.py b/src/common/database/api/context/Context.py
index 32991cc5ad2b29fe8492d42539edb7cccad7c5f1..bf6e56a1f350fb5c3223546479d1a8672b13e1f3 100644
--- a/src/common/database/api/context/Context.py
+++ b/src/common/database/api/context/Context.py
@@ -1,9 +1,10 @@
-from typing import Dict
-from ...engines._DatabaseEngine import _DatabaseEngine
-from ..entity._RootEntity import _RootEntity
-from ..entity.EntityCollection import EntityCollection
-from .Keys import KEY_CONTEXT, KEY_TOPOLOGIES
-from .Topology import Topology
+from typing import Dict, List
+from common.database.api.context.service.Service import Service
+from common.database.api.context.topology.Topology import Topology
+from common.database.api.context.Keys import KEY_CONTEXT, KEY_SERVICES, KEY_TOPOLOGIES
+from common.database.api.entity._RootEntity import _RootEntity
+from common.database.api.entity.EntityCollection import EntityCollection
+from common.database.engines._DatabaseEngine import _DatabaseEngine
 
 VALIDATORS = {}  # no attributes accepted
 TRANSCODERS = {} # no transcoding applied to attributes
@@ -12,6 +13,7 @@ class Context(_RootEntity):
     def __init__(self, context_uuid : str, database_engine : _DatabaseEngine):
         super().__init__(database_engine, context_uuid, KEY_CONTEXT, VALIDATORS, TRANSCODERS)
         self._topologies = EntityCollection(self, KEY_TOPOLOGIES)
+        self._services = EntityCollection(self, KEY_SERVICES)
 
     @property
     def parent(self) -> 'Context': return self
@@ -25,11 +27,17 @@ class Context(_RootEntity):
     @property
     def topologies(self) -> EntityCollection: return self._topologies
 
+    @property
+    def services(self) -> EntityCollection: return self._services
+
     def topology(self, topology_uuid : str) -> Topology: return Topology(topology_uuid, self)
 
+    def service(self, service_uuid : str) -> Service: return Service(service_uuid, self)
+
     def create(self) -> 'Context': return self
 
     def delete(self):
+        for service_uuid in self.services.get(): self.service(service_uuid).delete()
         for topology_uuid in self.topologies.get(): self.topology(topology_uuid).delete()
         self.attributes.delete()
 
@@ -38,5 +46,19 @@ class Context(_RootEntity):
             'contextUuid': {'uuid': self.context_uuid},
         }
 
+    def dump_topologies(self) -> List:
+        return [
+            self.topology(topology_uuid).dump() for topology_uuid in self.topologies.get()
+        ]
+
+    def dump_services(self) -> List:
+        return [
+            self.service(service_uuid).dump() for service_uuid in self.services.get()
+        ]
+
     def dump(self) -> Dict:
-        return {topology_uuid : self.topology(topology_uuid).dump() for topology_uuid in self.topologies.get()}
+        return {
+            'contextId': self.dump_id(),
+            'topologies': self.dump_topologies(),
+            'services': self.dump_services(),
+        }
diff --git a/src/common/database/api/context/Keys.py b/src/common/database/api/context/Keys.py
index 1c107ec1509949ef8b2f91a3e7e4505846fdf62a..c52079eec08ed6bd79e2fd637562fffe657acf37 100644
--- a/src/common/database/api/context/Keys.py
+++ b/src/common/database/api/context/Keys.py
@@ -1,11 +1,37 @@
-KEY_CONTEXT          =                'context[{context_uuid}]'
-KEY_TOPOLOGIES       = KEY_CONTEXT  + '/topologies{container_name}'
-KEY_TOPOLOGY         = KEY_CONTEXT  + '/topology[{topology_uuid}]' 
-KEY_DEVICES          = KEY_TOPOLOGY + '/devices{container_name}'
-KEY_LINKS            = KEY_TOPOLOGY + '/links{container_name}'
-KEY_DEVICE           = KEY_TOPOLOGY + '/device[{device_uuid}]' 
-KEY_DEVICE_ENDPOINTS = KEY_DEVICE   + '/endpoints{container_name}'
-KEY_ENDPOINT         = KEY_DEVICE   + '/endpoint[{endpoint_uuid}]' 
-KEY_LINK             = KEY_TOPOLOGY + '/link[{link_uuid}]' 
-KEY_LINK_ENDPOINTS   = KEY_LINK     + '/endpoints{container_name}'
-KEY_LINK_ENDPOINT    = KEY_LINK     + '/endpoint[{link_endpoint_uuid}]'
+# Database keys
+KEY_CONTEXTS            =                'contexts{container_name}'
+
+# Context keys
+KEY_CONTEXT             =                'context[{context_uuid}]'
+KEY_TOPOLOGIES          = KEY_CONTEXT  + '/topologies{container_name}'
+KEY_SERVICES            = KEY_CONTEXT  + '/services{container_name}'
+
+# Context.Topology keys
+KEY_TOPOLOGY            = KEY_CONTEXT  + '/topology[{topology_uuid}]'
+KEY_DEVICES             = KEY_TOPOLOGY + '/devices{container_name}'
+KEY_LINKS               = KEY_TOPOLOGY + '/links{container_name}'
+
+# Context.Topology.Device keys
+KEY_DEVICE              = KEY_TOPOLOGY + '/device[{device_uuid}]'
+KEY_DEVICE_ENDPOINTS    = KEY_DEVICE   + '/endpoints{container_name}'
+
+# Context.Topology.Device.Endpoint keys
+KEY_DEVICE_ENDPOINT     = KEY_DEVICE   + '/endpoint[{endpoint_uuid}]'
+
+# Context.Topology.Link keys
+KEY_LINK                = KEY_TOPOLOGY + '/link[{link_uuid}]'
+KEY_LINK_ENDPOINTS      = KEY_LINK     + '/endpoints{container_name}'
+
+# Context.Topology.Link.Endpoint Keys
+KEY_LINK_ENDPOINT       = KEY_LINK     + '/endpoint[{endpoint_uuid}]'
+
+# Service keys
+KEY_SERVICE             = KEY_CONTEXT  + '/service[{service_uuid}]'
+KEY_SERVICE_ENDPOINTS   = KEY_SERVICE  + '/endpoints{container_name}'
+KEY_SERVICE_CONSTRAINTS = KEY_SERVICE  + '/constraints{container_name}'
+
+# Context.Service.Endpoint Keys
+KEY_SERVICE_ENDPOINT    = KEY_SERVICE  + '/endpoint[{endpoint_uuid}]'
+
+# Context.Service.Constraint Keys
+KEY_SERVICE_CONSTRAINT  = KEY_SERVICE  + '/constraint[{constraint_uuid}]'
diff --git a/src/common/database/api/context/_structure.txt b/src/common/database/api/context/_structure.txt
index 7168763e394ebd0499434e1f62a7bc3d74086c30..0dc6219f8801bcb9d9d26c61707d82eb2925e895 100644
--- a/src/common/database/api/context/_structure.txt
+++ b/src/common/database/api/context/_structure.txt
@@ -2,7 +2,7 @@
 # Internal structure #
 ######################
 
-Note (1): for containers like topologies, devices, links, etc. two containers are defined:
+Note (1): for containers like topologies, devices, links, services, etc. two containers are defined:
 list    List is a sorted list containing the uuid's of th elements belonging to the parent element. It is used to
         define the order of the elements and enable to iterate them deterministically.
 
@@ -26,6 +26,14 @@ context[<context_uuid>]/topologies_<container>
         context[ctx-test]/topologies_set
             {'base-topo', 'other-topo'}
 
+context[<context_uuid>]/services_<container>
+    Containers (see Note 1) with the service_uuid's belonging to the context.
+    Examples:
+        context[ctx-test]/service_list
+            ['service-1', 'service-2']
+        context[ctx-test]/service_set
+            {'service-1', 'service-2'}
+
 
 Topology structure:
 -------------------
@@ -58,11 +66,11 @@ context[<context_uuid>]/topology[<topology_uuid>]/device[<device_uuid>]
     Defined attributes are:
         device_type              : string
         device_config            : string
-        device_operational_status: string "0"/"1"
+        device_operational_status: string "0" (KEEP_STATUS) / "-1" (DISABLED) / "1" (ENABLED)
     Example: {'device_type': 'ROADM', 'device_config': '<config/>', 'device_operational_status': '1'}
 
 context[<context_uuid>]/topology[<topology_uuid>]/device[<device_uuid>]/endpoints_<container>
-    Containers (see Note 1) with the endpoints_uuid's belonging to the device.
+    Containers (see Note 1) with the device_endpoints_uuid's belonging to the device.
     Examples:
         context[ctx-test]/topology[base-topo]/device[dev1]/endpoints_list
             ['to-dev2', 'to-dev3', 'to-dev4']
@@ -72,8 +80,8 @@ context[<context_uuid>]/topology[<topology_uuid>]/device[<device_uuid>]/endpoint
 
 Device Endpoint structure:
 --------------------------
-context[<context_uuid>]/topology[<topology_uuid>]/device[<device_uuid>]/endpoint[<endpoint_uuid>]
-    Hash set containing the attributes for the endpoint.
+context[<context_uuid>]/topology[<topology_uuid>]/device[<device_uuid>]/endpoint[<device_endpoint_uuid>]
+    Hash set containing the attributes for the device_endpoint.
     Defined attributes are:
         port_type: string
     Example: {'port_type': 'WDM'}
@@ -103,5 +111,55 @@ context[<context_uuid>]/topology[<topology_uuid>]/link[<link_uuid>]/endpoint[<li
         device_uuid: string
         endpoint_uuid: string
     Example:
-        context[ctx-test]/topology[base-topo]/link[dev1/to-dev2 ==> dev2/to-dev1]/endpointdev1/to-dev2
+        context[ctx-test]/topology[base-topo]/link[dev1/to-dev2 ==> dev2/to-dev1]/endpoint[dev1/to-dev2]
             {'device_uuid': 'dev1', 'endpoint_uuid': 'to-dev2'}
+
+
+Service structure:
+------------------
+context[<context_uuid>]/service[<service_uuid>]
+    Hash set containing the attributes for the service.
+    Defined attributes are:
+        service_type  : string "0" (UNKNOWN) / "1" (L3NM) / "2" (L2NM) / "3" (TAPI_CONNECTIVITY_SERVICE)
+        service_config: string
+        service_state : string "0" (PLANNED) / "1" (ACTIVE) / "2" (PENDING_REMOVAL)
+    Example: ...
+
+context[<context_uuid>]/service[<service_uuid>]/endpoints_<container>
+    Containers (see Note 1) with the service_endpoint_uuid's belonging to the service.
+    Examples:
+        context[ctx-test]/service[service-1]/endpoints_list
+            ['base-topo:dev2/to-dev1', 'base-topo:dev3/to-dev1']
+        context[ctx-test]/service[service-1]/endpoints_set
+            {'base-topo:dev2/to-dev1', 'base-topo:dev3/to-dev1'}
+
+context[<context_uuid>]/service[<service_uuid>]/constraints_<container>
+    Containers (see Note 1) with the constraint_type's belonging to the service.
+    Examples:
+        context[ctx-test]/service[service-1]/constraints_list
+            ['latency_ms', 'hops']
+        context[ctx-test]/service[service-1]/constraints_set
+            {'latency_ms', 'hops'}
+
+
+Service Endpoint structure:
+---------------------------
+context[<context_uuid>]/service[<service_uuid>]/endpoint[<service_endpoint_uuid>]
+    Hash set containing the attributes for the service_endpoint.
+    Defined attributes are:
+        topology_uuid: string
+        device_uuid: string
+        endpoint_uuid: string
+    Example:
+        context[ctx-test]/service[service-1]/endpoint[dev2/to-dev1]
+            {'topology_uuid': 'base-topo', 'device_uuid': 'dev2', 'endpoint_uuid': 'to-dev1'}
+
+Service Constraint structure:
+-----------------------------
+context[<context_uuid>]/service[<service_uuid>]/constraint[<constraint_type>]
+    Hash set containing the attributes for the constraint.
+    Defined attributes are:
+        constraint_value: string
+    Example:
+        context[ctx-test]/service[service-1]/constraint['latency_ms']
+            {'constraint_value': '100'}
diff --git a/src/common/database/api/context/service/Constraint.py b/src/common/database/api/context/service/Constraint.py
new file mode 100644
index 0000000000000000000000000000000000000000..1300d9883f7e050c8abbcb949875a322a639aafd
--- /dev/null
+++ b/src/common/database/api/context/service/Constraint.py
@@ -0,0 +1,63 @@
+from __future__ import annotations
+from typing import TYPE_CHECKING, Dict
+from common.database.api.context.Keys import KEY_SERVICE_CONSTRAINT
+from common.database.api.entity._Entity import _Entity
+
+if TYPE_CHECKING:
+    from common.database.api.context.Context import Context
+    from common.database.api.context.service.Service import Service
+
+VALIDATORS = {
+    'constraint_value': lambda v: v is not None and isinstance(v, str) and (len(v) > 0),
+}
+
+TRANSCODERS = {} # no transcoding applied to attributes
+
+class Constraint(_Entity):
+    def __init__(self, constraint_type : str, parent : 'Service'):
+        super().__init__(parent, constraint_type, KEY_SERVICE_CONSTRAINT, VALIDATORS, TRANSCODERS)
+
+    @property
+    def parent(self) -> 'Service': return self._parent
+
+    @property
+    def context(self) -> 'Context': return self.parent.context
+
+    @property
+    def context_uuid(self) -> str: return self.parent.context_uuid
+
+    @property
+    def service(self) -> 'Service': return self.parent
+
+    @property
+    def service_uuid(self) -> str: return self.parent.service_uuid
+
+    @property
+    def constraint_type(self) -> str: return self._entity_uuid
+
+    def create(self, constraint_value : str) -> 'Constraint':
+        self.update(update_attributes={
+            'constraint_value': constraint_value,
+        })
+        self.parent.endpoints.add(self.constraint_type)
+        return self
+
+    def update(self, update_attributes={}, remove_attributes=[]) -> 'Constraint':
+        self.attributes.update(update_attributes=update_attributes, remove_attributes=remove_attributes)
+        return self
+
+    def delete(self) -> None:
+        self.attributes.delete()
+        self.parent.endpoints.delete(self.constraint_type)
+
+    def dump_id(self) -> Dict:
+        return {
+            'constraint_type': self.constraint_type,
+        }
+
+    def dump(self) -> Dict:
+        attributes = self.attributes.get()
+        return {
+            'constraint_type': self.constraint_type,
+            'constraint_value': attributes.get('constraint_value', None),
+        }
diff --git a/src/common/database/api/context/service/Endpoint.py b/src/common/database/api/context/service/Endpoint.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f86002371f7c2288b75332061ba928c120ca621
--- /dev/null
+++ b/src/common/database/api/context/service/Endpoint.py
@@ -0,0 +1,67 @@
+from __future__ import annotations
+from typing import TYPE_CHECKING, Dict
+from common.database.api.context.topology.device.Endpoint import Endpoint as DeviceEndpoint
+from common.database.api.context.Keys import KEY_SERVICE_ENDPOINT
+from common.database.api.entity._Entity import _Entity
+
+if TYPE_CHECKING:
+    from common.database.api.context.Context import Context
+    from common.database.api.context.service.Service import Service
+
+VALIDATORS = {
+    'topology_uuid': lambda v: v is not None and isinstance(v, str) and (len(v) > 0),
+    'device_uuid': lambda v: v is not None and isinstance(v, str) and (len(v) > 0),
+    'endpoint_uuid': lambda v: v is not None and isinstance(v, str) and (len(v) > 0),
+}
+
+TRANSCODERS = {} # no transcoding applied to attributes
+
+class Endpoint(_Entity):
+    def __init__(self, endpoint_uuid : str, parent : 'Service'):
+        super().__init__(parent, endpoint_uuid, KEY_SERVICE_ENDPOINT, VALIDATORS, TRANSCODERS)
+
+    @property
+    def parent(self) -> 'Service': return self._parent
+
+    @property
+    def context(self) -> 'Context': return self.parent.context
+
+    @property
+    def context_uuid(self) -> str: return self.parent.context_uuid
+
+    @property
+    def service(self) -> 'Service': return self.parent
+
+    @property
+    def service_uuid(self) -> str: return self.parent.service_uuid
+
+    @property
+    def endpoint_uuid(self) -> str: return self._entity_uuid
+
+    def create(self, endpoint : DeviceEndpoint) -> 'Endpoint':
+        self.update(update_attributes={
+            'topology_uuid': endpoint.topology_uuid,
+            'device_uuid': endpoint.device_uuid,
+            'endpoint_uuid': endpoint.endpoint_uuid,
+        })
+        self.parent.endpoints.add(self.endpoint_uuid)
+        return self
+
+    def update(self, update_attributes={}, remove_attributes=[]) -> 'Endpoint':
+        self.attributes.update(update_attributes=update_attributes, remove_attributes=remove_attributes)
+        return self
+
+    def delete(self) -> None:
+        self.attributes.delete()
+        self.parent.endpoints.delete(self.endpoint_uuid)
+
+    def dump_id(self) -> Dict:
+        attributes = self.attributes.get()
+        topology_uuid = attributes.get('topology_uuid', None)
+        device_uuid = attributes.get('device_uuid', None)
+        endpoint_uuid = attributes.get('endpoint_uuid', None)
+        endpoint = self.context.topology(topology_uuid).device(device_uuid).endpoint(endpoint_uuid)
+        return endpoint.dump_id()
+
+    def dump(self) -> Dict:
+        return self.dump_id()
diff --git a/src/common/database/api/context/service/Service.py b/src/common/database/api/context/service/Service.py
new file mode 100644
index 0000000000000000000000000000000000000000..b537d729c6b2f339e40570c4629ae2faa71caf41
--- /dev/null
+++ b/src/common/database/api/context/service/Service.py
@@ -0,0 +1,102 @@
+from __future__ import annotations
+from typing import TYPE_CHECKING, Dict
+from common.database.api.context.Keys import KEY_SERVICE, KEY_SERVICE_CONSTRAINTS, KEY_SERVICE_ENDPOINTS
+from common.database.api.context.service.Constraint import Constraint
+from common.database.api.context.service.Endpoint import Endpoint
+from common.database.api.context.service.ServiceState import ServiceState, to_servicestate_enum
+from common.database.api.context.service.ServiceType import ServiceType, to_servicetype_enum
+from common.database.api.entity._Entity import _Entity
+from common.database.api.entity.EntityCollection import EntityCollection
+
+if TYPE_CHECKING:
+    from common.database.api.context.Context import Context
+
+VALIDATORS = {
+    'service_type': lambda v: v is not None and isinstance(v, ServiceType),
+    'service_config': lambda v: v is not None and isinstance(v, str) and (len(v) > 0),
+    'service_state': lambda v: v is not None and isinstance(v, ServiceState),
+}
+
+TRANSCODERS = {
+    'service_type': {
+        ServiceType: lambda v: v.value,
+        int        : lambda v: to_servicetype_enum(v),
+        str        : lambda v: to_servicetype_enum(v),
+    },
+    'service_state': {
+        ServiceState: lambda v: v.value,
+        int         : lambda v: to_servicestate_enum(v),
+        str         : lambda v: to_servicestate_enum(v),
+    },
+}
+
+class Service(_Entity):
+    def __init__(self, service_uuid : str, parent : 'Context'):
+        super().__init__(parent, service_uuid, KEY_SERVICE, VALIDATORS, TRANSCODERS)
+        self._endpoints = EntityCollection(self, KEY_SERVICE_ENDPOINTS)
+        self._constraints = EntityCollection(self, KEY_SERVICE_CONSTRAINTS)
+
+    @property
+    def parent(self) -> 'Context': return self._parent
+
+    @property
+    def context(self) -> 'Context': return self._parent
+
+    @property
+    def context_uuid(self) -> str: return self.context.context_uuid
+
+    @property
+    def service_uuid(self) -> str: return self._entity_uuid
+
+    @property
+    def endpoints(self) -> EntityCollection: return self._endpoints
+
+    @property
+    def constraints(self) -> EntityCollection: return self._constraints
+
+    def endpoint(self, endpoint_uuid : str) -> Endpoint: return Endpoint(endpoint_uuid, self)
+
+    def constraint(self, constraint_type : str) -> Constraint: return Constraint(constraint_type, self)
+
+    def create(self, service_type : ServiceType, service_config : str, service_state : ServiceState) -> 'Service':
+        self.update(update_attributes={
+            'service_type': service_type,
+            'service_config': service_config,
+            'service_state': service_state,
+        })
+        self.parent.services.add(self.service_uuid)
+        return self
+
+    def update(self, update_attributes={}, remove_attributes=[]) -> 'Service':
+        self.attributes.update(update_attributes=update_attributes, remove_attributes=remove_attributes)
+        return self
+
+    def delete(self) -> None:
+        for endpoint_uuid in self.endpoints.get(): self.endpoint(endpoint_uuid).delete()
+        for constraint_uuid in self.constraints.get(): self.constraint(constraint_uuid).delete()
+        self.attributes.delete()
+        self.parent.services.delete(self.service_uuid)
+
+    def dump_id(self) -> Dict:
+        return {
+            'contextId': self.context.dump_id(),
+            'cs_id': {'uuid': self.service_uuid},
+        }
+
+    def dump(self) -> Dict:
+        attributes = self.attributes.get()
+        service_type = attributes.get('service_type', None)
+        if isinstance(service_type, ServiceType): service_type = service_type.value
+        service_state = attributes.get('service_state', None)
+        if isinstance(service_state, ServiceState): service_state = service_state.value
+        service_config = attributes.get('device_config', None)
+        endpoints = [self.endpoint(endpoint_uuid).dump() for endpoint_uuid in self.endpoints.get()]
+        constraints = [self.constraint(constraint_type).dump() for constraint_type in self.constraints.get()]
+        return {
+            'cs_id': self.dump_id(),
+            'serviceType': service_type,
+            'endpointList': endpoints,
+            'constraint': constraints,
+            'serviceState': {'serviceState': service_state},
+            'serviceConfig': {'serviceConfig': service_config}
+        }
diff --git a/src/common/database/api/context/service/ServiceState.py b/src/common/database/api/context/service/ServiceState.py
new file mode 100644
index 0000000000000000000000000000000000000000..3855138d99c40b743885f256fe3aafbaa44aa18b
--- /dev/null
+++ b/src/common/database/api/context/service/ServiceState.py
@@ -0,0 +1,27 @@
+from enum import Enum
+
+class ServiceState(Enum):
+    PLANNED = 0
+    ACTIVE = 1
+    PENDING_REMOVAL = 2
+
+ANY_TO_ENUM = {
+    0: ServiceState.PLANNED,
+    1: ServiceState.ACTIVE,
+    2: ServiceState.PENDING_REMOVAL,
+
+    '0': ServiceState.PLANNED,
+    '1': ServiceState.ACTIVE,
+    '2': ServiceState.PENDING_REMOVAL,
+
+    'PLANNED': ServiceState.PLANNED,
+    'ACTIVE': ServiceState.ACTIVE,
+    'PENDING_REMOVAL': ServiceState.PENDING_REMOVAL,
+}
+
+def servicestate_enum_values():
+    return {m.value for m in ServiceState.__members__.values()}
+
+def to_servicestate_enum(int_or_str):
+    if isinstance(int_or_str, str): int_or_str = int_or_str.lower()
+    return ANY_TO_ENUM.get(int_or_str)
diff --git a/src/common/database/api/context/service/ServiceType.py b/src/common/database/api/context/service/ServiceType.py
new file mode 100644
index 0000000000000000000000000000000000000000..c779fc31c89c8746a547a38135f99d07716e2bbb
--- /dev/null
+++ b/src/common/database/api/context/service/ServiceType.py
@@ -0,0 +1,31 @@
+from enum import Enum
+
+class ServiceType(Enum):
+    UNKNOWN = 0
+    L3NM = 1
+    L2NM = 2
+    TAPI_CONNECTIVITY_SERVICE = 3
+
+ANY_TO_ENUM = {
+    0: ServiceType.UNKNOWN,
+    1: ServiceType.L3NM,
+    2: ServiceType.L2NM,
+    3: ServiceType.TAPI_CONNECTIVITY_SERVICE,
+
+    '0': ServiceType.UNKNOWN,
+    '1': ServiceType.L3NM,
+    '2': ServiceType.L2NM,
+    '3': ServiceType.TAPI_CONNECTIVITY_SERVICE,
+
+    'UNKNOWN': ServiceType.UNKNOWN,
+    'L3NM': ServiceType.L3NM,
+    'L2NM': ServiceType.L2NM,
+    'TAPI_CONNECTIVITY_SERVICE': ServiceType.TAPI_CONNECTIVITY_SERVICE,
+}
+
+def servicetype_enum_values():
+    return {m.value for m in ServiceType.__members__.values()}
+
+def to_servicetype_enum(int_or_str):
+    if isinstance(int_or_str, str): int_or_str = int_or_str.lower()
+    return ANY_TO_ENUM.get(int_or_str)
diff --git a/src/common/database/api/context/service/__init__.py b/src/common/database/api/context/service/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/common/database/api/context/Topology.py b/src/common/database/api/context/topology/Topology.py
similarity index 78%
rename from src/common/database/api/context/Topology.py
rename to src/common/database/api/context/topology/Topology.py
index 2fc36ed3c46a64dfb92337c2f62608529d2e65d9..de9cd67a41b822800f78f07208b090adf91b7bd8 100644
--- a/src/common/database/api/context/Topology.py
+++ b/src/common/database/api/context/topology/Topology.py
@@ -1,13 +1,13 @@
 from __future__ import annotations
 from typing import TYPE_CHECKING, Dict
-from ..entity._Entity import _Entity
-from ..entity.EntityCollection import EntityCollection
-from .Keys import KEY_TOPOLOGY, KEY_DEVICES, KEY_LINKS
-from .Device import Device
-from .Link import Link
+from common.database.api.context.Keys import KEY_TOPOLOGY, KEY_DEVICES, KEY_LINKS
+from common.database.api.context.topology.device.Device import Device
+from common.database.api.context.topology.link.Link import Link
+from common.database.api.entity._Entity import _Entity
+from common.database.api.entity.EntityCollection import EntityCollection
 
 if TYPE_CHECKING:
-    from .Context import Context
+    from common.database.api.context.Context import Context
 
 VALIDATORS = {}  # no attributes accepted
 TRANSCODERS = {} # no transcoding applied to attributes
@@ -44,7 +44,7 @@ class Topology(_Entity):
         self.parent.topologies.add(self.topology_uuid)
         return self
 
-    def delete(self):
+    def delete(self) -> None:
         for device_uuid in self.devices.get(): self.device(device_uuid).delete()
         for link_uuid in self.links.get(): self.link(link_uuid).delete()
         self.attributes.delete()
@@ -58,7 +58,7 @@ class Topology(_Entity):
 
     def dump(self) -> Dict:
         devices = [self.device(device_uuid).dump() for device_uuid in self.devices.get()]
-        links   = [self.link  (link_uuid  ).dump() for link_uuid   in self.links.get()]
+        links = [self.link(link_uuid).dump() for link_uuid in self.links.get()]
         return {
             'topoId': self.dump_id(),
             'device': devices,
diff --git a/src/common/database/api/context/topology/__init__.py b/src/common/database/api/context/topology/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/common/database/api/context/Device.py b/src/common/database/api/context/topology/device/Device.py
similarity index 85%
rename from src/common/database/api/context/Device.py
rename to src/common/database/api/context/topology/device/Device.py
index fb4b5becb6de1f158447b3e7630ff6f87fbbdf7d..06c560051e1b3d7d930efb6ddca16d9096a2509e 100644
--- a/src/common/database/api/context/Device.py
+++ b/src/common/database/api/context/topology/device/Device.py
@@ -1,14 +1,14 @@
 from __future__ import annotations
 from typing import TYPE_CHECKING, Dict
-from ..entity._Entity import _Entity
-from ..entity.EntityCollection import EntityCollection
-from .Endpoint import Endpoint
-from .Keys import KEY_DEVICE, KEY_DEVICE_ENDPOINTS
-from .OperationalStatus import OperationalStatus, to_operationalstatus_enum
+from common.database.api.context.Keys import KEY_DEVICE, KEY_DEVICE_ENDPOINTS
+from common.database.api.context.topology.device.Endpoint import Endpoint
+from common.database.api.context.topology.device.OperationalStatus import OperationalStatus, to_operationalstatus_enum
+from common.database.api.entity._Entity import _Entity
+from common.database.api.entity.EntityCollection import EntityCollection
 
 if TYPE_CHECKING:
-    from .Context import Context
-    from .Topology import Topology
+    from common.database.api.context.Context import Context
+    from common.database.api.context.topology.Topology import Topology
 
 VALIDATORS = {
     'device_type': lambda v: v is not None and isinstance(v, str) and (len(v) > 0),
diff --git a/src/common/database/api/context/Endpoint.py b/src/common/database/api/context/topology/device/Endpoint.py
similarity index 81%
rename from src/common/database/api/context/Endpoint.py
rename to src/common/database/api/context/topology/device/Endpoint.py
index 413a680a8e8cdb13e8df120a2514c46497d7a071..8ea516f3e50ad14fd133048570555abf4d872372 100644
--- a/src/common/database/api/context/Endpoint.py
+++ b/src/common/database/api/context/topology/device/Endpoint.py
@@ -1,12 +1,12 @@
 from __future__ import annotations
 from typing import TYPE_CHECKING, Dict
-from ..entity._Entity import _Entity
-from .Keys import KEY_ENDPOINT
+from common.database.api.entity._Entity import _Entity
+from common.database.api.context.Keys import KEY_DEVICE_ENDPOINT
 
 if TYPE_CHECKING:
-    from .Context import Context
-    from .Topology import Topology
-    from .Device import Device
+    from common.database.api.context.Context import Context
+    from common.database.api.context.topology.Topology import Topology
+    from common.database.api.context.topology.device.Device import Device
 
 VALIDATORS = {
     'port_type': lambda v: v is not None and isinstance(v, str) and (len(v) > 0),
@@ -16,7 +16,7 @@ TRANSCODERS = {} # no transcoding applied to attributes
 
 class Endpoint(_Entity):
     def __init__(self, endpoint_uuid : str, parent : 'Device'):
-        super().__init__(parent, endpoint_uuid, KEY_ENDPOINT, VALIDATORS, TRANSCODERS)
+        super().__init__(parent, endpoint_uuid, KEY_DEVICE_ENDPOINT, VALIDATORS, TRANSCODERS)
 
     @property
     def parent(self) -> 'Device': return self._parent
diff --git a/src/common/database/api/context/OperationalStatus.py b/src/common/database/api/context/topology/device/OperationalStatus.py
similarity index 100%
rename from src/common/database/api/context/OperationalStatus.py
rename to src/common/database/api/context/topology/device/OperationalStatus.py
diff --git a/src/common/database/api/context/topology/device/__init__.py b/src/common/database/api/context/topology/device/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/common/database/api/context/LinkEndpoint.py b/src/common/database/api/context/topology/link/Endpoint.py
similarity index 66%
rename from src/common/database/api/context/LinkEndpoint.py
rename to src/common/database/api/context/topology/link/Endpoint.py
index 4acb62fdb36fe78f65710d361370f41962312859..0fbdd26cbc222f7591ccfc8fbfdc6aa9062ead58 100644
--- a/src/common/database/api/context/LinkEndpoint.py
+++ b/src/common/database/api/context/topology/link/Endpoint.py
@@ -1,13 +1,13 @@
 from __future__ import annotations
 from typing import TYPE_CHECKING, Dict
-from ..entity._Entity import _Entity
-from .Endpoint import Endpoint
-from .Keys import KEY_LINK_ENDPOINT
+from common.database.api.context.topology.device.Endpoint import Endpoint as DeviceEndpoint
+from common.database.api.context.Keys import KEY_LINK_ENDPOINT
+from common.database.api.entity._Entity import _Entity
 
 if TYPE_CHECKING:
-    from .Context import Context
-    from .Topology import Topology
-    from .Link import Link
+    from common.database.api.context.Context import Context
+    from common.database.api.context.topology.Topology import Topology
+    from common.database.api.context.topology.link.Link import Link
 
 VALIDATORS = {
     'device_uuid': lambda v: v is not None and isinstance(v, str) and (len(v) > 0),
@@ -16,9 +16,9 @@ VALIDATORS = {
 
 TRANSCODERS = {} # no transcoding applied to attributes
 
-class LinkEndpoint(_Entity):
-    def __init__(self, link_endpoint_uuid : str, parent : 'Link'):
-        super().__init__(parent, link_endpoint_uuid, KEY_LINK_ENDPOINT, VALIDATORS, TRANSCODERS)
+class Endpoint(_Entity):
+    def __init__(self, endpoint_uuid : str, parent : 'Link'):
+        super().__init__(parent, endpoint_uuid, KEY_LINK_ENDPOINT, VALIDATORS, TRANSCODERS)
 
     @property
     def parent(self) -> 'Link': return self._parent
@@ -42,23 +42,23 @@ class LinkEndpoint(_Entity):
     def link_uuid(self) -> str: return self.parent.link_uuid
 
     @property
-    def link_endpoint_uuid(self) -> str: return self._entity_uuid
+    def endpoint_uuid(self) -> str: return self._entity_uuid
 
-    def create(self, endpoint : Endpoint) -> 'LinkEndpoint':
+    def create(self, endpoint : DeviceEndpoint) -> 'Endpoint':
         self.update(update_attributes={
             'device_uuid': endpoint.device_uuid,
             'endpoint_uuid': endpoint.endpoint_uuid,
         })
-        self.parent.endpoints.add(self.link_endpoint_uuid)
+        self.parent.endpoints.add(self.endpoint_uuid)
         return self
 
-    def update(self, update_attributes={}, remove_attributes=[]) -> 'LinkEndpoint':
+    def update(self, update_attributes={}, remove_attributes=[]) -> 'Endpoint':
         self.attributes.update(update_attributes=update_attributes, remove_attributes=remove_attributes)
         return self
 
     def delete(self) -> None:
         self.attributes.delete()
-        self.parent.endpoints.delete(self.link_endpoint_uuid)
+        self.parent.endpoints.delete(self.endpoint_uuid)
 
     def dump_id(self) -> Dict:
         attributes = self.attributes.get()
diff --git a/src/common/database/api/context/Link.py b/src/common/database/api/context/topology/link/Link.py
similarity index 76%
rename from src/common/database/api/context/Link.py
rename to src/common/database/api/context/topology/link/Link.py
index bf661dbb2897822a45071c157619b97c1ebca1d9..41d72e0d2284b6569a550216e0539ce950fcdc14 100644
--- a/src/common/database/api/context/Link.py
+++ b/src/common/database/api/context/topology/link/Link.py
@@ -1,13 +1,13 @@
 from __future__ import annotations
 from typing import TYPE_CHECKING, Dict
-from ..entity._Entity import _Entity
-from ..entity.EntityCollection import EntityCollection
-from .LinkEndpoint import LinkEndpoint
-from .Keys import KEY_LINK, KEY_LINK_ENDPOINTS
+from common.database.api.entity._Entity import _Entity
+from common.database.api.entity.EntityCollection import EntityCollection
+from common.database.api.context.topology.link.Endpoint import Endpoint
+from common.database.api.context.Keys import KEY_LINK, KEY_LINK_ENDPOINTS
 
 if TYPE_CHECKING:
-    from .Context import Context
-    from .Topology import Topology
+    from common.database.api.context.Context import Context
+    from common.database.api.context.topology.Topology import Topology
 
 VALIDATORS = {}  # no attributes accepted
 TRANSCODERS = {} # no transcoding applied to attributes
@@ -38,7 +38,7 @@ class Link(_Entity):
     @property
     def endpoints(self) -> EntityCollection: return self._endpoints
 
-    def endpoint(self, link_endpoint_uuid : str) -> LinkEndpoint: return LinkEndpoint(link_endpoint_uuid, self)
+    def endpoint(self, link_endpoint_uuid : str) -> Endpoint: return Endpoint(link_endpoint_uuid, self)
 
     def create(self) -> 'Link':
         self.parent.links.add(self.link_uuid)
diff --git a/src/common/database/api/context/topology/link/__init__.py b/src/common/database/api/context/topology/link/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/common/database/tests/script.py b/src/common/database/tests/script.py
index 2bd1a40296f943004d4c90db519406be512a449b..1387252a4dbdbe8759c972650ce8b640f51570bb 100644
--- a/src/common/database/tests/script.py
+++ b/src/common/database/tests/script.py
@@ -1,7 +1,9 @@
 import json, logging, time
-from ..api.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
-from ..api.context.OperationalStatus import OperationalStatus
-from ..api.Database import Database
+from common.database.api.Database import Database
+from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
+from common.database.api.context.service.ServiceState import ServiceState
+from common.database.api.context.service.ServiceType import ServiceType
+from common.database.api.context.topology.device.OperationalStatus import OperationalStatus
 
 LOGGER = logging.getLogger(__name__)
 
@@ -12,77 +14,107 @@ def populate_example(database : Database, context_uuid=DEFAULT_CONTEXT_ID, topol
         context = database.context(context_uuid).create()
         topology = context.topology(topology_uuid).create()
 
-        device_1 = topology.device('dev1').create(
+        dev_1 = topology.device('DEV1').create(
             device_type='ROADM', device_config='<config/>', device_operational_status=OperationalStatus.ENABLED)
-        endpoint_dev1_to_dev2 = device_1.endpoint('to-dev2').create(port_type='WDM')
-        endpoint_dev1_to_dev3 = device_1.endpoint('to-dev3').create(port_type='WDM')
-        endpoint_dev1_to_dev4 = device_1.endpoint('to-dev4').create(port_type='WDM')
-
-        device_2 = topology.device('dev2').create(
+        dev1_ep2 = dev_1.endpoint('EP2').create(port_type='WDM')
+        dev1_ep3 = dev_1.endpoint('EP3').create(port_type='WDM')
+        dev1_ep4 = dev_1.endpoint('EP4').create(port_type='WDM')
+        dev1_ep101 = dev_1.endpoint('EP5').create(port_type='OCH')
+        dev1_ep102 = dev_1.endpoint('EP6').create(port_type='OCH')
+        dev1_ep103 = dev_1.endpoint('EP7').create(port_type='OCH')
+
+        dev_2 = topology.device('DEV2').create(
             device_type='ROADM', device_config='<config/>', device_operational_status=OperationalStatus.ENABLED)
-        endpoint_dev2_to_dev1 = device_2.endpoint('to-dev1').create(port_type='WDM')
-        endpoint_dev2_to_dev3 = device_2.endpoint('to-dev3').create(port_type='WDM')
-        endpoint_dev2_to_dev4 = device_2.endpoint('to-dev4').create(port_type='WDM')
-
-        device_3 = topology.device('dev3').create(
+        dev2_ep1 = dev_2.endpoint('EP1').create(port_type='WDM')
+        dev2_ep3 = dev_2.endpoint('EP3').create(port_type='WDM')
+        dev2_ep4 = dev_2.endpoint('EP4').create(port_type='WDM')
+        dev2_ep101 = dev_2.endpoint('EP5').create(port_type='OCH')
+        dev2_ep102 = dev_2.endpoint('EP6').create(port_type='OCH')
+        dev2_ep103 = dev_2.endpoint('EP7').create(port_type='OCH')
+
+        dev_3 = topology.device('DEV3').create(
             device_type='ROADM', device_config='<config/>', device_operational_status=OperationalStatus.ENABLED)
-        endpoint_dev3_to_dev1 = device_3.endpoint('to-dev1').create(port_type='WDM')
-        endpoint_dev3_to_dev2 = device_3.endpoint('to-dev2').create(port_type='WDM')
-        endpoint_dev3_to_dev4 = device_3.endpoint('to-dev4').create(port_type='WDM')
-
-        device_4 = topology.device('dev4').create(
+        dev3_ep1 = dev_3.endpoint('EP1').create(port_type='WDM')
+        dev3_ep2 = dev_3.endpoint('EP2').create(port_type='WDM')
+        dev3_ep4 = dev_3.endpoint('EP4').create(port_type='WDM')
+        dev3_ep101 = dev_3.endpoint('EP5').create(port_type='OCH')
+        dev3_ep102 = dev_3.endpoint('EP6').create(port_type='OCH')
+        dev3_ep103 = dev_3.endpoint('EP7').create(port_type='OCH')
+
+        dev_4 = topology.device('DEV4').create(
             device_type='ROADM', device_config='<config/>', device_operational_status=OperationalStatus.ENABLED)
-        endpoint_dev4_to_dev1 = device_4.endpoint('to-dev1').create(port_type='WDM')
-        endpoint_dev4_to_dev2 = device_4.endpoint('to-dev2').create(port_type='WDM')
-        endpoint_dev4_to_dev3 = device_4.endpoint('to-dev3').create(port_type='WDM')
-
-        link_dev1_to_dev2 = topology.link('dev1/to-dev2 ==> dev2/to-dev1').create()
-        link_dev1_to_dev2.endpoint('dev1/to-dev2').create(endpoint_dev1_to_dev2)
-        link_dev1_to_dev2.endpoint('dev2/to-dev1').create(endpoint_dev2_to_dev1)
-
-        link_dev1_to_dev3 = topology.link('dev1/to-dev3 ==> dev3/to-dev1').create()
-        link_dev1_to_dev3.endpoint('dev1/to-dev3').create(endpoint_dev1_to_dev3)
-        link_dev1_to_dev3.endpoint('dev3/to-dev1').create(endpoint_dev3_to_dev1)
-
-        link_dev1_to_dev4 = topology.link('dev1/to-dev4 ==> dev4/to-dev1').create()
-        link_dev1_to_dev4.endpoint('dev1/to-dev4').create(endpoint_dev1_to_dev4)
-        link_dev1_to_dev4.endpoint('dev4/to-dev1').create(endpoint_dev4_to_dev1)
-
-        link_dev2_to_dev1 = topology.link('dev2/to-dev1 ==> dev1/to-dev2').create()
-        link_dev2_to_dev1.endpoint('dev2/to-dev1').create(endpoint_dev2_to_dev1)
-        link_dev2_to_dev1.endpoint('dev1/to-dev2').create(endpoint_dev1_to_dev2)
-
-        link_dev2_to_dev3 = topology.link('dev2/to-dev3 ==> dev3/to-dev2').create()
-        link_dev2_to_dev3.endpoint('dev2/to-dev3').create(endpoint_dev2_to_dev3)
-        link_dev2_to_dev3.endpoint('dev3/to-dev2').create(endpoint_dev3_to_dev2)
-
-        link_dev2_to_dev4 = topology.link('dev2/to-dev4 ==> dev4/to-dev2').create()
-        link_dev2_to_dev4.endpoint('dev2/to-dev4').create(endpoint_dev2_to_dev4)
-        link_dev2_to_dev4.endpoint('dev4/to-dev2').create(endpoint_dev4_to_dev2)
-
-        link_dev3_to_dev1 = topology.link('dev3/to-dev1 ==> dev1/to-dev3').create()
-        link_dev3_to_dev1.endpoint('dev3/to-dev1').create(endpoint_dev3_to_dev1)
-        link_dev3_to_dev1.endpoint('dev1/to-dev3').create(endpoint_dev1_to_dev3)
-
-        link_dev3_to_dev2 = topology.link('dev3/to-dev2 ==> dev2/to-dev3').create()
-        link_dev3_to_dev2.endpoint('dev3/to-dev2').create(endpoint_dev3_to_dev2)
-        link_dev3_to_dev2.endpoint('dev2/to-dev3').create(endpoint_dev2_to_dev3)
-
-        link_dev3_to_dev4 = topology.link('dev3/to-dev4 ==> dev4/to-dev3').create()
-        link_dev3_to_dev4.endpoint('dev3/to-dev4').create(endpoint_dev3_to_dev4)
-        link_dev3_to_dev4.endpoint('dev4/to-dev3').create(endpoint_dev4_to_dev3)
-
-        link_dev4_to_dev1 = topology.link('dev4/to-dev1 ==> dev1/to-dev4').create()
-        link_dev4_to_dev1.endpoint('dev4/to-dev1').create(endpoint_dev4_to_dev1)
-        link_dev4_to_dev1.endpoint('dev1/to-dev4').create(endpoint_dev1_to_dev4)
-
-        link_dev4_to_dev2 = topology.link('dev4/to-dev2 ==> dev2/to-dev4').create()
-        link_dev4_to_dev2.endpoint('dev4/to-dev2').create(endpoint_dev4_to_dev2)
-        link_dev4_to_dev2.endpoint('dev2/to-dev4').create(endpoint_dev2_to_dev4)
-
-        link_dev4_to_dev3 = topology.link('dev4/to-dev3 ==> dev3/to-dev4').create()
-        link_dev4_to_dev3.endpoint('dev4/to-dev3').create(endpoint_dev4_to_dev3)
-        link_dev4_to_dev3.endpoint('dev3/to-dev4').create(endpoint_dev3_to_dev4)
+        dev4_ep1 = dev_4.endpoint('EP1').create(port_type='WDM')
+        dev4_ep2 = dev_4.endpoint('EP2').create(port_type='WDM')
+        dev4_ep3 = dev_4.endpoint('EP3').create(port_type='WDM')
+        dev4_ep101 = dev_4.endpoint('EP5').create(port_type='OCH')
+        dev4_ep102 = dev_4.endpoint('EP6').create(port_type='OCH')
+        dev4_ep103 = dev_4.endpoint('EP7').create(port_type='OCH')
+
+        link_dev1_to_dev2 = topology.link('DEV1/EP2 ==> DEV2/EP1').create()
+        link_dev1_to_dev2.endpoint('DEV1/EP2').create(dev1_ep2)
+        link_dev1_to_dev2.endpoint('DEV2/EP1').create(dev2_ep1)
+
+        link_dev1_to_dev3 = topology.link('DEV1/EP3 ==> DEV3/EP1').create()
+        link_dev1_to_dev3.endpoint('DEV1/EP3').create(dev1_ep3)
+        link_dev1_to_dev3.endpoint('DEV3/EP1').create(dev3_ep1)
+
+        link_dev1_to_dev4 = topology.link('DEV1/EP4 ==> DEV4/EP1').create()
+        link_dev1_to_dev4.endpoint('DEV1/EP4').create(dev1_ep4)
+        link_dev1_to_dev4.endpoint('DEV4/EP1').create(dev4_ep1)
+
+        link_dev2_to_dev1 = topology.link('DEV2/EP1 ==> DEV1/EP2').create()
+        link_dev2_to_dev1.endpoint('DEV2/EP1').create(dev2_ep1)
+        link_dev2_to_dev1.endpoint('DEV1/EP2').create(dev1_ep2)
+
+        link_dev2_to_dev3 = topology.link('DEV2/EP3 ==> DEV3/EP2').create()
+        link_dev2_to_dev3.endpoint('DEV2/EP3').create(dev2_ep3)
+        link_dev2_to_dev3.endpoint('DEV3/EP2').create(dev3_ep2)
+
+        link_dev2_to_dev4 = topology.link('DEV2/EP4 ==> DEV4/EP2').create()
+        link_dev2_to_dev4.endpoint('DEV2/EP4').create(dev2_ep4)
+        link_dev2_to_dev4.endpoint('DEV4/EP2').create(dev4_ep2)
+
+        link_dev3_to_dev1 = topology.link('DEV3/EP1 ==> DEV1/EP3').create()
+        link_dev3_to_dev1.endpoint('DEV3/EP1').create(dev3_ep1)
+        link_dev3_to_dev1.endpoint('DEV1/EP3').create(dev1_ep3)
+
+        link_dev3_to_dev2 = topology.link('DEV3/EP2 ==> DEV2/EP3').create()
+        link_dev3_to_dev2.endpoint('DEV3/EP2').create(dev3_ep2)
+        link_dev3_to_dev2.endpoint('DEV2/EP3').create(dev2_ep3)
+
+        link_dev3_to_dev4 = topology.link('DEV3/EP4 ==> DEV4/EP3').create()
+        link_dev3_to_dev4.endpoint('DEV3/EP4').create(dev3_ep4)
+        link_dev3_to_dev4.endpoint('DEV4/EP3').create(dev4_ep3)
+
+        link_dev4_to_dev1 = topology.link('DEV4/EP1 ==> DEV1/EP4').create()
+        link_dev4_to_dev1.endpoint('DEV4/EP1').create(dev4_ep1)
+        link_dev4_to_dev1.endpoint('DEV1/EP4').create(dev1_ep4)
+
+        link_dev4_to_dev2 = topology.link('DEV4/EP2 ==> DEV2/EP4').create()
+        link_dev4_to_dev2.endpoint('DEV4/EP2').create(dev4_ep2)
+        link_dev4_to_dev2.endpoint('DEV2/EP4').create(dev2_ep4)
+
+        link_dev4_to_dev3 = topology.link('DEV4/EP3 ==> DEV3/EP4').create()
+        link_dev4_to_dev3.endpoint('DEV4/EP3').create(dev4_ep3)
+        link_dev4_to_dev3.endpoint('DEV3/EP4').create(dev3_ep4)
+
+        service = context.service('S01').create(ServiceType.L3NM, '<config/>', ServiceState.PLANNED)
+        service.endpoint('S01/EP01').create(dev1_ep101)
+        service.endpoint('S01/EP02').create(dev2_ep101)
+        service.endpoint('S01/EP03').create(dev3_ep101)
+        service.endpoint('S01/EP04').create(dev4_ep101)
+
+        service = context.service('S02').create(ServiceType.L3NM, '<config/>', ServiceState.PLANNED)
+        service.endpoint('S02/EP01').create(dev1_ep102)
+        service.endpoint('S02/EP02').create(dev2_ep102)
+        service.endpoint('S02/EP03').create(dev3_ep102)
+        service.endpoint('S02/EP04').create(dev4_ep102)
+
+        service = context.service('S03').create(ServiceType.L3NM, '<config/>', ServiceState.PLANNED)
+        service.endpoint('S03/EP01').create(dev1_ep103)
+        service.endpoint('S03/EP02').create(dev2_ep103)
+        service.endpoint('S03/EP03').create(dev3_ep103)
+        service.endpoint('S03/EP04').create(dev4_ep103)
 
 def sequence(database : Database):
     populate_example(database)
diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py
index 6a189d67835a3185c3d87f52bd76dd9582e261dc..e68dc6a24ecf8d3162da084a3ab78c604d381767 100644
--- a/src/context/service/ContextServiceServicerImpl.py
+++ b/src/context/service/ContextServiceServicerImpl.py
@@ -2,7 +2,7 @@ from typing import Dict, List, Set, Tuple
 import grpc, logging
 from prometheus_client import Counter, Histogram
 from common.Checkers import chk_string
-from common.database.api.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
+from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
 from common.database.api.Database import Database
 from common.exceptions.ServiceException import ServiceException
 from context.proto.context_pb2 import Empty, Link, LinkId, Topology
@@ -139,8 +139,11 @@ class ContextServiceServicerImpl(ContextServiceServicer):
                     raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, msg)
 
                 if not db_topology.devices.contains(ep_device_id):
-                    msg = 'Device({}) in Endpoint(#{}) of Link({}) does not exist in the database.'
-                    msg = msg.format(ep_device_id, i, link_id)
+                    msg = ' '.join([
+                        'Context({})/Topology({})/Device({}) in Endpoint(#{}) of Link({})',
+                        'does not exist in the database.',
+                    ])
+                    msg = msg.format(ep_context_id, ep_topology_id, ep_device_id, ep_port_id, i, link_id)
                     raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
 
                 added_device_and_endpoints = added_devices_and_endpoints.setdefault(ep_device_id, set())
@@ -152,10 +155,14 @@ class ContextServiceServicerImpl(ContextServiceServicer):
                     raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, msg)           # pragma: no cover
 
                 if not db_topology.device(ep_device_id).endpoints.contains(ep_port_id):
-                    msg = 'Device({})/Port({}) in Endpoint(#{}) of Link({}) does not exist in the database.'
-                    msg = msg.format(ep_device_id, ep_port_id, i, link_id)
+                    msg = ' '.join([
+                        'Context({})/Topology({})/Device({})/Port({}) in Endpoint(#{}) of Link({})',
+                        'does not exist in the database.',
+                    ])
+                    msg = msg.format(ep_context_id, ep_topology_id, ep_device_id, ep_port_id, i, link_id)
                     raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
 
+
                 added_device_and_endpoints.add(ep_port_id)
                 device_endpoint_pairs.append((ep_device_id, ep_port_id))
 
@@ -163,7 +170,7 @@ class ContextServiceServicerImpl(ContextServiceServicer):
             db_link = db_topology.link(link_id).create()
             for device_id,endpoint_id in device_endpoint_pairs:
                 link_endpoint_id = '{}/{}'.format(device_id, endpoint_id)
-                db_endpoint = db_topology.device(ep_device_id).endpoint(ep_port_id)
+                db_endpoint = db_topology.device(device_id).endpoint(endpoint_id)
                 db_link.endpoint(link_endpoint_id).create(db_endpoint)
 
             # ----- Compose reply --------------------------------------------------------------------------------------
diff --git a/src/context/tests/test_unitary.py b/src/context/tests/test_unitary.py
index 104736af195f0eb0643563f816bdaeefa5b0743b..c1e5d9658787b8150218f67d211744d32a514633 100644
--- a/src/context/tests/test_unitary.py
+++ b/src/context/tests/test_unitary.py
@@ -14,25 +14,25 @@ port = 10000 + GRPC_SERVICE_PORT # avoid first 1024 privileged ports to avoid ev
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
 
-LINK_ID = {'link_id': {'uuid': 'dev1/to-dev2 ==> dev2/to-dev1'}}
+LINK_ID = {'link_id': {'uuid': 'DEV1/EP2 ==> DEV2/EP1'}}
 LINK = {
-    'link_id': {'link_id': {'uuid': 'dev1/to-dev2 ==> dev2/to-dev1'}},
+    'link_id': {'link_id': {'uuid': 'DEV1/EP2 ==> DEV2/EP1'}},
     'endpointList' : [
         {
             'topoId': {
                 'contextId': {'contextUuid': {'uuid': 'admin'}},
                 'topoId': {'uuid': 'admin'}
             },
-            'dev_id': {'device_id': {'uuid': 'dev1'}},
-            'port_id': {'uuid' : 'to-dev2'}
+            'dev_id': {'device_id': {'uuid': 'DEV1'}},
+            'port_id': {'uuid' : 'EP2'}
         },
         {
             'topoId': {
                 'contextId': {'contextUuid': {'uuid': 'admin'}},
                 'topoId': {'uuid': 'admin'}
             },
-            'dev_id': {'device_id': {'uuid': 'dev2'}},
-            'port_id': {'uuid' : 'to-dev1'}
+            'dev_id': {'device_id': {'uuid': 'DEV2'}},
+            'port_id': {'uuid' : 'EP1'}
         },
     ]
 }
@@ -86,7 +86,7 @@ def test_add_link_already_exists(context_client : ContextClient):
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         context_client.AddLink(Link(**LINK))
     assert e.value.code() == grpc.StatusCode.ALREADY_EXISTS
-    assert e.value.details() == 'Link(dev1/to-dev2 ==> dev2/to-dev1) already exists in the database.'
+    assert e.value.details() == 'Link(DEV1/EP2 ==> DEV2/EP1) already exists in the database.'
 
 def test_delete_link(context_client : ContextClient):
     # should work
@@ -100,7 +100,7 @@ def test_delete_link_not_existing(context_client : ContextClient):
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         context_client.DeleteLink(LinkId(**LINK_ID))
     assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    assert e.value.details() == 'Link(dev1/to-dev2 ==> dev2/to-dev1) does not exist in the database.'
+    assert e.value.details() == 'Link(DEV1/EP2 ==> DEV2/EP1) does not exist in the database.'
 
 def test_add_link_uuid_empty(context_client : ContextClient):
     # should fail with link uuid empty
@@ -119,7 +119,7 @@ def test_add_link_endpoint_wrong_context(context_client : ContextClient):
         context_client.AddLink(Link(**copy_link))
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
     msg = ' '.join([
-        'Unsupported Context(wrong-context) in Endpoint(#0) of Link(dev1/to-dev2 ==> dev2/to-dev1).',
+        'Unsupported Context(wrong-context) in Endpoint(#0) of Link(DEV1/EP2 ==> DEV2/EP1).',
         'Only default Context(admin) is currently supported.',
         'Optionally, leave field empty to use default Context.',
     ])
@@ -133,7 +133,7 @@ def test_add_link_endpoint_wrong_topology(context_client : ContextClient):
         context_client.AddLink(Link(**copy_link))
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
     msg = ' '.join([
-        'Unsupported Topology(wrong-topo) in Endpoint(#0) of Link(dev1/to-dev2 ==> dev2/to-dev1).',
+        'Unsupported Topology(wrong-topo) in Endpoint(#0) of Link(DEV1/EP2 ==> DEV2/EP1).',
         'Only default Topology(admin) is currently supported.',
         'Optionally, leave field empty to use default Topology.',
     ])
@@ -155,7 +155,7 @@ def test_add_link_endpoint_wrong_device(context_client : ContextClient):
         copy_link['endpointList'][0]['dev_id']['device_id']['uuid'] = 'wrong-device'
         context_client.AddLink(Link(**copy_link))
     assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    msg = 'Device(wrong-device) in Endpoint(#0) of Link(dev1/to-dev2 ==> dev2/to-dev1) does not exist in the database.'
+    msg = 'Device(wrong-device) in Endpoint(#0) of Link(DEV1/EP2 ==> DEV2/EP1) does not exist in the database.'
     assert e.value.details() == msg
 
 def test_add_link_endpoint_wrong_port(context_client : ContextClient):
@@ -165,17 +165,17 @@ def test_add_link_endpoint_wrong_port(context_client : ContextClient):
         copy_link['endpointList'][0]['port_id']['uuid'] = 'wrong-port'
         context_client.AddLink(Link(**copy_link))
     assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    msg = 'Device(dev1)/Port(wrong-port) in Endpoint(#0) of Link(dev1/to-dev2 ==> dev2/to-dev1) does not exist in the database.'
+    msg = 'Device(DEV1)/Port(wrong-port) in Endpoint(#0) of Link(DEV1/EP2 ==> DEV2/EP1) does not exist in the database.'
     assert e.value.details() == msg
 
 def test_add_link_endpoint_duplicated_device(context_client : ContextClient):
     # should fail with duplicated endpoint device
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         copy_link = copy.deepcopy(LINK)
-        copy_link['endpointList'][1]['dev_id']['device_id']['uuid'] = 'dev1'
+        copy_link['endpointList'][1]['dev_id']['device_id']['uuid'] = 'DEV1'
         context_client.AddLink(Link(**copy_link))
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-    msg = 'Duplicated Device(dev1) in Endpoint(#1) of Link(dev1/to-dev2 ==> dev2/to-dev1).'
+    msg = 'Duplicated Device(DEV1) in Endpoint(#1) of Link(DEV1/EP2 ==> DEV2/EP1).'
     assert e.value.details() == msg
 
 def test_add_link_empty_port_uuid(context_client : ContextClient):
diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py
index 71c4bfc6d8dc809a837669614aaf60c7e6578fd9..2bda5d0480294fb6a1dc8ad545db7d7c3e2ddac3 100644
--- a/src/device/service/DeviceServiceServicerImpl.py
+++ b/src/device/service/DeviceServiceServicerImpl.py
@@ -2,10 +2,10 @@ from typing import List, Tuple
 import grpc, logging
 from prometheus_client import Counter, Histogram
 from common.Checkers import chk_options, chk_string
-from common.database.api.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
+from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
 from common.database.api.Database import Database
-from common.database.api.context.OperationalStatus import OperationalStatus, operationalstatus_enum_values, \
-    to_operationalstatus_enum
+from common.database.api.context.topology.device.OperationalStatus import OperationalStatus, \
+    operationalstatus_enum_values, to_operationalstatus_enum
 from common.exceptions.ServiceException import ServiceException
 from device.proto.context_pb2 import DeviceId, Device, Empty
 from device.proto.device_pb2_grpc import DeviceServiceServicer
diff --git a/src/device/tests/test_unitary.py b/src/device/tests/test_unitary.py
index 9834c5c39761997b336ed9feda11d6899dde19c0..fcabea92850b41e08d83b5e660c256ec1d1c30b5 100644
--- a/src/device/tests/test_unitary.py
+++ b/src/device/tests/test_unitary.py
@@ -1,7 +1,7 @@
 import copy, grpc, logging, pytest
 from google.protobuf.json_format import MessageToDict
 from common.database.Factory import get_database, DatabaseEngineEnum
-from common.database.api.context.OperationalStatus import OperationalStatus
+from common.database.api.context.topology.device.OperationalStatus import OperationalStatus
 from common.tests.Assertions import validate_device_id, validate_empty
 from device.client.DeviceClient import DeviceClient
 from device.proto.context_pb2 import Device, DeviceId
@@ -11,9 +11,9 @@ from device.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
 
-DEVICE_ID = {'device_id': {'uuid': 'dev1'}}
+DEVICE_ID = {'device_id': {'uuid': 'DEV1'}}
 DEVICE = {
-    'device_id': {'device_id': {'uuid': 'dev1'}},
+    'device_id': {'device_id': {'uuid': 'DEV1'}},
     'device_type': 'ROADM',
     'device_config': {'device_config': '<config/>'},
     'devOperationalStatus': OperationalStatus.ENABLED.value,
@@ -24,8 +24,8 @@ DEVICE = {
                     'contextId': {'contextUuid': {'uuid': 'admin'}},
                     'topoId': {'uuid': 'admin'}
                 },
-                'dev_id': {'device_id': {'uuid': 'dev1'}},
-                'port_id': {'uuid' : 'to-dev2'}
+                'dev_id': {'device_id': {'uuid': 'DEV1'}},
+                'port_id': {'uuid' : 'EP2'}
             },
             'port_type': 'WDM'
         },
@@ -35,8 +35,8 @@ DEVICE = {
                     'contextId': {'contextUuid': {'uuid': 'admin'}},
                     'topoId': {'uuid': 'admin'}
                 },
-                'dev_id': {'device_id': {'uuid': 'dev1'}},
-                'port_id': {'uuid' : 'to-dev3'}
+                'dev_id': {'device_id': {'uuid': 'DEV1'}},
+                'port_id': {'uuid' : 'EP3'}
             },
             'port_type': 'WDM'
         },
@@ -46,8 +46,8 @@ DEVICE = {
                     'contextId': {'contextUuid': {'uuid': 'admin'}},
                     'topoId': {'uuid': 'admin'}
                 },
-                'dev_id': {'device_id': {'uuid': 'dev1'}},
-                'port_id': {'uuid' : 'to-dev4'}
+                'dev_id': {'device_id': {'uuid': 'DEV1'}},
+                'port_id': {'uuid' : 'EP4'}
             },
             'port_type': 'WDM'
         },
@@ -113,7 +113,7 @@ def test_add_device_endpoint_wrong_context(device_client : DeviceClient):
         device_client.AddDevice(request)
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
     msg = ' '.join([
-        'Unsupported Context(wrong-context) in Endpoint(#0) of Device(dev1).',
+        'Unsupported Context(wrong-context) in Endpoint(#0) of Device(DEV1).',
         'Only default Context(admin) is currently supported.',
         'Optionally, leave field empty to use default Context.',
     ])
@@ -127,7 +127,7 @@ def test_add_device_endpoint_wrong_topology(device_client : DeviceClient):
         device_client.AddDevice(Device(**copy_device))
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
     msg = ' '.join([
-        'Unsupported Topology(wrong-topo) in Endpoint(#0) of Device(dev1).',
+        'Unsupported Topology(wrong-topo) in Endpoint(#0) of Device(DEV1).',
         'Only default Topology(admin) is currently supported.',
         'Optionally, leave field empty to use default Topology.',
     ])
@@ -142,7 +142,7 @@ def test_add_device_endpoint_wrong_device(device_client : DeviceClient):
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
     msg = ' '.join([
         'Wrong Device(wrong-device) in Endpoint(#0).',
-        'Parent specified in message is Device(dev1).',
+        'Parent specified in message is Device(DEV1).',
         'Optionally, leave field empty to use parent Device.',
     ])
     assert e.value.details() == msg
@@ -169,10 +169,10 @@ def test_add_device_duplicate_port(device_client : DeviceClient):
     # should fail with uplicate port in device
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         copy_device = copy.deepcopy(DEVICE)
-        copy_device['endpointList'][1]['port_id']['port_id']['uuid'] = 'to-dev2'
+        copy_device['endpointList'][1]['port_id']['port_id']['uuid'] = 'EP2'
         device_client.AddDevice(Device(**copy_device))
     assert e.value.code() == grpc.StatusCode.ALREADY_EXISTS
-    assert e.value.details() == 'Duplicated Port(to-dev2) in Endpoint(#1) of Device(dev1).'
+    assert e.value.details() == 'Duplicated Port(EP2) in Endpoint(#1) of Device(DEV1).'
 
 def test_add_device(device_client : DeviceClient):
     # should work
@@ -186,7 +186,7 @@ def test_add_device_duplicate(device_client : DeviceClient):
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         device_client.AddDevice(Device(**DEVICE))
     assert e.value.code() == grpc.StatusCode.ALREADY_EXISTS
-    assert e.value.details() == 'Device(dev1) already exists in the database.'
+    assert e.value.details() == 'Device(DEV1) already exists in the database.'
 
 def test_delete_device_empty_uuid(device_client : DeviceClient):
     # should fail with device uuid is empty
@@ -249,7 +249,7 @@ def test_configure_device_wrong_device_type(device_client : DeviceClient):
         copy_device['device_type'] = 'wrong-type'
         device_client.ConfigureDevice(Device(**copy_device))
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-    assert e.value.details() == 'Device(dev1) has Type(ROADM) in the database. Cannot be changed to Type(wrong-type).'
+    assert e.value.details() == 'Device(DEV1) has Type(ROADM) in the database. Cannot be changed to Type(wrong-type).'
 
 def test_configure_device_with_endpoints(device_client : DeviceClient):
     # should fail with endpoints cannot be modified
@@ -257,7 +257,7 @@ def test_configure_device_with_endpoints(device_client : DeviceClient):
         copy_device = copy.deepcopy(DEVICE)
         device_client.ConfigureDevice(Device(**copy_device))
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-    assert e.value.details() == 'Endpoints belonging to Device(dev1) cannot be modified.'
+    assert e.value.details() == 'Endpoints belonging to Device(DEV1) cannot be modified.'
 
 def test_configure_device_no_change(device_client : DeviceClient):
     # should fail with any change detected
@@ -269,7 +269,7 @@ def test_configure_device_no_change(device_client : DeviceClient):
         device_client.ConfigureDevice(Device(**copy_device))
     assert e.value.code() == grpc.StatusCode.ABORTED
     msg = ' '.join([
-        'Any change has been requested for Device(dev1).',
+        'Any change has been requested for Device(DEV1).',
         'Either specify a new configuration or a new device operational status.',
     ])
     assert e.value.details() == msg
diff --git a/src/service/.gitlab-ci.yml b/src/service/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..de771e6729580e8d68063dc757cfb26cccdcc5b9
--- /dev/null
+++ b/src/service/.gitlab-ci.yml
@@ -0,0 +1,59 @@
+# Build, tag, and push the Docker images to the GitLab Docker registry
+build service:
+  variables:
+    IMAGE_NAME: 'service' # name of the microservice
+    IMAGE_NAME_TEST: 'service-test' # name of the microservice
+    IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
+  stage: build
+  before_script:
+    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
+  script:
+    - docker build -t "$IMAGE_NAME:$IMAGE_TAG" -f ./src/$IMAGE_NAME/Dockerfile ./src/
+    - docker tag "$IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
+    - docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
+  rules:
+    - changes:
+      - src/$IMAGE_NAME/**
+      - .gitlab-ci.yml
+
+# Pull, execute, and run unitary tests for the Docker image from the GitLab registry
+test service:
+  variables:
+    IMAGE_NAME: 'service' # name of the microservice
+    IMAGE_NAME_TEST: 'service-test' # name of the microservice
+    IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
+  stage: test
+  needs:
+    - build service
+  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  
+  script:
+    - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
+    - docker run -d -p 3030:3030 --name $IMAGE_NAME --network=teraflowbridge "$IMAGE_NAME:$IMAGE_TAG"
+    - docker ps -a
+    - sleep 5
+    - docker ps -a
+    - docker logs $IMAGE_NAME
+    - docker exec -i $IMAGE_NAME bash -c "pytest --log-level=DEBUG --verbose $IMAGE_NAME/tests/test_unitary.py"
+  after_script:
+    - docker stop $IMAGE_NAME
+    - docker rm $IMAGE_NAME
+  rules:
+    - changes:
+      - src/$IMAGE_NAME/**
+      - .gitlab-ci.yml
+
+# Deployment of the service in Kubernetes Cluster
+deploy service:
+  stage: deploy
+  needs:
+    - build service
+    - test service
+    - dependencies all
+  script:
+    - kubectl version
+    - kubectl get all
+    - kubectl apply -f "manifests/serviceservice.yaml"
+    - kubectl delete pods --selector app=serviceservice
+    - kubectl get all
diff --git a/src/service/Config.py b/src/service/Config.py
new file mode 100644
index 0000000000000000000000000000000000000000..592392a1bde5757f83fd67589a7b7b7d6cc3e6c0
--- /dev/null
+++ b/src/service/Config.py
@@ -0,0 +1,12 @@
+import logging
+
+# General settings
+LOG_LEVEL = logging.WARNING
+
+# gRPC settings
+GRPC_SERVICE_PORT = 3030
+GRPC_MAX_WORKERS  = 10
+GRPC_GRACE_PERIOD = 60
+
+# Prometheus settings
+METRICS_PORT = 9192
diff --git a/src/service/Dockerfile b/src/service/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..306379a06d33c67c082540e19f3b1ca349becff2
--- /dev/null
+++ b/src/service/Dockerfile
@@ -0,0 +1,35 @@
+FROM python:3-slim
+
+# Install dependencies
+RUN apt-get --yes --quiet --quiet update && \
+    apt-get --yes --quiet --quiet install wget g++ && \
+    rm -rf /var/lib/apt/lists/*
+
+# Set Python to show logs as they occur
+ENV PYTHONUNBUFFERED=0
+
+# Download the gRPC health probe
+RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \
+    wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \
+    chmod +x /bin/grpc_health_probe
+
+# Get generic Python packages
+RUN python3 -m pip install --upgrade pip setuptools wheel pip-tools
+
+# Set working directory
+WORKDIR /var/teraflow
+
+# Create module sub-folders
+RUN mkdir -p /var/teraflow/service
+
+# Get Python packages per module
+COPY service/requirements.in service/requirements.in
+RUN pip-compile --output-file=service/requirements.txt service/requirements.in
+RUN python3 -m pip install -r service/requirements.in
+
+# Add files into working directory
+COPY common/. common
+COPY service/. service
+
+# Start service service
+ENTRYPOINT ["python", "-m", "service.service"]
diff --git a/src/service/__init__.py b/src/service/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/service/client/ServiceClient.py b/src/service/client/ServiceClient.py
new file mode 100644
index 0000000000000000000000000000000000000000..95b18863879d3f3c6d8dfd38a7073eca0a492440
--- /dev/null
+++ b/src/service/client/ServiceClient.py
@@ -0,0 +1,69 @@
+import grpc, logging
+from common.tools.RetryDecorator import retry, delay_exponential
+from service.proto.context_pb2 import Empty
+from service.proto.service_pb2 import ConnectionList, Service, ServiceId, ServiceList
+from service.proto.service_pb2_grpc import ServiceServiceStub
+
+LOGGER = logging.getLogger(__name__)
+MAX_RETRIES = 15
+DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0)
+
+class ServiceClient:
+    def __init__(self, address, port):
+        self.endpoint = '{}:{}'.format(address, port)
+        LOGGER.debug('Creating channel to {}...'.format(self.endpoint))
+        self.channel = None
+        self.stub = None
+        self.connect()
+        LOGGER.debug('Channel created')
+
+    def connect(self):
+        self.channel = grpc.insecure_channel(self.endpoint)
+        self.stub = ServiceServiceStub(self.channel)
+
+    def close(self):
+        if(self.channel is not None): self.channel.close()
+        self.channel = None
+        self.stub = None
+
+    @retry(exceptions=set(), max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')
+    def GetServiceList(self, request : Empty) -> ServiceList:
+        LOGGER.debug('GetServiceList request: {}'.format(request))
+        response = self.stub.GetServiceList(request)
+        LOGGER.debug('GetServiceList result: {}'.format(response))
+        return response
+
+    @retry(exceptions=set(), max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')
+    def CreateService(self, request : Service) -> ServiceId:
+        LOGGER.debug('CreateService request: {}'.format(request))
+        response = self.stub.CreateService(request)
+        LOGGER.debug('CreateService result: {}'.format(response))
+        return response
+
+    @retry(exceptions=set(), max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')
+    def UpdateService(self, request : Service) -> ServiceId:
+        LOGGER.debug('UpdateService request: {}'.format(request))
+        response = self.stub.UpdateService(request)
+        LOGGER.debug('UpdateService result: {}'.format(response))
+        return response
+
+    @retry(exceptions=set(), max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')
+    def DeleteService(self, request : Service) -> ServiceId:
+        LOGGER.debug('DeleteService request: {}'.format(request))
+        response = self.stub.DeleteService(request)
+        LOGGER.debug('DeleteService result: {}'.format(response))
+        return response
+
+    @retry(exceptions=set(), max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')
+    def GetServiceById(self, request : ServiceId) -> Service:
+        LOGGER.debug('GetServiceById request: {}'.format(request))
+        response = self.stub.GetServiceById(request)
+        LOGGER.debug('GetServiceById result: {}'.format(response))
+        return response
+
+    @retry(exceptions=set(), max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')
+    def GetConnectionList(self, request : Empty) -> ConnectionList:
+        LOGGER.debug('GetConnectionList request: {}'.format(request))
+        response = self.stub.GetConnectionList(request)
+        LOGGER.debug('GetConnectionList result: {}'.format(response))
+        return response
diff --git a/src/service/client/__init__.py b/src/service/client/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/service/genproto.sh b/src/service/genproto.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9b6387a8a0739ce1cbf2cb75f1e178880a5dbc8e
--- /dev/null
+++ b/src/service/genproto.sh
@@ -0,0 +1,33 @@
+#!/bin/bash -eu
+#
+# Copyright 2018 Google LLC
+#
+# 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.
+
+#!/bin/bash -e
+
+# Make folder containing the script the root folder for its execution
+cd $(dirname $0)
+
+rm -rf proto/*.py
+rm -rf proto/__pycache__
+touch proto/__init__.py
+
+python -m grpc_tools.protoc -I../../proto --python_out=proto --grpc_python_out=proto context.proto
+python -m grpc_tools.protoc -I../../proto --python_out=proto --grpc_python_out=proto service.proto
+
+rm proto/context_pb2_grpc.py
+
+sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' proto/context_pb2.py
+sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' proto/service_pb2.py
+sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' proto/service_pb2_grpc.py
diff --git a/src/service/proto/__init__.py b/src/service/proto/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/service/proto/context_pb2.py b/src/service/proto/context_pb2.py
new file mode 100644
index 0000000000000000000000000000000000000000..a41b1de47f4df97a6e90b42a02fab7556feafd34
--- /dev/null
+++ b/src/service/proto/context_pb2.py
@@ -0,0 +1,880 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: context.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='context.proto',
+  package='context',
+  syntax='proto3',
+  serialized_options=None,
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\rcontext.proto\x12\x07\x63ontext\"\x07\n\x05\x45mpty\"{\n\x07\x43ontext\x12%\n\tcontextId\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x1f\n\x04topo\x18\x02 \x01(\x0b\x32\x11.context.Topology\x12(\n\x03\x63tl\x18\x03 \x01(\x0b\x32\x1b.context.TeraFlowController\"/\n\tContextId\x12\"\n\x0b\x63ontextUuid\x18\x01 \x01(\x0b\x32\r.context.Uuid\"m\n\x08Topology\x12#\n\x06topoId\x18\x02 \x01(\x0b\x32\x13.context.TopologyId\x12\x1f\n\x06\x64\x65vice\x18\x03 \x03(\x0b\x32\x0f.context.Device\x12\x1b\n\x04link\x18\x04 \x03(\x0b\x32\r.context.Link\"S\n\x04Link\x12 \n\x07link_id\x18\x01 \x01(\x0b\x32\x0f.context.LinkId\x12)\n\x0c\x65ndpointList\x18\x02 \x03(\x0b\x32\x13.context.EndPointId\"R\n\nTopologyId\x12%\n\tcontextId\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x1d\n\x06topoId\x18\x02 \x01(\x0b\x32\r.context.Uuid\"?\n\nConstraint\x12\x17\n\x0f\x63onstraint_type\x18\x01 \x01(\t\x12\x18\n\x10\x63onstraint_value\x18\x02 \x01(\t\"\xda\x01\n\x06\x44\x65vice\x12$\n\tdevice_id\x18\x01 \x01(\x0b\x32\x11.context.DeviceId\x12\x13\n\x0b\x64\x65vice_type\x18\x02 \x01(\t\x12,\n\rdevice_config\x18\x03 \x01(\x0b\x32\x15.context.DeviceConfig\x12>\n\x14\x64\x65vOperationalStatus\x18\x04 \x01(\x0e\x32 .context.DeviceOperationalStatus\x12\'\n\x0c\x65ndpointList\x18\x05 \x03(\x0b\x32\x11.context.EndPoint\"%\n\x0c\x44\x65viceConfig\x12\x15\n\rdevice_config\x18\x01 \x01(\t\"C\n\x08\x45ndPoint\x12$\n\x07port_id\x18\x01 \x01(\x0b\x32\x13.context.EndPointId\x12\x11\n\tport_type\x18\x02 \x01(\t\"t\n\nEndPointId\x12#\n\x06topoId\x18\x01 \x01(\x0b\x32\x13.context.TopologyId\x12!\n\x06\x64\x65v_id\x18\x02 \x01(\x0b\x32\x11.context.DeviceId\x12\x1e\n\x07port_id\x18\x03 \x01(\x0b\x32\r.context.Uuid\",\n\x08\x44\x65viceId\x12 \n\tdevice_id\x18\x01 \x01(\x0b\x32\r.context.Uuid\"(\n\x06LinkId\x12\x1e\n\x07link_id\x18\x01 \x01(\x0b\x32\r.context.Uuid\"\x14\n\x04Uuid\x12\x0c\n\x04uuid\x18\x01 \x01(\t\"K\n\x12TeraFlowController\x12\"\n\x06\x63tl_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x11\n\tipaddress\x18\x02 \x01(\t\"Q\n\x14\x41uthenticationResult\x12\"\n\x06\x63tl_id\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x15\n\rauthenticated\x18\x02 \x01(\x08*N\n\x17\x44\x65viceOperationalStatus\x12\x0f\n\x0bKEEP_STATUS\x10\x00\x12\x15\n\x08\x44ISABLED\x10\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x12\x0b\n\x07\x45NABLED\x10\x01\x32\xa2\x01\n\x0e\x43ontextService\x12\x32\n\x0bGetTopology\x12\x0e.context.Empty\x1a\x11.context.Topology\"\x00\x12+\n\x07\x41\x64\x64Link\x12\r.context.Link\x1a\x0f.context.LinkId\"\x00\x12/\n\nDeleteLink\x12\x0f.context.LinkId\x1a\x0e.context.Empty\"\x00\x62\x06proto3'
+)
+
+_DEVICEOPERATIONALSTATUS = _descriptor.EnumDescriptor(
+  name='DeviceOperationalStatus',
+  full_name='context.DeviceOperationalStatus',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='KEEP_STATUS', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='DISABLED', index=1, number=-1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='ENABLED', index=2, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=1271,
+  serialized_end=1349,
+)
+_sym_db.RegisterEnumDescriptor(_DEVICEOPERATIONALSTATUS)
+
+DeviceOperationalStatus = enum_type_wrapper.EnumTypeWrapper(_DEVICEOPERATIONALSTATUS)
+KEEP_STATUS = 0
+DISABLED = -1
+ENABLED = 1
+
+
+
+_EMPTY = _descriptor.Descriptor(
+  name='Empty',
+  full_name='context.Empty',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=26,
+  serialized_end=33,
+)
+
+
+_CONTEXT = _descriptor.Descriptor(
+  name='Context',
+  full_name='context.Context',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='contextId', full_name='context.Context.contextId', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='topo', full_name='context.Context.topo', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='ctl', full_name='context.Context.ctl', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=35,
+  serialized_end=158,
+)
+
+
+_CONTEXTID = _descriptor.Descriptor(
+  name='ContextId',
+  full_name='context.ContextId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='contextUuid', full_name='context.ContextId.contextUuid', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=160,
+  serialized_end=207,
+)
+
+
+_TOPOLOGY = _descriptor.Descriptor(
+  name='Topology',
+  full_name='context.Topology',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='topoId', full_name='context.Topology.topoId', index=0,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='device', full_name='context.Topology.device', index=1,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='link', full_name='context.Topology.link', index=2,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=209,
+  serialized_end=318,
+)
+
+
+_LINK = _descriptor.Descriptor(
+  name='Link',
+  full_name='context.Link',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='link_id', full_name='context.Link.link_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='endpointList', full_name='context.Link.endpointList', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=320,
+  serialized_end=403,
+)
+
+
+_TOPOLOGYID = _descriptor.Descriptor(
+  name='TopologyId',
+  full_name='context.TopologyId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='contextId', full_name='context.TopologyId.contextId', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='topoId', full_name='context.TopologyId.topoId', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=405,
+  serialized_end=487,
+)
+
+
+_CONSTRAINT = _descriptor.Descriptor(
+  name='Constraint',
+  full_name='context.Constraint',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='constraint_type', full_name='context.Constraint.constraint_type', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='constraint_value', full_name='context.Constraint.constraint_value', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=489,
+  serialized_end=552,
+)
+
+
+_DEVICE = _descriptor.Descriptor(
+  name='Device',
+  full_name='context.Device',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='device_id', full_name='context.Device.device_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='device_type', full_name='context.Device.device_type', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='device_config', full_name='context.Device.device_config', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='devOperationalStatus', full_name='context.Device.devOperationalStatus', index=3,
+      number=4, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='endpointList', full_name='context.Device.endpointList', index=4,
+      number=5, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=555,
+  serialized_end=773,
+)
+
+
+_DEVICECONFIG = _descriptor.Descriptor(
+  name='DeviceConfig',
+  full_name='context.DeviceConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='device_config', full_name='context.DeviceConfig.device_config', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=775,
+  serialized_end=812,
+)
+
+
+_ENDPOINT = _descriptor.Descriptor(
+  name='EndPoint',
+  full_name='context.EndPoint',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='port_id', full_name='context.EndPoint.port_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='port_type', full_name='context.EndPoint.port_type', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=814,
+  serialized_end=881,
+)
+
+
+_ENDPOINTID = _descriptor.Descriptor(
+  name='EndPointId',
+  full_name='context.EndPointId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='topoId', full_name='context.EndPointId.topoId', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='dev_id', full_name='context.EndPointId.dev_id', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='port_id', full_name='context.EndPointId.port_id', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=883,
+  serialized_end=999,
+)
+
+
+_DEVICEID = _descriptor.Descriptor(
+  name='DeviceId',
+  full_name='context.DeviceId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='device_id', full_name='context.DeviceId.device_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1001,
+  serialized_end=1045,
+)
+
+
+_LINKID = _descriptor.Descriptor(
+  name='LinkId',
+  full_name='context.LinkId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='link_id', full_name='context.LinkId.link_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1047,
+  serialized_end=1087,
+)
+
+
+_UUID = _descriptor.Descriptor(
+  name='Uuid',
+  full_name='context.Uuid',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='uuid', full_name='context.Uuid.uuid', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1089,
+  serialized_end=1109,
+)
+
+
+_TERAFLOWCONTROLLER = _descriptor.Descriptor(
+  name='TeraFlowController',
+  full_name='context.TeraFlowController',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='ctl_id', full_name='context.TeraFlowController.ctl_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='ipaddress', full_name='context.TeraFlowController.ipaddress', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1111,
+  serialized_end=1186,
+)
+
+
+_AUTHENTICATIONRESULT = _descriptor.Descriptor(
+  name='AuthenticationResult',
+  full_name='context.AuthenticationResult',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='ctl_id', full_name='context.AuthenticationResult.ctl_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='authenticated', full_name='context.AuthenticationResult.authenticated', index=1,
+      number=2, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1188,
+  serialized_end=1269,
+)
+
+_CONTEXT.fields_by_name['contextId'].message_type = _CONTEXTID
+_CONTEXT.fields_by_name['topo'].message_type = _TOPOLOGY
+_CONTEXT.fields_by_name['ctl'].message_type = _TERAFLOWCONTROLLER
+_CONTEXTID.fields_by_name['contextUuid'].message_type = _UUID
+_TOPOLOGY.fields_by_name['topoId'].message_type = _TOPOLOGYID
+_TOPOLOGY.fields_by_name['device'].message_type = _DEVICE
+_TOPOLOGY.fields_by_name['link'].message_type = _LINK
+_LINK.fields_by_name['link_id'].message_type = _LINKID
+_LINK.fields_by_name['endpointList'].message_type = _ENDPOINTID
+_TOPOLOGYID.fields_by_name['contextId'].message_type = _CONTEXTID
+_TOPOLOGYID.fields_by_name['topoId'].message_type = _UUID
+_DEVICE.fields_by_name['device_id'].message_type = _DEVICEID
+_DEVICE.fields_by_name['device_config'].message_type = _DEVICECONFIG
+_DEVICE.fields_by_name['devOperationalStatus'].enum_type = _DEVICEOPERATIONALSTATUS
+_DEVICE.fields_by_name['endpointList'].message_type = _ENDPOINT
+_ENDPOINT.fields_by_name['port_id'].message_type = _ENDPOINTID
+_ENDPOINTID.fields_by_name['topoId'].message_type = _TOPOLOGYID
+_ENDPOINTID.fields_by_name['dev_id'].message_type = _DEVICEID
+_ENDPOINTID.fields_by_name['port_id'].message_type = _UUID
+_DEVICEID.fields_by_name['device_id'].message_type = _UUID
+_LINKID.fields_by_name['link_id'].message_type = _UUID
+_TERAFLOWCONTROLLER.fields_by_name['ctl_id'].message_type = _CONTEXTID
+_AUTHENTICATIONRESULT.fields_by_name['ctl_id'].message_type = _CONTEXTID
+DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY
+DESCRIPTOR.message_types_by_name['Context'] = _CONTEXT
+DESCRIPTOR.message_types_by_name['ContextId'] = _CONTEXTID
+DESCRIPTOR.message_types_by_name['Topology'] = _TOPOLOGY
+DESCRIPTOR.message_types_by_name['Link'] = _LINK
+DESCRIPTOR.message_types_by_name['TopologyId'] = _TOPOLOGYID
+DESCRIPTOR.message_types_by_name['Constraint'] = _CONSTRAINT
+DESCRIPTOR.message_types_by_name['Device'] = _DEVICE
+DESCRIPTOR.message_types_by_name['DeviceConfig'] = _DEVICECONFIG
+DESCRIPTOR.message_types_by_name['EndPoint'] = _ENDPOINT
+DESCRIPTOR.message_types_by_name['EndPointId'] = _ENDPOINTID
+DESCRIPTOR.message_types_by_name['DeviceId'] = _DEVICEID
+DESCRIPTOR.message_types_by_name['LinkId'] = _LINKID
+DESCRIPTOR.message_types_by_name['Uuid'] = _UUID
+DESCRIPTOR.message_types_by_name['TeraFlowController'] = _TERAFLOWCONTROLLER
+DESCRIPTOR.message_types_by_name['AuthenticationResult'] = _AUTHENTICATIONRESULT
+DESCRIPTOR.enum_types_by_name['DeviceOperationalStatus'] = _DEVICEOPERATIONALSTATUS
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), {
+  'DESCRIPTOR' : _EMPTY,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.Empty)
+  })
+_sym_db.RegisterMessage(Empty)
+
+Context = _reflection.GeneratedProtocolMessageType('Context', (_message.Message,), {
+  'DESCRIPTOR' : _CONTEXT,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.Context)
+  })
+_sym_db.RegisterMessage(Context)
+
+ContextId = _reflection.GeneratedProtocolMessageType('ContextId', (_message.Message,), {
+  'DESCRIPTOR' : _CONTEXTID,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.ContextId)
+  })
+_sym_db.RegisterMessage(ContextId)
+
+Topology = _reflection.GeneratedProtocolMessageType('Topology', (_message.Message,), {
+  'DESCRIPTOR' : _TOPOLOGY,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.Topology)
+  })
+_sym_db.RegisterMessage(Topology)
+
+Link = _reflection.GeneratedProtocolMessageType('Link', (_message.Message,), {
+  'DESCRIPTOR' : _LINK,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.Link)
+  })
+_sym_db.RegisterMessage(Link)
+
+TopologyId = _reflection.GeneratedProtocolMessageType('TopologyId', (_message.Message,), {
+  'DESCRIPTOR' : _TOPOLOGYID,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.TopologyId)
+  })
+_sym_db.RegisterMessage(TopologyId)
+
+Constraint = _reflection.GeneratedProtocolMessageType('Constraint', (_message.Message,), {
+  'DESCRIPTOR' : _CONSTRAINT,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.Constraint)
+  })
+_sym_db.RegisterMessage(Constraint)
+
+Device = _reflection.GeneratedProtocolMessageType('Device', (_message.Message,), {
+  'DESCRIPTOR' : _DEVICE,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.Device)
+  })
+_sym_db.RegisterMessage(Device)
+
+DeviceConfig = _reflection.GeneratedProtocolMessageType('DeviceConfig', (_message.Message,), {
+  'DESCRIPTOR' : _DEVICECONFIG,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.DeviceConfig)
+  })
+_sym_db.RegisterMessage(DeviceConfig)
+
+EndPoint = _reflection.GeneratedProtocolMessageType('EndPoint', (_message.Message,), {
+  'DESCRIPTOR' : _ENDPOINT,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.EndPoint)
+  })
+_sym_db.RegisterMessage(EndPoint)
+
+EndPointId = _reflection.GeneratedProtocolMessageType('EndPointId', (_message.Message,), {
+  'DESCRIPTOR' : _ENDPOINTID,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.EndPointId)
+  })
+_sym_db.RegisterMessage(EndPointId)
+
+DeviceId = _reflection.GeneratedProtocolMessageType('DeviceId', (_message.Message,), {
+  'DESCRIPTOR' : _DEVICEID,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.DeviceId)
+  })
+_sym_db.RegisterMessage(DeviceId)
+
+LinkId = _reflection.GeneratedProtocolMessageType('LinkId', (_message.Message,), {
+  'DESCRIPTOR' : _LINKID,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.LinkId)
+  })
+_sym_db.RegisterMessage(LinkId)
+
+Uuid = _reflection.GeneratedProtocolMessageType('Uuid', (_message.Message,), {
+  'DESCRIPTOR' : _UUID,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.Uuid)
+  })
+_sym_db.RegisterMessage(Uuid)
+
+TeraFlowController = _reflection.GeneratedProtocolMessageType('TeraFlowController', (_message.Message,), {
+  'DESCRIPTOR' : _TERAFLOWCONTROLLER,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.TeraFlowController)
+  })
+_sym_db.RegisterMessage(TeraFlowController)
+
+AuthenticationResult = _reflection.GeneratedProtocolMessageType('AuthenticationResult', (_message.Message,), {
+  'DESCRIPTOR' : _AUTHENTICATIONRESULT,
+  '__module__' : 'context_pb2'
+  # @@protoc_insertion_point(class_scope:context.AuthenticationResult)
+  })
+_sym_db.RegisterMessage(AuthenticationResult)
+
+
+
+_CONTEXTSERVICE = _descriptor.ServiceDescriptor(
+  name='ContextService',
+  full_name='context.ContextService',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=None,
+  create_key=_descriptor._internal_create_key,
+  serialized_start=1352,
+  serialized_end=1514,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='GetTopology',
+    full_name='context.ContextService.GetTopology',
+    index=0,
+    containing_service=None,
+    input_type=_EMPTY,
+    output_type=_TOPOLOGY,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='AddLink',
+    full_name='context.ContextService.AddLink',
+    index=1,
+    containing_service=None,
+    input_type=_LINK,
+    output_type=_LINKID,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='DeleteLink',
+    full_name='context.ContextService.DeleteLink',
+    index=2,
+    containing_service=None,
+    input_type=_LINKID,
+    output_type=_EMPTY,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_CONTEXTSERVICE)
+
+DESCRIPTOR.services_by_name['ContextService'] = _CONTEXTSERVICE
+
+# @@protoc_insertion_point(module_scope)
diff --git a/src/service/proto/service_pb2.py b/src/service/proto/service_pb2.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b2e9753bb57d6303c5862a1e98c7cd22c6d306a
--- /dev/null
+++ b/src/service/proto/service_pb2.py
@@ -0,0 +1,617 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: service.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+from . import context_pb2 as context__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='service.proto',
+  package='service',
+  syntax='proto3',
+  serialized_options=None,
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\rservice.proto\x12\x07service\x1a\rcontext.proto\"+\n\x0bServiceList\x12\x1c\n\x02\x63s\x18\x01 \x03(\x0b\x32\x10.service.Service\"\x87\x02\n\x07Service\x12!\n\x05\x63s_id\x18\x01 \x01(\x0b\x32\x12.service.ServiceId\x12)\n\x0bserviceType\x18\x02 \x01(\x0e\x32\x14.service.ServiceType\x12)\n\x0c\x65ndpointList\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\x12\'\n\nconstraint\x18\x04 \x03(\x0b\x32\x13.context.Constraint\x12+\n\x0cserviceState\x18\x05 \x01(\x0b\x32\x15.service.ServiceState\x12-\n\rserviceConfig\x18\x06 \x01(\x0b\x32\x16.service.ServiceConfig\"&\n\rServiceConfig\x12\x15\n\rserviceConfig\x18\x01 \x01(\t\"P\n\tServiceId\x12%\n\tcontextId\x18\x01 \x01(\x0b\x32\x12.context.ContextId\x12\x1c\n\x05\x63s_id\x18\x02 \x01(\x0b\x32\r.context.Uuid\":\n\rServiceIdList\x12)\n\rserviceIdList\x18\x01 \x03(\x0b\x32\x12.service.ServiceId\"?\n\x0cServiceState\x12/\n\x0cserviceState\x18\x01 \x01(\x0e\x32\x19.service.ServiceStateEnum\"=\n\x0e\x43onnectionList\x12+\n\x0e\x63onnectionList\x18\x01 \x03(\x0b\x32\x13.service.Connection\"\x84\x01\n\nConnection\x12%\n\x06\x63on_id\x18\x01 \x01(\x0b\x32\x15.service.ConnectionId\x12,\n\x10relatedServiceId\x18\x02 \x01(\x0b\x32\x12.service.ServiceId\x12!\n\x04path\x18\x03 \x03(\x0b\x32\x13.context.EndPointId\"-\n\x0c\x43onnectionId\x12\x1d\n\x06\x63on_id\x18\x01 \x01(\x0b\x32\r.context.Uuid*M\n\x0bServiceType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04L3NM\x10\x01\x12\x08\n\x04L2NM\x10\x02\x12\x1d\n\x19TAPI_CONNECTIVITY_SERVICE\x10\x03*@\n\x10ServiceStateEnum\x12\x0b\n\x07PLANNED\x10\x00\x12\n\n\x06\x41\x43TIVE\x10\x01\x12\x13\n\x0fPENDING_REMOVAL\x10\x02\x32\xef\x02\n\x0eServiceService\x12\x38\n\x0eGetServiceList\x12\x0e.context.Empty\x1a\x14.service.ServiceList\"\x00\x12\x37\n\rCreateService\x12\x10.service.Service\x1a\x12.service.ServiceId\"\x00\x12\x37\n\rUpdateService\x12\x10.service.Service\x1a\x12.service.ServiceId\"\x00\x12\x37\n\rDeleteService\x12\x10.service.Service\x1a\x12.service.ServiceId\"\x00\x12\x38\n\x0eGetServiceById\x12\x12.service.ServiceId\x1a\x10.service.Service\"\x00\x12>\n\x11GetConnectionList\x12\x0e.context.Empty\x1a\x17.service.ConnectionList\"\x00\x62\x06proto3'
+  ,
+  dependencies=[context__pb2.DESCRIPTOR,])
+
+_SERVICETYPE = _descriptor.EnumDescriptor(
+  name='ServiceType',
+  full_name='service.ServiceType',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='UNKNOWN', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='L3NM', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='L2NM', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='TAPI_CONNECTIVITY_SERVICE', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=844,
+  serialized_end=921,
+)
+_sym_db.RegisterEnumDescriptor(_SERVICETYPE)
+
+ServiceType = enum_type_wrapper.EnumTypeWrapper(_SERVICETYPE)
+_SERVICESTATEENUM = _descriptor.EnumDescriptor(
+  name='ServiceStateEnum',
+  full_name='service.ServiceStateEnum',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='PLANNED', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='ACTIVE', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='PENDING_REMOVAL', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=923,
+  serialized_end=987,
+)
+_sym_db.RegisterEnumDescriptor(_SERVICESTATEENUM)
+
+ServiceStateEnum = enum_type_wrapper.EnumTypeWrapper(_SERVICESTATEENUM)
+UNKNOWN = 0
+L3NM = 1
+L2NM = 2
+TAPI_CONNECTIVITY_SERVICE = 3
+PLANNED = 0
+ACTIVE = 1
+PENDING_REMOVAL = 2
+
+
+
+_SERVICELIST = _descriptor.Descriptor(
+  name='ServiceList',
+  full_name='service.ServiceList',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='cs', full_name='service.ServiceList.cs', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=41,
+  serialized_end=84,
+)
+
+
+_SERVICE = _descriptor.Descriptor(
+  name='Service',
+  full_name='service.Service',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='cs_id', full_name='service.Service.cs_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='serviceType', full_name='service.Service.serviceType', index=1,
+      number=2, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='endpointList', full_name='service.Service.endpointList', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='constraint', full_name='service.Service.constraint', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='serviceState', full_name='service.Service.serviceState', index=4,
+      number=5, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='serviceConfig', full_name='service.Service.serviceConfig', index=5,
+      number=6, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=87,
+  serialized_end=350,
+)
+
+
+_SERVICECONFIG = _descriptor.Descriptor(
+  name='ServiceConfig',
+  full_name='service.ServiceConfig',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='serviceConfig', full_name='service.ServiceConfig.serviceConfig', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=352,
+  serialized_end=390,
+)
+
+
+_SERVICEID = _descriptor.Descriptor(
+  name='ServiceId',
+  full_name='service.ServiceId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='contextId', full_name='service.ServiceId.contextId', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='cs_id', full_name='service.ServiceId.cs_id', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=392,
+  serialized_end=472,
+)
+
+
+_SERVICEIDLIST = _descriptor.Descriptor(
+  name='ServiceIdList',
+  full_name='service.ServiceIdList',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='serviceIdList', full_name='service.ServiceIdList.serviceIdList', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=474,
+  serialized_end=532,
+)
+
+
+_SERVICESTATE = _descriptor.Descriptor(
+  name='ServiceState',
+  full_name='service.ServiceState',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='serviceState', full_name='service.ServiceState.serviceState', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=534,
+  serialized_end=597,
+)
+
+
+_CONNECTIONLIST = _descriptor.Descriptor(
+  name='ConnectionList',
+  full_name='service.ConnectionList',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='connectionList', full_name='service.ConnectionList.connectionList', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=599,
+  serialized_end=660,
+)
+
+
+_CONNECTION = _descriptor.Descriptor(
+  name='Connection',
+  full_name='service.Connection',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='con_id', full_name='service.Connection.con_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='relatedServiceId', full_name='service.Connection.relatedServiceId', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='path', full_name='service.Connection.path', index=2,
+      number=3, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=663,
+  serialized_end=795,
+)
+
+
+_CONNECTIONID = _descriptor.Descriptor(
+  name='ConnectionId',
+  full_name='service.ConnectionId',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='con_id', full_name='service.ConnectionId.con_id', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=797,
+  serialized_end=842,
+)
+
+_SERVICELIST.fields_by_name['cs'].message_type = _SERVICE
+_SERVICE.fields_by_name['cs_id'].message_type = _SERVICEID
+_SERVICE.fields_by_name['serviceType'].enum_type = _SERVICETYPE
+_SERVICE.fields_by_name['endpointList'].message_type = context__pb2._ENDPOINTID
+_SERVICE.fields_by_name['constraint'].message_type = context__pb2._CONSTRAINT
+_SERVICE.fields_by_name['serviceState'].message_type = _SERVICESTATE
+_SERVICE.fields_by_name['serviceConfig'].message_type = _SERVICECONFIG
+_SERVICEID.fields_by_name['contextId'].message_type = context__pb2._CONTEXTID
+_SERVICEID.fields_by_name['cs_id'].message_type = context__pb2._UUID
+_SERVICEIDLIST.fields_by_name['serviceIdList'].message_type = _SERVICEID
+_SERVICESTATE.fields_by_name['serviceState'].enum_type = _SERVICESTATEENUM
+_CONNECTIONLIST.fields_by_name['connectionList'].message_type = _CONNECTION
+_CONNECTION.fields_by_name['con_id'].message_type = _CONNECTIONID
+_CONNECTION.fields_by_name['relatedServiceId'].message_type = _SERVICEID
+_CONNECTION.fields_by_name['path'].message_type = context__pb2._ENDPOINTID
+_CONNECTIONID.fields_by_name['con_id'].message_type = context__pb2._UUID
+DESCRIPTOR.message_types_by_name['ServiceList'] = _SERVICELIST
+DESCRIPTOR.message_types_by_name['Service'] = _SERVICE
+DESCRIPTOR.message_types_by_name['ServiceConfig'] = _SERVICECONFIG
+DESCRIPTOR.message_types_by_name['ServiceId'] = _SERVICEID
+DESCRIPTOR.message_types_by_name['ServiceIdList'] = _SERVICEIDLIST
+DESCRIPTOR.message_types_by_name['ServiceState'] = _SERVICESTATE
+DESCRIPTOR.message_types_by_name['ConnectionList'] = _CONNECTIONLIST
+DESCRIPTOR.message_types_by_name['Connection'] = _CONNECTION
+DESCRIPTOR.message_types_by_name['ConnectionId'] = _CONNECTIONID
+DESCRIPTOR.enum_types_by_name['ServiceType'] = _SERVICETYPE
+DESCRIPTOR.enum_types_by_name['ServiceStateEnum'] = _SERVICESTATEENUM
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+ServiceList = _reflection.GeneratedProtocolMessageType('ServiceList', (_message.Message,), {
+  'DESCRIPTOR' : _SERVICELIST,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:service.ServiceList)
+  })
+_sym_db.RegisterMessage(ServiceList)
+
+Service = _reflection.GeneratedProtocolMessageType('Service', (_message.Message,), {
+  'DESCRIPTOR' : _SERVICE,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:service.Service)
+  })
+_sym_db.RegisterMessage(Service)
+
+ServiceConfig = _reflection.GeneratedProtocolMessageType('ServiceConfig', (_message.Message,), {
+  'DESCRIPTOR' : _SERVICECONFIG,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:service.ServiceConfig)
+  })
+_sym_db.RegisterMessage(ServiceConfig)
+
+ServiceId = _reflection.GeneratedProtocolMessageType('ServiceId', (_message.Message,), {
+  'DESCRIPTOR' : _SERVICEID,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:service.ServiceId)
+  })
+_sym_db.RegisterMessage(ServiceId)
+
+ServiceIdList = _reflection.GeneratedProtocolMessageType('ServiceIdList', (_message.Message,), {
+  'DESCRIPTOR' : _SERVICEIDLIST,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:service.ServiceIdList)
+  })
+_sym_db.RegisterMessage(ServiceIdList)
+
+ServiceState = _reflection.GeneratedProtocolMessageType('ServiceState', (_message.Message,), {
+  'DESCRIPTOR' : _SERVICESTATE,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:service.ServiceState)
+  })
+_sym_db.RegisterMessage(ServiceState)
+
+ConnectionList = _reflection.GeneratedProtocolMessageType('ConnectionList', (_message.Message,), {
+  'DESCRIPTOR' : _CONNECTIONLIST,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:service.ConnectionList)
+  })
+_sym_db.RegisterMessage(ConnectionList)
+
+Connection = _reflection.GeneratedProtocolMessageType('Connection', (_message.Message,), {
+  'DESCRIPTOR' : _CONNECTION,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:service.Connection)
+  })
+_sym_db.RegisterMessage(Connection)
+
+ConnectionId = _reflection.GeneratedProtocolMessageType('ConnectionId', (_message.Message,), {
+  'DESCRIPTOR' : _CONNECTIONID,
+  '__module__' : 'service_pb2'
+  # @@protoc_insertion_point(class_scope:service.ConnectionId)
+  })
+_sym_db.RegisterMessage(ConnectionId)
+
+
+
+_SERVICESERVICE = _descriptor.ServiceDescriptor(
+  name='ServiceService',
+  full_name='service.ServiceService',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=None,
+  create_key=_descriptor._internal_create_key,
+  serialized_start=990,
+  serialized_end=1357,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='GetServiceList',
+    full_name='service.ServiceService.GetServiceList',
+    index=0,
+    containing_service=None,
+    input_type=context__pb2._EMPTY,
+    output_type=_SERVICELIST,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='CreateService',
+    full_name='service.ServiceService.CreateService',
+    index=1,
+    containing_service=None,
+    input_type=_SERVICE,
+    output_type=_SERVICEID,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='UpdateService',
+    full_name='service.ServiceService.UpdateService',
+    index=2,
+    containing_service=None,
+    input_type=_SERVICE,
+    output_type=_SERVICEID,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='DeleteService',
+    full_name='service.ServiceService.DeleteService',
+    index=3,
+    containing_service=None,
+    input_type=_SERVICE,
+    output_type=_SERVICEID,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='GetServiceById',
+    full_name='service.ServiceService.GetServiceById',
+    index=4,
+    containing_service=None,
+    input_type=_SERVICEID,
+    output_type=_SERVICE,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='GetConnectionList',
+    full_name='service.ServiceService.GetConnectionList',
+    index=5,
+    containing_service=None,
+    input_type=context__pb2._EMPTY,
+    output_type=_CONNECTIONLIST,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_SERVICESERVICE)
+
+DESCRIPTOR.services_by_name['ServiceService'] = _SERVICESERVICE
+
+# @@protoc_insertion_point(module_scope)
diff --git a/src/service/proto/service_pb2_grpc.py b/src/service/proto/service_pb2_grpc.py
new file mode 100644
index 0000000000000000000000000000000000000000..05be96c21a167997a6963af6223cf1c7e2b2acbe
--- /dev/null
+++ b/src/service/proto/service_pb2_grpc.py
@@ -0,0 +1,232 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+from . import context_pb2 as context__pb2
+from . import service_pb2 as service__pb2
+
+
+class ServiceServiceStub(object):
+    """Missing associated documentation comment in .proto file."""
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.GetServiceList = channel.unary_unary(
+                '/service.ServiceService/GetServiceList',
+                request_serializer=context__pb2.Empty.SerializeToString,
+                response_deserializer=service__pb2.ServiceList.FromString,
+                )
+        self.CreateService = channel.unary_unary(
+                '/service.ServiceService/CreateService',
+                request_serializer=service__pb2.Service.SerializeToString,
+                response_deserializer=service__pb2.ServiceId.FromString,
+                )
+        self.UpdateService = channel.unary_unary(
+                '/service.ServiceService/UpdateService',
+                request_serializer=service__pb2.Service.SerializeToString,
+                response_deserializer=service__pb2.ServiceId.FromString,
+                )
+        self.DeleteService = channel.unary_unary(
+                '/service.ServiceService/DeleteService',
+                request_serializer=service__pb2.Service.SerializeToString,
+                response_deserializer=service__pb2.ServiceId.FromString,
+                )
+        self.GetServiceById = channel.unary_unary(
+                '/service.ServiceService/GetServiceById',
+                request_serializer=service__pb2.ServiceId.SerializeToString,
+                response_deserializer=service__pb2.Service.FromString,
+                )
+        self.GetConnectionList = channel.unary_unary(
+                '/service.ServiceService/GetConnectionList',
+                request_serializer=context__pb2.Empty.SerializeToString,
+                response_deserializer=service__pb2.ConnectionList.FromString,
+                )
+
+
+class ServiceServiceServicer(object):
+    """Missing associated documentation comment in .proto file."""
+
+    def GetServiceList(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def CreateService(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def UpdateService(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def DeleteService(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def GetServiceById(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def GetConnectionList(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+
+def add_ServiceServiceServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'GetServiceList': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetServiceList,
+                    request_deserializer=context__pb2.Empty.FromString,
+                    response_serializer=service__pb2.ServiceList.SerializeToString,
+            ),
+            'CreateService': grpc.unary_unary_rpc_method_handler(
+                    servicer.CreateService,
+                    request_deserializer=service__pb2.Service.FromString,
+                    response_serializer=service__pb2.ServiceId.SerializeToString,
+            ),
+            'UpdateService': grpc.unary_unary_rpc_method_handler(
+                    servicer.UpdateService,
+                    request_deserializer=service__pb2.Service.FromString,
+                    response_serializer=service__pb2.ServiceId.SerializeToString,
+            ),
+            'DeleteService': grpc.unary_unary_rpc_method_handler(
+                    servicer.DeleteService,
+                    request_deserializer=service__pb2.Service.FromString,
+                    response_serializer=service__pb2.ServiceId.SerializeToString,
+            ),
+            'GetServiceById': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetServiceById,
+                    request_deserializer=service__pb2.ServiceId.FromString,
+                    response_serializer=service__pb2.Service.SerializeToString,
+            ),
+            'GetConnectionList': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetConnectionList,
+                    request_deserializer=context__pb2.Empty.FromString,
+                    response_serializer=service__pb2.ConnectionList.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'service.ServiceService', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class ServiceService(object):
+    """Missing associated documentation comment in .proto file."""
+
+    @staticmethod
+    def GetServiceList(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/service.ServiceService/GetServiceList',
+            context__pb2.Empty.SerializeToString,
+            service__pb2.ServiceList.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def CreateService(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/service.ServiceService/CreateService',
+            service__pb2.Service.SerializeToString,
+            service__pb2.ServiceId.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def UpdateService(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/service.ServiceService/UpdateService',
+            service__pb2.Service.SerializeToString,
+            service__pb2.ServiceId.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def DeleteService(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/service.ServiceService/DeleteService',
+            service__pb2.Service.SerializeToString,
+            service__pb2.ServiceId.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def GetServiceById(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/service.ServiceService/GetServiceById',
+            service__pb2.ServiceId.SerializeToString,
+            service__pb2.Service.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def GetConnectionList(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/service.ServiceService/GetConnectionList',
+            context__pb2.Empty.SerializeToString,
+            service__pb2.ConnectionList.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/src/service/requirements.in b/src/service/requirements.in
new file mode 100644
index 0000000000000000000000000000000000000000..25abdad1b5767117956a88b816399635348884c7
--- /dev/null
+++ b/src/service/requirements.in
@@ -0,0 +1,6 @@
+grpcio-health-checking
+grpcio
+prometheus-client
+pytest
+pytest-benchmark
+redis
diff --git a/src/service/service/ServiceService.py b/src/service/service/ServiceService.py
new file mode 100644
index 0000000000000000000000000000000000000000..be7d73c5434014d0d2c2d2b3e197cdef2932c86e
--- /dev/null
+++ b/src/service/service/ServiceService.py
@@ -0,0 +1,55 @@
+import grpc
+import logging
+from concurrent import futures
+from grpc_health.v1.health import HealthServicer, OVERALL_HEALTH
+from grpc_health.v1.health_pb2 import HealthCheckResponse
+from grpc_health.v1.health_pb2_grpc import add_HealthServicer_to_server
+from service.proto.service_pb2_grpc import add_ServiceServiceServicer_to_server
+from service.service.ServiceServiceServicerImpl import ServiceServiceServicerImpl
+from service.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD
+
+BIND_ADDRESS = '0.0.0.0'
+LOGGER = logging.getLogger(__name__)
+
+class ServiceService:
+    def __init__(self, database, address=BIND_ADDRESS, port=GRPC_SERVICE_PORT, max_workers=GRPC_MAX_WORKERS,
+                 grace_period=GRPC_GRACE_PERIOD):
+        self.database = database
+        self.address = address
+        self.port = port
+        self.endpoint = None
+        self.max_workers = max_workers
+        self.grace_period = grace_period
+        self.device_servicer = None
+        self.health_servicer = None
+        self.pool = None
+        self.server = None
+
+    def start(self):
+        self.endpoint = '{}:{}'.format(self.address, self.port)
+        LOGGER.debug('Starting Service (tentative endpoint: {}, max_workers: {})...'.format(
+            self.endpoint, self.max_workers))
+
+        self.pool = futures.ThreadPoolExecutor(max_workers=self.max_workers)
+        self.server = grpc.server(self.pool) # , interceptors=(tracer_interceptor,))
+
+        self.service_servicer = ServiceServiceServicerImpl(self.database)
+        add_ServiceServiceServicer_to_server(self.device_servicer, self.server)
+
+        self.health_servicer = HealthServicer(
+            experimental_non_blocking=True, experimental_thread_pool=futures.ThreadPoolExecutor(max_workers=1))
+        add_HealthServicer_to_server(self.health_servicer, self.server)
+
+        port = self.server.add_insecure_port(self.endpoint)
+        self.endpoint = '{}:{}'.format(self.address, port)
+        LOGGER.info('Listening on {}...'.format(self.endpoint))
+        self.server.start()
+        self.health_servicer.set(OVERALL_HEALTH, HealthCheckResponse.SERVING) # pylint: disable=maybe-no-member
+
+        LOGGER.debug('Service started')
+
+    def stop(self):
+        LOGGER.debug('Stopping service (grace period {} seconds)...'.format(self.grace_period))
+        self.health_servicer.enter_graceful_shutdown()
+        self.server.stop(self.grace_period)
+        LOGGER.debug('Service stopped')
diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py
new file mode 100644
index 0000000000000000000000000000000000000000..11aad76831bd4930d575480474bef3664ad0f4b0
--- /dev/null
+++ b/src/service/service/ServiceServiceServicerImpl.py
@@ -0,0 +1,333 @@
+from typing import Dict, List, Set, Tuple
+import grpc, logging
+from prometheus_client import Counter, Histogram
+from common.Checkers import chk_options, chk_string
+from common.database.api.Database import Database
+from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
+from common.database.api.context.service.ServiceState import ServiceState, servicestate_enum_values, \
+    to_servicestate_enum
+from common.database.api.context.service.ServiceType import ServiceType, servicetype_enum_values, to_servicetype_enum
+from common.exceptions.ServiceException import ServiceException
+from service.proto.context_pb2 import Empty
+from service.proto.service_pb2 import ConnectionList, Service, ServiceId, ServiceList
+from service.proto.service_pb2_grpc import ServiceServiceServicer
+
+LOGGER = logging.getLogger(__name__)
+
+GETSERVICELIST_COUNTER_STARTED    = Counter  ('service_getservicelist_counter_started',
+                                              'Service:GetServiceList counter of requests started'  )
+GETSERVICELIST_COUNTER_COMPLETED  = Counter  ('service_getservicelist_counter_completed',
+                                              'Service:GetServiceList counter of requests completed')
+GETSERVICELIST_COUNTER_FAILED     = Counter  ('service_getservicelist_counter_failed',
+                                              'Service:GetServiceList counter of requests failed'   )
+GETSERVICELIST_HISTOGRAM_DURATION = Histogram('service_getservicelist_histogram_duration',
+                                              'Service:GetServiceList histogram of request duration')
+
+CREATESERVICE_COUNTER_STARTED    = Counter  ('service_createservice_counter_started',
+                                             'Service:CreateService counter of requests started'  )
+CREATESERVICE_COUNTER_COMPLETED  = Counter  ('service_createservice_counter_completed',
+                                             'Service:CreateService counter of requests completed')
+CREATESERVICE_COUNTER_FAILED     = Counter  ('service_createservice_counter_failed',
+                                             'Service:CreateService counter of requests failed'   )
+CREATESERVICE_HISTOGRAM_DURATION = Histogram('service_createservice_histogram_duration',
+                                             'Service:CreateService histogram of request duration')
+
+UPDATESERVICE_COUNTER_STARTED    = Counter  ('service_updateservice_counter_started',
+                                             'Service:UpdateService counter of requests started'  )
+UPDATESERVICE_COUNTER_COMPLETED  = Counter  ('service_updateservice_counter_completed',
+                                             'Service:UpdateService counter of requests completed')
+UPDATESERVICE_COUNTER_FAILED     = Counter  ('service_updateservice_counter_failed',
+                                             'Service:UpdateService counter of requests failed'   )
+UPDATESERVICE_HISTOGRAM_DURATION = Histogram('service_updateservice_histogram_duration',
+                                             'Service:UpdateService histogram of request duration')
+
+DELETESERVICE_COUNTER_STARTED    = Counter  ('service_deleteservice_counter_started',
+                                             'Service:DeleteService counter of requests started'  )
+DELETESERVICE_COUNTER_COMPLETED  = Counter  ('service_deleteservice_counter_completed',
+                                             'Service:DeleteService counter of requests completed')
+DELETESERVICE_COUNTER_FAILED     = Counter  ('service_deleteservice_counter_failed',
+                                             'Service:DeleteService counter of requests failed'   )
+DELETESERVICE_HISTOGRAM_DURATION = Histogram('service_deleteservice_histogram_duration',
+                                             'Service:DeleteService histogram of request duration')
+
+GETSERVICEBYID_COUNTER_STARTED    = Counter  ('service_getservicebyid_counter_started',
+                                              'Service:GetServiceById counter of requests started'  )
+GETSERVICEBYID_COUNTER_COMPLETED  = Counter  ('service_getservicebyid_counter_completed',
+                                              'Service:GetServiceById counter of requests completed')
+GETSERVICEBYID_COUNTER_FAILED     = Counter  ('service_getservicebyid_counter_failed',
+                                              'Service:GetServiceById counter of requests failed'   )
+GETSERVICEBYID_HISTOGRAM_DURATION = Histogram('service_getservicebyid_histogram_duration',
+                                              'Service:GetServiceById histogram of request duration')
+
+GETCONNECTIONLIST_COUNTER_STARTED    = Counter  ('service_getconnectionlist_counter_started',
+                                                 'Service:GetConnectionList counter of requests started'  )
+GETCONNECTIONLIST_COUNTER_COMPLETED  = Counter  ('service_getconnectionlist_counter_completed',
+                                                 'Service:GetConnectionList counter of requests completed')
+GETCONNECTIONLIST_COUNTER_FAILED     = Counter  ('service_getconnectionlist_counter_failed',
+                                                 'Service:GetConnectionList counter of requests failed'   )
+GETCONNECTIONLIST_HISTOGRAM_DURATION = Histogram('service_getconnectionlist_histogram_duration',
+                                                 'Service:GetConnectionList histogram of request duration')
+
+class ServiceServiceServicerImpl(ServiceServiceServicer):
+    def __init__(self, database : Database):
+        LOGGER.debug('Creating Servicer...')
+        self.database = database
+        LOGGER.debug('Servicer Created')
+
+    @GETSERVICELIST_HISTOGRAM_DURATION.time()
+    def GetServiceList(self, request : Empty, grpc_context : grpc.ServicerContext) -> ServiceList:
+        GETSERVICELIST_COUNTER_STARTED.inc()
+        try:
+            LOGGER.debug('GetServiceList request: {}'.format(str(request)))
+
+            # ----- Validate request data and pre-conditions -----------------------------------------------------------
+
+            # ----- Retrieve data from the database --------------------------------------------------------------------
+            db_context_uuids = self.database.contexts
+            json_services = []
+            for db_context_uuid in db_context_uuids:
+                json_services.extend(self.database.context(db_context_uuid).dump_services())
+
+            # ----- Compose reply --------------------------------------------------------------------------------------
+            reply = ServiceList(cs=json_services)
+            LOGGER.debug('GetServiceList reply: {}'.format(str(reply)))
+            GETSERVICELIST_COUNTER_COMPLETED.inc()
+            return reply
+        except ServiceException as e:
+            grpc_context.abort(e.code, e.details)
+        except Exception as e:                                      # pragma: no cover
+            LOGGER.exception('GetServiceList exception')            # pragma: no cover
+            GETSERVICELIST_COUNTER_FAILED.inc()                     # pragma: no cover
+            grpc_context.abort(grpc.StatusCode.INTERNAL, str(e))    # pragma: no cover
+
+    @CREATESERVICE_HISTOGRAM_DURATION.time()
+    def CreateService(self, request : Service, grpc_context : grpc.ServicerContext) -> ServiceId:
+        CREATESERVICE_COUNTER_STARTED.inc()
+        try:
+            LOGGER.debug('CreateService request: {}'.format(str(request)))
+
+            # ----- Validate request data and pre-conditions -----------------------------------------------------------
+            try:
+                context_id     = chk_string ('service.cs_id.contextId.contextUuid.uuid',
+                                            request.cs_id.contextId.contextUuid.uuid,
+                                            allow_empty=False)
+                service_id     = chk_string ('service.cs_id.cs_id.uuid',
+                                            request.cs_id.cs_id.uuid,
+                                            allow_empty=False)
+                service_type   = chk_options('service.serviceType',
+                                            request.serviceType,
+                                            servicetype_enum_values())
+                service_config = chk_string ('service.serviceConfig.serviceConfig',
+                                            request.serviceConfig.serviceConfig,
+                                            allow_empty=True)
+                service_state  = chk_options('device.serviceState.serviceState',
+                                            request.serviceState.serviceState,
+                                            servicestate_enum_values())
+            except Exception as e:
+                LOGGER.exception('Invalid arguments:')
+                raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, str(e))
+
+            service_type = to_servicetype_enum(service_type)
+            # should not happen because gRPC limits accepted values in enums
+            if service_type is None:                                            # pragma: no cover
+                msg = 'Unsupported ServiceType({}).'                            # pragma: no cover
+                msg = msg.format(request.serviceType)                           # pragma: no cover
+                raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, msg)   # pragma: no cover
+
+            if service_type == ServiceType.UNKNOWN:
+                msg = ' '.join([
+                    'Service has to be created with a known ServiceType.',
+                    'UNKNOWN is only for internal use.',
+                ])
+                raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, msg)
+
+            service_state = to_servicestate_enum(service_state)
+            # should not happen because gRPC limits accepted values in enums
+            if service_state is None:                                           # pragma: no cover
+                msg = 'Unsupported ServiceState({}).'                           # pragma: no cover
+                msg = msg.format(request.serviceState.serviceState)             # pragma: no cover
+                raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, msg)   # pragma: no cover
+
+            if service_state != ServiceState.PLANNED:
+                msg = ' '.join([
+                    'Service has to be created with PLANNED state.',
+                    'State will be updated by the service appropriately.',
+                ])
+                raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, msg)
+
+            db_context = self.database.context(context_id).create()
+            if db_context.services.contains(service_id):
+                msg = 'Context({})/Service({}) already exists in the database.'
+                msg = msg.format(context_id, service_id)
+                raise ServiceException(grpc.StatusCode.ALREADY_EXISTS, msg)
+
+            added_context_topology_devices_endpoints : Dict[str, Dict[str, Dict[str, Set[str]]]] = {}
+            context_topology_device_endpoint_tuples : List[Tuple[str, str, str, str]] = []
+            for i,endpoint in enumerate(request.endpointList):
+                try:
+                    ep_context_id  = chk_string('endpoint[#{}].topoId.contextId.contextUuid.uuid'.format(i),
+                                                endpoint.topoId.contextId.contextUuid.uuid,
+                                                allow_empty=True)
+                    ep_topology_id = chk_string('endpoint[#{}].topoId.topoId.uuid'.format(i),
+                                                endpoint.topoId.topoId.uuid,
+                                                allow_empty=True)
+                    ep_device_id   = chk_string('endpoint[#{}].dev_id.device_id.uuid'.format(i),
+                                                endpoint.dev_id.device_id.uuid,
+                                                allow_empty=False)
+                    ep_port_id     = chk_string('endpoint[#{}].port_id.uuid'.format(i),
+                                                endpoint.port_id.uuid,
+                                                allow_empty=False)
+                except Exception as e:
+                    LOGGER.exception('Invalid arguments:')
+                    raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, str(e))
+
+                if len(ep_context_id) == 0: ep_context_id = DEFAULT_CONTEXT_ID
+                if len(ep_topology_id) == 0: ep_topology_id = DEFAULT_TOPOLOGY_ID
+
+                added_devices = added_context_topology_devices_endpoints.get(ep_context_id, {}).get(ep_topology_id, {})
+                if ep_device_id in added_devices:
+                    msg = 'Duplicated Device({}) in Endpoint(#{}) of Service({}).'
+                    msg = msg.format(ep_device_id, i, service_id)
+                    raise ServiceException(grpc.StatusCode.INVALID_ARGUMENT, msg)
+
+                if not self.database.contexts.contains(ep_context_id):
+                    msg = ' '.join([
+                        'Context({}) in Endpoint(#{}) of Service({})',
+                        'does not exist in the database.',
+                    ])
+                    msg = msg.format(ep_context_id, i, service_id)
+                    raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
+
+                db_ep_context = self.database.context(ep_context_id)
+                if not db_ep_context.topologies.contains(ep_topology_id):
+                    msg = ' '.join([
+                        'Context({})/Topology({}) in Endpoint(#{}) of Service({})',
+                        'does not exist in the database.',
+                    ])
+                    msg = msg.format(ep_context_id, ep_topology_id, i, service_id)
+                    raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
+
+                db_ep_topology = db_ep_context.topology(ep_topology_id)
+                if not db_ep_topology.devices.contains(ep_device_id):
+                    msg = ' '.join([
+                        'Context({})/Topology({})/Device({}) in Endpoint(#{}) of Service({})',
+                        'does not exist in the database.',
+                    ])
+                    msg = msg.format(ep_context_id, ep_topology_id, ep_device_id, i, service_id)
+                    raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
+
+                added_device_and_endpoints = added_context_topology_devices_endpoints\
+                    .setdefault(ep_context_id, {})\
+                    .setdefault(ep_topology_id, {})\
+                    .setdefault(ep_device_id, {})
+
+                # should never happen since same device cannot appear 2 times in the service
+                if ep_port_id in added_device_and_endpoints:                                # pragma: no cover
+                    msg = 'Duplicated Context({})/Topology({})/Device({})/Port({}) in Endpoint(#{}) of Service({}).'
+                    msg = msg.format(ep_context_id, ep_topology_id, ep_device_id, ep_port_id, i, service_id)
+                    raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
+
+                db_ep_device = db_ep_topology.device(ep_device_id)
+                if not db_ep_device.endpoints.contains(ep_port_id):
+                    msg = ' '.join([
+                        'Context({})/Topology({})/Device({})/Port({}) in Endpoint(#{}) of Service({})',
+                        'does not exist in the database.',
+                    ])
+                    msg = msg.format(ep_context_id, ep_topology_id, ep_device_id, ep_port_id, i, service_id)
+                    raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
+
+                added_device_and_endpoints.add(ep_port_id)
+                context_topology_device_endpoint_tuples.append(
+                    (ep_context_id, ep_topology_id, ep_device_id, ep_port_id))
+
+            # ----- Implement changes in the database ------------------------------------------------------------------
+            db_service = db_context.service(service_id).create(service_type, service_config, service_state)
+            for context_id,topology_id,device_id,endpoint_id in context_topology_device_endpoint_tuples:
+                service_endpoint_id = '{}:{}/{}'.format(topology_id, device_id, endpoint_id)
+                db_endpoint = db_context.topology(topology_id).device(device_id).endpoint(endpoint_id)
+                db_service.endpoint(service_endpoint_id).create(db_endpoint)
+            for cons_type,cons_value in constraint_pairs: db_service.constraint(cons_type).create(cons_value)
+
+            # ----- Compose reply --------------------------------------------------------------------------------------
+            reply = ServiceId(**db_service.dump_id())
+            LOGGER.debug('CreateService reply: {}'.format(str(reply)))
+            CREATESERVICE_COUNTER_COMPLETED.inc()
+            return reply
+        except ServiceException as e:
+            grpc_context.abort(e.code, e.details)
+        except Exception as e:                                      # pragma: no cover
+            LOGGER.exception('CreateService exception')             # pragma: no cover
+            CREATESERVICE_COUNTER_FAILED.inc()                      # pragma: no cover
+            grpc_context.abort(grpc.StatusCode.INTERNAL, str(e))    # pragma: no cover
+
+    @UPDATESERVICE_HISTOGRAM_DURATION.time()
+    def UpdateService(self, request : Service, grpc_context : grpc.ServicerContext) -> ServiceId:
+        UPDATESERVICE_COUNTER_STARTED.inc()
+        try:
+            LOGGER.debug('UpdateService request: {}'.format(str(request)))
+
+
+            reply = None
+            LOGGER.debug('UpdateService reply: {}'.format(str(reply)))
+            UPDATESERVICE_COUNTER_COMPLETED.inc()
+            return reply
+        except ServiceException as e:
+            grpc_context.abort(e.code, e.details)
+        except Exception as e:                                      # pragma: no cover
+            LOGGER.exception('UpdateService exception')             # pragma: no cover
+            UPDATESERVICE_COUNTER_FAILED.inc()                      # pragma: no cover
+            grpc_context.abort(grpc.StatusCode.INTERNAL, str(e))    # pragma: no cover
+
+    @DELETESERVICE_HISTOGRAM_DURATION.time()
+    def DeleteService(self, request : Service, grpc_context : grpc.ServicerContext) -> ServiceId:
+        DELETESERVICE_COUNTER_STARTED.inc()
+        try:
+            LOGGER.debug('DeleteService request: {}'.format(str(request)))
+
+
+            reply = None
+            LOGGER.debug('DeleteService reply: {}'.format(str(reply)))
+            DELETESERVICE_COUNTER_COMPLETED.inc()
+            return reply
+        except ServiceException as e:
+            grpc_context.abort(e.code, e.details)
+        except Exception as e:                                      # pragma: no cover
+            LOGGER.exception('DeleteService exception')             # pragma: no cover
+            DELETESERVICE_COUNTER_FAILED.inc()                      # pragma: no cover
+            grpc_context.abort(grpc.StatusCode.INTERNAL, str(e))    # pragma: no cover
+
+    @GETSERVICEBYID_HISTOGRAM_DURATION.time()
+    def GetServiceById(self, request : ServiceId, grpc_context : grpc.ServicerContext) -> Service:
+        GETSERVICEBYID_COUNTER_STARTED.inc()
+        try:
+            LOGGER.debug('GetServiceById request: {}'.format(str(request)))
+
+
+            reply = None
+            LOGGER.debug('GetServiceById reply: {}'.format(str(reply)))
+            GETSERVICEBYID_COUNTER_COMPLETED.inc()
+            return reply
+        except ServiceException as e:
+            grpc_context.abort(e.code, e.details)
+        except Exception as e:                                      # pragma: no cover
+            LOGGER.exception('GetServiceById exception')            # pragma: no cover
+            GETSERVICEBYID_COUNTER_FAILED.inc()                     # pragma: no cover
+            grpc_context.abort(grpc.StatusCode.INTERNAL, str(e))    # pragma: no cover
+
+    @GETCONNECTIONLIST_HISTOGRAM_DURATION.time()
+    def GetConnectionList(self, request : Empty, grpc_context : grpc.ServicerContext) -> ConnectionList:
+        GETCONNECTIONLIST_COUNTER_STARTED.inc()
+        try:
+            LOGGER.debug('GetConnectionList request: {}'.format(str(request)))
+
+
+            reply = None
+            LOGGER.debug('GetConnectionList reply: {}'.format(str(reply)))
+            GETCONNECTIONLIST_COUNTER_COMPLETED.inc()
+            return reply
+        except ServiceException as e:
+            grpc_context.abort(e.code, e.details)
+        except Exception as e:                                      # pragma: no cover
+            LOGGER.exception('GetConnectionList exception')         # pragma: no cover
+            GETCONNECTIONLIST_COUNTER_FAILED.inc()                  # pragma: no cover
+            grpc_context.abort(grpc.StatusCode.INTERNAL, str(e))    # pragma: no cover
diff --git a/src/service/service/__init__.py b/src/service/service/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/service/service/__main__.py b/src/service/service/__main__.py
new file mode 100644
index 0000000000000000000000000000000000000000..2eef3598396ceb74633b9c529532dc3cb11dc03e
--- /dev/null
+++ b/src/service/service/__main__.py
@@ -0,0 +1,52 @@
+import logging, os, signal, sys, threading
+from prometheus_client import start_http_server
+from common.database.Factory import get_database
+from service.service.ServiceService import ServiceService
+from service.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD, LOG_LEVEL, METRICS_PORT
+
+terminate = threading.Event()
+logger = None
+
+def signal_handler(signal, frame):
+    global terminate, logger
+    logger.warning('Terminate signal received')
+    terminate.set()
+
+def main():
+    global terminate, logger
+
+    service_port = os.environ.get('SERVICESERVICE_SERVICE_PORT_GRPC', GRPC_SERVICE_PORT)
+    max_workers  = os.environ.get('MAX_WORKERS',  GRPC_MAX_WORKERS )
+    grace_period = os.environ.get('GRACE_PERIOD', GRPC_GRACE_PERIOD)
+    log_level    = os.environ.get('LOG_LEVEL',    LOG_LEVEL   )
+    metrics_port = os.environ.get('METRICS_PORT', METRICS_PORT)
+
+    logging.basicConfig(level=log_level)
+    logger = logging.getLogger(__name__)
+
+    signal.signal(signal.SIGINT,  signal_handler)
+    signal.signal(signal.SIGTERM, signal_handler)
+
+    logger.info('Starting...')
+
+    # Start metrics server
+    start_http_server(metrics_port)
+
+    # Get database instance
+    database = get_database()
+
+    # Starting service service
+    service = ServiceService(database, port=service_port, max_workers=max_workers, grace_period=grace_period)
+    service.start()
+
+    # Wait for Ctrl+C or termination signal
+    while not terminate.wait(0.1): pass
+
+    logger.info('Terminating...')
+    service.stop()
+
+    logger.info('Bye')
+    return(0)
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/src/service/tests/__init__.py b/src/service/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/service/tests/test_unitary.py b/src/service/tests/test_unitary.py
new file mode 100644
index 0000000000000000000000000000000000000000..69eb3171e21abe445fe46dd9b5a40c4b98b3c2b3
--- /dev/null
+++ b/src/service/tests/test_unitary.py
@@ -0,0 +1,27 @@
+import logging, pytest
+from common.database.Factory import get_database, DatabaseEngineEnum
+from service.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD
+from service.client.ServiceClient import ServiceClient
+from service.service.ServiceService import ServiceService
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+@pytest.fixture(scope='session')
+def service_database():
+    _database = get_database(engine=DatabaseEngineEnum.INMEMORY)
+    return _database
+
+@pytest.fixture(scope='session')
+def service_service(service_database):
+    _service = ServiceService(
+        service_database, port=GRPC_SERVICE_PORT, max_workers=GRPC_MAX_WORKERS, grace_period=GRPC_GRACE_PERIOD)
+    _service.start()
+    yield _service
+    _service.stop()
+
+@pytest.fixture(scope='session')
+def service_client(service_service):
+    _client = ServiceClient(address='127.0.0.1', port=GRPC_SERVICE_PORT)
+    yield _client
+    _client.close()