Config Manager Render Service

View as Markdown

Overview

The NVIDIA Config Manager Network Template Render Service is an event-driven microservice that automatically generates and versions network device configurations. The configured DCIM provider supplies device data and change events; the built-in nautobot-2x provider remains the default. Rendered configurations are stored in the Config Store.

Architecture

The service consists of three main components: the API, the event consumers, and the event dispatcher.

API endpoints

You can use the render service’s API endpoints to trigger the rendering of network device configurations.

  • POST /v1/render/{device_uuid}/render - Render the configuration for a single device
  • POST /v1/render/all - Queue renders for all devices that are enabled for rendering
  • POST /v1/render/batch - Queue renders for a list of devices

Event Consumers

Two specialized pull-based consumers process NATS JetStream events:

The DCIM event consumer responds to provider-neutral change events for objects such as devices, interfaces, cables, and IP addresses. The consumer validates the event envelope, dispatches it to model-specific handlers, and queues device renders. The built-in Nautobot provider translates its legacy changelog payload at the provider boundary during the compatibility window.

The device change consumer responds to queued render requests from event handlers. It executes renders with distributed locking and updates the Config Store.

External NATS administration

External NATS deployments using password or JWT authentication must provide a tls:// or wss:// endpoint. Secure WebSockets (wss://) establish TLS before the NATS handshake and do not require the native NATS handshake_first setting. Native tls:// endpoints must enable TLS-first negotiation on the server. Add handshake_first: true to the server’s existing tls block, retaining the deployment’s certificate and verification settings:

tls {
cert_file: "/path/to/server.crt"
key_file: "/path/to/server.key"
handshake_first: true
}

For native tls:// endpoints, the password- or JWT-authenticated client performs TLS before reading the initial server INFO message and does not fall back to INFO-first negotiation. NATS defaults to sending INFO before TLS, so a server without this setting can cause a TLS error or connection timeout even when its certificates and credentials are valid. The Helm chart does not configure an externally managed server; coordinate this setting with its administrator before connecting.

TLS-first avoids relying on an unauthenticated INFO message to request encryption before sending credentials. This requirement applies to external password and JWT authentication; the bundled nats:// deployment retains its existing negotiation behavior.

The bundled NATS deployment creates the streams automatically. The application creates missing durable consumers at runtime in both bundled and externally managed deployments. When NATS is owned outside the Config Manager deployment, coordinate the streams, account imports, and user permissions with the NATS administrator. An administrator can own consumer provisioning instead by omitting create permission and provisioning the fixed durables described below.

The application uses three fixed durable names in every deployment:

Stream valueDefault streamDurable consumer
externalServices.nats.streams.configManagernv-config-managernv-config-manager-device
externalServices.nats.streams.configManager.archiveConsumernv-config-managernv-config-manager-archive
externalServices.nats.streams.nautobotnautobotnv-config-manager-nautobot

Each stream also has an apiPrefix value. Its default, $JS.API, addresses JetStream in the connected account directly. Override it when the stream belongs to another NATS account and its JetStream API service export is imported under a different local subject prefix. For example:

externalServices:
nats:
streams:
configManager:
apiPrefix: $JS.API
nautobot:
apiPrefix: $JS.IMPORTED.API

The prefix is configured per stream because the Config Manager stream can remain local while the Nautobot event stream is imported from another account. It is a local routing prefix, not a stream or consumer name. The NATS user permissions and account service imports must refer to the selected prefix.

For each render pull-consumer <prefix>, <stream>, and <consumer> tuple, the application account needs these consumer subjects:

SubjectRequiredPurpose
<prefix>.CONSUMER.INFO.<stream>.<consumer>YesValidate the durable and export backlog metrics
<prefix>.CONSUMER.MSG.NEXT.<stream>.<consumer>YesFetch messages from the pull consumer
<prefix>.CONSUMER.DURABLE.CREATE.<stream>.<consumer>OptionalCreate a missing fixed durable; omit only when an administrator owns provisioning
<prefix>.CONSUMER.DELETE.<stream>.<consumer>OptionalReset backlog by deleting the durable; omit when resets are administrator-operated

The account also needs the ordinary data-plane permissions for its configured subjects: subscribe access to request/delivery inboxes, permission to publish acknowledgements to the reply subjects supplied by JetStream, and publish access to any event subjects produced by the application. In an account-import design, the owning administrator must export the corresponding JetStream service subjects and the application account must import them at apiPrefix.

When temporal.archive.enabled=true, the archive service consumes archiveSubject through the fixed archiveConsumer.name and archiveConsumer.deliverySubject. It requires consumer INFO and durable CREATE for that exact stream and durable, subscribe access to the configured delivery subject, and publish access to JetStream acknowledgement subjects. The archive service creates the push durable when it is missing. An administrator can provision the same durable with deliver_policy=new, ack_policy=explicit, ack_wait=360s, max_deliver=-1, the configured filter and delivery subjects, and a delivery group matching the durable name.

Clients specify their stream explicitly and do not request STREAM.INFO for externally managed streams. Stream creation, mutation, and inspection therefore remain administrator operations. When externalServices.nats.local=true, the application retains its existing stream setup behavior for local development.

An administrator-provisioned consumer should use the configured stream and filter subject with the fixed durable name, deliver_policy=new, ack_policy=explicit, ack_wait=360s, and max_deliver=-1. The application validates operational settings but does not change an existing consumer or require its delivery policy to match; the owner can retain the delivery policy chosen for a migration boundary.

If create permission is omitted and the durable is absent, the consumer logs the exact provisioning request. If delete permission is omitted, the reset API returns instructions to delete and recreate the exact durable at the stream head. Configuration mismatches likewise produce an administrator-ready update request in the consumer log.

Event Dispatcher

The event dispatcher is a dynamic event routing system that maps normalized DCIM object types to handler functions. It maintains a dispatch table for supported render impacts and exposes Prometheus metrics for event processing.

Rendering Process

The rendering process is as follows:

  1. Fetch normalized RenderData from the selected DCIM provider.
  2. Render the configuration using the nv_config_manager_templates.Renderer.
  3. Persist the rendered files using the Config Store client.
  4. Record intended-configuration metadata through the DCIM provider.

Template Version Management

Template updater: Runs as a Kubernetes job after Helm installs and upgrades. It queries the selected DCIM provider for devices with a stale template_version and renders those devices directly with bounded concurrency. Each update uses the device’s Redis-backed render lock.

Version tracking: A successful render records the nv_config_manager_templates version through the selected DCIM provider. The next template-updater job skips devices that already have the current version.

Deployment

The service uses two consumer deployments (nautobot and device), a separate template-updater job that runs after Helm installs and upgrades, and Redis for distributed locking. It exposes Prometheus metrics on port 8000.

The service is configured using a configuration file (config.py). The configuration file contains the selected DCIM provider settings, NATS connection details (TLS, credentials), Redis connection for locking, Config Store client settings, and environment-specific aggregate management flags. External providers configure dcim_change_stream and dcim_change_subject; empty Helm values retain the historical Nautobot stream and subject.

Monitoring

Prometheus metrics:

Event processing:

  • nv_config_manager_events_received - Events received through NATS (by model, instance, namespace).
  • nv_config_manager_events_processed - Events successfully processed.
  • nv_config_manager_events_skipped - Events skipped (no handler, device not enabled).
  • nv_config_manager_events_failed - Events that failed processing (by exception type).
  • nv_config_manager_event_processing_time - Event processing duration histogram.

Legacy Nautobot change compatibility:

  • nv_config_manager_nautobot_change_messages_received
  • nv_config_manager_nautobot_change_messages_processed
  • nv_config_manager_nautobot_change_messages_failed
  • nv_config_manager_nautobot_change_message_processing_time - Render duration
  • nv_config_manager_nautobot_change_message_end_to_end_time - Nautobot publish to Config Store persist

Error handling

Exception types:

  • DCIMError - DCIM provider API errors, retry on transient failures
  • RenderException - Template rendering failures, ACK (do not retry)
  • DeviceNotEnabledError - Device not enabled for rendering, ACK
  • EventParseError - Malformed event data, fail counter incremented
  • ConfigStoreException - Config store persistence errors

Consumer behavior:

  • ACK: Successful processing, render exceptions (will not succeed on retry), disabled devices
  • NAK: Transient failures and lock acquisition failures (5s delay)
  • Consumer recreation: Any fetch/heartbeat failure triggers automatic consumer rebuild

Key design patterns

Provider-owned handler registration: The event dispatcher exposes a registration surface; the selected provider registers its own object-type handlers and owns affected-device resolution.

Pull-based consumption: Consumers fetch messages on demand instead of using push-based subscriptions, which improves flow control and horizontal scaling.

Distributed locking: Redis-backed locks prevent concurrent renders for the same device across multiple consumer instances.

Version-aware processing: The template-updater job compares the current template package version with the version recorded by the selected DCIM provider. It renders stale devices directly with bounded concurrency and per-device locks.

Provider-backed data access: Render obtains normalized device data and managed-device state from the configured DCIM provider. Template rendering runs in a thread pool using asyncio.to_thread() to avoid blocking the event loop.

Connection sharing: NATSConnectionManager shares the NATS connection across components within a process.