diff --git a/proto/context.proto b/proto/context.proto
index 3104f1b545c02bab71c8638ebba03efdcbfe71ff..39abc081d4a652eda246f876c5184faffc7065d5 100644
--- a/proto/context.proto
+++ b/proto/context.proto
@@ -494,6 +494,12 @@ message ConfigRule {
 
 
 // ----- Constraint ----------------------------------------------------------------------------------------------------
+enum ConstraintActionEnum {
+  CONSTRAINTACTION_UNDEFINED = 0;
+  CONSTRAINTACTION_SET       = 1;
+  CONSTRAINTACTION_DELETE    = 2;
+}
+
 message Constraint_Custom {
   string constraint_type = 1;
   string constraint_value = 2;
@@ -564,16 +570,17 @@ message Constraint_Exclusions {
 }
 
 message Constraint {
+  ConstraintActionEnum action = 1;
   oneof constraint {
-    Constraint_Custom custom = 1;
-    Constraint_Schedule schedule = 2;
-    Constraint_EndPointLocation endpoint_location = 3;
-    Constraint_EndPointPriority endpoint_priority = 4;
-    Constraint_SLA_Capacity sla_capacity = 5;
-    Constraint_SLA_Latency sla_latency = 6;
-    Constraint_SLA_Availability sla_availability = 7;
-    Constraint_SLA_Isolation_level sla_isolation = 8;
-    Constraint_Exclusions exclusions = 9;
+    Constraint_Custom custom = 2;
+    Constraint_Schedule schedule = 3;
+    Constraint_EndPointLocation endpoint_location = 4;
+    Constraint_EndPointPriority endpoint_priority = 5;
+    Constraint_SLA_Capacity sla_capacity = 6;
+    Constraint_SLA_Latency sla_latency = 7;
+    Constraint_SLA_Availability sla_availability = 8;
+    Constraint_SLA_Isolation_level sla_isolation = 9;
+    Constraint_Exclusions exclusions = 10;
   }
 }
 
diff --git a/src/common/tests/MockServicerImpl_Context.py b/src/common/tests/MockServicerImpl_Context.py
index 0e6f819d8c5e9ddc823b8090a8d4b74548471bd2..3f4af19eced89843552737ae6f8b773d3fa26a58 100644
--- a/src/common/tests/MockServicerImpl_Context.py
+++ b/src/common/tests/MockServicerImpl_Context.py
@@ -13,15 +13,15 @@
 # limitations under the License.
 
 import grpc, json, logging
-from typing import Any, Dict, Iterator, List
+from typing import Any, Dict, Iterator, List, Set
 from common.proto.context_pb2 import (
     Connection, ConnectionEvent, ConnectionId, ConnectionIdList, ConnectionList,
     Context, ContextEvent, ContextId, ContextIdList, ContextList,
-    Device, DeviceEvent, DeviceId, DeviceIdList, DeviceList,
+    Device, DeviceEvent, DeviceFilter, DeviceId, DeviceIdList, DeviceList,
     Empty, EventTypeEnum,
     Link, LinkEvent, LinkId, LinkIdList, LinkList,
-    Service, ServiceEvent, ServiceId, ServiceIdList, ServiceList,
-    Slice, SliceEvent, SliceId, SliceIdList, SliceList,
+    Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList,
+    Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList,
     Topology, TopologyEvent, TopologyId, TopologyIdList, TopologyList)
 from common.proto.context_pb2_grpc import ContextServiceServicer
 from common.tests.MockMessageBroker import (
@@ -68,10 +68,19 @@ def del_entry(
     del container[entry_uuid]
     return Empty()
 
+def select_entries(database : Dict[str, Dict[str, Any]], container_name : str, entry_uuids : Set[str]) -> List[Any]:
+    if len(entry_uuids) == 0: return get_entries(database, container_name)
+    container = get_container(database, container_name)
+    return [
+        container[entry_uuid]
+        for entry_uuid in sorted(container.keys())
+        if entry_uuid in entry_uuids
+    ]
+
 class MockServicerImpl_Context(ContextServiceServicer):
     def __init__(self):
         LOGGER.info('[__init__] Creating Servicer...')
-        self.database : Dict[str, Any] = {}
+        self.database : Dict[str, Dict[str, Any]] = {}
         self.msg_broker = MockMessageBroker()
         LOGGER.info('[__init__] Servicer Created')
 
@@ -210,6 +219,33 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.info('[GetDeviceEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_DEVICE}): yield DeviceEvent(**json.loads(message.content))
 
+    def SelectDevice(self, request : DeviceFilter, context : grpc.ServicerContext) -> DeviceList:
+        LOGGER.info('[SelectDevice] request={:s}'.format(grpc_message_to_json_string(request)))
+        container_entry_uuids : Dict[str, Set[str]] = {}
+        container_name = 'device'
+        for device_id in request.device_ids.device_ids:
+            device_uuid = device_id.device_uuid.uuid
+            container_entry_uuids.setdefault(container_name, set()).add(device_uuid)
+
+        exclude_endpoints = not request.include_endpoints
+        exclude_config_rules = not request.include_config_rules
+        exclude_components  = not request.include_components
+
+        devices = list()
+        for container_name in sorted(container_entry_uuids.keys()):
+             entry_uuids = container_entry_uuids[container_name]
+        for device in select_entries(self.database, container_name, entry_uuids):
+            reply_device = Device()
+            reply_device.CopyFrom(device)
+            if exclude_endpoints:    del reply_device.device_endpoints [:] # pylint: disable=no-member
+            if exclude_config_rules: del reply_device.device_config.config_rules[:] # pylint: disable=no-member
+            if exclude_components:   del reply_device.component[:] # pylint: disable=no-member
+            devices.append(reply_device)
+                
+        reply = DeviceList(devices=devices) 
+        LOGGER.info('[SelectDevice] reply={:s}'.format(grpc_message_to_json_string(reply)))
+        return reply
+
 
     # ----- Link -------------------------------------------------------------------------------------------------------
 
@@ -291,6 +327,37 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.info('[GetSliceEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_SLICE}): yield SliceEvent(**json.loads(message.content))
 
+    def SelectSlice(self, request : SliceFilter, context : grpc.ServicerContext) -> SliceList:
+        LOGGER.info('[SelectSlice] request={:s}'.format(grpc_message_to_json_string(request)))
+        container_entry_uuids : Dict[str, Set[str]] = {}
+        for slice_id in request.slice_ids.slice_ids:
+            container_name = 'slice[{:s}]'.format(str(slice_id.context_id.context_uuid.uuid))
+            slice_uuid = slice_id.slice_uuid.uuid
+            container_entry_uuids.setdefault(container_name, set()).add(slice_uuid)
+            
+        exclude_endpoint_ids = not request.include_endpoint_ids
+        exclude_constraints  = not request.include_constraints
+        exclude_service_ids  = not request.include_service_ids
+        exclude_subslice_ids = not request.include_subslice_ids 
+        exclude_config_rules = not request.include_config_rules
+        
+        slices = list()
+        for container_name in sorted(container_entry_uuids.keys()):
+            entry_uuids = container_entry_uuids[container_name]
+            for eslice in select_entries(self.database, container_name, entry_uuids):
+                reply_slice = Slice()
+                reply_slice.CopyFrom(eslice)
+                if exclude_endpoint_ids: del reply_slice.service_endpoint_ids[:] # pylint: disable=no-member
+                if exclude_constraints : del reply_slice.service_constraints[:] # pylint: disable=no-member
+                if exclude_service_ids : del reply_slice.slice_service_ids[:] # pylint: disable=no-member
+                if exclude_subslice_ids : del reply_slice.slice_subslice_ids[:] # pylint: disable=no-member
+                if exclude_config_rules: del reply_slice.slice_config .config_rules[:] # pylint: disable=no-member
+                slices.append(reply_slice)
+                
+        reply = SliceList(slices=slices)
+        LOGGER.info('[SelectSlice] reply={:s}'.format(grpc_message_to_json_string(reply)))
+        return reply
+
 
     # ----- Service ----------------------------------------------------------------------------------------------------
 
@@ -335,6 +402,32 @@ class MockServicerImpl_Context(ContextServiceServicer):
         LOGGER.info('[GetServiceEvents] request={:s}'.format(grpc_message_to_json_string(request)))
         for message in self.msg_broker.consume({TOPIC_SERVICE}): yield ServiceEvent(**json.loads(message.content))
 
+    def SelectService(self, request : ServiceFilter, context : grpc.ServicerContext) -> ServiceList:
+        LOGGER.info('[SelectService] request={:s}'.format(grpc_message_to_json_string(request)))
+        container_entry_uuids : Dict[str, Set[str]] = {}
+        for service_id in request.service_ids.service_ids:
+            container_name = 'service[{:s}]'.format(str(service_id.context_id.context_uuid.uuid))
+            service_uuid = service_id.service_uuid.uuid
+            container_entry_uuids.setdefault(container_name, set()).add(service_uuid)
+            
+        exclude_endpoint_ids = not request.include_endpoint_ids
+        exclude_constraints  = not request.include_constraints
+        exclude_config_rules = not request.include_config_rules
+        
+        services = list()
+        for container_name in sorted(container_entry_uuids.keys()):
+            entry_uuids = container_entry_uuids[container_name]
+            for service in select_entries(self.database, container_name, entry_uuids):
+                reply_service = Service()
+                reply_service.CopyFrom(service)
+                if exclude_endpoint_ids: del reply_service.service_endpoint_ids[:] # pylint: disable=no-member
+                if exclude_constraints : del reply_service.service_constraints[:] # pylint: disable=no-member
+                if exclude_config_rules: del reply_service.service_config.config_rules[:] # pylint: disable=no-member
+                services.append(reply_service)
+                
+        reply = ServiceList(services=services) 
+        LOGGER.info('[SelectService] reply={:s}'.format(grpc_message_to_json_string(reply)))
+        return reply
 
     # ----- Connection -------------------------------------------------------------------------------------------------
 
diff --git a/src/common/tools/object_factory/EndPoint.py b/src/common/tools/object_factory/EndPoint.py
index 326c67e1e942e5c4056389a633c70e2830737217..a38ad0d5c59ee75742459729003d43ef01612f53 100644
--- a/src/common/tools/object_factory/EndPoint.py
+++ b/src/common/tools/object_factory/EndPoint.py
@@ -30,7 +30,7 @@ def json_endpoint_ids(
 
 def json_endpoint(
         device_id : Dict, endpoint_uuid : str, endpoint_type : str, topology_id : Optional[Dict] = None,
-        kpi_sample_types : List[int] = []
+        kpi_sample_types : List[int] = [], location : Optional[Dict] = None
     ):
 
     result = {
@@ -38,6 +38,7 @@ def json_endpoint(
         'endpoint_type': endpoint_type,
     }
     if len(kpi_sample_types) > 0: result['kpi_sample_types'] = copy.deepcopy(kpi_sample_types)
+    if location: result['endpoint_location'] = copy.deepcopy(location)
     return result
 
 def json_endpoints(
diff --git a/src/common/tools/object_factory/Location.py b/src/common/tools/object_factory/Location.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac44ef4c64d8466be123c5a722bf7fe69f5e48a8
--- /dev/null
+++ b/src/common/tools/object_factory/Location.py
@@ -0,0 +1,30 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import copy
+from typing import Dict, Optional
+
+
+def json_gps_position(latitude : float, longitude : float):
+    return {'latitude': latitude, 'longitude': longitude}
+
+def json_location(region : Optional[str] = None, gps_position : Optional[Dict] = None):
+    if not region and not gps_position:
+        raise Exception('One of "region" or "gps_position" arguments must be filled')
+    if region:
+        result = {'region': region}
+    else:
+        result = {'gps_position': copy.deepcopy(gps_position)}
+
+    return result
diff --git a/src/compute/service/rest_server/nbi_plugins/debug_api/Resources.py b/src/compute/service/rest_server/nbi_plugins/debug_api/Resources.py
index 67ef3dfb0ba1519440b0a22f46935165c8388cb8..ffdbba88f077f6490261372f7048b2e2526d8196 100644
--- a/src/compute/service/rest_server/nbi_plugins/debug_api/Resources.py
+++ b/src/compute/service/rest_server/nbi_plugins/debug_api/Resources.py
@@ -19,7 +19,6 @@ from .Tools import (
     format_grpc_to_json, grpc_connection_id, grpc_context_id, grpc_device_id, grpc_link_id, grpc_policy_rule_id,
     grpc_service_id, grpc_slice_id, grpc_topology_id)
 
-
 class _Resource(Resource):
     def __init__(self) -> None:
         super().__init__()
diff --git a/src/context/service/database/Constraint.py b/src/context/service/database/Constraint.py
index b33316539e7ab728194bda52e80cbc4896981ca2..2ca49338a6ac0ba2d57ec57dffa26555b9fa6507 100644
--- a/src/context/service/database/Constraint.py
+++ b/src/context/service/database/Constraint.py
@@ -12,15 +12,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import datetime, logging
+import datetime, json, logging
 from sqlalchemy import delete
 #from sqlalchemy.dialects import postgresql
 from sqlalchemy.dialects.postgresql import insert
 from sqlalchemy.orm import Session
-from typing import Dict, List, Optional
+from typing import Dict, List, Optional, Set
 from common.proto.context_pb2 import Constraint
 from common.tools.grpc.Tools import grpc_message_to_json_string
 from .models.ConstraintModel import ConstraintKindEnum, ServiceConstraintModel, SliceConstraintModel
+from .models.enums.ConstraintAction import ORM_ConstraintActionEnum, grpc_to_enum__constraint_action
 from .uuids._Builder import get_uuid_from_string
 from .uuids.EndPoint import endpoint_get_uuid
 
@@ -37,6 +38,7 @@ def compose_constraints_data(
         dict_constraint = {
             'position'  : position,
             'kind'      : kind,
+            'action'    : grpc_to_enum__constraint_action(constraint.action),
             'data'      : grpc_message_to_json_string(getattr(constraint, str_kind, {})),
             'created_at': now,
             'updated_at': now,
@@ -50,7 +52,8 @@ def compose_constraints_data(
             dict_constraint['slice_uuid'] = slice_uuid
             parent_kind,parent_uuid = 'slice',slice_uuid
         else:
-            MSG = 'Parent for Constraint({:s}) cannot be identified (service_uuid={:s}, slice_uuid={:s})'
+            MSG = 'Parent for Constraint({:s}) cannot be identified '+\
+                  '(service_uuid={:s}, slice_uuid={:s})'
             str_constraint = grpc_message_to_json_string(constraint)
             raise Exception(MSG.format(str_constraint, str(service_uuid), str(slice_uuid)))
 
@@ -70,7 +73,8 @@ def compose_constraints_data(
         }:
             constraint_name = '{:s}:{:s}:'.format(parent_kind, kind.value)
         else:
-            MSG = 'Name for Constraint({:s}) cannot be inferred (service_uuid={:s}, slice_uuid={:s})'
+            MSG = 'Name for Constraint({:s}) cannot be inferred '+\
+                  '(service_uuid={:s}, slice_uuid={:s})'
             str_constraint = grpc_message_to_json_string(constraint)
             raise Exception(MSG.format(str_constraint, str(service_uuid), str(slice_uuid)))
 
@@ -91,27 +95,34 @@ def upsert_constraints(
     else:
         MSG = 'DataModel cannot be identified (service_uuid={:s}, slice_uuid={:s})'
         raise Exception(MSG.format(str(service_uuid), str(slice_uuid)))
-
+    uuids_to_delete : Set[str] = set()
     uuids_to_upsert : Dict[str, int] = dict()
     rules_to_upsert : List[Dict] = list()
     for constraint in constraints:
         constraint_uuid = constraint['constraint_uuid']
-        position = uuids_to_upsert.get(constraint_uuid)
-        if position is None:
-            # if not added, add it
-            rules_to_upsert.append(constraint)
-            uuids_to_upsert[constraint_uuid] = len(rules_to_upsert) - 1
+        constraint_action = constraint['action']
+        if is_delete or constraint_action == ORM_ConstraintActionEnum.DELETE:
+            uuids_to_delete.add(constraint_uuid)
+        elif constraint_action == ORM_ConstraintActionEnum.SET:
+            position = uuids_to_upsert.get(constraint_uuid)
+            if position is None:
+                # if not added, add it
+                rules_to_upsert.append(constraint)
+                uuids_to_upsert[constraint_uuid] = len(rules_to_upsert) - 1
+            else:
+                # if already added, update occurrence
+                rules_to_upsert[position] = constraint
         else:
-            # if already added, update occurrence
-            rules_to_upsert[position] = constraint
+            MSG = 'Action for ConstraintRule({:s}) is not supported (service_uuid={:s}, slice_uuid={:s})'
+            LOGGER.warning(MSG.format(str(constraint), str(service_uuid), str(slice_uuid)))
+            # raise Exception(MSG.format(str_constraint, str(service_uuid), str(slice_uuid)))
 
-    # Delete all constraints not in uuids_to_upsert
     delete_affected = False
-    if len(uuids_to_upsert) > 0:
+    if len(uuids_to_delete) > 0:
         stmt = delete(klass)
         if service_uuid is not None: stmt = stmt.where(klass.service_uuid == service_uuid)
         if slice_uuid   is not None: stmt = stmt.where(klass.slice_uuid   == slice_uuid  )
-        stmt = stmt.where(klass.constraint_uuid.not_in(set(uuids_to_upsert.keys())))
+        stmt = stmt.where(klass.constraint_uuid.in_(uuids_to_delete)
         #str_stmt = stmt.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True})
         #LOGGER.warning('delete stmt={:s}'.format(str(str_stmt)))
         constraint_deletes = session.execute(stmt)
@@ -125,6 +136,7 @@ def upsert_constraints(
             index_elements=[klass.constraint_uuid],
             set_=dict(
                 position   = stmt.excluded.position,
+                action     = stmt.excluded.action,
                 data       = stmt.excluded.data,
                 updated_at = stmt.excluded.updated_at,
             )
diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py
index 7fc202b9077f2e1212d0c81313fcfbd1c05efb43..8560399cc705729685cbaa7c10399a0ec7589015 100644
--- a/src/context/service/database/Device.py
+++ b/src/context/service/database/Device.py
@@ -20,7 +20,7 @@ from sqlalchemy_cockroachdb import run_transaction
 from typing import Dict, List, Optional, Set, Tuple
 from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException
 from common.proto.context_pb2 import Device, DeviceFilter, DeviceId, TopologyId
-#from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.tools.grpc.Tools import grpc_message_to_json_string
 from common.tools.object_factory.Device import json_device_id
 from context.service.database.uuids.Topology import topology_get_uuid
 from .models.DeviceModel import DeviceModel
@@ -115,14 +115,15 @@ def device_set(db_engine : Engine, request : Device) -> Tuple[Dict, bool]:
         kpi_sample_types = [grpc_to_enum__kpi_sample_type(kst) for kst in endpoint.kpi_sample_types]
 
         endpoints_data.append({
-            'endpoint_uuid'   : endpoint_uuid,
-            'device_uuid'     : endpoint_device_uuid,
-            'topology_uuid'   : endpoint_topology_uuid,
-            'name'            : endpoint_name,
-            'endpoint_type'   : endpoint.endpoint_type,
-            'kpi_sample_types': kpi_sample_types,
-            'created_at'      : now,
-            'updated_at'      : now,
+            'endpoint_uuid'    : endpoint_uuid,
+            'device_uuid'      : endpoint_device_uuid,
+            'topology_uuid'    : endpoint_topology_uuid,
+            'name'             : endpoint_name,
+            'endpoint_type'    : endpoint.endpoint_type,
+            'kpi_sample_types' : kpi_sample_types,
+            'endpoint_location': grpc_message_to_json_string(endpoint.endpoint_location),
+            'created_at'       : now,
+            'updated_at'       : now,
         })
 
         if endpoint_topology_uuid not in topology_uuids:
diff --git a/src/context/service/database/models/ConstraintModel.py b/src/context/service/database/models/ConstraintModel.py
index d093e782adde23092d9c9d3949f9153c8ee9d4f3..112a5f35c8d23f4b4b84f5472c14dc3b1bc7fbec 100644
--- a/src/context/service/database/models/ConstraintModel.py
+++ b/src/context/service/database/models/ConstraintModel.py
@@ -16,6 +16,7 @@ import enum, json
 from sqlalchemy import CheckConstraint, Column, DateTime, Enum, ForeignKey, Integer, String
 from sqlalchemy.dialects.postgresql import UUID
 from typing import Dict
+from .enums.ConstraintAction import ORM_ConstraintActionEnum
 from ._Base import _Base
 
 # Enum values should match name of field in Constraint message
@@ -39,6 +40,7 @@ class ServiceConstraintModel(_Base):
     service_uuid    = Column(ForeignKey('service.service_uuid', ondelete='CASCADE'), nullable=False) #, index=True
     position        = Column(Integer, nullable=False)
     kind            = Column(Enum(ConstraintKindEnum), nullable=False)
+    action          = Column(Enum(ORM_ConstraintActionEnum), nullable=False)
     data            = Column(String, nullable=False)
     created_at      = Column(DateTime, nullable=False)
     updated_at      = Column(DateTime, nullable=False)
@@ -49,7 +51,10 @@ class ServiceConstraintModel(_Base):
     )
 
     def dump(self) -> Dict:
-        return {self.kind.value: json.loads(self.data)}
+        return {
+            'action': self.action.value,
+            self.kind.value: json.loads(self.data),
+        }
 
 class SliceConstraintModel(_Base):
     __tablename__ = 'slice_constraint'
@@ -58,6 +63,7 @@ class SliceConstraintModel(_Base):
     slice_uuid      = Column(ForeignKey('slice.slice_uuid', ondelete='CASCADE'), nullable=False) #, index=True
     position        = Column(Integer, nullable=False)
     kind            = Column(Enum(ConstraintKindEnum), nullable=False)
+    action          = Column(Enum(ORM_ConstraintActionEnum), nullable=False)
     data            = Column(String, nullable=False)
     created_at      = Column(DateTime, nullable=False)
     updated_at      = Column(DateTime, nullable=False)
@@ -68,4 +74,7 @@ class SliceConstraintModel(_Base):
     )
 
     def dump(self) -> Dict:
-        return {self.kind.value: json.loads(self.data)}
+        return {
+            'action': self.action.value,
+            self.kind.value: json.loads(self.data),
+        }
diff --git a/src/context/service/database/models/EndPointModel.py b/src/context/service/database/models/EndPointModel.py
index a079f9900e39fdf3a4329e604f4e596e7f5d1f89..9bb2adb2d4209bde8cee4299d10521887f371428 100644
--- a/src/context/service/database/models/EndPointModel.py
+++ b/src/context/service/database/models/EndPointModel.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import json
 from sqlalchemy import Column, DateTime, Enum, ForeignKey, String
 from sqlalchemy.dialects.postgresql import ARRAY, UUID
 from sqlalchemy.orm import relationship
@@ -22,14 +23,15 @@ from ._Base import _Base
 class EndPointModel(_Base):
     __tablename__ = 'endpoint'
 
-    endpoint_uuid    = Column(UUID(as_uuid=False), primary_key=True)
-    device_uuid      = Column(ForeignKey('device.device_uuid',     ondelete='CASCADE' ), nullable=False, index=True)
-    topology_uuid    = Column(ForeignKey('topology.topology_uuid', ondelete='RESTRICT'), nullable=False, index=True)
-    name             = Column(String, nullable=False)
-    endpoint_type    = Column(String, nullable=False)
-    kpi_sample_types = Column(ARRAY(Enum(ORM_KpiSampleTypeEnum), dimensions=1))
-    created_at       = Column(DateTime, nullable=False)
-    updated_at       = Column(DateTime, nullable=False)
+    endpoint_uuid     = Column(UUID(as_uuid=False), primary_key=True)
+    device_uuid       = Column(ForeignKey('device.device_uuid',     ondelete='CASCADE' ), nullable=False, index=True)
+    topology_uuid     = Column(ForeignKey('topology.topology_uuid', ondelete='RESTRICT'), nullable=False, index=True)
+    name              = Column(String, nullable=False)
+    endpoint_type     = Column(String, nullable=False)
+    kpi_sample_types  = Column(ARRAY(Enum(ORM_KpiSampleTypeEnum), dimensions=1))
+    created_at        = Column(DateTime, nullable=False)
+    updated_at        = Column(DateTime, nullable=False)
+    endpoint_location = Column(String, nullable=True)
 
     device            = relationship('DeviceModel',          back_populates='endpoints') # lazy='selectin'
     topology          = relationship('TopologyModel', lazy='selectin')
@@ -46,10 +48,11 @@ class EndPointModel(_Base):
 
     def dump(self) -> Dict:
         return {
-            'endpoint_id'     : self.dump_id(),
-            'name'            : self.name,
-            'endpoint_type'   : self.endpoint_type,
-            'kpi_sample_types': [kst.value for kst in self.kpi_sample_types],
+            'endpoint_id'      : self.dump_id(),
+            'name'             : self.name,
+            'endpoint_type'    : self.endpoint_type,
+            'kpi_sample_types' : [kst.value for kst in self.kpi_sample_types],
+            'endpoint_location': json.loads(self.endpoint_location)
         }
 
     def dump_name(self) -> Dict:
diff --git a/src/context/service/database/models/enums/ConstraintAction.py b/src/context/service/database/models/enums/ConstraintAction.py
new file mode 100644
index 0000000000000000000000000000000000000000..65533b6f579ffe153b046dfcb39d37758f4c0577
--- /dev/null
+++ b/src/context/service/database/models/enums/ConstraintAction.py
@@ -0,0 +1,25 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import enum, functools
+from common.proto.context_pb2 import ConstraintActionEnum
+from ._GrpcToEnum import grpc_to_enum
+
+class ORM_ConstraintActionEnum(enum.Enum):
+    UNDEFINED = ConstraintActionEnum.CONSTRAINTACTION_UNDEFINED
+    SET       = ConstraintActionEnum.CONSTRAINTACTION_SET
+    DELETE    = ConstraintActionEnum.CONSTRAINTACTION_DELETE
+
+grpc_to_enum__constraint_action = functools.partial(
+    grpc_to_enum, ConstraintActionEnum, ORM_ConstraintActionEnum)
diff --git a/src/device/service/Tools.py b/src/device/service/Tools.py
index 8717254cb59ad1b83a6e65ca3c1ba68757663674..c242ab1f64995a0e5d7bc21ae9300c70cb888ff8 100644
--- a/src/device/service/Tools.py
+++ b/src/device/service/Tools.py
@@ -16,12 +16,11 @@ import json, logging
 from typing import Any, Dict, List, Optional, Tuple, Union
 from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
 from common.method_wrappers.ServiceExceptions import InvalidArgumentException
-from common.proto.context_pb2 import ConfigActionEnum, Device, DeviceConfig, Link
+from common.proto.context_pb2 import ConfigActionEnum, Device, DeviceConfig, Link, Location
 from common.proto.device_pb2 import MonitoringSettings
 from common.proto.kpi_sample_types_pb2 import KpiSampleType
 from common.tools.grpc.ConfigRules import update_config_rule_custom
 from common.tools.grpc.Tools import grpc_message_to_json
-from context.client.ContextClient import ContextClient
 from .driver_api._Driver import _Driver, RESOURCE_ENDPOINTS
 from .monitoring.MonitoringLoops import MonitoringLoops
 from .ErrorMessages import (
@@ -202,6 +201,10 @@ def populate_endpoints(
                 device_endpoint.kpi_sample_types.append(kpi_sample_type)
                 monitoring_loops.add_resource_key(device_uuid, endpoint_uuid, kpi_sample_type, monitor_resource_key)
 
+            location = resource_value.get('location', None)
+            if location is not None:
+                device_endpoint.endpoint_location.MergeFrom(Location(**location))
+
         elif resource_key.startswith('/links/link'):
             # create sub-link
             _sub_link_uuid = resource_value['uuid']
diff --git a/src/device/service/drivers/emulated/Tools.py b/src/device/service/drivers/emulated/Tools.py
index 0ac92bf56d5538a5ed4d3e7c53bc480d5ecd40bd..15fa342388159a19bf071985ab1a7fc74d8b28a2 100644
--- a/src/device/service/drivers/emulated/Tools.py
+++ b/src/device/service/drivers/emulated/Tools.py
@@ -79,7 +79,10 @@ def compose_resource_endpoint(endpoint_data : Dict[str, Any]) -> Optional[Tuple[
 
         if len(sample_types) > 0:
             endpoint_resource_value['sample_types'] = sample_types
-
+    
+        if 'location' in endpoint_data:
+            endpoint_resource_value['location'] = endpoint_data['location']
+            
         return endpoint_resource_key, endpoint_resource_value
     except: # pylint: disable=bare-except
         LOGGER.exception('Problem composing endpoint({:s})'.format(str(endpoint_data)))
diff --git a/src/service/requirements.in b/src/service/requirements.in
index 83b6342c0c0ed5e969ba03e8af5ac502b1f525c9..48fd76485d6bbaf53c3867147882614fc0cf1b04 100644
--- a/src/service/requirements.in
+++ b/src/service/requirements.in
@@ -14,6 +14,7 @@
 
 
 anytree==2.8.0
+geopy==2.3.0
 networkx==2.6.3
 pydot==1.4.2
 redis==4.1.2
diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py
index 6d23fd4cee53d1639c9eefbd943d45dab497b253..11d191d4b08d642c228bbfc5ce33c45bd587021a 100644
--- a/src/service/service/ServiceServiceServicerImpl.py
+++ b/src/service/service/ServiceServiceServicerImpl.py
@@ -12,13 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import grpc, json, logging, random, uuid
+import copy, grpc, json, logging, random, uuid
 from typing import Optional
 from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method
 from common.method_wrappers.ServiceExceptions import (
     AlreadyExistsException, InvalidArgumentException, NotFoundException, NotImplementedException,
     OperationFailedException)
-from common.proto.context_pb2 import Connection, Empty, Service, ServiceId, ServiceStatusEnum, ServiceTypeEnum
+from common.proto.context_pb2 import Connection, Empty, Service, ServiceId, ServiceStatusEnum, ServiceTypeEnum, ConstraintActionEnum
 from common.proto.pathcomp_pb2 import PathCompRequest
 from common.proto.service_pb2_grpc import ServiceServiceServicer
 from common.tools.context_queries.Service import get_service_by_id
@@ -28,6 +28,7 @@ from pathcomp.frontend.client.PathCompClient import PathCompClient
 from service.service.tools.ConnectionToString import connection_to_string
 from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory
 from .task_scheduler.TaskScheduler import TasksScheduler
+from .tools.GeodesicDistance import gps_distance
 
 LOGGER = logging.getLogger(__name__)
 
@@ -96,6 +97,28 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
             include_config_rules=False, include_constraints=False, include_endpoint_ids=False)
         service = Service()
         service.CopyFrom(request if _service is None else _service)
+
+        for constraint in request.service_constraints:
+            if constraint.action == ConstraintActionEnum.CONSTRAINTACTION_SET:
+                if constraint.WhichOneof('constraint') == 'endpoint_location' and not constraint.endpoint_location.HasField('endpoint_id'):
+                    device_list = context_client.ListDevices(Empty())
+                    service_location = constraint.endpoint_location.location
+                    distances = {}
+                    for device in device_list.devices:
+                        for endpoint in device.device_endpoints:
+                            if not endpoint.endpoint_location.HasField('gps_position'): continue
+
+                            distance = gps_distance(service_location.gps_position, endpoint.endpoint_location.gps_position)
+                            distances[distance] = endpoint.endpoint_id
+
+                    closer_endpoint_id = distances[min(distances)]
+                    constraint.endpoint_location.endpoint_id.CopyFrom(closer_endpoint_id)
+
+                    if closer_endpoint_id not in [endpoint.endpoint_id.endpoint_uuid for endpoint in service.service_endpoint_ids]:
+                        service.service_endpoint_ids.append(closer_endpoint_id)
+
+
+
         if service.service_type == ServiceTypeEnum.SERVICETYPE_UNKNOWN:                     # pylint: disable=no-member
             service.service_type = request.service_type                                     # pylint: disable=no-member
         service.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_PLANNED     # pylint: disable=no-member
diff --git a/src/service/service/tools/GeodesicDistance.py b/src/service/service/tools/GeodesicDistance.py
new file mode 100644
index 0000000000000000000000000000000000000000..b66d336f0f617aa834905785e2e49f95073a2df9
--- /dev/null
+++ b/src/service/service/tools/GeodesicDistance.py
@@ -0,0 +1,18 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from geopy.distance import geodesic
+
+def gps_distance(gps1, gps2):
+    return geodesic((gps1.latitude, gps1.longitude), (gps2.latitude, gps2.longitude)).km
diff --git a/src/service/tests/PrepareTestScenario.py b/src/service/tests/PrepareTestScenario.py
index e4609ec416803312926422aca16cb02a6785a789..a5244f5a7c3fe35089c52c077db5a57b1e69ba5b 100644
--- a/src/service/tests/PrepareTestScenario.py
+++ b/src/service/tests/PrepareTestScenario.py
@@ -26,7 +26,7 @@ from service.tests.MockService_Dependencies import MockService_Dependencies
 
 LOCAL_HOST = '127.0.0.1'
 MOCKSERVICE_PORT = 10000
-SERVICE_SERVICE_PORT = MOCKSERVICE_PORT + get_service_port_grpc(ServiceNameEnum.SERVICE) # avoid privileged ports
+SERVICE_SERVICE_PORT = MOCKSERVICE_PORT + int(get_service_port_grpc(ServiceNameEnum.SERVICE)) # avoid privileged ports
 os.environ[get_env_var_name(ServiceNameEnum.SERVICE, ENVVAR_SUFIX_SERVICE_HOST     )] = str(LOCAL_HOST)
 os.environ[get_env_var_name(ServiceNameEnum.SERVICE, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(SERVICE_SERVICE_PORT)
 
diff --git a/src/service/tests/ServiceHandler_L3NM_EMU.py b/src/service/tests/ServiceHandler_L3NM_EMU.py
index 3df27b439626dad652e443cca4195ce36f4ac86f..2618e204c00a1bb956812daeb6f831275cac7b5a 100644
--- a/src/service/tests/ServiceHandler_L3NM_EMU.py
+++ b/src/service/tests/ServiceHandler_L3NM_EMU.py
@@ -13,8 +13,10 @@
 # limitations under the License.
 
 from typing import Dict, List, Tuple
+
+from common.tools.object_factory.Location import json_location, json_gps_position
 from common.tools.object_factory.ConfigRule import json_config_rule_set
-from common.tools.object_factory.Constraint import json_constraint_custom
+from common.tools.object_factory.Constraint import json_constraint_custom, json_constraint_endpoint_location_gps
 from common.tools.object_factory.Device import (
     json_device_emulated_packet_router_disabled, json_device_emulated_tapi_disabled, json_device_id)
 from common.tools.object_factory.EndPoint import json_endpoint, json_endpoint_id
@@ -24,21 +26,37 @@ from .CommonObjects import CONTEXT, CONTEXT_ID, PACKET_PORT_SAMPLE_TYPES, TOPOLO
 
 SERVICE_HANDLER_NAME = 'l3nm_emulated'
 
-def json_endpoint_ids(device_id : Dict, endpoint_descriptors : List[Tuple[str, str]]):
+def json_endpoint_ids(device_id : Dict, endpoint_descriptors : List[Tuple[str, str, str]]):
     return [
         json_endpoint_id(device_id, ep_uuid)
-        for ep_uuid, _ in endpoint_descriptors
+        for ep_uuid, _, _ in endpoint_descriptors
     ]
 
-def json_endpoints(device_id : Dict, endpoint_descriptors : List[Tuple[str, str]]):
+def json_endpoints(device_id : Dict, endpoint_descriptors : List[Tuple[str, str, str]]):
     return [
-        json_endpoint(device_id, ep_uuid, ep_type, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES)
-        for ep_uuid, ep_type in endpoint_descriptors
+        json_endpoint(device_id, ep_uuid, ep_type, kpi_sample_types=PACKET_PORT_SAMPLE_TYPES, location=ep_location)
+        for ep_uuid, ep_type, ep_location in endpoint_descriptors
     ]
 
+
+BARCELONA_GPS = (41.386726, 2.170107)
+MALAGA_GPS = (36.721162, -4.418339)
+ZARAGOZA_GPS = (41.655552, -0.876442)
+MADRID_GPS = (40.416741, -3.703285)
+TOLEDO_GPS = (39.862947, -4.027485)
+ANDORRA_GPS = (42.506017, 1.525923)
+SANTIAGO_GPS = (42.876254, -8.543588)
+GRANADA_GPS =    (37.178106, -3.599816)
+PONFERRADA_GPS = (42.550116, -6.597930)
+ALBACETE_GPS = (38.998249, -1.858145)
+
+
 # ----- Devices --------------------------------------------------------------------------------------------------------
 DEVICE_R1_UUID          = 'R1'
-DEVICE_R1_ENDPOINT_DEFS = [('EP1', 'optical'), ('EP100', 'copper')]
+DEVICE_R1_ENDPOINT_DEFS = [
+    ('EP1', 'optical', json_location(gps_position=json_gps_position(*BARCELONA_GPS))),
+    ('EP100', 'copper', json_location(gps_position=json_gps_position(*BARCELONA_GPS)))
+]
 DEVICE_R1_ID            = json_device_id(DEVICE_R1_UUID)
 DEVICE_R1_ENDPOINTS     = json_endpoints(DEVICE_R1_ID, DEVICE_R1_ENDPOINT_DEFS)
 DEVICE_R1_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R1_ID, DEVICE_R1_ENDPOINT_DEFS)
@@ -47,7 +65,10 @@ ENDPOINT_ID_R1_EP1      = DEVICE_R1_ENDPOINT_IDS[0]
 ENDPOINT_ID_R1_EP100    = DEVICE_R1_ENDPOINT_IDS[1]
 
 DEVICE_R2_UUID          = 'R2'
-DEVICE_R2_ENDPOINT_DEFS = [('EP1', 'optical'), ('EP100', 'copper')]
+DEVICE_R2_ENDPOINT_DEFS = [
+    ('EP1', 'optical', json_location(gps_position=json_gps_position(*MADRID_GPS))),
+    ('EP100', 'copper', json_location(gps_position=json_gps_position(*MADRID_GPS)))
+]
 DEVICE_R2_ID            = json_device_id(DEVICE_R2_UUID)
 DEVICE_R2_ENDPOINTS     = json_endpoints(DEVICE_R2_ID, DEVICE_R2_ENDPOINT_DEFS)
 DEVICE_R2_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R2_ID, DEVICE_R2_ENDPOINT_DEFS)
@@ -56,7 +77,10 @@ ENDPOINT_ID_R2_EP1      = DEVICE_R2_ENDPOINT_IDS[0]
 ENDPOINT_ID_R2_EP100    = DEVICE_R2_ENDPOINT_IDS[1]
 
 DEVICE_R3_UUID          = 'R3'
-DEVICE_R3_ENDPOINT_DEFS = [('EP1', 'optical'), ('EP100', 'copper')]
+DEVICE_R3_ENDPOINT_DEFS = [
+    ('EP1', 'optical', json_location(gps_position=json_gps_position(*MALAGA_GPS))),
+    ('EP100', 'copper', json_location(gps_position=json_gps_position(*MALAGA_GPS)))
+]
 DEVICE_R3_ID            = json_device_id(DEVICE_R3_UUID)
 DEVICE_R3_ENDPOINTS     = json_endpoints(DEVICE_R3_ID, DEVICE_R3_ENDPOINT_DEFS)
 DEVICE_R3_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_R3_ID, DEVICE_R3_ENDPOINT_DEFS)
@@ -65,7 +89,11 @@ ENDPOINT_ID_R3_EP1      = DEVICE_R3_ENDPOINT_IDS[0]
 ENDPOINT_ID_R3_EP100    = DEVICE_R3_ENDPOINT_IDS[1]
 
 DEVICE_O1_UUID          = 'O1'
-DEVICE_O1_ENDPOINT_DEFS = [('EP1', 'optical'), ('EP2', 'optical'), ('EP3', 'optical')]
+DEVICE_O1_ENDPOINT_DEFS = [
+    ('EP1', 'optical', json_location(gps_position=json_gps_position(*PONFERRADA_GPS))),
+    ('EP2', 'optical', json_location(gps_position=json_gps_position(*PONFERRADA_GPS))),
+    ('EP3', 'optical', json_location(gps_position=json_gps_position(*PONFERRADA_GPS)))
+]
 DEVICE_O1_ID            = json_device_id(DEVICE_O1_UUID)
 DEVICE_O1_ENDPOINTS     = json_endpoints(DEVICE_O1_ID, DEVICE_O1_ENDPOINT_DEFS)
 DEVICE_O1_ENDPOINT_IDS  = json_endpoint_ids(DEVICE_O1_ID, DEVICE_O1_ENDPOINT_DEFS)
@@ -104,6 +132,18 @@ SERVICE_R1_R3_CONSTRAINTS  = [
     json_constraint_custom('latency_ms', 15.2),
     json_constraint_custom('jitter_us', 1.2),
 ]
+
+
+SERVICE_R1_R3_CONSTRAINTS_LOCATION = [
+    json_constraint_endpoint_location_gps(None, ZARAGOZA_GPS[0], ZARAGOZA_GPS[1]),
+    json_constraint_endpoint_location_gps(None, TOLEDO_GPS[0], TOLEDO_GPS[1]),
+]
+SERVICE_R1_R3_CONSTRAINTS_LOCATION_NEW = [
+    json_constraint_endpoint_location_gps(None, SANTIAGO_GPS[0], SANTIAGO_GPS[1]),
+    json_constraint_endpoint_location_gps(None, GRANADA_GPS[0], GRANADA_GPS[1]),
+]
+
+
 SERVICE_R1_R3_CONFIG_RULES = [
     json_config_rule_set(
         '/settings',
@@ -123,14 +163,15 @@ SERVICE_R1_R3_DESCRIPTOR   = json_service_l3nm_planned(SERVICE_R1_R3_UUID)
 
 # ----- Test Descriptor ------------------------------------------------------------------------------------------------
 TEST_SERVICE_HANDLER = (SERVICE_HANDLER_NAME, {
-    'contexts'              : [CONTEXT],
-    'topologies'            : [TOPOLOGY],
-    'devices'               : [DEVICE_R1, DEVICE_R2, DEVICE_R3, DEVICE_O1],
-    'links'                 : [LINK_R1_O1, LINK_R2_O1, LINK_R3_O1],
-
-    'service_id'            : SERVICE_R1_R3_ID,
-    'service_descriptor'    : SERVICE_R1_R3_DESCRIPTOR,
-    'service_endpoint_ids'  : SERVICE_R1_R3_ENDPOINT_IDS,
-    'service_config_rules'  : SERVICE_R1_R3_CONFIG_RULES,
-    'service_constraints'   : SERVICE_R1_R3_CONSTRAINTS,
+    'contexts'                          : [CONTEXT],
+    'topologies'                        : [TOPOLOGY],
+    'devices'                           : [DEVICE_R1, DEVICE_R2, DEVICE_R3, DEVICE_O1],
+    'links'                             : [LINK_R1_O1, LINK_R2_O1, LINK_R3_O1],
+    'service_id'                        : SERVICE_R1_R3_ID,
+    'service_descriptor'                : SERVICE_R1_R3_DESCRIPTOR,
+    'service_endpoint_ids'              : SERVICE_R1_R3_ENDPOINT_IDS,
+    'service_config_rules'              : SERVICE_R1_R3_CONFIG_RULES,
+    'service_constraints'               : SERVICE_R1_R3_CONSTRAINTS,
+    'service_constraints_location'      : SERVICE_R1_R3_CONSTRAINTS_LOCATION,
+    'service_constraints_location_new'  : SERVICE_R1_R3_CONSTRAINTS_LOCATION_NEW,
 })
diff --git a/src/service/tests/test_unitary.py b/src/service/tests/test_unitary.py
index f99f9b191083db017486d03d0bc93b0d9152b35f..aa44714af081307377fe52106cb715f5e0774c73 100644
--- a/src/service/tests/test_unitary.py
+++ b/src/service/tests/test_unitary.py
@@ -38,6 +38,7 @@ class TestServiceHandlers:
 
     def test_prepare_environment(
         self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
         contexts, topologies, devices, links,
         context_client : ContextClient,     # pylint: disable=redefined-outer-name
         device_client : DeviceClient,       # pylint: disable=redefined-outer-name
@@ -51,6 +52,7 @@ class TestServiceHandlers:
 
     def test_service_create_error_cases(
         self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
         contexts, topologies, devices, links,
         context_client : ContextClient,     # pylint: disable=redefined-outer-name
         device_client : DeviceClient,       # pylint: disable=redefined-outer-name
@@ -92,6 +94,7 @@ class TestServiceHandlers:
 
     def test_service_create_correct(
         self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
         contexts, topologies, devices, links,
         context_client : ContextClient,     # pylint: disable=redefined-outer-name
         device_client : DeviceClient,       # pylint: disable=redefined-outer-name
@@ -102,6 +105,7 @@ class TestServiceHandlers:
 
     def test_service_get_created(
         self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
         contexts, topologies, devices, links,
         context_client : ContextClient,     # pylint: disable=redefined-outer-name
         device_client : DeviceClient,       # pylint: disable=redefined-outer-name
@@ -113,6 +117,7 @@ class TestServiceHandlers:
 
     def test_service_update_configure(
         self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
         contexts, topologies, devices, links,
         context_client : ContextClient,     # pylint: disable=redefined-outer-name
         device_client : DeviceClient,       # pylint: disable=redefined-outer-name
@@ -123,7 +128,6 @@ class TestServiceHandlers:
         service_with_settings['service_config']['config_rules'].extend(service_config_rules)
         service_with_settings['service_constraints'].extend(service_constraints)
         service_client.UpdateService(Service(**service_with_settings))
-
         for endpoint_id in service_endpoint_ids:
             device_id = endpoint_id['device_id']
             device_data = context_client.GetDevice(DeviceId(**device_id))
@@ -131,9 +135,9 @@ class TestServiceHandlers:
                 LOGGER.info('device_data[{:s}][#{:d}] => {:s}'.format(
                     str(device_id), i, grpc_message_to_json_string(config_rule)))
 
-
     def test_service_update_deconfigure(
         self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
         contexts, topologies, devices, links,
         context_client : ContextClient,     # pylint: disable=redefined-outer-name
         device_client : DeviceClient,       # pylint: disable=redefined-outer-name
@@ -153,6 +157,7 @@ class TestServiceHandlers:
 
     def test_service_get_updated(
         self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
         contexts, topologies, devices, links,
         context_client : ContextClient,     # pylint: disable=redefined-outer-name
         device_client : DeviceClient,       # pylint: disable=redefined-outer-name
@@ -162,18 +167,84 @@ class TestServiceHandlers:
         LOGGER.info('service_data = {:s}'.format(grpc_message_to_json_string(service_data)))
 
 
-    def test_service_delete(
+    def test_service_update_configure_loc(
         self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
         contexts, topologies, devices, links,
         context_client : ContextClient,     # pylint: disable=redefined-outer-name
         device_client : DeviceClient,       # pylint: disable=redefined-outer-name
         service_client : ServiceClient):    # pylint: disable=redefined-outer-name
 
-        service_client.DeleteService(ServiceId(**service_id))
+        service_with_settings = copy.deepcopy(service_descriptor)
+        service_with_settings['service_config']['config_rules'].extend(service_config_rules)
+        service_with_settings['service_constraints'].extend(service_constraints_location)
+        service_client.UpdateService(Service(**service_with_settings))
 
+        for endpoint_id in service_endpoint_ids:
+            device_id = endpoint_id['device_id']
+            device_data = context_client.GetDevice(DeviceId(**device_id))
+            for i,config_rule in enumerate(device_data.device_config.config_rules):
+                LOGGER.info('device_data[{:s}][#{:d}] => {:s}'.format(
+                    str(device_id), i, grpc_message_to_json_string(config_rule)))
+
+
+    def test_service_get_updated_1(
+        self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
+        contexts, topologies, devices, links,
+        context_client : ContextClient,     # pylint: disable=redefined-outer-name
+        device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+        service_client : ServiceClient):    # pylint: disable=redefined-outer-name
+
+        service_data = context_client.GetService(ServiceId(**service_id))
+        LOGGER.info('service_data = {:s}'.format(grpc_message_to_json_string(service_data)))
+
+
+    def test_service_update_configure_loc_new(
+        self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
+        contexts, topologies, devices, links,
+        context_client : ContextClient,     # pylint: disable=redefined-outer-name
+        device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+        service_client : ServiceClient):    # pylint: disable=redefined-outer-name
+    
+        service_with_settings = copy.deepcopy(service_descriptor)
+        service_with_settings['service_config']['config_rules'].extend(service_config_rules)
+        service_with_settings['service_constraints'].extend(service_constraints_location_new)
+        service_client.UpdateService(Service(**service_with_settings))
+
+        for endpoint_id in service_endpoint_ids:
+            device_id = endpoint_id['device_id']
+            device_data = context_client.GetDevice(DeviceId(**device_id))
+            for i,config_rule in enumerate(device_data.device_config.config_rules):
+                LOGGER.info('device_data[{:s}][#{:d}] => {:s}'.format(
+                    str(device_id), i, grpc_message_to_json_string(config_rule)))
+
+
+    def test_service_get_updated_2(
+        self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
+        contexts, topologies, devices, links,
+        context_client : ContextClient,     # pylint: disable=redefined-outer-name
+        device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+        service_client : ServiceClient):    # pylint: disable=redefined-outer-name
+
+        service_data = context_client.GetService(ServiceId(**service_id))
+        LOGGER.info('service_data = {:s}'.format(grpc_message_to_json_string(service_data)))
+
+    def test_service_delete_loc(
+        self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
+        contexts, topologies, devices, links,
+        context_client : ContextClient,     # pylint: disable=redefined-outer-name
+        device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+        service_client : ServiceClient):    # pylint: disable=redefined-outer-name
+
+        service_client.DeleteService(ServiceId(**service_id))
 
     def test_cleanup_environment(
         self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
+        service_constraints_location, service_constraints_location_new,
         contexts, topologies, devices, links,
         context_client : ContextClient,     # pylint: disable=redefined-outer-name
         device_client : DeviceClient,       # pylint: disable=redefined-outer-name
diff --git a/src/webui/service/templates/device/detail.html b/src/webui/service/templates/device/detail.html
index 4d33578e2532c26b4062565bd2cbb52106773a1a..c35ae163d3f8344f1ebb49241cc15a4afa3401d5 100644
--- a/src/webui/service/templates/device/detail.html
+++ b/src/webui/service/templates/device/detail.html
@@ -63,6 +63,7 @@
                     <th scope="col">Endpoint UUID</th>
                     <th scope="col">Name</th>
                     <th scope="col">Type</th>
+                    <th scope="col">Location</th>
                 </tr>
             </thead>
             <tbody>
@@ -77,6 +78,9 @@
                     <td>
                         {{ endpoint.endpoint_type }}
                     </td>
+                    <td>
+                        {{ endpoint.endpoint_location }}
+                    </td>
                 </tr>
                 {% endfor %}
             </tbody>