DSX Agent Deployment Guide#
Deploy the DSX Agent to connect Dynamic Power Software (DPS) NvGrid power management to DSX Exchange. This guide is for Kubernetes administrators configuring the bidirectional connection.
The configuration and topics in this guide match DPS
0.10.0-rc1. Select the corresponding DSX Agent chart and container image
from your release artifacts. Do not assume the agent chart version, image
tag, and DPS version are identical.
Connection Overview#
The DSX Agent runs as a separate Kubernetes Deployment. It connects to DPS over gRPC, DSX Exchange over Message Queuing Telemetry Transport (MQTT), and PostgreSQL for persistent message queues.
The agent implements the following message paths:
Load targets: Subscribe to
grid/v1/isv/+/loadtarget/set, validate incoming CloudEvents and JSON Web Signatures (JWS), queue the messages, and submit load schedules to the DPS NvGrid API.Power state: Read NvGrid metadata, schedules, and status, then publish signed
grid.powerstate.status.v1CloudEvents ongrid/v1/dsx-flex-agent/<agent-id>/powerstate/status. The default periodic interval is 30 seconds.Power events: Register the agent webhook with DPS. DPS calls the agent when ramp-up or ramp-down starts or ends, and the agent publishes the resulting power state to DSX Exchange.
The agent provides these load-target and power-state operations. It does not implement every DSX OS integration. For NvGrid concepts and feed configuration, refer to NvGrid and Managing NvGrid.
Prepare the Deployment#
Before you install the agent, prepare the following resources:
A configured DPS server, reachable from the agent over verified Transport Layer Security (TLS). Configure feed metadata and the power-management topology before testing load targets. Refer to Deployment and Configuration Guide.
A DPS automation identity authorized to call the NvGrid API. The example uses a DPS password login. Use the authentication mode configured for your server.
A PostgreSQL database and role for agent queues. The agent applies its database migrations at startup; the role must be able to create and use the required tables, type, function, and trigger.
DSX Exchange broker addresses, credentials, and topic permissions from your Exchange administrator. Allow the agent to subscribe to
grid/v1/isv/+/loadtarget/setand publish to its power-state topic. This release also subscribes to the legacygrid.setloadtarget.v1topic for migration compatibility; include that subscription in the broker permissions.A JWS signing private key for outbound messages and trusted public keys for inbound messages. Agree on the algorithm and key IDs with the Exchange participants. Register the agent public key with the participants that verify its outbound messages.
Network access to DPS, PostgreSQL, and the MQTT broker, plus your identity provider if you use OAuth 2.0. Allow DPS to reach the agent webhook on TCP port
9100.Helm,
kubectl, release-matcheddpsctl, and permission to create the chart resources and Secrets in the target namespace.
This procedure uses namespace dps, DPS release dps,
and agent release dps-dsx-agent. The broker certificate must chain to a
certificate authority (CA) trusted by the agent container. PostgreSQL and DPS
use the CA files you supply. Replace example hostnames, identifiers, and
file paths with values for your environment.
Select the Chart and Image#
Obtain the versioned DSX Agent chart package and corresponding image tag from your release distribution. Inspect the package before installation:
export DSX_AGENT_CHART="/path/to/dps-dsx-agent-<chart-version>.tgz"
export DSX_AGENT_IMAGE_TAG="<release-image-tag>"
helm show chart "${DSX_AGENT_CHART}"
helm show values "${DSX_AGENT_CHART}" > dsx-agent-reference.yaml
The agent chart is installed separately from the DPS
chart. Retain the reference values for your selected package. If you use
a private image mirror, configure image.repository and
imagePullSecrets for that mirror.
Create the Secrets#
Create the dps namespace if it does not exist:
kubectl create namespace dps --dry-run=client -o yaml | kubectl apply -f -
Store credentials in local files protected by your organization’s secret handling process. Create Kubernetes Secrets from those files. The following commands use an Exchange access token and a DPS login password:
Create Credential and Key Secrets
kubectl create secret generic dsx-agent-db --namespace dps \
--from-file=password=/secure/path/postgres-password
kubectl create secret generic dsx-agent-mqtt --namespace dps \
--from-file=token=/secure/path/exchange-token
kubectl create secret generic dsx-agent-dps-auth --namespace dps \
--from-file=password=/secure/path/dps-password
kubectl create secret generic dsx-agent-dps-ca --namespace dps \
--from-file=ca.crt=/secure/path/dps-ca.crt
kubectl create secret generic dsx-agent-db-ca --namespace dps \
--from-file=ca.crt=/secure/path/postgres-ca.crt
kubectl create secret generic dsx-agent-jws --namespace dps \
--from-file=signing-key.pem=/secure/path/agent-signing-key.pem \
--from-file=exchange-public-key.pem=/secure/path/exchange-public-key.pem
The signing key stays with the agent. Share its public key, not the private
key. The verification key in this example belongs to the participant that
signs incoming load-target messages. If the message includes a JWS kid
header, it must match the configured verification key ID.
Keep credentials out of Helm values and command-line literals. If your platform provisions Secrets, use the same Secret names and keys or adapt the values to your platform’s resources.
Configure the Agent#
Save the following overrides as dsx-agent-values.yaml. This example uses
RSA signing with RS256, verified TLS, PostgreSQL server verification,
and mounted credentials:
DSX Agent Values
fullnameOverride: dps-dsx-agent
agentConfig:
agentName: dps
logLevel: info
database:
hostname: postgres.example.com
port: 5432
name: dps
user: dps
existingSecret: dsx-agent-db
existingSecretKey: password
ssl_mode: verify-full
ssl_root_cert: /secrets/db-ca/ca.crt
mqtt:
servers: ["tls://exchange.example.com:8883"]
clientId: dps-dsx-agent
username: oauthtoken
tokenFile: /secrets/mqtt/token
secretRef:
name: dsx-agent-mqtt
key: token
tls:
insecure_skip_verify: false
jws:
signatureAlgorithm: RS256
signatureKeyFile: /secrets/jws/signing-key.pem
signatureKeyId: dps-agent-signing-key
verificationPublicKeyFiles:
exchange-signing-key: /secrets/jws/exchange-public-key.pem
dps:
serverAddr: dps-server-grpc:8080
tls:
transportSecurity: tls
secretRef:
name: dsx-agent-dps-ca
auth:
dps:
username: dps-agent
secretRef:
name: dsx-agent-dps-auth
key: password
dpsWebhookBindAddress: ":9100"
dpsWebhookAnnounceAddress: http://dps-dsx-agent-webhook:9100
handlers:
PowerState:
enabled: true
agentId: dps
publishPeriod: 30s
networkPolicy:
dps:
releaseName: dps
namespace: dps
secrets:
- name: dsx-agent-db-ca
secretKey: ca.crt
mountPath: /secrets/db-ca/ca.crt
- name: dsx-agent-jws
secretKey: signing-key.pem
mountPath: /secrets/jws/signing-key.pem
- name: dsx-agent-jws
secretKey: exchange-public-key.pem
mountPath: /secrets/jws/exchange-public-key.pem
Set handlers.PowerState.agentId to the identifier assigned for your
deployment; it determines the outbound MQTT topic. Use a unique MQTT
clientId for each simultaneously connected agent instance. The example
uses the default single replica.
The dps.serverAddr value uses the standard DPS Helm
gRPC Service. Adapt its host and port if your release overrides them.
The server certificate must cover the hostname you configure.
The chart supports the following authentication alternatives:
MQTT: Replace
tokenFilewithoauth2settings if Exchange provides client credentials. ConfiguretokenUrl,scopes, andcredentialsFile, and pointmqtt.secretRefto the credentials Secret. The credential file defaults to JSON fieldsclient_idandclient_secret. Select only one MQTT credential source.DPS: Use a bearer-token Secret by omitting
auth.dpsand configuringauth.secretRef. For OAuth 2.0, replaceauth.dpswithauth.oauth2settings and use a credentials Secret. Select only one DPS credential source.Mutual TLS: Set
dps.tls.transportSecurity: mtlsand reference a Secret containingca.crt,tls.crt, andtls.key.
For incoming-command-only deployments, set
handlers.PowerState.enabled: false. Verification keys and the signature
algorithm are still required; the agent does not initialize the outbound
signer or register the power-state webhook in this mode.
Configure Webhook Delivery#
The standard webhook URL is http://dps-dsx-agent-webhook:9100. The
DPS chart in 0.10.0-rc1 includes this URL in
dps.nvgrid.webhook.whitelist. Confirm that your server’s deployed values
permit it before starting the agent.
If you use another service name or namespace, update the announce URL
and the DPS whitelist to match. For a separate agent
namespace, use a service DNS name that resolves from the
DPS namespace. Set networkPolicy.dps.releaseName and
networkPolicy.dps.namespace to the server’s release and namespace.
Retain any other whitelist entries your deployment requires.
The webhook listener uses HTTP. Restrict its ingress to DPS. The chart enables an ingress NetworkPolicy for this purpose; your cluster network plugin must enforce NetworkPolicy. If your security policy requires encryption on this path, provide it through your platform’s service mesh or gateway and configure the announced URL and allowed peers accordingly.
Install and Check Startup#
Install the selected chart with your overrides and explicit image tag:
helm upgrade --install dps-dsx-agent "${DSX_AGENT_CHART}" \
--namespace dps \
--values dsx-agent-values.yaml \
--set-string image.tag="${DSX_AGENT_IMAGE_TAG}" \
--wait --timeout 5m
Check the Deployment and its logs:
kubectl rollout status deployment/dps-dsx-agent --namespace dps
kubectl logs deployment/dps-dsx-agent --namespace dps --tail=200
Confirm that the logs report connected to mqtt and, with power-state
publication enabled, starting DPS webhook server. Resolve any database,
JWS, subscription, or DPS authentication errors.
Webhook registration happens asynchronously; a registration failure can
leave the agent running without webhook delivery.
The health endpoints return HTTP 200 while their server is running.
A ready pod establishes process health but does not establish successful
message delivery, webhook registration, or power control.
Verify the Signed Message Flow#
Use your configured dpsctl connection to confirm that NvGrid has feed
metadata and readable status:
dpsctl nvgrid get-metadata
dpsctl nvgrid get-status
dpsctl nvgrid get-current
For client connection and authentication setup, refer to Installing dpsctl. For schedule queries, refer to dpsctl nvgrid.
Use the DPS 0.10.0-rc1
DSX Flex AsyncAPI schema archive
when preparing the test command. Extract dsx-flex.yaml from the archive.
The schema defines the envelope at
components.schemas.LoadTargetSetEvent and the payload at
components.schemas.SetLoadTargetData.
Set type to grid.loadtarget.set.v1
and specversion to "1.0.2". Sign the JSON payload and place its compact
JWS serialization in the envelope’s data string. The JWS protects only
that payload; the envelope fields, including the correlation ID, are unsigned.
The shipped DSX schema requires the exact specversion value "1.0.2".
If your CloudEvents SDK emits "1.0", configure it to emit "1.0.2" for
this integration; "1.0" does not pass the release schema validation.
With handlers.PowerState.enabled: true, complete the following verification
with your Exchange administrator in an approved test environment:
Receive a periodic message on
grid/v1/dsx-flex-agent/<agent-id>/powerstate/status. Verify its JWS signature with the agent’s public key and confirm the feed metadata, schedules, and status against the NvGrid API results.Publish a schema-valid, signed load-target CloudEvent through Exchange on
grid/v1/isv/<isv-id>/loadtarget/set. Use a unique event ID, a UUID correlation ID, known feed tags, and an approved target and time interval. Follow the Exchange message contract, including its tracing fields.Read the schedule for the test interval with
dpsctl nvgrid get-scheduleand read status withdpsctl nvgrid get-status. Confirm that DPS accepted the target. Retain the correlation ID when comparing the schedule and subsequent power-state messages.Confirm ramp events reach the agent webhook and produce signed power-state messages on Exchange. Check both the agent and DPS logs for delivery or processing errors.
Confirm the target’s effects through DPS status and your test environment’s device telemetry. A received message or accepted schedule alone does not prove hardware actuation.
For incoming-command-only deployments with handlers.PowerState.enabled: false,
complete steps 2, 3, and 5. Check the accepted schedule’s correlation ID and
the agent’s processing logs. Skip the outbound message and webhook checks;
this mode does not publish power-state messages or register that webhook.
Do not send a production load-target command solely to test connectivity. Use the approved target, rollback, and telemetry procedure for your site.
Troubleshooting#
Use the following checks to isolate deployment and message-flow failures:
Symptom |
Check |
|---|---|
Pod does not start |
Check chart and image compatibility, image access, Secret names and keys, mounted-file permissions, and configuration parsing errors. |
Database migration fails |
Check database hostname, TLS CA and hostname verification, credentials, and migration permissions. |
MQTT connection or subscription fails |
Check broker DNS and egress, certificate trust, token validity or OAuth 2.0 settings, topic permissions, and duplicate client IDs. |
JWS setup or message validation fails |
Check the algorithm, PEM key formats, signature key ID, trusted sender key IDs, and the release-matched message schema. |
Webhook registration fails |
Check NvGrid authorization and the server whitelist. A non-network registration error stops webhook startup. |
Periodic messages arrive but ramp events do not |
Check webhook service DNS, port |
Load target does not appear in NvGrid |
Check signature or schema rejection, feed tags, time intervals, and agent queue-processing errors. |
Pod is ready but messages stop |
Check dependency connectivity and message-processing logs; the readiness endpoint does not inspect these dependencies. |
Update Credentials and Configuration#
Update Secrets through your platform’s credential-management process. MQTT and DPS credential Secret references use directory mounts so Kubernetes can project changed files. Token caches and connection lifetimes can delay when a new credential takes effect.
The additional secrets entries use file mounts with subPath.
Restart the agent after changing those files, including JWS keys or the
database CA. Also restart after changing startup-loaded verification
keys or database credentials. Coordinate JWS key changes with Exchange
participants before the restart.
After applying your changes, restart the Deployment and repeat the message-flow verification:
kubectl rollout restart deployment/dps-dsx-agent --namespace dps
kubectl rollout status deployment/dps-dsx-agent --namespace dps
If you supply the full configuration through config.existingSecret,
keep chart-managed ports and file mounts consistent with that file.
Changes to an existing configuration Secret do not add a chart-generated
configuration checksum; restart the Deployment to load the updated file.