src/daemon/dyncfg/README.md
Dynamic Configuration (DynCfg) is a system in Netdata that enables both internal and external plugins/modules to expose their configurations dynamically to users through a unified interface. This document explains how DynCfg works and how to integrate your module with it.
DynCfg provides a centralized mechanism for:
Key features:
DynCfg consists of several API layers:
There are two main ways to integrate with DynCfg:
The configuration ID is a crucial part of the DynCfg system. It serves as a unique identifier and determines how the configuration appears in the UI.
Configuration IDs typically follow a colon-separated hierarchical structure:
component:category:name
Where:
For example:
health:alert:prototype: Health alert prototype templatehealth:alert:prototype:ram_usage: Specific health alert prototypego.d:nginx: Nginx collector templatego.d:nginx:local_server: Specific Nginx collector jobsystemd-journal:monitored-directories: Systemd journal configurationFor templates and jobs, the ID follows a specific pattern:
component:template_namecomponent:template_name:job_nameThe part before the last colon in a job ID must match an existing template ID.
The first component of the ID is used to organize configurations in the UI, creating separate tabs or sections. This allows for logical grouping of related configurations.
When choosing an ID, consider:
DynCfg uses HTTP-like response codes to indicate the status of operations. These are crucial for both internal and external plugins to properly communicate with the DynCfg system:
Standard HTTP error codes are used, including:
When implementing a callback function, always return the appropriate response code to indicate the status of the operation. The DynCfg system uses these codes to determine how to handle the configuration and what to display to the user.
Here's how to implement DynCfg for an internal plugin/module:
For internal plugins, the Netdata daemon already handles initialization and shutdown of the DynCfg system. You don't need to call dyncfg_init() or dyncfg_shutdown() in your plugin code.
Register your configurations when your plugin initializes:
bool dyncfg_add(
RRDHOST *host, // The host this configuration belongs to (localhost for global configs)
const char *id, // Unique ID for this configuration
const char *path, // Path for UI organization
DYNCFG_STATUS status, // Initial status (ACCEPTED, DISABLED, etc.)
DYNCFG_TYPE type, // SINGLE, TEMPLATE, or JOB
DYNCFG_SOURCE_TYPE source_type, // INTERNAL, DYNCFG, USER
const char *source, // Source identifier (e.g., "internal")
DYNCFG_CMDS cmds, // Supported commands (bitwise OR of DYNCFG_CMD_* values)
HTTP_ACCESS view_access, // Access permissions for viewing
HTTP_ACCESS edit_access, // Access permissions for editing
dyncfg_cb_t cb, // Callback function for handling commands
void *data // User data passed to the callback
);
Example (from health_dyncfg.c):
dyncfg_add(
localhost,
DYNCFG_HEALTH_ALERT_PROTOTYPE_PREFIX,
"/health/alerts/prototypes",
DYNCFG_STATUS_ACCEPTED,
DYNCFG_TYPE_TEMPLATE,
DYNCFG_SOURCE_TYPE_INTERNAL,
"internal",
DYNCFG_CMD_SCHEMA | DYNCFG_CMD_ADD | DYNCFG_CMD_ENABLE | DYNCFG_CMD_DISABLE | DYNCFG_CMD_USERCONFIG,
HTTP_ACCESS_NONE,
HTTP_ACCESS_NONE,
dyncfg_health_cb,
NULL
);
int your_dyncfg_callback(
const char *transaction, // Transaction ID
const char *id, // Configuration ID
DYNCFG_CMDS cmd, // Command being executed
const char *add_name, // For ADD: the name to add
BUFFER *payload, // Command payload
usec_t *stop_monotonic_ut, // Timeout info
bool *cancelled, // Whether the operation was cancelled
BUFFER *result, // Buffer to write results to
HTTP_ACCESS access, // Access level of the user
const char *source, // Configuration source
void *data // User data passed during registration
) {
// Handle the command
switch(cmd) {
case DYNCFG_CMD_SCHEMA:
// Return JSON schema
buffer_json_initialize(result, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
// Add your schema here
buffer_json_finalize(result);
return HTTP_RESP_OK;
case DYNCFG_CMD_GET:
// Return current configuration
buffer_json_initialize(result, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
// Add your configuration here
buffer_json_finalize(result);
return HTTP_RESP_OK;
case DYNCFG_CMD_UPDATE:
// Process configuration update
// If update successful
return DYNCFG_RESP_RUNNING; // or DYNCFG_RESP_ACCEPTED if not running yet
// If restart is required
// return DYNCFG_RESP_ACCEPTED_RESTART_REQUIRED;
// If validation fails
// return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, "your error message");
case DYNCFG_CMD_DISABLE:
// Handle disabling the configuration
return DYNCFG_RESP_ACCEPTED_DISABLED;
case DYNCFG_CMD_ENABLE:
// Handle enabling the configuration
return DYNCFG_RESP_RUNNING; // or DYNCFG_RESP_ACCEPTED if not running yet
// Handle other commands
default:
// Unsupported command
return dyncfg_default_response(result, HTTP_RESP_BAD_REQUEST, "unsupported command");
}
}
Unregister configurations only when they’re no longer conceptually relevant (such as when a feature becomes unavailable), not during plugin or module shutdown:
dyncfg_del(host, id); // Remove a specific configuration that no longer applies
When a plugin or module exits, the Netdata Functions manager automatically stops accepting requests for its functions. The configurations will remain in the DynCfg system and will become active again when the plugin restarts.
The Netdata daemon also handles shutting down the entire DynCfg system, so you don't need to call dyncfg_shutdown() in your plugin code.
External plugins like go.d.plugin use a different approach based on the plugins.d protocol. For detailed information on implementing DynCfg for external plugins, please refer to the External Plugins DynCfg documentation.
This documentation covers:
The UI for modifying configurations is generated from JSON Schema. Netdata supports two ways to provide schema definitions:
Netdata first attempts to load schema files from the disk before calling the plugin or module. Schema files should be placed in:
CONFIG_DIR/schema.d/ (user-provided schemas, typically /etc/netdata/schema.d/)LIBCONFIG_DIR/schema.d/ (stock schemas, typically /usr/lib/netdata/conf.d/schema.d/)Schema files should be named after the configuration ID with .json extension, for example:
health:alert:prototype.jsongo.d:nginx.jsonIf no static schema file is found, Netdata will call the plugin or module with the DYNCFG_CMD_SCHEMA command:
This gives you flexibility to either:
Example JSON Schema:
{
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri",
"title": "Server URL",
"description": "The URL of the server to connect to"
},
"timeout": {
"type": "integer",
"minimum": 1,
"maximum": 60,
"title": "Timeout",
"description": "Connection timeout in seconds"
},
"auth": {
"type": "object",
"title": "Authentication",
"properties": {
"username": {
"type": "string",
"title": "Username"
},
"password": {
"type": "string",
"format": "password",
"title": "Password"
}
}
}
},
"required": [
"url"
]
}
Different actions behave differently depending on the configuration type. The following table explains what happens when each action is applied to different configuration types:
| Action | SINGLE | TEMPLATE | JOB |
|---|---|---|---|
| SCHEMA | Returns schema from file or plugin | Returns schema from file or plugin | Uses template's schema |
| GET | Returns current configuration | Not supported (templates don't maintain data) | Returns current configuration |
| UPDATE | Updates single configuration | Not supported (templates don't maintain data) | Updates job configuration |
| ADD | Not supported | Creates a new job based on template | Not supported |
| REMOVE | Not supported | Not supported | Removes job (only for DYNCFG_SOURCE_TYPE_DYNCFG jobs) |
| ENABLE | Enables single configuration | Enables template AND all its jobs | Enables job (fails if its template is disabled) |
| DISABLE | Disables single configuration | Disables template AND all its jobs | Disables job |
| RESTART | Sends restart command to plugin | Restarts all template's jobs | Restarts specific job |
| TEST | Tests configuration without applying | Tests a new job configuration | Tests updated job configuration |
| USERCONFIG | Returns user-friendly configuration | Returns template for user-friendly configuration | Returns user-friendly configuration |
Important Notes:
The DynCfg system exposes configurations via the Netdata API for management:
Netdata provides a tree API that returns the entire DynCfg tree or a specific subpath:
/api/v3/config?action=tree&path=/collectors
Parameters:
action: Set to "tree" to get the configuration treepath: The configuration path to start from (e.g., "/collectors", "/health/alerts")id (optional): Return only a specific configuration IDThis returns a JSON structure of all configurations, organized by path, with their status, commands, access controls, and other metadata.
Individual configurations can be managed via:
/api/v3/config?action=<command>&id=<configuration_id>&name=<name>
Where:
action: One of the supported commands (get, update, add, remove, etc.)id: The configuration ID to act uponname: Required for add/test actions (new job name)The API automatically routes commands to the appropriate plugin or module that registered the configuration.
Health alerts use DynCfg to manage alert definitions. Key files:
src/health/health_dyncfg.c: Implements DynCfg integration for health alertsThe health module uses the high-level API with IDs like:
health:alert:prototype for the alert templatehealth:alert:prototype:ram_usage for specific alert prototypesIt supports multiple configuration objects, validation of alert definitions, and conversion between different configuration formats (JSON and traditional Netdata health configuration syntax).
The systemd-journal.plugin is an external plugin written in C that uses DynCfg to manage journal directory configurations:
src/collectors/systemd-journal.plugin/systemd-journal-dyncfg.c: Implements DynCfg integrationsystemd-journal:monitored-directories IDThis is a good example of an external plugin using the DynCfg system for a single configuration object.
go.d.plugin uses DynCfg to manage job configurations. It:
It uses IDs like:
go.d:nginx for the Nginx collector templatego.d:nginx:local_server for a specific Nginx collector jobgo.d.plugin demonstrates how external plugins can leverage DynCfg to provide dynamic configuration capabilities through the plugins.d protocol.
NETDATA_DEBUG_DYNCFG=1 to enable debug logging for DynCfg/var/lib/netdata/config/ for persisted configuration files/api/v3/config?id=<your-config-id>