Agent configuration
Configure the libre-agent service through its Helm chart.
The chart’s rhizeAgentConfig
value holds the application configuration, and the other chart values control
the deployment, including environment variables that override individual
settings.
Application configuration
Everything in this section goes into the chart’s rhizeAgentConfig value, which
becomes libre-agent’s entire configuration file.
The chart ships a populated
rhizeAgentConfig with defaults.
If you delete a key, most take no value.
Some revert to a built-in value meant for a developer’s own machine:
-libreDataStoreGraphQl.serverUrl becomeshttp://localhost:8080/graphql
oidc.serverUrlbecomeshttp://localhost:8090,nats.serverUrlbecomesnats://localhost:4222,datasource.idbecomesserver.
To override individual keys, use the environment variable supplied through the chart’s envVars or additionalSecrets.
Many of the following sections are required for only some deployments. There are three ways to set libre-agent up:
- Run a subscription: watches a source system and publishes every value change it
sees.
This source is configured by the
datasource.idvalue on the BAAS data source record. - Answer commands: answers a caller’s request to read a tag, write a value, or call a method on a device.
- Bridge: carries messages from one broker to another.
A subscription and commands can run in the same deployment, and most deployments run both. However, a bridge cannot run with a subscription or command.
General settings
| Value | Description |
|---|---|
datasource.id[Required] |
|
libreDataStoreGraphQl.serverUrl[Required] |
|
libreDataStoreGraphQl.caFile |
|
logging.level |
|
logging.type |
|
openTelemetry.serverUrl |
|
oidc
| Value | Description |
|---|---|
oidc.serverUrl[Required] |
|
oidc.realm[Required when oidc.enableGenericOidc is false] |
|
oidc.clientId[Required] |
|
oidc.clientSecret[Required] |
|
oidc.enableGenericOidc |
|
oidc.customAudienceKey |
|
oidc.credentialsScope |
|
Commands
Alongside the subscription, libre-agent answers individual commands:
- Read a tag now.
- Write a value to a tag or topic on the data source.
- Call a method on a device.
When restate.enabled is on, which is the chart’s default, the command
API is served through Restate, and these settings describe how it is reached.
An answer returns to the caller the same way it came rather than through an
egress handler.
Which commands can be answered depends on the type of data source.
- An OPC UA data source answers all three. The libre-agent will not start without
restate.enabled, stopping withAt least one of NATS or Kafka or Restate must be enabled for OPCUA data source. - An MQTT data source answers writes only, and requires
restate.enabledto betrue: iffalse, libre-agent runs but accepts no commands at all. - A Kafka, Azure Service Bus, or Azure Event Hubs data source
answers no commands. These need
restate.enabledto befalse. Iftrue, libre-agent still tries to register with Restate at startup and exits if it cannot.
| Value | Description |
|---|---|
restate.enabled[Required when the data source is Kafka, Azure Service Bus, or Azure Event Hubs] |
|
restate.adminUrl[Required when restate.enabled is true] |
|
restate.serviceName |
|
Data sources
How libre-agent connects to the system it reads from. Fill in the one section
that matches the data source record in BAAS — kafka, opcUa, mqtt, azure
for Azure Service Bus, or eventHubs — and leave the others out. health
applies only to an OPC UA server.
kafka
How libre-agent connects to the Kafka broker supplying the data.
| Value | Description |
|---|---|
kafka.bootstrapServerUrl[Required when the data source is Kafka] |
|
kafka.groupId[Required when the data source is Kafka] |
|
kafka.workerThreads |
|
kafka.sessionTimeout |
|
kafka.maxSendRetries |
|
opcUa
How libre-agent connects to the OPC UA server supplying the data. Relevant only when the data source is an OPC UA server.
| Value | Description |
|---|---|
opcUa.serverUrl[Required when the data source is OPC UA] |
|
opcUa.discoveryUrl[Required when the data source is OPC UA] |
|
opcUa.authentication |
|
opcUa.username[Required when opcUa.authentication is UserName] |
|
opcUa.password[Required when opcUa.authentication is UserName] |
|
opcUa.mode |
|
opcUa.policy |
|
opcUa.applicationUri |
|
opcUa.certFile / opcUa.keyFile[Required when opcUa.mode is Sign or SignAndEncrypt, opcUa.authentication is Certificate, or opcUa.genCert is true] |
|
opcUa.genCert |
|
opcUa.subscription.publishingInterval |
|
opcUa.subscription.lifetimeCount |
|
opcUa.subscription.maxKeepAliveCount |
|
opcUa.subscription.maxNotificationsPerPublish |
|
opcUa.subscription.priority |
|
opcUa.monitoredItem.samplingInterval |
|
opcUa.monitoredItem.queueSize |
|
opcUa.monitoredItem.discardOldest |
|
The opcUa.policy value accepts the following security policies:
| Value | Description |
|---|---|
Auto | Takes the strongest policy the server advertises, leaving the choice to the server. |
None | No signing or encryption, and it forces opcUa.mode to None as well. |
Basic128Rsa15 | 128-bit AES with SHA-1 signatures and RSA PKCS#1 v1.5 key exchange. Deprecated in OPC UA 1.04 and refused by many servers; set it only for equipment that offers nothing else. |
Basic256 | 256-bit AES with SHA-1 signatures. Deprecated on the same grounds as Basic128Rsa15. |
Basic256Sha256 | 256-bit AES with SHA-256 signatures. The policy most servers have in common, and the usual choice. |
Aes128_Sha256_RsaOaep | 128-bit AES with SHA-256 signatures and RSA-OAEP key exchange, introduced in OPC UA 1.04. |
Aes256_Sha256_RsaPss | 256-bit AES with SHA-256 signatures and RSA-PSS key exchange. The strongest of the set and the newest, so the least widely supported. |
health
Watches the tags libre-agent has subscribed to and renews the subscription for any that stop reporting or begin returning errors. Only relevant when the data source is an OPC UA server.
| Value | Description |
|---|---|
health.pollInterval |
|
health.subscriptionTimeout |
|
health.subscriptionMaxCount |
|
Health is reported in two places:
The log carries a line per tag as it is renewed, at warn level, reading
Node status is not OK. Last seen 1m2s. Renewing subscription.with the tag in anodefield and the OPC UA status alongside, so a tag renewing over and over is a tag worth investigating at the server. Setlogging.leveltodebugto also see the intervals in force at startup, or totraceto see every health update as it lands.Counts come from a Prometheus endpoint each pod serves on port 6061 at
/metrics. Scrape it at the pod’s own address, since the Service carries onlyservice.port. Five values are published:opcua_handles_active, the number of monitored items currently subscribed;opcua_monitored_item_handledandopcua_messages_handled_total, counters that should keep climbing while the source is alive; andopcua_notify_channel_lengthwithmessage_handler_data_channel_length, queue depths inside libre-agent that sit near zero unless it is falling behind what it is being sent.
mqtt
How libre-agent connects to the MQTT broker supplying the data. Only relevant when the data source is MQTT.
| Value | Description |
|---|---|
mqtt.serverUrl[Required when the data source is MQTT] |
|
mqtt.version |
|
mqtt.clientId |
|
mqtt.username |
|
mqtt.password |
|
mqtt.qos |
|
mqtt.decomposeJson |
|
mqtt.timestampField |
|
mqtt.timestampFormat |
|
mqtt.requestTimeout |
|
The delivery guarantees mqtt.qos accepts:
| Value | Description |
|---|---|
0 | Sent once, with no acknowledgement and no retry. The cheapest and the fastest, and the level at which a message is simply gone if it does not arrive. |
1 | Redelivered until it is acknowledged, so a message is not lost, at the price of the same message sometimes arriving more than once. Nothing downstream filters repeats, so a second delivery becomes a second value change carrying the same reading. |
2 | Delivered exactly once, using a four-step exchange per message. The slowest of the three, so consider lowering the guarantee on a fast-moving feed. |
Two things bound what raising the level buys:
- A message is delivered at the
lower of the level it was published with and the level libre-agent subscribed
with, so
2cannot improve on a device that publishes at0. - And a level above
0only covers messages that arrive while libre-agent is connected, unless the broker is holding a session for it: on3.1.1the session outlives a dropped connection after the first one, so the broker queues what was missed and delivers it on reconnect, while the MQTT 5 path asks for no session expiry, which ends the session with the connection and leaves nothing to queue into.
azure
Azure Service Bus credentials, used when the data source is Service Bus.
| Value | Description |
|---|---|
azure.clientId[Required when the data source is Azure Service Bus] |
|
azure.clientSecret[Required when the data source is Azure Service Bus] |
|
azure.tenantId[Required when the data source is Azure Service Bus] |
|
azure.serviceBusHostName[Required when the data source is Azure Service Bus] |
|
eventHubs
Azure Event Hubs consumer. Hub entity names come from the data source topic labels in BAAS rather than from configuration.
| Value | Description |
|---|---|
eventHubs.namespaceConnectionString[Required when the data source is Event Hubs and eventHubs.fullyQualifiedNamespace is empty] |
|
eventHubs.fullyQualifiedNamespace |
|
eventHubs.consumerGroup |
|
eventHubs.checkpointStorageConnectionString[Required when the data source is Event Hubs and eventHubs.checkpointStorageAccountUrl is empty] |
|
eventHubs.checkpointStorageAccountUrl |
|
eventHubs.checkpointBlobContainerName[Required when the data source is Event Hubs] |
|
eventHubs.receivePartitionId |
|
eventHubs.receiveAllPartitions |
|
eventHubs.receiveMaxBatchSize |
|
eventHubs.receiveStartFromEarliest |
|
egress
Where the subscription sends what it reads. Each handler listed receives every value change, and with no handler listed nothing is published at all, so a deployment that subscribes to anything defines at least one.
egress.handlers is a map whose keys are names you choose, so each setting is
written egress.handlers.<name>.<field>. Define each handler in
rhizeAgentConfig. The environment variables in the table then set that
handler’s fields, provided each field is written in the handler’s block. To
take a field’s value from its variable alone, write it in the block as "".
| Value | Description |
|---|---|
egress.handlers.<name>.protocol[Required when the handler is defined] |
|
egress.handlers.<name>.serverUrl[Required when the handler’s protocol is not nats] |
|
egress.handlers.<name>.topic[Required when the handler’s protocol is kafka] |
|
egress.handlers.<name>.patterns |
|
A Kafka handler that splits temperatures onto their own topic, alongside an HTTP
handler, as the block appears inside rhizeAgentConfig:
egress:
handlers:
kafka-values:
protocol: kafka
serverUrl: kafka:9092
topic: value-changes
patterns:
- topic: temperatures
regex: '.*Temperature$'
- topic: 'values_$1'
regex: '^bulktimeseries/Acme/([^/]+)/.*'
historian:
protocol: http
serverUrl: http://ingest:8080/values/{id}nats
The NATS connection an egress handler with protocol nats opens. Nothing else
on this page uses it, and without such a handler none of these settings are
read.
| Value | Description |
|---|---|
nats.serverUrl |
|
nats.username |
|
nats.password |
|
bridge
Turns libre-agent into a broker-to-broker message bridge. This is a
replacement for normal operation.
When a bridge section is present, libre-agent forwards messages between the brokers defined here and
ignores every other section on this page, datasource included.
Each handler is one broker connection, and a message arriving on one is published to all others. Messages are never sent back to the handler they arrived on, and a message that has already been routed once is not routed again, so two handlers cannot loop.
bridge.handlers is a map whose keys are names you choose, and the name is what
identifies the connection in the logs. As with egress, define each handler in
rhizeAgentConfig, writing every field that its variable should set, using ""
for a field whose value comes only from the variable.
| Value | Description |
|---|---|
bridge.topics[Required when a bridge section is present] |
|
bridge.handlers.<name>.protocol[Required when the handler is defined] |
|
bridge.handlers.<name>.serverUrl[Required when the handler is defined] |
|
bridge.handlers.<name>.username |
|
bridge.handlers.<name>.password |
|
bridge.handlers.<name>.clientId |
|
A minimal two-broker bridge, as the block appears inside rhizeAgentConfig,
with the NATS password left empty for additionalSecrets to fill:
bridge:
topics:
- libre.>
handlers:
plant:
protocol: mqtt
serverUrl: mqtt://plant-broker:1883
clientId: libre-bridge
central:
protocol: nats
serverUrl: nats://nats:4222
username: bridge
password: ""Environment-only settings
These are read directly from the environment and carry no RHIZE_AGENT_ prefix.
| Value | Description |
|---|---|
all_proxy |
|
Helm chart values
Values shared by every chart.
| Value | Description |
|---|---|
rhizeAgentConfig[Required] |
|
envVars |
|
additionalSecrets |
|
caFile |
|
service.port |
|
extraVolumes / extraVolumeMounts |
|
A log level set directly, two credentials taken from Secrets, and an OPC UA certificate pair mounted from a third:
envVars:
RHIZE_AGENT_LOGGING_LEVEL: info
additionalSecrets:
- name: RHIZE_AGENT_OIDC_CLIENTSECRET
secretName: libre-client-secrets
secretKey: libreAgent
- name: RHIZE_AGENT_MQTT_PASSWORD
secretName: libre-passwords
secretKey: agentMqtt
extraVolumes:
- name: opcua-certs
secret:
secretName: agent-opcua-certs
extraVolumeMounts:
- name: opcua-certs
mountPath: /opcua-certs
readOnly: true