diff --git a/up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto b/up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto index 12b8352..dcf3034 100644 --- a/up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto +++ b/up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Contributors to the Eclipse Foundation + * SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -14,7 +14,6 @@ syntax = "proto3"; package uprotocol.core.udiscovery.v3; -import "google/protobuf/timestamp.proto"; import "uprotocol/uoptions.proto"; import "uprotocol/v1/uri.proto"; @@ -25,332 +24,97 @@ option java_multiple_files = true; // Enables generation of generic service attributes in C++ option cc_generic_services = true; -// Platform USE Discovery Service Interface +// Client facing APIs to the uProtocol Discovery Service. +// +// The uDiscovery service is used to store information about devices and services namely their +// addresses (in URI format), and properties of topics. This API is used by clients (uEs) to be +// about to access the information within the database. Clients talk to their local uDiscovery service +// who, when is unable to find what it is looking for, queries the central database to find the information. +// UDiscovery works in heiarchial mode where the local uDiscovery service is the first point of contact +// and the domain level service (for information about devices within a domain), and then central service +// is the last point of contact. +// +// NOTE: the internal uDiscovery communication protocol (for how data is replicated between the local, domain, +// and central) is NOT covered in this interface as this is ONLY the client APIs. service uDiscovery { option (uprotocol.service_name) = "core.udiscovery"; // Service name option (uprotocol.service_version_major) = 3; option (uprotocol.service_version_minor) = 0; option (uprotocol.service_id) = 1; - // uDiscovery Node Change Notification that sends the Update message - option (uprotocol.notification_topic) = { - id: 0x8000, - name: "NodeChange", - message: "Notification" - }; - - - // Used by any uProtocol application or service to find service instances - // locations. The passed UUri contains valid UEntity, UResource, and UAuthority information - // for a query. - // What is returned is a list of UUris that match the query. - // If lookup fails, the response will be a UStatus with - // 2. code.NOT_FOUND: No matching UUris were found - // 3. code.INVALID_ARGUMENT: The passed UUri is invalid - // 4. code.PERMISSION_DENIED: The caller does not have permission to perform the query - rpc LookupUri(LookupUriRequest) returns (LookupUriResponse) { + // Find Services. + // + // Discover t authorities, instances, and versions of services based on the passed URI. + // The only mandatory portion of the URI that must be passed is the ue_id, the rest can be discovered. + // When you pass the wildcard for authority_name, the search will be done up to the domain, in order to seach + // in the central discovery database, you must set search_central=true. + rpc FindServices(FindServicesRequest) returns (FindServicesResponse) { option (uprotocol.method_id) = 1; } - // Update a node in the database. - // **NOTE:** You MUST have write permission to the node in the database - rpc UpdateNode(UpdateNodeRequest) returns (UpdateNodeResponse) { - option (uprotocol.method_id) = 2; - } - - // Query the database to find Node(s). What is passed is the search criterial in - // the FindNodeRequest message. the returned FindNodeResponse contains the - // resulting query node(s) and their child nodes. Below are some example queries: - // 1. uDomain: `//*.device/` - // 2. uDevice: `//device` - // 3. uService: `//device.domain/body.access/` - // 4. uResource: `//device.domain/body.access//door.door_front_left` - // **NOTE:** You MUST have read permission to the node in the database - rpc FindNodes(FindNodesRequest) returns (FindNodesResponse) { - option (uprotocol.method_id) = 3; - } - - // Query the database to fetch a list of 1 or more properties for a given node. - rpc FindNodeProperties(FindNodePropertiesRequest) returns (FindNodePropertiesResponse) { - option (uprotocol.method_id) = 4; - } - - // Remove one or more nodes (and all its children nodes) in the database. - // **NOTE:** You MUST have write permission to the deleted all the nodes passed, - // all the children nodes, as well as write permission to the parent otherwise - // you will get PERMISSION_DENIED and no nodes will be deleted. - rpc DeleteNodes(DeleteNodesRequest) returns (DeleteNodesResponse) { - option (uprotocol.method_id) = 5; - } - - - // Add one of more nodes to a parent node. If one of the nodes already exists, this RPC will fail - // with a UStatus containing an ALREADY_EXISTS UCode and none of the nodes shall be added to the parent. - // **NOTE:** You MUST have write permission to the parent node - rpc AddNodes(AddNodesRequest) returns (AddNodesResponse) { - option (uprotocol.method_id) = 6; - } - - - // Update a property in a node - // **NOTE:** You MUST have write permission to the node who's property you - // are updating - rpc UpdateProperty(UpdatePropertyRequest) returns (UpdatePropertyResponse) { - option (uprotocol.method_id) = 7; - } - - - // Register to receive Notifications to changes to one of more Nodes. The changes - // are published on the notification topic: '/core.udiscovery/3/nodes#Notification' - rpc RegisterForNotifications(NotificationsRequest) returns (NotificationsResponse) { - option (uprotocol.method_id) = 8; - } - - - // Unregister for Node change notifications - rpc UnregisterForNotifications(NotificationsRequest) returns (NotificationsResponse) { - option (uprotocol.method_id) = 9; - } - - // Resolve a UUri filling in the missing names/numbers from the Discovery database. - // If the resolution was successful, the resolved UUri containing names and numbers - // is returned. - // If resolving fails, the response will be a UStatus with - // - code.NOT_FOUND: Unable to find the missing names or numbers for the passed UUri - // - code.INVALID_ARGUMENT: The passed UUri is invalid (missing names or numbers) - // - code.PERMISSION_DENIED: The caller does not have permission to perform the resolution - rpc ResolveUri(ResolveUriRequest) returns (ResolveUriResponse) { - option (uprotocol.method_id) = 10; - } -} - - -// Typedef for a node properties. A node property can be any one of the uProtocol ("u_") types -// defined below -message PropertyValue { - oneof attr { - bool u_boolean = 1; // Boolean - int32 u_integer = 2; // Integer - string u_string = 3; // String - bytes u_bytes = 4; // Raw Bytes - string u_uri = 5; // A URI - google.protobuf.Timestamp u_timestamp = 6; // Timestamp - double u_double = 7; // Double - int64 u_integer_64 = 8; // 64 bit Integer + // Get information about one or more topics that is being served by a service + // + // The API is used to fetch metadata about one or more topics (depending on what is passed in the UUri). + // Wildcard ue_id and/or resource_id can be used to fetch multiple metadata for multiple topics. + // The UServiceTopic stores topic metadata such as the permission level, message name, payload format + // (how the message is encoded) and more. + // + rpc GetServiceTopics(GetServiceTopicsRequest) returns (GetServiceTopicsResponse) { + option (uprotocol.method_id) = 2; } -} - - -// Node can be domain, device, service, resource, method, etc... -message Node { - // uProtocol long form URI pointing to this node - string uri = 1; - - // List of child nodes under this node - repeated Node nodes = 2; - // List of node properties - map properties = 3; - - // The node type - Type type = 4; - - - // What is the uThing (stored in Node) type. This is used to more easily - // identify the Node rather than parsing from uri and inferring the type - enum Type { - UNSPECIFIED = 0; // Unspecified node type - DOMAIN = 1; // uDomain - DEVICE = 2; // uDevice - ENTITY = 3; // uEntity (uE) - VERSION = 9; // uEntity version - TOPIC = 4; // uE Topic - METHOD = 5; // uE Method - MESSAGE = 6; // uE Message - RESOURCE = 7; // uE Resource - USER = 8; // User Information - } } -// Message passed to the UpdateNode() RPC call -message UpdateNodeRequest { - // Node to be updated in the database - Node node = 1; - - // Time-to-live: How long (ms) the information should be live for in the database. - // -1 means lives forever - optional int32 ttl = 2; -} - -// The (empty) response message representing the successful execution of the UpdateNode operation. -message UpdateNodeResponse {} +// Request to get information about a topic +// Example might be to get information about a specific topic, all topics for a service (using wildcard resource_id), +// or all topics for all services for a given device (using wildcard ue_id and resource_id) +message GetServiceTopicsRequest { + // The URI of the topics that we would like to query. for example, + // to fetch a specific topic, we would set + uprotocol.v1.UUri topic = 1; -// Delete one or more nodes request -message DeleteNodesRequest { - repeated string uris = 1; // uProtocol formatted URI + // Recursively search up to the central level when true, otherwise only search up to the domain level + bool search_central = 2; } -// The (empty) response message representing the successful execution of the DeleteNodes operation. -message DeleteNodesResponse {} - -// FindNodesRequest passed to FindNodes() -message FindNodesRequest { - // uProtocol formatted URI for the node to search, ex. '//vcu.VIN/core.app.hartley' - // shall return the 'core.app.hartley' node - string uri = 1; - // How deep in the node tree should the results return. A value of -1 or - // the field is not present means all child nodes are returned, value of 0 - // returns only the parent node, any other value is the depth of child nodes - optional int32 depth = 2; +// Response to GetTopicInfoRequest +message GetServiceTopicsResponse { + repeated ServiceTopicInfo topics = 1; } -// FindNodesResponse that is returned from the FindNodes() API -message FindNodesResponse { - - // List of node information - repeated Node nodes = 1; - - // Time-to-live: How long (ms) the information should be live for in the database. - // -1 means lives forever - optional int32 ttl = 2; -} - - -// Find 1 or more properties for a given node passed to FindNodeProperties() -message FindNodePropertiesRequest { - // the uri for the node in the database - string uri = 1; - - // List of 1 or more properties names to fetch from the database - // **NOTE:** When this is not populated with any property name, all properties are returned - repeated string properties = 2; -} - - -// Returned from FindNodeProperties() -message FindNodePropertiesResponse { - // a list of property name/value pairs - map properties = 1; -} - - -// Passed to AddNodes() API containing the parent node URI and a list of nodes -message AddNodesRequest { - // the URI of the parent node that you would like to add nodes to - string parent_uri = 1; - - // One or more nodes that you would like to add to the parent node. - // **NOTE:** The node uri field MAY be unqualified meaning it does not include the parent_uri - // authority & path). Support for unqualified URIs allows for the same node to be inserted into - // multiple parent nodes (ex. installing a uE node to multiple uDevice parent nodes) - repeated Node nodes = 2; -} - -// The (empty) response message representing the successful execution of the AddNodes operation. -message AddNodesResponse {} - -// Message passed to UpdateProperty() to update a property in a Node -message UpdatePropertyRequest { - // the uri for the node whos property will be updated - string uri = 1; - - // The name of the property that is to be updated - string property = 2; - - // The value to set in the property - PropertyValue value = 3; -} - -// The (empty) response message representing the successful execution of the UpdateProperty operation. -message UpdatePropertyResponse {} - -// Node Change Notification Message. -// When uEs call RegisterForNotifications(), a Notification message is sent when the node either -// changes, added, or removed. -message Notification { - // The URI to the node that has changed - string uri = 1; - - // the URI of the parent node (if it was affected) - optional string parent_uri = 2; - - // The operation performed on said Node - Operation operation = 3; - - // Operation - enum Operation { - INVALID = 0; // Invalid - UPDATE = 1; // Updated - ADD = 2; // Added to the parent - REMOVE = 3; // Removed - } - - // Time-to-live: How long (ms) the information should be live for in the database. - // A value of -1 means lives forever. - optional int32 ttl = 4; - - // uDiscovery resource that it serves (per SDV-202 definition): database - enum Resources { nodes = 0; } -} - - -// Observer Identification Information -message ObserverInfo { - // Fully qualified URI for the Observer who is registering to receive the - // notifications from uDiscovery ex. `//vcu.VIN/com.gm.app.hartley` - string uri = 1; -} - - -// Passed to the RegisterForNotifications() and UnregisterForNotifications() -// APIs this message includes the list of one or more node addresses we would like -// to receive updates for as well as information about the caller so the notification -// can be routed to the right destination. -message NotificationsRequest { - // A list of one or more Node URIs to receive notifications for - repeated string uris = 1; - - // Observer's identification information - ObserverInfo observer = 2; +// Message that stores the metadata about a topic and the topic URI so +// it can be passed back in GetServiceTopicsResponse. +message ServiceTopicInfo { + // The URI of the topic + uprotocol.v1.UUri topic = 1; + + // The topic metadata + UServiceTopic info = 2; - // How deep in the node tree should the notifications be sent for. A value of -1 or if - // the field is not present in the message, signifies that changes to any child nodes will trigger - // a Notification event. A value of 0 returns only the parent node. Any other value specified is - // the depth of child nodes to receive notifications for. - optional int32 depth = 3; + // How long the topic metadata is valid for in seconds. + // If the metadata is older than this value, the client MAY re-fetch the metadata. + // If the field is missed or the value is 0, the client MAY assume the metadata lives forever. + optional uint32 ttl = 3; } -// The (empty) response message representing the successful execution of the -// RegisterForNotifications and UnregisterForNotifications operations. -message NotificationsResponse {} -// Request message passed to ResolveUri() API to resolve the missing names or numbers. -message ResolveUriRequest { - // The URI to resolve +// The URI containing the service that we would like to find. +message FindServicesRequest { + // The Uri to look up uprotocol.v1.UUri uri = 1; -} - -// Response message returned from ResolveUri() API containing the resolved UUri -message ResolveUriResponse { - // Resolved URI - uprotocol.v1.UUri uri = 1; + // Recursively search up to the central level when true, otherwise only search up to the domain level + bool search_central = 2; } -// Request message passed to LookupUri() API. -message LookupUriRequest { - // The Uri to look up - uprotocol.v1.UUri uri = 1; -} -// Return value from LookupUri() API that contains the batch of Uris for the -// lookup -message LookupUriResponse { +// Return value from FindService API that contains a batch of all services that match the search criteria +message FindServicesResponse { // Batch of URIs uprotocol.v1.UUriBatch uris = 1; } diff --git a/up-core-api/uprotocol/core/udiscovery/v3/udiscovery_replicator.proto b/up-core-api/uprotocol/core/udiscovery/v3/udiscovery_replicator.proto new file mode 100644 index 0000000..5186e02 --- /dev/null +++ b/up-core-api/uprotocol/core/udiscovery/v3/udiscovery_replicator.proto @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under + * the terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-FileType: SOURCE + * SPDX-License-Identifier: Apache-2.0 + */ +syntax = "proto3"; + +package uprotocol.core.udiscovery.v3; +import "google/protobuf/timestamp.proto"; +import "uprotocol/uoptions.proto"; +import "uprotocol/v1/uri.proto"; +import "uprotocol/core/udiscovery/v3/udiscovery.proto"; + +option java_package = "org.eclipse.uprotocol.core.udiscovery.v3"; +option java_outer_classname = "UDiscoveryReplicatorProto"; +option java_multiple_files = true; + + +// UDiscovery Replicator is a set of APIs that are used internal to UDiscovery to populate and replicate +// information in the uDiscovery database. This API is for internal (to UDiscovery service) use only and +// not accessible for client uEs to use. + service UDiscoveryReplicator { + option (uprotocol.service_name) = "core.udiscovery"; // Service name + option (uprotocol.service_version_major) = 3; + option (uprotocol.service_version_minor) = 0; + option (uprotocol.service_id) = 1; + + + // Add, update, or remove one or more UServiceTopic from the Udiscovery database. + // + // This API is used to add, update, or remove UServiceTopic information and is called from + // between UDiscovery services (ex. local to domain, domain to central, etc..). + // To remove a topic, simply set the ttl in SetServiceTopicsRequest to be 0. + // The API returns a SetServiceTopicsResponse when the operation was successful, or it will return an + // error (the method invocation fails) with one of the following reasons: + // UCode.INVALID_ARGUMENT - The URI passed is invalid + // UCode.PERMISSION_DENIED - The caller is not permissed to set the UServiceTopics for that service. + rpc SetServiceTopics(SetServiceTopicsRequest) returns (SetServiceTopicsResponse) { + option (uprotocol.method_id) = 10; + } +} + +// Request message for SetServiceTopics that contains a repeated list of service topic metadata +message SetServiceTopicsRequest { + // The topics to add (update) in the database. + repeated ServiceTopicInfo topics = 1; + + // How long the topic metadata (in seconds) is valid for from the moment the API is called. + // If the metadata has expired, the UDiscovery service that received this data must flush the ServiceTopic info. + // If the field is missed, the ServiceTopicInfo is valid forever. + // If the field is set to 0, the ServiceTopicInfo should be removed from the database immediately. + optional uint32 ttl = 2; +} + + +// Empty message returned from SetServiceTopics when the command returned successfully +message SetServiceTopicsResponse {} + \ No newline at end of file diff --git a/up-l3/udiscovery/v3/README.adoc b/up-l3/udiscovery/v3/README.adoc index f78d278..013611c 100644 --- a/up-l3/udiscovery/v3/README.adoc +++ b/up-l3/udiscovery/v3/README.adoc @@ -1,11 +1,12 @@ = uDiscovery -:toc: +:toc: preamble :sectnums: +:source-highlighter: highlight.js The key words "*MUST*", "*MUST NOT*", "*REQUIRED*", "*SHALL*", "*SHALL NOT*", "*SHOULD*", "*SHOULD NOT*", "*RECOMMENDED*", "*MAY*", and "*OPTIONAL*" in this document are to be interpreted as described in https://www.rfc-editor.org/info/bcp14[IETF BCP14 (RFC2119 & RFC8174)] ---- -SPDX-FileCopyrightText: 2023 Contributors to the Eclipse Foundation +SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation See the NOTICE file(s) distributed with this work for additional information regarding copyright ownership. @@ -18,332 +19,13 @@ SPDX-FileType: DOCUMENTATION SPDX-License-Identifier: Apache-2.0 ---- -== Purpose - -uE's (Software Entities) will be deployed dynamically on devices that are scattered throughout the uProtocol network. In order for these dynamically deployed uE's to be able to know about what is available on their own device or on other devices, we need the ability to discover not only uEs but also what uEs serve (resources, methods, messages, etc...) as well as properties about devices. There exists today a number of Internet protocols such as DNS, Zeroconf, and others, to discover devices and of services running on said devices. the goal is to reuse as much as possible, existing Internet standards for discovering of uThings as well. - -The purpose of this proposal is to define the discovery architecture so that uEs can dynamically discovery uThings (other uEs, uDevices, uDomains, uResources, uMethods, etc...), for example what topics a service in another device shall publish, properties of a service, etc... - - -== Background -=== Definitions of Terms -.Definition of Terms -[%autowidth] -[cols=",",options="header",] -|=== -|Term |Definition -|DNS |Domain Name System covered in various IETF RFCs -|CDS |Central Discovery Service implementation of uDiscovery -|LDS |Local (to a device) implementation of uDiscovery -|Local Node |Node who is local to the device (local information) -|Remote Node |Node that is fetched from the CDS and cached in the LDS -|=== - - == Overview -uDiscovery provides the ability to discovery stuff that is addressable using UUri notation (devices, services, topics/methods) as well as properties of said stuff. - -NOTE: Data model and interface is described in link:../../../up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto[udiscovery.proto] - -.uProtocol Discovery Architecture -image::overview.drawio.svg[Overview] - -NOTE: Components described in <> below all implement link:../../../up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto[udiscovery.proto] - - -.uDiscovery Software Entities -[#udiscovery-ues] -[width="100%",cols="15%,35%,50%",options="header"]] -|=== -|Component |Description |Requirements - -|*Local uDiscovery Service (LDS)* -|Service to provide discovery of uThings per device. Every LDS has-a database that stores all of its local Nodes as well as caches node information for remote devices. -a|* Every uDevice *MUST* have LDS - -| *Domain uDiscovery Service (uDDS)* -| Storage for discovery information for all devices within its domain -a| -* uDDS *MUST* store `Nodes` for all the devices under a given domain hierarchy -* *MUST* be only one uDDS within a domain -* A uLDS *MAY* be also function as uDDS and a uCDS for a uDomain or network -* uDDS *MUST* support queries from uLDSs that are within its domain -* uDDS *MUST* relay quires from uLDS to the uCDS and then cache the results per the TTL requirements from query API response -* uDDS *SHOULD* be located in the always-on uDevices - -|*Central uDiscovery Service (CDS)* -|Central repository storing all deployed uDevice information in the network of connected devices residing in the Cloud. It is a superset of the local uDiscovery database content -a| -* *MUST* have one CDS that is globally addressable by the various domain/device LDS -|=== - -Function specific requirements shall be covered later in this document. - -=== Hierarchical Specifications - -The following section will elaborate on the uProtocol hierarchy elaborating how information is organized, referenced, and structured. This is the system classification specification used to identify and define "things" along with the storage of information (properties) of the uThings in the registry. - -<> below introduces node and properties that we will define in this section. The diagram illustrates the hierarchy (taxonomy) for things in the network. - - -.Hierarchical Classification -[#img-hierarchical] -image::hierarchical.drawio.svg[Classification] - - -==== Node - -Nodes are addressable uThings like device, service, topics, etc.... Each node has-a list of properties as well as 0-n child nodes. The declarations of nodes and properties can be found in the link:../../../up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto[udiscovery.proto], the snippet is below: - - -.Node & Property Definitions -[source] ----- -// Typedef for a node properties. A node property can be any one of the types -// defined below -message PropertyValue { - oneof attr { - bool u_boolean = 1; // Boolean - int32 u_integer = 2; // Integer - string u_string = 3; // String - bytes u_bytes = 4; // Raw Bytes - string u_uri = 5; // A URI - google.protobuf.Timestamp u_timestamp = 6; // Timestamp - } -} - -// Node can be domain, device, service, resource, method, etc... -message Node { - // URI pointing to this node - string uri = 1; - - // List of child nodes under this node - repeated Node nodes = 2; - - // List of node properties - map properties = 3; - - // The node type - Type type = 4; - - - // What is the uThing (stored in Node) type. This is used to more easily - // identify the Node rather than parsing from uri and inferring the type - enum Type { - INVALID = 0; // Invalid node type - DOMAIN = 1; // uDomain - DEVICE = 2; // uDevice - ENTITY = 3; // uEntity (uE) - VERSION = 9; // uE Version - TOPIC = 4; // uE Topic - METHOD = 5; // uE Method - MESSAGE = 6; // uE Message - RESOURCE = 7; // uE Resource - USER = 8; // User Information - } -} ----- - - -* The Node `uri` field *MUST* follow the URI specifications defined in uProtocol Specifications -** UE_VERSION *MUST* contain MAJOR -** UE_VERSION *MUST NOT* contain MINOR and PATCH - -Table below lists example URIs for the various node types in the database hierarchy. - -.Example URIs -[cols=",",options="header",] -|=== -|Node Type |Example -|domain |up://UDOMAIN -|device |up://UDEVICE.UDOMAIN -|ue |up://UDEVICE.UDOMAIN/UE_NAME -|ue_version |up://UDEVICE.UDOMAIN/UE_NAME/UE_VERSION -|topic |up://UDEVICE.UDOMAIN/UE_NAME/UE_VERSION/RESOURCE#MESSAGE -|resource |up://UDEVICE.UDOMAIN/UE_NAME/UE_VERSION/RESOURCE -|message |up://UDEVICE.UDOMAIN/UE_NAME/UE_VERSION/#MESSAGE -|method |up://UDEVICE.UDOMAIN/UE_NAME/UE_VERSION/rpc.METHOD -|=== - -==== Markup Language - -* YAML *SHALL* be used as the standard format for human-readable files (defining resources, services, properties, etc...) -* JSON *SHALL* be used as the runtime (machine-readable) markup language - -==== Naming Conventions - -* Identifiers nodes, and service names *SHALL* use lowercase a-z with underscore between words -* The service and resource names *SHALL* use lowercase a-z with underscore between words -* Interface (APIs) and event names *SHALL* use camel case notation starting with a capital letter. It is recommended to use only A-Z, a-z and 0-9 in node names -* Resources *SHALL* have a singular name (ex door, sunroof, etc.) - -NOTE: Please see https://protobuf.dev/programming-guides/style/[Protobuf Style Guide] for more details - - -==== Properties - -A property is a name-value pair of information that is declared using Protobuf Options. There are two types of properties: - -1. *uProtocol Properties:* Required properties that all services must set, these are defined in link:../up-core-api/uprotocol/v1/uoptions.proto[uoptions.proto] -2. *uService Specific Properties:* Properties that are declared in their respective service proto. - -Services can declare any non-reserved identifier in their own proto files. - -NOTE: It is *STRONGLY RECOMMENDED* to scope your property names to avoid namespace collision - - -=== Database Access - -The uDiscovery service, through the query and update APIs, allows any uE to discover or change the contents of the local and central databases. Given that we obviously do not want any uE to access anything in the database, we need to build in safety checks that are validated in both the local and central discovery service. - -==== Policy - -Table below outlines the database access policies written like network firewall rules (top to bottom). The rules will be broken down for specific rules for the LDS vs CDS. - -===== All Components -* *MUST* block access by default - -===== uLDS - -* *MUST* allow local uE to read or write its own Node as well as its children Nodes -* *MUST* allow local uE to read Nodes that it has associated link:../../../up-l2/permissions.adoc[permissions] to do so -* Fetched Nodes *MUST* be cached per ttl requirements - -===== uDDS -* *MUST* allow uLDS to read or write its own Node or its children Nodes -* Fetched Nodes *MUST* be cached per ttl requirements - -===== uCDS -* *MUST* allow uDDS to read or write its own Node or its children Nodes - -|3 | | -|4 | |*MUST* allow LDS to read additional uDevice Nodes that are within its scope Scoping (or grouping) of devices shall be defined in a later version of this specification - - -=== Node Metadata - -Node metadata are stored outside the Node structure and describe the Node itself (freshness, etc...). - - -.Node Metadata Definition -|=== -|Attribute |Type |RFC2119 |Description - -|ttl |int32 |*REQUIRED* |Time-to-Live. How long (in milliseconds) the Node is valid for before it is outdated and needs to be refreshed. When the value is -1 the Node is considered to be valid forever. A Node is expired when the following is true: \begin\{array}\{l}\displaystyle expired = t_\{current} > t_\{last_updated} + ttl\end\{array} -|last_updated |Timestamp |*REQUIRED* |Last time the content of the Node has changed (been written) -|last_accessed |Timestamp |*OPTIONAL* |The last time the Node was read (accessed) from a FindNodes() API call -|inactive |bool |*REQUIRED* |The Node has been tagged as inactive through the DeleteNode() API call -|=== - -API requirements related to Node metadata shall be covered in the subsequent section. - - -== uDiscovery Interface - -In the following section we will explain the various APIs and interfaces that are defined in uDiscovery and their requirements. Interface definitions (input and output parameters, etc...) are covered in the link:../../../up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto[udiscovery.proto]. - -=== Notifications - -Notifications are used for replicating information between uLDS, uDDS, and uCDS, and to notify local uEs if/when the content of the database has changed for various reasons such as: - -* Installation of a new service version -* Change in property values -* Updates to device configurations -* etc... - -In order for uEs to receive notifications, the uE calls the uDiscovery API `RegisterForNotifications()` passing `NotificationsRequest` message that includes the list of URIs that it would like to be notified of changes, and a value of how deep in the tree should the change notification be sent. When the depth field is set to -1 or not present, the notifications shall be sent for changes to all children nodes. Below are a few high level requirements for uDiscovery notifications: - -* uE *MUST* be permitted to receive the notification (access the node). Permission is granted if the node is public or per [Appendix: Code-Based uE Access Permissions (CAPs)] -* Notifications *MUST* be sent on the topic `/core.udiscovery/3/nodes#Notification` - -* uCDS *MUST* only allow notification registration from uDDS, and uDDS registration from uLDS - -NOTE: uCDS or uDDS MAY allow local notification registration when it is also acting as a uLDS for the local device - -* uLDS *MUST* only accept registration for Node Updates from local uEs or from the CDS and *MUST NOT* accept notification registration from other uDevices uEs - - - -NOTE: Dynamic discovery of the CDS is out of scope at the time of writing of this specification and as such the CDS authority is known to the LDS. The CDS does not need to call `RegisterForNotifications()`, the LDS simply sends the notification event to the CDS. - -==== Registration - -When a uE wants to be notified of changes to Nodes for either local or remote devices, the uE calls RegisterForNotifications() passing the list of URIs of said nodes. Figure below illustrates the usage of the notification registration API. - -.Registration for Notifications -image:notifications.svg[Notifications] - -=== Read/Query APIs - -Query APIs are used to lookup content in the database, either to resolve URIs (to be used by applications) or to fetch content of a database. - -* Any uE *MAY* call the query APIs defined in the sections below -* *MUST NOT* return Nodes that are flagged as `inactive` -* Remote Nodes that have `expired` *MUST* be refreshed to the CDS -* Locally `expired` Nodes *MUST NOT* be returned in a query - -==== URI Resolution: LookupUri() - -Used by any uEs to find service instance location, and its current version. What is returned is a list of Uri strings of fully qualified uris. The lookup searches the node database to find instances that match the search criteria. - -.Lookup URI -image:lookup_uri.svg[LookupURI] - -==== Find Node - -Figure below illustrates the flows for performing a query to the LDS. An _empty node_, shown in the figure below, is a node with only the URI populated and is returned from LDS and CDS when the node is not found. The _empty node_ is used by the LDS to know that a node does not exist in the CDS and we do not need to keep querying the same node. - -* *MUST* update `last_accessed` Node attribute when API is called - -.Find Node -image:find_node.svg[FindNode] - -=== Write APIs - -uDiscovery includes a set of APIs that allows uEs to change the content of the database. We will explain each APIs functions in the following section. - -* *MUST* only allow uEs to update their own Node -* When `ttl` is not specified, *MUST* assume -1 (live forever) -* *MUST* verify caller has write permission to update, add, or delete a Node -* *MUST* verify caller has write permission the parent node when adding or deleting a Node -* *MUST* set the Node's `last_updated` to the current time when a write API is called - -Additional CDS Requirements: - -* LDS *SHALL* ONLY be permitted to update Node information for which the uDevice that the LDS runs on is in the list of ancestors of the Node. - -==== Updating a Node - -Below is the sequence when a change happens in the database -.Updating Nodes -image:update_nodes.svg["Update Nodes"] - -==== Adding Node(s) - -Below we shall give an example of a service called `uOTA` that will install a new service called `uService` to `Device1` illustrating how the `AddNodes()` API could be used. We will also show how the Update notification is sent to two observers; local uApp and the CDS (a remote observer). - -.Add Nodes -image:add_nodes.svg[Add Nodes] - - -==== Deleting Node(s) - -DeleteNode() API informs uDiscovery to tag a Node to be inactive. that the Node is no longer active Below shall provide an example of a service called `uOTA` that shall remove a service called `uService` from `Device1` illustrating how the `DeleteNode()` API can be used to remove a uE. We will also show how the Update notification is sent to two observers; a local uApp and the CDS (remote observer). - -.Delete Node -image:delete_node.svg[Delete Node] - - -==== ResolveUri - -`ResolveUri()` is used to lookup names from ids or vice versa meaning to go to/from Long Uri from/to micro Uri. - -For portability between SDKs, Long Form URIs shall be serialized to String and Short form Uris shall be serialized to Bytes per link:../../../basics/uri.adoc[URI Specifications]. +The purpose of uDiscovery Service is for uEs to be able to find services (their location, version, instances, etc...), and lookup a service's topic metadata (ex. message format, id, name, permission level, etc...). - * *MUST* be passed either a Long or Short form URI and return both the Micro and Long form URI if successful +The specification shall be split up into two parts: +1. xref:client.adoc[Client APIs]: APIs used by uEs to find services and their topic metadata +2. xref:server.adoc[Service Implementation]: Internal design and implementation details for how UDiscovery service will serve the client APIs and replicate the information between the local, domain, and central service instances. -== Failure Recovery -In the event that the databases between the CDS and LDS becomes out of sync, the discovery service components (uLDS, uDDS, uCDS) *MAY* fetch the contents using `FindNodes()` API. diff --git a/up-l3/udiscovery/v3/add_nodes.puml b/up-l3/udiscovery/v3/add_nodes.puml deleted file mode 100644 index be938a0..0000000 --- a/up-l3/udiscovery/v3/add_nodes.puml +++ /dev/null @@ -1,90 +0,0 @@ -@startuml -'https://plantuml.com/sequence-diagram - -' SPDX-FileCopyrightText: 2023 Contributors to the Eclipse Foundation -' -' See the NOTICE file(s) distributed with this work for additional -' information regarding copyright ownership. -' -' This program and the accompanying materials are made available under -' the terms of the Apache License Version 2.0 which is available at -' https://www.apache.org/licenses/LICENSE-2.0 -' -' SPDX-FileType: SOURCE -' SPDX-License-Identifier: Apache-2.0 - - -autonumber - -box Device2 #white - actor CDS #orange -endbox -box Device1 #white - entity uDiscovery as DS #orange - entity uOTA as US #blue - actor uApp #red -endbox -US -> US: Installation of uService -US -> DS: AddNode(\nAddNodesRequest) -note right - **AddNodesRequest:** - ""parent_uri"" : "up://Device1" - ""nodes"" [ - \t{ - \t\t""uri"": "up://Device1/uService" - \t\t// Additional uService Node info here// - \t\t""properties"": //uService Properties// - \t\t""type"": ""ENTITY"" - \t} - ] - ""ttl"": -1 -end note -DS -> DS: Save Node -note right - **Node Metadata:** - save //""ttl""// - //""last_updated""//=//current time// - //""inactive""//=""false"" -end note -DS --> US: Status -note right - **Status:** - ""code"": ""OK"" -end note -||| -loop Observers - DS -[#0000FF]-\ uApp: Notification - note right - **Notification:** - ""uri"" "up:/uService" - ""parent_uri"": "up://Device1" - ""operation"": ""ADD"" - ""ttl"": -1 - end note - DS -[#0000FF]-\ CDS: Notification - - opt Fetch Newly Added Node - CDS -> DS: FindNodes(FindNodesRequest) - note right - **FindNodesRequest:** - ""uri"": "up://Device1/uService" - ""depth"": -1 - end note - DS --> CDS: FindNodesResponse - note right - **FindNodesResponse:** - ""nodes"": { //added node for uService// } - ""status"": {""code"": ""OK""} - end note - - CDS -> CDS: Save Node - note right - **Node Metadata:** - save //""ttl""// - //""last_updated""//=//current time// - //""inactive""//=""false"" - end note - end opt -end loop - -@enduml \ No newline at end of file diff --git a/up-l3/udiscovery/v3/add_nodes.svg b/up-l3/udiscovery/v3/add_nodes.svg deleted file mode 100644 index b2d46b3..0000000 --- a/up-l3/udiscovery/v3/add_nodes.svg +++ /dev/null @@ -1 +0,0 @@ -Device2Device1CDSCDSuDiscoveryuDiscoveryuOTAuOTAuAppuApp1Installation of uService2AddNode(AddNodesRequest)AddNodesRequest:parent_uri: "up://Device1"nodes[{uri: "up://Device1/uService"Additional uService Node info hereproperties:uService Propertiestype:ENTITY}]ttl: -13Save NodeNode Metadata:savettllast_updated=current timeinactive=false4StatusStatus:code:OKloop[Observers]5NotificationNotification: uri"up:/uService"parent_uri: "up://Device1"operation:ADDttl: -16Notificationopt[Fetch Newly Added Node]7FindNodes(FindNodesRequest)FindNodesRequest:uri: "up://Device1/uService"depth: -18FindNodesResponseFindNodesResponse:nodes: {added node for uService}status: {code:OK}9Save NodeNode Metadata:savettllast_updated=current timeinactive=false \ No newline at end of file diff --git a/up-l3/udiscovery/v3/client.adoc b/up-l3/udiscovery/v3/client.adoc new file mode 100644 index 0000000..dfee1da --- /dev/null +++ b/up-l3/udiscovery/v3/client.adoc @@ -0,0 +1,128 @@ += uDiscovery Client APIs +:toc: preamble +:sectnums: +:source-highlighter: highlight.js +:discovery-proto-ref: xref:../../../up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto[udiscovery.proto] +:up-l2-ref: xref:up-l2/README.adoc[uProtocol Communication Layer (uP-L2) API] + + +The key words "*MUST*", "*MUST NOT*", "*REQUIRED*", "*SHALL*", "*SHALL NOT*", "*SHOULD*", "*SHOULD NOT*", "*RECOMMENDED*", "*MAY*", and "*OPTIONAL*" in this document are to be interpreted as described in https://www.rfc-editor.org/info/bcp14[IETF BCP14 (RFC2119 & RFC8174)] + +---- +SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation + +See the NOTICE file(s) distributed with this work for additional +information regarding copyright ownership. + +This program and the accompanying materials are made available under +the terms of the Apache License Version 2.0 which is available at +https://www.apache.org/licenses/LICENSE-2.0 + +SPDX-FileType: DOCUMENTATION +SPDX-License-Identifier: Apache-2.0 +---- + +== Overview + +In the following document we will elaborate on the design and requirements for the uDiscovery service client facing APIs. + +.Client APIs +[#client-api] +[mermaid] +ifdef::env-github[[source,mermaid]] +---- +sequenceDiagram + +Client ->> UDiscoveryService: FindService() + +Client ->> UDiscoveryService: FindServiceTopics() +---- + +In <> above, _Client_ represents the client-facing APIs to talk to uDiscovery database that can be found in the various language libraries such as https://github.com/eclipse-uprotocol/up-cpp[up-cpp], https://github.com/eclipse-uprotocol/up-java[up-java], etc.. that are used to find services and their topics. + +== Client Facing APIs + +The client facing APIs of uDiscovery provide the means for uEs to discover services (where they are located, versions, etc...), and topic metadata that a service produces (method id and permissions, publish topic message formats, etc...). The API is declared in the {discovery-proto-ref}. + +[.specitem,oft-sid="dsn~discovery-client-apis~1",oft-needs="impl"] +-- +Each link:../languages.adoc[uProtocol Language Library] *MUST* implement the client-side APIs of {discovery-proto-ref} using the {up-l2-ref} RpcClient. +-- + +=== FindServices() + +The FindServices() API is used to find the authority(ies), instance(s), and version(s) of services based on the passed URI. The only mandatory portion of the URI that must be passed is the ue_id, the rest can be discovered. When you pass the wildcard for authority_name, the search will be done up to the domain, in order to search in the central discovery database, you must set `search_central=true`. + +[.specitem,oft-sid="dsn~discovery-findservices-error-notfound~1",oft-needs="impl,test"] +-- +* *MUST* return a `UCode.NOT_FOUND` if no service matching the passed URI was found. +-- + +[.specitem,oft-sid="dsn~discovery-findservices-error-invalid-argument~1",oft-needs="impl,test"] +-- +* *MUST* return a `UCode.INVALID_ARGUMENT` if: + * `search_central==true` and `authority_name` does not contain the wildcard `*`. + * `UUri` is empty + +-- + +[.specitem,oft-sid="dsn~discovery-findservices-error-permission-denied~1",oft-needs="impl,test"] +-- +* *MUST* return a `UCode.PERMISSION_DENIED` if the caller is not permitted to query for that service. +-- + +==== Example Use Cases + + Below are example string URIs that could be passed to the API. + +.FindServices() Examples +[#findservices-examples, cols="1,1,3", options="header", width="80%"] +|=== +| URI | `search_central` | Description + +| `up:/FFFF1234/FF/0` | false | Find local instances & versions of service 1234. +| `up://*/FFFF1234/FF/0` | false | Find instances & versions of service 1234 within a domain. +| `up://*/FFFF0004/FF/0` | true | Find instances & versions of service 4 that are globally addressable. +| `up://*/11234/2/0` | false | Find the authority_name for version 2 & instance 1 of service 1234. + +|=== + + +=== GetServiceTopics() + +The GetServiceTopics() API is used to fetch metadata about one or more topics (depending on what is passed in the UUri) so clients can know more metadata about the topic(s). Wildcard ue_id and/or resource_id can be used to fetch multiple `UServiceTopic` information. The `UServiceTopic` contains topic metadata such as the minimum permission level required to read from the topic, message name, payload format (how the message is encoded) and more. + +[.specitem,oft-sid="dsn~discovery-getservicetopics-error-notfound~1",oft-needs="impl,test"] +-- +* *MUST* return a `UCode.NOT_FOUND` if no topic matching the URI was found. +-- + +[.specitem,oft-sid="dsn~discovery-getservicetopics-error-invalid-argument~1",oft-needs="impl,test"] +-- +* *MUST* return a `UCode.INVALID_ARGUMENT` if the URI passed in is not a valid xref:../../../basics/uri.adoc[uProtocol UUri]. +-- + +[.specitem,oft-sid="dsn~discovery-getservicetopics-error-permission-denied~1",oft-needs="impl,test"] +-- +* *MUST* return a `UCode.PERMISSION_DENIED` if the caller is not permitted to query for that topic. +-- + +==== Example Use Cases + +Below are example use cases for the API when passed certain URIs (shown in string form) along with the expected results. + +.GetServiceTopics() Examples +[#getservicetopics-examples, cols="1,3", options="header", width="80%"] +|=== +| URI | Description + +| `up:/1234/2/8000` | Return the `UServiceTopic` for topic 8000 of service 1234 version 2. + +| `up:/1234/2/FFFF` | Return repeated list of `UServiceTopic` for all tpoics from service 1234 version 2. + +|=== + + + +NOTE: Please refer to the {discovery-proto-ref} for details of the UDiscovery Client APIs. + diff --git a/up-l3/udiscovery/v3/delete_node.puml b/up-l3/udiscovery/v3/delete_node.puml deleted file mode 100644 index 4cc5f72..0000000 --- a/up-l3/udiscovery/v3/delete_node.puml +++ /dev/null @@ -1,60 +0,0 @@ -@startuml -'https://plantuml.com/sequence-diagram - -' SPDX-FileCopyrightText: 2023 Contributors to the Eclipse Foundation -' -' See the NOTICE file(s) distributed with this work for additional -' information regarding copyright ownership. -' -' This program and the accompanying materials are made available under -' the terms of the Apache License Version 2.0 which is available at -' https://www.apache.org/licenses/LICENSE-2.0 -' -' SPDX-FileType: SOURCE -' SPDX-License-Identifier: Apache-2.0 - -autonumber - -box Device2 #white - actor CDS #orange -endbox -box Device1 #white - entity uDiscovery as DS #orange - entity uOTA as US #blue - actor uApp #red -endbox -US -> US: Uninstall of uService -US -> DS: DeleteNodes(\nDeleteNodesRequest) -note right - **DeleteNodesRequest:** - ""uris"": ["up://Device1/uService"] -end note -DS -> DS: Delete Node -note right - **Node Metadata:** - //""last_updated""//=//current time// - //""inactive""//=""true"" -end note -DS --> US: Status -note right - **Status:** - ""code"": ""OK"" -end note -||| -loop Observers - DS -[#0000FF]-\ uApp: Notification - note right - **Notification:** - ""uri"": "up://Device1/uService" - ""operation"": ""DELETE"" - end note - DS -[#0000FF]-\ CDS: Notification - CDS -> CDS: Delete Node - note right - **Node Metadata:** - //""last_updated""//=//current time// - //""inactive""//=""true"" - end note -end loop - -@enduml \ No newline at end of file diff --git a/up-l3/udiscovery/v3/delete_node.svg b/up-l3/udiscovery/v3/delete_node.svg deleted file mode 100644 index 37f3b2f..0000000 --- a/up-l3/udiscovery/v3/delete_node.svg +++ /dev/null @@ -1 +0,0 @@ -Device2Device1CDSCDSuDiscoveryuDiscoveryuOTAuOTAuAppuApp1Uninstall of uService2DeleteNodes(DeleteNodesRequest)DeleteNodesRequest:uris: ["up://Device1/uService"]3Delete NodeNode Metadata:last_updated=current timeinactive=true4StatusStatus:code:OKloop[Observers]5NotificationNotification: uri: "up://Device1/uService"operation:DELETE6Notification7Delete NodeNode Metadata:last_updated=current timeinactive=true \ No newline at end of file diff --git a/up-l3/udiscovery/v3/design.drawio.svg b/up-l3/udiscovery/v3/design.drawio.svg new file mode 100644 index 0000000..b86091c --- /dev/null +++ b/up-l3/udiscovery/v3/design.drawio.svg @@ -0,0 +1,605 @@ + + + + + + + + +
+
+
+ Legend +
+
+
+
+ + Legend + +
+
+ + + + +
+
+
+ + + FindService() + +
+ + GetServiceTopics() + +
+ + SetServiceTopics() + +
+
+
+
+
+ + FindService()... + +
+
+ + + + +
+
+
+
+

+
+

+
+
+
+
+
+ +
+
+ + + + +
+
+
+

+ + uDDS + +
+ + + Domain Discovery + + +

+
+
+
+
+ + uDDS... + +
+
+ + + + +
+
+
+ uApps +
+
+
+
+ + uApps + +
+
+ + + + +
+
+
+ uApps +
+
+
+
+ + uApps + +
+
+ + + + +
+
+
+ + uEs + +
+
+
+
+ + uEs + +
+
+ + + + + + +
+
+
+ + + FindService() + +
+ + GetServiceTopics() + +
+
+
+
+
+
+ + FindService()... + +
+
+ + + + +
+
+
+
+

+
+

+
+
+
+
+
+ +
+
+ + + + +
+
+
+

+ + uLDS + +
+ + + Domain Discovery + + +

+
+
+
+
+ + uLDS... + +
+
+ + + + +
+
+
+ uApps +
+
+
+
+ + uApps + +
+
+ + + + +
+
+
+ uApps +
+
+
+
+ + uApps + +
+
+ + + + +
+
+
+ + uEs + +
+
+
+
+ + uEs + +
+
+ + + + + + +
+
+
+ + + FindService() + +
+ + GetServiceTopics() + +
+
+
+
+
+
+ + FindService()... + +
+
+ + + + + +
+
+
+

+ + uCDS + +
+ + + Central Discovery + + +

+
+
+
+
+ + uCDS... + +
+
+ + + + +
+
+
+ uApps +
+
+
+
+ + uApps + +
+
+ + + + +
+
+
+ uApps +
+
+
+
+ + uApps + +
+
+ + + + +
+
+
+ + uEs + +
+
+
+
+ + uEs + +
+
+ + + + + +
+
+
+ + + FindService() + +
+ + GetServiceTopics() + +
+
+
+
+
+
+ + FindService()... + +
+
+ + + + + + + + +
+
+
+ + + FindService() + +
+ + GetServiceTopics() + +
+ + SetServiceTopics() + +
+
+
+
+
+ + FindService()... + +
+
+ + + + + + +
+
+
+

+ + OTA Client + +
+

+
+
+
+
+ + OTA Client + +
+
+ + + + +
+
+
+ + SetServiceTopics() + +
+
+
+
+ + SetServiceTopics... + +
+
+ + + + +
+
+
+

+ + uService/ +
+ uApp +
+

+
+
+
+
+ + uService/... + +
+
+ + + + +
+
+
+

+ uProtocol Core uE +
+

+
+
+
+
+ + uProtocol C... + +
+
+ + + + +
+
+
+
+

+ + + Device + + +
+

+
+
+
+
+
+ + Device + +
+
+ + + + +
+
+
+ + uEs + +
+
+
+
+ + uEs + +
+
+ + + + +
+
+
+ + uEs + +
+
+
+
+ + uEs + +
+
+
+ + + + + Text is not SVG - cannot display + + + +
\ No newline at end of file diff --git a/up-l3/udiscovery/v3/find_node.puml b/up-l3/udiscovery/v3/find_node.puml deleted file mode 100644 index 0e7c104..0000000 --- a/up-l3/udiscovery/v3/find_node.puml +++ /dev/null @@ -1,90 +0,0 @@ -@startuml -'https://plantuml.com/sequence-diagram - -' SPDX-FileCopyrightText: 2023 Contributors to the Eclipse Foundation -' -' See the NOTICE file(s) distributed with this work for additional -' information regarding copyright ownership. -' -' This program and the accompanying materials are made available under -' the terms of the Apache License Version 2.0 which is available at -' https://www.apache.org/licenses/LICENSE-2.0 -' -' SPDX-FileType: SOURCE -' SPDX-License-Identifier: Apache-2.0 - - -autonumber - -box uDevice1 #white - Collections uEs #red - entity LDS #orange -end box -entity CDS #orange - -group Local uDevice Query - uEs -> LDS: FindNodes(FindNodesRequest) - note right - **FindNodesRequest:** - ""uri"": "up://Device1/uService" - ""depth"": -1 - end note - alt Found - LDS --> uEs: FindNodesResponse - note right - **FindNodesResponse:** - ""nodes"": { //One or more nodes// } - ""status"": {""code"": ""OK""} - end note - else Error - LDS --> uEs: FindNodesResponse - note right - **FindNodesResponse:** - ""nodes"": { //Empty Node// } - ""status"": {""code"": ""INVALID_ARGUMENT | NOT_FOUND | PERMISSION_DENIED""} - end note - end alt -end -||| -group Remote uDevice Query - uEs -> LDS: FindNodes(FindNodesRequest) - note right - **FindNodesRequest:** - ""uri"": "up://Device2/uService" - ""depth"": -1 - end note - LDS -> CDS: FindNodes(FindNodesRequest) - alt Found - CDS --> LDS: FindNodesResponse - note right - **FindNodesResponse:** - ""nodes"": { //One or more nodes// } - ""status"": {""code"": ""OK""} - end note - LDS -> LDS: Cache Node Info (per ttl) - else NOT FOUND - CDS --> LDS: FindNodesResponse - note right - **FindNodesResponse:** - ""nodes"": { //Empty Node// } - ""status"": {""code"": ""NOT_FOUND""} - ""ttl"": 432000000 ///* 5 days */// - end note - LDS -> LDS: Cache Node Info (per ttl) - else TIMEOUT - note right - **FindNodesResponse:** - ""nodes"": { //Empty Node// } - ""status"": {""code"": ""DEADLINE_EXCEEDED""} - end note - else ERROR - CDS --> LDS: FindNodesResponse - note right - **FindNodesResponse:** - ""nodes"": { //One or more nodes// } - ""status"": {""code"": ""INVALID_ARGUMENT | PERMISSION_DENIED""} - end note - end alt - LDS --> uEs: FindNodesResponse -end -@enduml \ No newline at end of file diff --git a/up-l3/udiscovery/v3/find_node.svg b/up-l3/udiscovery/v3/find_node.svg deleted file mode 100644 index 38bd5cc..0000000 --- a/up-l3/udiscovery/v3/find_node.svg +++ /dev/null @@ -1 +0,0 @@ -uDevice1uEsuEsLDSLDSCDSCDSLocal uDevice Query1FindNodes(FindNodesRequest)FindNodesRequest:uri: "up://Device1/uService"depth: -1alt[Found]2FindNodesResponseFindNodesResponse:nodes: {One or more nodes}status: {code:OK}[Error]3FindNodesResponseFindNodesResponse:nodes: {Empty Node}status: {code:INVALID_ARGUMENT | NOT_FOUND | PERMISSION_DENIED}Remote uDevice Query4FindNodes(FindNodesRequest)FindNodesRequest:uri: "up://Device2/uService"depth: -15FindNodes(FindNodesRequest)alt[Found]6FindNodesResponseFindNodesResponse:nodes: {One or more nodes}status: {code:OK}7Cache Node Info (per ttl)[NOT FOUND]8FindNodesResponseFindNodesResponse:nodes: {Empty Node}status: {code:NOT_FOUND}ttl: 432000000/* 5 days */9Cache Node Info (per ttl)FindNodesResponse:nodes: {Empty Node}status: {code:DEADLINE_EXCEEDED}[TIMEOUT][ERROR]10FindNodesResponseFindNodesResponse:nodes: {One or more nodes}status: {code:INVALID_ARGUMENT | PERMISSION_DENIED}11FindNodesResponse \ No newline at end of file diff --git a/up-l3/udiscovery/v3/hierarchical.drawio.svg b/up-l3/udiscovery/v3/hierarchical.drawio.svg deleted file mode 100644 index 80de190..0000000 --- a/up-l3/udiscovery/v3/hierarchical.drawio.svg +++ /dev/null @@ -1,370 +0,0 @@ - - - - - - - - - - - -
-
-
- domain -
-
-
-
- - domain - -
-
- - - - - - - - -
-
-
- device -
-
-
-
- - device - -
-
- - - - -
-
-
- ue_version -
- (MAJOR) -
-
-
-
- - ue_version... - -
-
- - - - -
-
-
- property -
-
-
-
- - property - -
-
- - - - -
-
-
- property -
-
-
-
- - property - -
-
- - - - -
-
-
- property -
-
-
-
- - property - -
-
- - - - -
-
-
- method -
-
-
-
- - method - -
-
- - - - - - - - -
-
-
- property -
-
-
-
- - property - -
-
- - - - - - -
-
-
- Legend -
-
-
-
- - Legend - -
-
- - - - -
-
-
- node -
-
-
-
- - node - -
-
- - - - -
-
-
- property -
-
-
-
- - property - -
-
- - - - -
-
-
- resource -
-
-
-
- - resource - -
-
- - - - - - -
-
-
- property -
-
-
-
- - property - -
-
- - - - - - -
-
-
- message -
-
-
-
- - message - -
-
- - - - -
-
-
- property -
-
-
-
- - property - -
-
- - - - - - -
-
-
- topic -
-
-
-
- - topic - -
-
- - - - -
-
-
- property -
-
-
-
- - property - -
-
- - - - - - - - - - -
-
-
- generated node -
-
-
-
- - generated... - -
-
- - - - - - -
-
-
- ue -
- - (sw entity) - -
-
-
-
- - ue... - -
-
-
- - - - - Text is not SVG - cannot display - - - -
diff --git a/up-l3/udiscovery/v3/lookup_uri.puml b/up-l3/udiscovery/v3/lookup_uri.puml deleted file mode 100644 index db4c972..0000000 --- a/up-l3/udiscovery/v3/lookup_uri.puml +++ /dev/null @@ -1,79 +0,0 @@ -@startuml -'https://plantuml.com/sequence-diagram - -' SPDX-FileCopyrightText: 2023 Contributors to the Eclipse Foundation -' -' See the NOTICE file(s) distributed with this work for additional -' information regarding copyright ownership. -' -' This program and the accompanying materials are made available under -' the terms of the Apache License Version 2.0 which is available at -' https://www.apache.org/licenses/LICENSE-2.0 -' -' SPDX-FileType: SOURCE -' SPDX-License-Identifier: Apache-2.0 - -autonumber - -box uDevice #white - Collections uEs #red - entity LDS #orange -end box -entity CDS #orange - -uEs -> LDS: LookupUri(UriRequest) -note right -**UriRequest:** -""uri"": ""//topic//"" -end note - -alt Found Locally -LDS --> uEs: UriResponse -note right -**UriRequest:** -""uris"": {""//topic//"", ""//topic//""} -""result"": {""code"": ""OK""} -end note -||| -else Invalid Argument or Permission Denied -LDS --> uEs: UriResponse -note right -**UriResponse:** -""result"" : { ""code"": ""INVALID_ARGUMENT | PERMISSION_DENIED"" } -end note -||| -else Remote Lookup Required -LDS -> CDS: LookupUri(UriRequest) -alt Success -CDS --> LDS: UriResponse -note right -**UriResponse:** -""uris"": {""//topic//"", ""//topic//""} -""result"": {""code"": ""OK""} -end note -LDS -> LDS: Cache (per ttl) -LDS --> uEs: UriResponse -note right -**UriResponse:** -""uris"": {""//topic//"", ""//topic//""} -""result"": {""code"": ""OK""} -end note -else Failure -CDS --> LDS: UriResponse -note right -**UriResponse:** -""result"": {""code"": ""INVALID_ARGUMENT | NOT_FOUND | PERMISSION_DENIED""} -end note -LDS --> uEs: UriResponse -end alt - -else Not Found -LDS --> uEs: UriResponse -note right -**UriResponse:** -""result"": {""code"": ""NOT_FOUND""} -end note -end alt - -LDS --> uEs: UriResponse -@enduml \ No newline at end of file diff --git a/up-l3/udiscovery/v3/lookup_uri.svg b/up-l3/udiscovery/v3/lookup_uri.svg deleted file mode 100644 index d4d3887..0000000 --- a/up-l3/udiscovery/v3/lookup_uri.svg +++ /dev/null @@ -1 +0,0 @@ -uDeviceuEsuEsLDSLDSCDSCDS1LookupUri(UriRequest)UriRequest:uri:topicalt[Found Locally]2UriResponseUriRequest:uris: {topic,topic}result: {code:OK}[Invalid Argument or Permission Denied]3UriResponseUriResponse:result: {code:INVALID_ARGUMENT | PERMISSION_DENIED}[Remote Lookup Required]4LookupUri(UriRequest)alt[Success]5UriResponseUriResponse:uris: {topic,topic}result: {code:OK}6Cache (per ttl)7UriResponseUriResponse:uris: {topic,topic}result: {code:OK}[Failure]8UriResponseUriResponse:result: {code:INVALID_ARGUMENT | NOT_FOUND | PERMISSION_DENIED}9UriResponse[Not Found]10UriResponseUriResponse:result: {code:NOT_FOUND}11UriResponse \ No newline at end of file diff --git a/up-l3/udiscovery/v3/notifications.puml b/up-l3/udiscovery/v3/notifications.puml deleted file mode 100644 index 95e0596..0000000 --- a/up-l3/udiscovery/v3/notifications.puml +++ /dev/null @@ -1,75 +0,0 @@ -@startuml -'https://plantuml.com/sequence-diagram - -' SPDX-FileCopyrightText: 2023 Contributors to the Eclipse Foundation -' -' See the NOTICE file(s) distributed with this work for additional -' information regarding copyright ownership. -' -' This program and the accompanying materials are made available under -' the terms of the Apache License Version 2.0 which is available at -' https://www.apache.org/licenses/LICENSE-2.0 -' -' SPDX-FileType: SOURCE -' SPDX-License-Identifier: Apache-2.0 - - -autonumber - -box uDevice2 #white - actor CDS #orange -end box -box uDevice1 #white - entity LDS as DS #orange - actor uApp #red -endbox -group uApp to LDS Registration - uApp ->DS: RegisterForNotifications(\nNotificationsRequest) - note right - **NotificationsRequest:** - ""uris"": [ "up://Device1/uService/1", "up://Device2/uService/1"] - ""observer"": { ""uri": "up://Device1/uApp/1" } - end note - alt Success - DS -> DS: Save NotificationRequest - DS --> uApp: Status - note right - **Status:** - ""code"": ""OK"" - end note - else Error - DS --> uApp: Status - note right - **Status:** - ""code"": ""INVALID_ARGUMENT |"" - ""NOT_FOUND | PERMISSION_DENIED"" - end note - end alt -end -||| -group LDS to CDS Registration -DS -> CDS: RegisterForNotifications(\nNotificationsRequest) -note right - **NotificationsRequest:** - ""uris"": "up://Device2/uSerivce/1" - ""observer"": { ""uri"": "up://Device1/core.udiscovery/2" } - } -end note -alt Success - CDS -> CDS: Save NotificationRequest - CDS --> DS: Status - note right - **Status:** - ""code"": ""OK"" - end note -else Error - CDS --> DS: Status - note right - **Status:** - ""code"": ""INVALID_ARGUMENT |"" - ""NOT_FOUND | PERMISSION_DENIED"" - end note -end alt -end - -@enduml \ No newline at end of file diff --git a/up-l3/udiscovery/v3/notifications.svg b/up-l3/udiscovery/v3/notifications.svg deleted file mode 100644 index b706a12..0000000 --- a/up-l3/udiscovery/v3/notifications.svg +++ /dev/null @@ -1 +0,0 @@ -uDevice2uDevice1CDSCDSLDSLDSuAppuAppuApp to LDS Registration1RegisterForNotifications(NotificationsRequest)NotificationsRequest:uris: [ "up:Device1/uService/1", "up:Device2/uService/1"]observer: { ""uri": "up://Device1/uApp/1" }alt[Success]2Save NotificationRequest3StatusStatus:code:OK[Error]4StatusStatus:code:INVALID_ARGUMENT |NOT_FOUND | PERMISSION_DENIEDLDS to CDS Registration5RegisterForNotifications(NotificationsRequest)NotificationsRequest:uris: "up://Device2/uSerivce/1"observer: {uri: "up://Device1/core.udiscovery/2" }}alt[Success]6Save NotificationRequest7StatusStatus:code:OK[Error]8StatusStatus:code:INVALID_ARGUMENT |NOT_FOUND | PERMISSION_DENIED \ No newline at end of file diff --git a/up-l3/udiscovery/v3/overview.drawio.svg b/up-l3/udiscovery/v3/overview.drawio.svg deleted file mode 100644 index f6d32c0..0000000 --- a/up-l3/udiscovery/v3/overview.drawio.svg +++ /dev/null @@ -1,463 +0,0 @@ - - - - - - - - - -
-
-
- uDomain -
- - - (ex. Vehicle) - - -
-
-
-
- - uDomain... - -
-
- - - - -
-
-
- Legend -
-
-
-
- - Legend - -
-
- - - - - -
-
-
- Database -
-
-
-
- - Database - -
-
- - - - - -
-
-
- RPC -
-
-
-
- - RPC - -
-
- - - - -
-
-
- - Cloud - -
-
-
-
- - Cloud - -
-
- - - - - -
-
-
- Notifications -
-
-
-
- - Notifications - -
-
- - - - -
-
-
- uDevice -
-
-
-
- - uDevice - -
-
- - - - -
-
-
- Local uDiscovery Service (uLDS) -
-
-
-
- - Local uDiscovery Se... - -
-
- - - - -
-
-
- Central uDiscovery Service (uCDS) -
-
-
-
- - Central uDiscovery S... - -
-
- - - - - - - - -
-
-
- uEs -
-
-
-
- - uEs - -
-
- - - - - - - - - - -
-
-
- uDevice -
-
-
-
- - uDevice - -
-
- - - - -
-
-
- Local uDiscovery Service (uLDS) -
-
-
-
- - Local uDiscovery S... - -
-
- - - - - - - - -
-
-
- uEs -
-
-
-
- - uEs - -
-
- - - - - - - - -
-
-
- uDevice -
-
-
-
- - uDevice - -
-
- - - - -
-
-
- uDomain Discovery Service (uDDS) -
-
-
-
- - uDomain Discovery Servi... - -
-
- - - - - - - - -
-
-
- uEs -
-
-
-
- - uEs - -
-
- - - - - - - - - - -
-
-
- RPC -
-
-
-
- - RPC - -
-
- - - - - - -
-
-
- RPC -
-
-
-
- - RPC - -
-
- - - - - - -
-
-
- Notifications -
-
-
-
- - Notifications - -
-
- - - - - - -
-
-
- Notifications -
-
-
-
- - Notifications - -
-
- - - - - - -
-
-
- RPC -
-
-
-
- - RPC - -
-
- - - - - - -
-
-
- Notifications -
-
-
-
- - Notifications - -
-
- - - - - - -
-
-
- uEs -
-
-
-
- - uEs - -
-
- - - - -
- - - - - Text is not SVG - cannot display - - - -
diff --git a/up-l3/udiscovery/v3/service.adoc b/up-l3/udiscovery/v3/service.adoc new file mode 100644 index 0000000..18c1f22 --- /dev/null +++ b/up-l3/udiscovery/v3/service.adoc @@ -0,0 +1,253 @@ += uDiscovery Service +:toc: preamble +:sectnums: +:source-highlighter: highlight.js +:client-proto-ref: xref:../../../up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto[udiscovery.proto] +:replicator-proto-ref: xref:../../../up-core-api/uprotocol/core/udiscovery/v3/udiscovery.proto[udiscovery_replicator.proto] + + +The key words "*MUST*", "*MUST NOT*", "*REQUIRED*", "*SHALL*", "*SHALL NOT*", "*SHOULD*", "*SHOULD NOT*", "*RECOMMENDED*", "*MAY*", and "*OPTIONAL*" in this document are to be interpreted as described in https://www.rfc-editor.org/info/bcp14[IETF BCP14 (RFC2119 & RFC8174)] + +---- +SPDX-FileCopyrightText: 2024 Contributors to the Eclipse Foundation + +See the NOTICE file(s) distributed with this work for additional +information regarding copyright ownership. + +This program and the accompanying materials are made available under +the terms of the Apache License Version 2.0 which is available at +https://www.apache.org/licenses/LICENSE-2.0 + +SPDX-FileType: DOCUMENTATION +SPDX-License-Identifier: Apache-2.0 +---- + +== Overview + +UDiscovery provides the means for uEs to discover services (and their metadata), for local and remote services. Implementation of uDiscovery takes inspiration from Domain Name System (DNS) principles in that we store and cache queries and replicate local information to more centralized databases. The local uDiscovery service acts as the first point of contact for discovery and then the discovery service looks up at the domain level service for information about services across a domain (i.e. vehicle). The central instance of uDiscovery service is the last point of contact for global searches of services. + +UDiscovery Service implements two sets of APIs: + +- *Client APIs ({client-proto-ref}):* Used by uEs to find services and their topic metadata, and for recursive lookups at the domain and central levels. + +- *Replication API ({replicator-proto-ref}):* Used Internally by uDiscovery services to add, update, or delete service metadata from local, domain, and/or central service instances. + +<> below provides an overview of the design and use of the Client and Replication APIs to implement the uDiscovery business logic. + +.uProtocol Discovery Design +[#udiscovery-design] +image::design.drawio.svg[Overview] + +=== Terms + +- *Fully Qualified Service URI (FQURI):* A URI that contains all the information needed to uniquely identify a service. A fully qualified service URI contains the following information: + - *ue_id:* The unique identifier of the service (both the instance and service ID portions). + - *authority_name:* The name of the authority that hosts the service. + - *ue_version_major:* The version of the service. + - *resource_id:* The resource ID (value of 0 is used to indicate the default ID for the service). + + +== Client APIs + +In the following section we will elaborate on the service-side requirements for the uDiscover service when it serves the client facing APIs defined in the {client-proto-ref}. + +=== FindServices() + +A client uE invokes `FindServices()` to get meta data (authority, version, instance ID) of (deployed) service instances of a given type.``` + +[.specitem,oft-sid="dsn~discovery-findservices-error-invalid~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.INVALID_ARGUMENT` if the URI passed does not contain a valid ue_id or a FQURI. +-- + +[.specitem,oft-sid="dsn~discovery-findservices-error-notfound~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.NOT_FOUND` if no service matching the URI was found. +-- + +[.specitem,oft-sid="dsn~discovery-findservices-error-permission~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.PERMISSION_DENIED` if the caller is not permitted to query for that service. +-- + +[.specitem,oft-sid="dsn~discovery-findservices-error-internal~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.INTERNAL` if an internal error occurs (database is corrupted). +-- + + + +=== FindServiceTopics() + +`FindServiceTopics()` is used to fetch metadata about one or more topics based on the passed `UUri`. Clients call this API to get additional information about the topic(s) such as the message format, id, permission level, etc. + +[.specitem,oft-sid="dsn~discovery-findservicetopics-error-invalid~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.INVALID_ARGUMENT` if the URI passed does not contain a valid ue_id or a FQURI. +-- + +[.specitem,oft-sid="dsn~discovery-findservicetopics-error-notfound~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.NOT_FOUND` if no topic matching the URI was found. +-- + +[.specitem,oft-sid="dsn~discovery-findservicetopics-error-permission~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.PERMISSION_DENIED` if the caller is not permitted to query for that topic(s). +-- + +[.specitem,oft-sid="dsn~discovery-findservicetopics-error-internal~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.INTERNAL` if an internal error occurs (database is corrupted). +-- + +=== Recursive Lookups + +Recursive lookups happen when the client sets the following information in the request message of the FindService() or FindServiceTopics() API. wishes to To recursively lookup up to the domain (or central) levels, the client calling the API : +[.specitem,oft-sid="dsn~discovery-recursive-authority-wildcard~1",oft-needs="impl,test"] +-- +* `authority_name` *MUST* contain the wildcard `*`. +-- + +If `search_central` inside of the `FindServicesRequest` or `GetServiceTopicsRequest` is `true``: +[.specitem,oft-sid="dsn~discovery-recursive-central~1",oft-needs="impl,test"] +-- +* *MUST* search recursively up to and including the central instance. +-- + +UDiscovery services perform a recursive search when the local or domain instance calls `FindService()` or `FindServiceTopics()` API and then propagates the response back to the client. + +[.specitem,oft-sid="dsn~discovery-recursive-async~1",oft-needs="impl,test"] +-- +* The original local search *MUST ONLY* return the response message when the recursive search has completed. +-- + +[.specitem,oft-sid="dsn~discovery-recursive-internal~1",oft-needs="impl,test"] +-- +* The uDiscovery service *MUST* cache the results of the recursive search for the duration `ttl` that is returned in the response message. +-- + + +.Recursive Search to Central +[#recursive-search-central] +[mermaid] +ifdef::env-github[[source,mermaid]] +---- +sequenceDiagram + +Client ->> Local-UDiscovery: FindService() +Local-UDiscovery ->> Domain-UDiscovery: FindService() +Domain-UDiscovery ->> Central-UDiscovery: FindService() +Central-UDiscovery -->> Domain-UDiscovery: FindServicesResponse +Domain-UDiscovery -->> Local-UDiscovery: FindServicesResponse +Local-UDiscovery -->> Client: FindServicesResponse +---- + + +== Replication API + + +=== SetServiceTopics() +The `SetServiceTopics()` API is used by the uDiscovery business logic to add, update, or remove information recursively between the local, domain, and central instances. The API is passed `SetServiceTopicsRequest` containing a repeated list of `UServiceTopicInfo` and `ttl` for when the info will expire. The function returns `SetServiceTopicsResponse` message if the method was successfully processed or it returns `UStatus` containing the error values specified below. + +[.specitem,oft-sid="dsn~discovery-replication-client~1",oft-needs="impl"] +-- +* link:../languages.adoc[uProtocol Language Libraries] *MUST NOT* implement the client-side of {replicator-proto-ref} API as these APIs are only used internally by uDiscovery business logic. +-- + +To replicate new or updated `UServiceTopic` metadata: +[.specitem,oft-sid="dsn~discovery-setservicetopic-update~1",oft-needs="impl,test"] +-- +* `ttl` value in `SetServiceTopicsRequest` *MUST* be set to the duration the metadata is valid for or absent from the message to indicate the metadata is valid forever. +-- + +To replicate removal of `UServiceTopic` metadata: +[.specitem,oft-sid="dsn~discovery-setservicetopic-remove~1",oft-needs="impl,test"] +-- +* `ttl` value in `SetServiceTopicsRequest` *MUST* be set to 0. +-- + +`SetServiceTopics()` Failure Reasons: + +[.specitem,oft-sid="dsn~discovery-setservicetopic-error-invalid~1",oft-needs="impl,test"] +-- +*MUST* return `UCode.INVALID_ARGUMENT` if the URI passed does not contain a valid ue_id or a FQURI. +-- + +[.specitem,oft-sid="dsn~discovery-setservicetopic-error-permission~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.PERMISSION_DENIED` if the caller is not uDiscovery service in the correct recursive order (i.e. local -> domain -> central). +* *MAY* grant access to deployment specific uEs such as a the software manager that installs or removes uEs. +-- + +[.specitem,oft-sid="dsn~discovery-setservicetopic-error-notfound~1",oft-needs="impl,test"] +-- +* *MUST* return `UCode.NOT_FOUND` if no topic matching the URI was found when the `UServiceTopic` is being removed (i.e. `ttl=0`). +-- + + + +.Replication API Design +[#udiscovery-replication-design] +[mermaid] +ifdef::env-github[[source,mermaid]] +---- +sequenceDiagram + +OTAClient ->> Local-UDiscovery: SetServiceTopics() +Local-UDiscovery -->> OTAClient: SetServiceTopicsResponse + +Local-UDiscovery ->> Domain-UDiscovery: SetServiceTopics() +Domain-UDiscovery -->> Local-UDiscovery: SetServiceTopicsResponse + +Domain-UDiscovery ->> Central-UDiscovery: SetServiceTopics() +Central-UDiscovery -->> Domain-UDiscovery: SetServiceTopicsResponse +---- + + +== Implementation Consideration + +It is possible the information in domain or central instances might become out of sync with what is stored in the other instances. In order to rectify this situation: + +[.specitem,oft-sid="dsn~discovery-data-reconciliation~1",oft-needs="impl,test"] +-- +* Domain and central instances *MUST* ensure that the information within its database is accurate and up to date and reconcile any differences periodically using the client and replication APIs described in this specification. +-- + +[.specitem,oft-sid="dsn~discovery-data-reconciliation-frequency~1",oft-needs="impl,test"] +-- +* *MUST* provide an implementation of data reconciliation using the above APIs where the frequency of reconciliation is customizable so the deployment can adjust the frequency based on the deployment needs. +-- + +[.specitem,oft-sid="dsn~discovery-data-reconciliation-data~1",oft-needs="impl,test"] +-- +* When reconciling data, the data fetched *MUST* be used in lieu of current cached data. +-- + +[.specitem,oft-sid="dsn~discovery-data-reconciliation-not-found~1",oft-needs="impl,test"] +-- +* If `GetServiceTopics()` returns `UCode.NOT_FOUND` for data we had in our local instance, we *MUST* flush the local cache and then replicate the deletion. we fetch information to reconcile the data If the reconciliation fails, the service *MUST* log the error and continue to use the current cached data. +-- + +<> below provides an example of the domain instance reconciling with local instance and then propagating the change to the central instance. In the example the reconciliation (determining if the data is out of sync or not) happens in the `ReconcileData()` function. + +.Reconciliation Example +[#udiscovery-reconciliation] +[mermaid] +ifdef::env-github[[source,mermaid]] +---- +sequenceDiagram + +participant Local-UDiscovery +participant Domain-UDiscovery +participant Central-UDiscovery + +Domain-UDiscovery ->> Local-UDiscovery: GetServiceTopics() +Local-UDiscovery -->> Domain-UDiscovery: GetServiceTopicsResponse +Domain-UDiscovery ->> Domain-UDiscovery: ReconcileData() + +Domain-UDiscovery ->> Central-UDiscovery: SetServiceTopics() +Central-UDiscovery -->> Domain-UDiscovery: SetServiceTopicsResponse +---- + + diff --git a/up-l3/udiscovery/v3/update_nodes.puml b/up-l3/udiscovery/v3/update_nodes.puml deleted file mode 100644 index e20ce34..0000000 --- a/up-l3/udiscovery/v3/update_nodes.puml +++ /dev/null @@ -1,72 +0,0 @@ -@startuml -'https://plantuml.com/sequence-diagram - -' SPDX-FileCopyrightText: 2023 Contributors to the Eclipse Foundation -' -' See the NOTICE file(s) distributed with this work for additional -' information regarding copyright ownership. -' -' This program and the accompanying materials are made available under -' the terms of the Apache License Version 2.0 which is available at -' https://www.apache.org/licenses/LICENSE-2.0 -' -' SPDX-FileType: SOURCE -' SPDX-License-Identifier: Apache-2.0 - - -autonumber - -box Device2 #white - actor CDS #orange -endbox -box Device1 #white - entity LDS as DS #orange - entity uService as US #blue - actor uApp #red -endbox - -US -> DS: UpdateNode(\nUpdateNodeRequest) -note right - **UpdateNodeRequest:** - ""node"" { //Changed Info// } - ""ttl"": -1 -end note -DS -> DS: Update Node -note right - **Node Metadata:** - save //""ttl""// - //""last_updated""//=//current time// - //""inactive""//=""false"" -end note -DS --> US: Status -note right - **Status:** - ""code"": ""OK"" -end note -||| -loop Notify Observers - DS -[#0000FF]-\ uApp: Notification - note right - **Notification:** - ""uri"" : //uri of changed node// - ""operation"": ""UPDATE"" - ""ttl"": -1 - end note - DS -[#0000FF]-\ CDS: Notification - - opt Fetch Updated Node - CDS -> DS: FindNodes(FindNodesRequest) - note right - **FindNodesRequest:** - ""uri"": //uri of the changed node// - ""depth"": -1 - end note - DS --> CDS: FindNodesResponse - note right - **FindNodesResponse:** - ""nodes"": { //updated node// } - ""status"": {""code"": ""OK""} - end note - end opt -end loop -@enduml \ No newline at end of file diff --git a/up-l3/udiscovery/v3/update_nodes.svg b/up-l3/udiscovery/v3/update_nodes.svg deleted file mode 100644 index d501fa7..0000000 --- a/up-l3/udiscovery/v3/update_nodes.svg +++ /dev/null @@ -1 +0,0 @@ -Device2Device1CDSCDSLDSLDSuServiceuServiceuAppuApp1UpdateNode(UpdateNodeRequest)UpdateNodeRequest:node{Changed Info}ttl: -12Update NodeNode Metadata:savettllast_updated=current timeinactive=false3StatusStatus:code:OKloop[Notify Observers]4NotificationNotification:uri:uri of changed nodeoperation:UPDATEttl: -15Notificationopt[Fetch Updated Node]6FindNodes(FindNodesRequest)FindNodesRequest:uri:uri of the changed nodedepth: -17FindNodesResponseFindNodesResponse:nodes: {updated node}status: {code:OK} \ No newline at end of file