Loading src/common/tools/context_queries/InterDomain.py +113 −12 Original line number Diff line number Diff line Loading @@ -14,14 +14,15 @@ import logging from typing import Dict, List, Set, Tuple from common.Constants import DEFAULT_CONTEXT_UUID, INTERDOMAIN_TOPOLOGY_UUID from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID, INTERDOMAIN_TOPOLOGY_UUID from common.DeviceTypes import DeviceTypeEnum from common.proto.context_pb2 import ContextId, Device, Empty, EndPointId, ServiceTypeEnum, Slice from common.proto.context_pb2 import ContextId, Device, Empty, EndPointId, ServiceTypeEnum, Slice, TopologyId from common.proto.pathcomp_pb2 import PathCompRequest from common.tools.context_queries.CheckType import device_type_is_network from common.tools.context_queries.Device import get_devices_in_topology, get_uuids_of_devices_in_topology from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Topology import json_topology_id from context.client.ContextClient import ContextClient from pathcomp.frontend.client.PathCompClient import PathCompClient Loading @@ -33,18 +34,41 @@ DATACENTER_DEVICE_TYPES = {DeviceTypeEnum.DATACENTER, DeviceTypeEnum.EMULATED_DA def get_local_device_uuids(context_client : ContextClient) -> Set[str]: topologies = context_client.ListTopologies(ADMIN_CONTEXT_ID) topologies = {topology.topology_id.topology_uuid.uuid : topology for topology in topologies.topologies} LOGGER.info('[get_local_device_uuids] topologies.keys()={:s}'.format(str(topologies.keys()))) local_topology_uuids = set(topologies.keys()) local_topology_uuids.discard(INTERDOMAIN_TOPOLOGY_UUID) LOGGER.info('[get_local_device_uuids] local_topology_uuids={:s}'.format(str(local_topology_uuids))) local_device_uuids = set() # add topology names except DEFAULT_TOPOLOGY_UUID and INTERDOMAIN_TOPOLOGY_UUID; they are abstracted as a # local device in inter-domain and the name of the topology is used as abstract device name for local_topology_uuid in local_topology_uuids: if local_topology_uuid == DEFAULT_TOPOLOGY_UUID: continue local_device_uuids.add(local_topology_uuid) # add physical devices in the local topologies for local_topology_uuid in local_topology_uuids: topology_device_ids = topologies[local_topology_uuid].device_ids topology_device_uuids = {device_id.device_uuid.uuid for device_id in topology_device_ids} LOGGER.info('[get_local_device_uuids] [loop] local_topology_uuid={:s} topology_device_uuids={:s}'.format( str(local_topology_uuid), str(topology_device_uuids))) local_device_uuids.update(topology_device_uuids) LOGGER.info('[get_local_device_uuids] local_device_uuids={:s}'.format(str(local_device_uuids))) return local_device_uuids def get_interdomain_device_uuids(context_client : ContextClient) -> Set[str]: interdomain_topology_id = TopologyId(**json_topology_id(INTERDOMAIN_TOPOLOGY_UUID, context_id=ADMIN_CONTEXT_ID)) interdomain_topology = context_client.GetTopology(interdomain_topology_id) # add abstracted devices in the interdomain topology interdomain_device_ids = interdomain_topology.device_ids interdomain_device_uuids = {device_id.device_uuid.uuid for device_id in interdomain_device_ids} LOGGER.info('[get_interdomain_device_uuids] interdomain_device_uuids={:s}'.format(str(interdomain_device_uuids))) return interdomain_device_uuids def get_local_domain_devices(context_client : ContextClient) -> List[Device]: local_device_uuids = get_local_device_uuids(context_client) all_devices = context_client.ListDevices(Empty()) Loading @@ -56,16 +80,38 @@ def get_local_domain_devices(context_client : ContextClient) -> List[Device]: local_domain_devices.append(device) return local_domain_devices def is_inter_domain(context_client : ContextClient, endpoint_ids : List[EndPointId]) -> bool: interdomain_device_uuids = get_interdomain_device_uuids(context_client) LOGGER.info('[is_inter_domain] interdomain_device_uuids={:s}'.format(str(interdomain_device_uuids))) non_interdomain_endpoint_ids = [ endpoint_id for endpoint_id in endpoint_ids if endpoint_id.device_id.device_uuid.uuid not in interdomain_device_uuids ] str_non_interdomain_endpoint_ids = [ (endpoint_id.device_id.device_uuid.uuid, endpoint_id.endpoint_uuid.uuid) for endpoint_id in non_interdomain_endpoint_ids ] LOGGER.info('[is_inter_domain] non_interdomain_endpoint_ids={:s}'.format(str(str_non_interdomain_endpoint_ids))) is_inter_domain_ = len(non_interdomain_endpoint_ids) == 0 LOGGER.info('[is_inter_domain] is_inter_domain={:s}'.format(str(is_inter_domain_))) return is_inter_domain_ def is_multi_domain(context_client : ContextClient, endpoint_ids : List[EndPointId]) -> bool: local_device_uuids = get_local_device_uuids(context_client) LOGGER.info('[is_multi_domain] local_device_uuids={:s}'.format(str(local_device_uuids))) remote_endpoint_ids = [ endpoint_id for endpoint_id in endpoint_ids if endpoint_id.device_id.device_uuid.uuid not in local_device_uuids ] LOGGER.info('remote_endpoint_ids = {:s}'.format(str(remote_endpoint_ids))) str_remote_endpoint_ids = [ (endpoint_id.device_id.device_uuid.uuid, endpoint_id.endpoint_uuid.uuid) for endpoint_id in remote_endpoint_ids ] LOGGER.info('[is_multi_domain] remote_endpoint_ids={:s}'.format(str(str_remote_endpoint_ids))) is_multi_domain_ = len(remote_endpoint_ids) > 0 LOGGER.info('is_multi_domain = {:s}'.format(str(is_multi_domain_))) LOGGER.info('[is_multi_domain] is_multi_domain={:s}'.format(str(is_multi_domain_))) return is_multi_domain_ def compute_interdomain_path( Loading Loading @@ -128,23 +174,78 @@ def compute_interdomain_path( for domain_uuid in domain_list ] def get_device_to_domain_map(context_client : ContextClient) -> Dict[str, str]: devices_to_domains : Dict[str, str] = dict() contexts = context_client.ListContexts(Empty()) for context in contexts.contexts: context_id = context.context_id context_uuid = context_id.context_uuid.uuid topologies = context_client.ListTopologies(context_id) if context_uuid == DEFAULT_CONTEXT_UUID: for topology in topologies.topologies: topology_id = topology.topology_id topology_uuid = topology_id.topology_uuid.uuid if topology_uuid in {DEFAULT_TOPOLOGY_UUID, INTERDOMAIN_TOPOLOGY_UUID}: continue # add topology names except DEFAULT_TOPOLOGY_UUID and INTERDOMAIN_TOPOLOGY_UUID; they are # abstracted as a local device in inter-domain and the name of the topology is used as # abstract device name devices_to_domains[topology_uuid] = topology_uuid # add physical devices in the local topology for device_id in topology.device_ids: device_uuid = device_id.device_uuid.uuid devices_to_domains[device_uuid] = topology_uuid else: # for each topology in a remote context for topology in topologies.topologies: topology_id = topology.topology_id topology_uuid = topology_id.topology_uuid.uuid # if topology is not interdomain if topology_uuid in {INTERDOMAIN_TOPOLOGY_UUID}: continue # add devices to the remote domain list for device_id in topology.device_ids: device_uuid = device_id.device_uuid.uuid devices_to_domains[device_uuid] = context_uuid return devices_to_domains def compute_traversed_domains( context_client : ContextClient, interdomain_path : List[Tuple[str, List[EndPointId]]] ) -> List[Tuple[str, Device, bool, List[EndPointId]]]: ) -> List[Tuple[str, bool, List[EndPointId]]]: local_device_uuids = get_local_device_uuids(context_client) LOGGER.info('[compute_traversed_domains] local_device_uuids={:s}'.format(str(local_device_uuids))) interdomain_devices = get_devices_in_topology(context_client, ADMIN_CONTEXT_ID, INTERDOMAIN_TOPOLOGY_UUID) interdomain_devices = { device.device_id.device_uuid.uuid : device for device in interdomain_devices } traversed_domains : List[Tuple[str, Device, bool, List[EndPointId]]] = list() devices_to_domains = get_device_to_domain_map(context_client) LOGGER.info('[compute_traversed_domains] devices_to_domains={:s}'.format(str(devices_to_domains))) traversed_domains : List[Tuple[str, bool, List[EndPointId]]] = list() domains_dict : Dict[str, Tuple[str, bool, List[EndPointId]]] = dict() for device_uuid, endpoint_ids in interdomain_path: abstract_device = interdomain_devices[device_uuid] if abstract_device.device_type in DATACENTER_DEVICE_TYPES: continue is_local_domain = device_uuid not in local_device_uuids domain = (device_uuid, abstract_device, is_local_domain, endpoint_ids) domain_uuid = devices_to_domains.get(device_uuid, '---') domain = domains_dict.get(domain_uuid) if domain is None: is_local_domain = domain_uuid in local_device_uuids domain = (domain_uuid, is_local_domain, []) traversed_domains.append(domain) domains_dict[domain_uuid] = domain domain[2].extend(endpoint_ids) str_traversed_domains = [ (domain_uuid, is_local_domain, [ (endpoint_id.device_id.device_uuid.uuid, endpoint_id.endpoint_uuid.uuid) for endpoint_id in endpoint_ids ]) for domain_uuid,is_local_domain,endpoint_ids in traversed_domains ] LOGGER.info('[compute_traversed_domains] devices_to_domains={:s}'.format(str(str_traversed_domains))) return traversed_domains src/common/tools/grpc/Constraints.py +40 −5 Original line number Diff line number Diff line Loading @@ -21,7 +21,33 @@ from typing import Any, Dict, Optional, Tuple from common.proto.context_pb2 import Constraint, EndPointId from common.tools.grpc.Tools import grpc_message_to_json_string def update_constraint_custom(constraints, constraint_type : str, fields : Dict[str, Tuple[Any, bool]]) -> Constraint: def update_constraint_custom_scalar( constraints, constraint_type : str, value : Any, raise_if_differs : bool = False ) -> Constraint: for constraint in constraints: if constraint.WhichOneof('constraint') != 'custom': continue if constraint.custom.constraint_type != constraint_type: continue json_constraint_value = json.loads(constraint.custom.constraint_value) break # found, end loop else: # not found, add it constraint = constraints.add() # pylint: disable=no-member constraint.custom.constraint_type = constraint_type json_constraint_value = None if (json_constraint_value is None) or not raise_if_differs: # missing or raise_if_differs=False, add/update it json_constraint_value = value elif json_constraint_value != value: # exists, differs, and raise_if_differs=True msg = 'Specified value({:s}) differs existing value({:s})' raise Exception(msg.format(str(value), str(json_constraint_value))) constraint.custom.constraint_value = json.dumps(json_constraint_value, sort_keys=True) return constraint def update_constraint_custom_dict(constraints, constraint_type : str, fields : Dict[str, Tuple[Any, bool]]) -> Constraint: # fields: Dict[field_name : str, Tuple[field_value : Any, raise_if_differs : bool]] for constraint in constraints: Loading @@ -45,6 +71,7 @@ def update_constraint_custom(constraints, constraint_type : str, fields : Dict[s raise Exception(msg.format(str(field_name), str(field_value), str(json_constraint_value[field_name]))) constraint.custom.constraint_value = json.dumps(json_constraint_value, sort_keys=True) return constraint def update_constraint_endpoint_location( constraints, endpoint_id : EndPointId, Loading Loading @@ -129,10 +156,18 @@ def copy_constraints(source_constraints, target_constraints): if constraint_kind == 'custom': custom = source_constraint.custom constraint_type = custom.constraint_type try: constraint_value = json.loads(custom.constraint_value) except: # pylint: disable=bare-except constraint_value = custom.constraint_value if isinstance(constraint_value, dict): raise_if_differs = True fields = {name:(value, raise_if_differs) for name,value in constraint_value.items()} update_constraint_custom(target_constraints, constraint_type, fields) update_constraint_custom_dict(target_constraints, constraint_type, fields) else: raise_if_differs = True update_constraint_custom_scalar( target_constraints, constraint_type, constraint_value, raise_if_differs=raise_if_differs) elif constraint_kind == 'endpoint_location': endpoint_id = source_constraint.endpoint_location.endpoint_id Loading Loading
src/common/tools/context_queries/InterDomain.py +113 −12 Original line number Diff line number Diff line Loading @@ -14,14 +14,15 @@ import logging from typing import Dict, List, Set, Tuple from common.Constants import DEFAULT_CONTEXT_UUID, INTERDOMAIN_TOPOLOGY_UUID from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID, INTERDOMAIN_TOPOLOGY_UUID from common.DeviceTypes import DeviceTypeEnum from common.proto.context_pb2 import ContextId, Device, Empty, EndPointId, ServiceTypeEnum, Slice from common.proto.context_pb2 import ContextId, Device, Empty, EndPointId, ServiceTypeEnum, Slice, TopologyId from common.proto.pathcomp_pb2 import PathCompRequest from common.tools.context_queries.CheckType import device_type_is_network from common.tools.context_queries.Device import get_devices_in_topology, get_uuids_of_devices_in_topology from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.object_factory.Context import json_context_id from common.tools.object_factory.Topology import json_topology_id from context.client.ContextClient import ContextClient from pathcomp.frontend.client.PathCompClient import PathCompClient Loading @@ -33,18 +34,41 @@ DATACENTER_DEVICE_TYPES = {DeviceTypeEnum.DATACENTER, DeviceTypeEnum.EMULATED_DA def get_local_device_uuids(context_client : ContextClient) -> Set[str]: topologies = context_client.ListTopologies(ADMIN_CONTEXT_ID) topologies = {topology.topology_id.topology_uuid.uuid : topology for topology in topologies.topologies} LOGGER.info('[get_local_device_uuids] topologies.keys()={:s}'.format(str(topologies.keys()))) local_topology_uuids = set(topologies.keys()) local_topology_uuids.discard(INTERDOMAIN_TOPOLOGY_UUID) LOGGER.info('[get_local_device_uuids] local_topology_uuids={:s}'.format(str(local_topology_uuids))) local_device_uuids = set() # add topology names except DEFAULT_TOPOLOGY_UUID and INTERDOMAIN_TOPOLOGY_UUID; they are abstracted as a # local device in inter-domain and the name of the topology is used as abstract device name for local_topology_uuid in local_topology_uuids: if local_topology_uuid == DEFAULT_TOPOLOGY_UUID: continue local_device_uuids.add(local_topology_uuid) # add physical devices in the local topologies for local_topology_uuid in local_topology_uuids: topology_device_ids = topologies[local_topology_uuid].device_ids topology_device_uuids = {device_id.device_uuid.uuid for device_id in topology_device_ids} LOGGER.info('[get_local_device_uuids] [loop] local_topology_uuid={:s} topology_device_uuids={:s}'.format( str(local_topology_uuid), str(topology_device_uuids))) local_device_uuids.update(topology_device_uuids) LOGGER.info('[get_local_device_uuids] local_device_uuids={:s}'.format(str(local_device_uuids))) return local_device_uuids def get_interdomain_device_uuids(context_client : ContextClient) -> Set[str]: interdomain_topology_id = TopologyId(**json_topology_id(INTERDOMAIN_TOPOLOGY_UUID, context_id=ADMIN_CONTEXT_ID)) interdomain_topology = context_client.GetTopology(interdomain_topology_id) # add abstracted devices in the interdomain topology interdomain_device_ids = interdomain_topology.device_ids interdomain_device_uuids = {device_id.device_uuid.uuid for device_id in interdomain_device_ids} LOGGER.info('[get_interdomain_device_uuids] interdomain_device_uuids={:s}'.format(str(interdomain_device_uuids))) return interdomain_device_uuids def get_local_domain_devices(context_client : ContextClient) -> List[Device]: local_device_uuids = get_local_device_uuids(context_client) all_devices = context_client.ListDevices(Empty()) Loading @@ -56,16 +80,38 @@ def get_local_domain_devices(context_client : ContextClient) -> List[Device]: local_domain_devices.append(device) return local_domain_devices def is_inter_domain(context_client : ContextClient, endpoint_ids : List[EndPointId]) -> bool: interdomain_device_uuids = get_interdomain_device_uuids(context_client) LOGGER.info('[is_inter_domain] interdomain_device_uuids={:s}'.format(str(interdomain_device_uuids))) non_interdomain_endpoint_ids = [ endpoint_id for endpoint_id in endpoint_ids if endpoint_id.device_id.device_uuid.uuid not in interdomain_device_uuids ] str_non_interdomain_endpoint_ids = [ (endpoint_id.device_id.device_uuid.uuid, endpoint_id.endpoint_uuid.uuid) for endpoint_id in non_interdomain_endpoint_ids ] LOGGER.info('[is_inter_domain] non_interdomain_endpoint_ids={:s}'.format(str(str_non_interdomain_endpoint_ids))) is_inter_domain_ = len(non_interdomain_endpoint_ids) == 0 LOGGER.info('[is_inter_domain] is_inter_domain={:s}'.format(str(is_inter_domain_))) return is_inter_domain_ def is_multi_domain(context_client : ContextClient, endpoint_ids : List[EndPointId]) -> bool: local_device_uuids = get_local_device_uuids(context_client) LOGGER.info('[is_multi_domain] local_device_uuids={:s}'.format(str(local_device_uuids))) remote_endpoint_ids = [ endpoint_id for endpoint_id in endpoint_ids if endpoint_id.device_id.device_uuid.uuid not in local_device_uuids ] LOGGER.info('remote_endpoint_ids = {:s}'.format(str(remote_endpoint_ids))) str_remote_endpoint_ids = [ (endpoint_id.device_id.device_uuid.uuid, endpoint_id.endpoint_uuid.uuid) for endpoint_id in remote_endpoint_ids ] LOGGER.info('[is_multi_domain] remote_endpoint_ids={:s}'.format(str(str_remote_endpoint_ids))) is_multi_domain_ = len(remote_endpoint_ids) > 0 LOGGER.info('is_multi_domain = {:s}'.format(str(is_multi_domain_))) LOGGER.info('[is_multi_domain] is_multi_domain={:s}'.format(str(is_multi_domain_))) return is_multi_domain_ def compute_interdomain_path( Loading Loading @@ -128,23 +174,78 @@ def compute_interdomain_path( for domain_uuid in domain_list ] def get_device_to_domain_map(context_client : ContextClient) -> Dict[str, str]: devices_to_domains : Dict[str, str] = dict() contexts = context_client.ListContexts(Empty()) for context in contexts.contexts: context_id = context.context_id context_uuid = context_id.context_uuid.uuid topologies = context_client.ListTopologies(context_id) if context_uuid == DEFAULT_CONTEXT_UUID: for topology in topologies.topologies: topology_id = topology.topology_id topology_uuid = topology_id.topology_uuid.uuid if topology_uuid in {DEFAULT_TOPOLOGY_UUID, INTERDOMAIN_TOPOLOGY_UUID}: continue # add topology names except DEFAULT_TOPOLOGY_UUID and INTERDOMAIN_TOPOLOGY_UUID; they are # abstracted as a local device in inter-domain and the name of the topology is used as # abstract device name devices_to_domains[topology_uuid] = topology_uuid # add physical devices in the local topology for device_id in topology.device_ids: device_uuid = device_id.device_uuid.uuid devices_to_domains[device_uuid] = topology_uuid else: # for each topology in a remote context for topology in topologies.topologies: topology_id = topology.topology_id topology_uuid = topology_id.topology_uuid.uuid # if topology is not interdomain if topology_uuid in {INTERDOMAIN_TOPOLOGY_UUID}: continue # add devices to the remote domain list for device_id in topology.device_ids: device_uuid = device_id.device_uuid.uuid devices_to_domains[device_uuid] = context_uuid return devices_to_domains def compute_traversed_domains( context_client : ContextClient, interdomain_path : List[Tuple[str, List[EndPointId]]] ) -> List[Tuple[str, Device, bool, List[EndPointId]]]: ) -> List[Tuple[str, bool, List[EndPointId]]]: local_device_uuids = get_local_device_uuids(context_client) LOGGER.info('[compute_traversed_domains] local_device_uuids={:s}'.format(str(local_device_uuids))) interdomain_devices = get_devices_in_topology(context_client, ADMIN_CONTEXT_ID, INTERDOMAIN_TOPOLOGY_UUID) interdomain_devices = { device.device_id.device_uuid.uuid : device for device in interdomain_devices } traversed_domains : List[Tuple[str, Device, bool, List[EndPointId]]] = list() devices_to_domains = get_device_to_domain_map(context_client) LOGGER.info('[compute_traversed_domains] devices_to_domains={:s}'.format(str(devices_to_domains))) traversed_domains : List[Tuple[str, bool, List[EndPointId]]] = list() domains_dict : Dict[str, Tuple[str, bool, List[EndPointId]]] = dict() for device_uuid, endpoint_ids in interdomain_path: abstract_device = interdomain_devices[device_uuid] if abstract_device.device_type in DATACENTER_DEVICE_TYPES: continue is_local_domain = device_uuid not in local_device_uuids domain = (device_uuid, abstract_device, is_local_domain, endpoint_ids) domain_uuid = devices_to_domains.get(device_uuid, '---') domain = domains_dict.get(domain_uuid) if domain is None: is_local_domain = domain_uuid in local_device_uuids domain = (domain_uuid, is_local_domain, []) traversed_domains.append(domain) domains_dict[domain_uuid] = domain domain[2].extend(endpoint_ids) str_traversed_domains = [ (domain_uuid, is_local_domain, [ (endpoint_id.device_id.device_uuid.uuid, endpoint_id.endpoint_uuid.uuid) for endpoint_id in endpoint_ids ]) for domain_uuid,is_local_domain,endpoint_ids in traversed_domains ] LOGGER.info('[compute_traversed_domains] devices_to_domains={:s}'.format(str(str_traversed_domains))) return traversed_domains
src/common/tools/grpc/Constraints.py +40 −5 Original line number Diff line number Diff line Loading @@ -21,7 +21,33 @@ from typing import Any, Dict, Optional, Tuple from common.proto.context_pb2 import Constraint, EndPointId from common.tools.grpc.Tools import grpc_message_to_json_string def update_constraint_custom(constraints, constraint_type : str, fields : Dict[str, Tuple[Any, bool]]) -> Constraint: def update_constraint_custom_scalar( constraints, constraint_type : str, value : Any, raise_if_differs : bool = False ) -> Constraint: for constraint in constraints: if constraint.WhichOneof('constraint') != 'custom': continue if constraint.custom.constraint_type != constraint_type: continue json_constraint_value = json.loads(constraint.custom.constraint_value) break # found, end loop else: # not found, add it constraint = constraints.add() # pylint: disable=no-member constraint.custom.constraint_type = constraint_type json_constraint_value = None if (json_constraint_value is None) or not raise_if_differs: # missing or raise_if_differs=False, add/update it json_constraint_value = value elif json_constraint_value != value: # exists, differs, and raise_if_differs=True msg = 'Specified value({:s}) differs existing value({:s})' raise Exception(msg.format(str(value), str(json_constraint_value))) constraint.custom.constraint_value = json.dumps(json_constraint_value, sort_keys=True) return constraint def update_constraint_custom_dict(constraints, constraint_type : str, fields : Dict[str, Tuple[Any, bool]]) -> Constraint: # fields: Dict[field_name : str, Tuple[field_value : Any, raise_if_differs : bool]] for constraint in constraints: Loading @@ -45,6 +71,7 @@ def update_constraint_custom(constraints, constraint_type : str, fields : Dict[s raise Exception(msg.format(str(field_name), str(field_value), str(json_constraint_value[field_name]))) constraint.custom.constraint_value = json.dumps(json_constraint_value, sort_keys=True) return constraint def update_constraint_endpoint_location( constraints, endpoint_id : EndPointId, Loading Loading @@ -129,10 +156,18 @@ def copy_constraints(source_constraints, target_constraints): if constraint_kind == 'custom': custom = source_constraint.custom constraint_type = custom.constraint_type try: constraint_value = json.loads(custom.constraint_value) except: # pylint: disable=bare-except constraint_value = custom.constraint_value if isinstance(constraint_value, dict): raise_if_differs = True fields = {name:(value, raise_if_differs) for name,value in constraint_value.items()} update_constraint_custom(target_constraints, constraint_type, fields) update_constraint_custom_dict(target_constraints, constraint_type, fields) else: raise_if_differs = True update_constraint_custom_scalar( target_constraints, constraint_type, constraint_value, raise_if_differs=raise_if_differs) elif constraint_kind == 'endpoint_location': endpoint_id = source_constraint.endpoint_location.endpoint_id Loading