Service providers
A module can become the provider of some kind of service for other modules running in the same cluster. To ease the service discovery, information about how to reach the service and any other application parameter must be written in the Redis database as explained in the next sections.
srv
keys
A module can own one or more srv
Redis keys. Each one identifies a
service endpoint on a given transport protocol. For instance
module/mail1/srv/tcp/imap
module/mail1/dovecot/srv/http/openmetrics
module/mail1/rspamd/srv/http/openmetrics
The generic key pattern is
module/{MODULE_ID}[/{OPTIONAL_QUALIFIER}]/srv/{TRANSPORT}/{SERVICE_NAME}
Each key must be of type HASH. The hash content depends on the service
requirements, typically the host
and IP port
entries are set.
Raising events
The service provider should raise one or more distinct events whenever
the information in its srv
keys is changed. The event name and payload
must be documented by the service provider. A common convention for the
event name is:
service-{SERVICE_NAME}-changed
The event payload is a JSON-encoded string representing an object. The object can contain the needed attributes to identify the source of the event. They are necessary to event listeners to identify the event source and retrieve further information as needed, an example payload can be:
{
"key": "module/mail1/srv/tcp/imap",
"module_uuid": "8d257122-0a7f-49c7-a620-08961a68cfa0",
"module_id": "mail1"
}
Service discovery
Service consumers can look up a given service name with the
agent.list_service_providers()
function, or the corresponding
list-service-providers
base module action.
For instance, to find IMAP servers on node 1:
api-cli run module/mail1/list-service-providers --data '{"service":"imap", "transport":"tcp", "filter":{"node":"1"}}' | jq
Yields
[
{
"port": "143",
"host": "10.5.4.1",
"node": "1",
"user_domain": "dp.nethserver.net",
"module_uuid": "8d257122-0a7f-49c7-a620-08961a68cfa0",
"module_id": "mail1",
"transport": "tcp",
"ui_name": null
}
]
The input JSON object attributes are:
service
(mandatory): look up this service nametransport
(optional): look up records with the given transport, or any transport if the attribute is missingfilter
: an object where each entry represents an additional filter condition. Only services matching all the given conditions are returned. The actual attributes depend on the record structure: service providers must document which attributes they define. Thelist-service-providers
base implementation in any case, provides at least the following attributes for convenience:module_id
copy ofHGET module/{id}/environment MODULE_ID
module_uuid
copy ofHGET module/{id}/environment MODULE_UUID
ui_name
, copy ofGET module/{id}/ui_name
)transport
, copy oftransport
of the Redis key name
The following Python code snippet invokes agent.list_service_providers()
to discover an IMAP server. It connects to the local Redis replica, so it
works even if the leader is temporarly unreachable: this makes the service
startup more robust.
import agent
rdb = agent.redis_connect(use_replica=True) # connect the local Redis replica
print(agent.list_service_providers(rdb, 'imap', 'tcp'))