Configuration¶
The command source reads a per-instance YAML config file. The default
path on a deployed box is
/etc/pdns-pf/oxfeed-commandsource/<instance>.yml, where
<instance> matches the systemd template instance name. A commented
template with every option is shipped as
/etc/pdns-pf/oxfeed-commandsource/example.yml.
Environment variables in YAML values are only expanded when the
service is started with -expand-env. With expansion enabled you can
write command: "some-tool --token ${SOURCE_TOKEN}" and supply the
variable through the unit's environment file.
The shared config struct also exposes feed.http_upstream and
feed.rpz_downloader sections, but the command source binary refuses
to start without feed.command_source.command and never instantiates
those sources. Use the dedicated
pdns-pf-oxfeed-httpapi-downloader and
pdns-pf-oxfeed-rpz-downloader services for those sources.
Top-level structure¶
| Parameter | Type | Default | Description |
|---|---|---|---|
run_once |
boolean |
depends | Exit after a single update cycle. Defaults to true when no -config is given and false when a config file is loaded. |
feed |
Feed |
— | Where and how the feed is written, plus the command source itself. Required. |
http |
HTTP |
{} |
Status / metrics HTTP server. Disabled if address is empty. |
log |
Log |
see section | Log format and level. |
Deprecation policy¶
No fields have been deprecated or removed as of the current release.
Full example config¶
Click to expand the shipped example config
# Example config file for the pdns-pf-oxfeed-commandsource service
#
# To add a systemd service instance, you need to take these steps (replace SOMENAME):
#
# cp /etc/pdns-pf/oxfeed-commandsource/example.yml \
# /etc/pdns-pf/oxfeed-commandsource/SOMENAME.yml
# ln -s /lib/systemd/system/pdns-pf-oxfeed-commandsource@.service \
# /etc/systemd/system/pdns-pf-oxfeed-commandsource@SOMENAME.service
#
# By default we run as a service when a config file is used.
# Set this to true to only do a single run.
#run_once: false
# Configures where and how the feed directory with feed.json is written
feed:
# Path where the feed is saved to.
# This is equivalent to `simpleblob://fs?root_path=/tmp/feed`
# or `file:///tmp/feed`.
# As an alternative, the following format is accepted:
#root:
# # The kind of storage.
# # One of "fs", "memory", or "s3"
# type: fs
# # Options for storage, passed on to simpleblob.
# # Backend "memory" takes no option.
# # See the following links for "fs" and "s3" options:
# # https://pkg.go.dev/github.com/PowerDNS/simpleblob/backends/fs#Options
# # https://pkg.go.dev/github.com/PowerDNS/simpleblob/backends/s3#Options
# options:
# root_path: /tmp/feed
root: /tmp/feed
# Optional. Allows trying again storage operations.
retry:
# Duration for which consecutive network errors are tolerated.
# After this, an error will be returned.
#timeout: 5m
# Time to wait in case an error occurred while reading/writing.
#interval: 20s
# Optional. Maximum random time to add to interval to avoid multiple retries at once.
#max_jitter: 1s
# Optional. Static time to add to the interval for each failure.
#backoff: 2s
# Interval we want snaps to be written, 0s is on any incoming update
#snap_interval: 6h
# Make every code have its own namespace.
# WARNING: Changing this later will trigger a full feed UUID reset!
#namespace_per_code: false
# Enable internal memdb stores pruning.
#prune_enabled: false
# Time between two memdb stores prunings.
#prune_interval: 24h
command_source:
# The external command to provide the data for the feed (required)
#command: some-command-source --wait
# If the command supports waiting for changes, this interval effectively
# rate-limits updates. If the command does not support --wait, it
# also affects update latency and resource usage for polling.
#interval: 5s
# Timeout for the command run. If the command takes longer than this,
# it will be killed.
#timeout: 10m
# Configure snapshot and delta expiry rules for automatic feed cleaning.
#expiry:
# snapshots:
# must_keep_count: 3
# must_keep_interval: 30m
# max_keep_count: 3
# max_keep_interval: 0s
# deltas:
# must_keep_count: 5
# must_keep_interval: 6h
# max_keep_count: 200
# max_keep_interval: 168h
# The HTTP server exposes Prometheus /metrics and a status page
http:
# Address to listen on. ":8910" listens on port 8910 on all interfaces.
# Disabled by default.
#address: ":9605"
# Serve feed under /feed. Not for production use!
#serve_feed: false
log:
level: info # options: trace, debug, info, warning, error, fatal
format: human # options: human, logfmt, json
timestamp: short # options: short, full, disable
feed¶
The feed section configures both the destination of the produced
feed and the command source that drives it.
| Parameter | Type | Default | Description |
|---|---|---|---|
root |
string / Root |
— | Storage destination for the feed tree. Required. |
retry |
retry.Config |
{} |
Retry policy for storage operations. |
namespace_per_code |
boolean |
false |
Place each classification code in its own namespace. Changing this resets the feed. |
command_source |
CommandSource |
— | The command to run and its scheduling. Required. |
expiry |
ExpiryConfig |
see defaults | Snapshot and delta retention rules. |
snap_interval |
go: Duration |
1h |
Force a fresh snapshot at this cadence. |
prune_enabled |
boolean |
false |
Compact the in-memory feed state periodically. |
prune_interval |
go: Duration |
24h |
Time-based pruning trigger. Only consulted when prune_enabled is true. |
feed.root¶
The simpleblob storage where the feed tree is written. Accepts either a string URI / path or a struct.
String form (the recommended default):
A bare filesystem path is equivalent to file:///path and to the
simpleblob://fs?root_path=/path URI.
Struct form, for backends that need options:
feed:
root:
type: fs # one of "fs", "memory", "s3"
options:
root_path: /var/lib/pdns-pf-oxfeed-commandsource/feeds/my-feed
The shipped example uses the bare-path string. The -o CLI flag
overrides this field at startup. See
simpleblob/backends/fs
and
simpleblob/backends/s3
for backend-specific options.
feed.retry¶
Wraps every storage call (snapshot write, delta write, codes write, cleanup) in a retry loop. All durations are optional and an empty section disables retries entirely.
| Parameter | Type | Default | Description |
|---|---|---|---|
timeout |
go: Duration |
— | Total time window during which retries are attempted. Must be strictly greater than 2*interval + max_jitter + backoff. |
interval |
go: Duration |
— | Time to wait after a failed attempt before retrying. Minimum 10 ms. |
max_jitter |
go: Duration |
0 |
Random extra delay added on top of interval. Minimum 2 ms when non-zero. |
backoff |
go: Duration |
0 |
Static delay added to interval for every failure. Minimum 1 ms when non-zero. |
feed.namespace_per_code¶
When true, every classification code gets its own LMDB namespace on
downstream clients. This is required for domain-list style feeds where
the same domain may carry different code sets per tenant.
Warning
Changing namespace_per_code after a feed has been written resets
the feed UUID, which forces every downstream client to re-snap
from scratch. Decide this value once per feed and leave it alone.
feed.command_source¶
| Parameter | Type | Default | Description |
|---|---|---|---|
command |
string |
— | Shell command executed via /bin/sh -c. Required. |
interval |
go: Duration |
60s |
Time between command runs. Minimum 100 ms. See Interval sizing. |
timeout |
go: Duration |
10m |
Command runtime budget. The process is killed if it exceeds this. Minimum 1 s. |
Interval sizing¶
If the command supports a --wait (or equivalent) mode that blocks
until the source data changes, interval mainly acts as a rate limit
on delta production during heavy update bursts and as a CPU guard if
the command keeps exiting with an error. With --wait, update latency
is dominated by how fast the source actually changes, not by this
interval.
If the command always returns immediately, interval directly
controls update latency and the polling load on the source.
The command contract — what it must print, the exit codes it can return, the environment it receives — is documented under Architecture → The command contract.
feed.expiry¶
Snapshot and delta retention. The default values are
feed.expiry.snapshots = {must_keep_count: 3, must_keep_interval: 30m, max_keep_count: 3}
and
feed.expiry.deltas = {must_keep_count: 5, must_keep_interval: 6h, max_keep_count: 200, max_keep_interval: 7d}.
Deltas on the upgrade path from the latest snapshot to the latest
delta are always preserved, even when expiry would otherwise drop
them.
Each of snapshots and deltas accepts the same four fields:
| Parameter | Type | Default | Description |
|---|---|---|---|
must_keep_count |
int |
0 |
Never drop the last N entries, regardless of max_keep_*. |
must_keep_interval |
go: Duration |
0 |
Never drop entries newer than this age. |
max_keep_count |
int |
0 |
Drop oldest entries beyond N newest, subject to must-keep rules. 0 means no count limit. |
max_keep_interval |
go: Duration |
0 |
Drop entries older than this age, subject to must-keep rules. 0 means no age limit. |
Example: keep the last three snapshots and a week of deltas, capped at 200 to bound disk usage.
feed:
expiry:
snapshots:
must_keep_count: 3
must_keep_interval: 30m
max_keep_count: 3
deltas:
must_keep_count: 5
must_keep_interval: 6h
max_keep_count: 200
max_keep_interval: 168h
feed.snap_interval¶
How often to force a fresh snapshot even when the content has not
changed enough to demand one. Shorter intervals shrink the delta chain
that newly connecting clients must replay but produce more snapshot
churn on disk. Set to 0s to write a snapshot on every accepted
change (rarely useful — clients usually only need one snapshot per
day).
feed.prune_enabled¶
When true, the service periodically compacts the in-memory feed
state to recover stringstore space taken by deleted domains. See
Architecture → In-memory pruning
for trigger conditions and the CPU cost.
feed.prune_interval¶
Time-based prune trigger. Only consulted when prune_enabled is
true. 0s disables the time-based trigger; mutation-based pruning
still applies.
http¶
| Parameter | Type | Default | Description |
|---|---|---|---|
address |
string |
— | Bind address in host:port form (for example :9605). Empty disables the HTTP server entirely. |
serve_feed |
boolean |
false |
Expose the feed tree under /feed/. See warning below. |
-http-addr and -http-serve-feed on the command line override the
matching fields.
Warning
serve_feed is intended for development and one-shot testing.
The shipped status server has no ETag support, no auth, and no
rate limiting — it is not safe to expose to clients. In
production, write the feed to a directory and front it with a
proper static HTTP server (Caddy or nginx).
log¶
| Parameter | Type | Default | Description |
|---|---|---|---|
level |
string |
info |
One of trace, debug, info, warning, error, fatal. |
format |
string |
human |
One of human, logfmt, json. |
timestamp |
string |
short |
One of short, full, disable. |
-log-level, -log-format, -log-timestamp, and -debug on the
command line override the matching fields.