Skip to content

Operations

Service control

The RPM ships a systemd template unit named pdns-pf-oxfeed-commandsource@.service, running as the pdns-oxfeed user. One instance is started per logical feed.

To add an instance called my-feed:

# 1. Drop a config file for this instance.
cp /etc/pdns-pf/oxfeed-commandsource/example.yml \
   /etc/pdns-pf/oxfeed-commandsource/my-feed.yml
$EDITOR /etc/pdns-pf/oxfeed-commandsource/my-feed.yml

# 2. Enable an instance of the template unit.
ln -s /lib/systemd/system/pdns-pf-oxfeed-commandsource@.service \
      /etc/systemd/system/pdns-pf-oxfeed-commandsource@my-feed.service

# 3. Bring it up.
systemctl daemon-reload
systemctl enable --now pdns-pf-oxfeed-commandsource@my-feed

Everyday commands for an existing instance:

# Status and recent logs
systemctl status pdns-pf-oxfeed-commandsource@my-feed

# Follow the log stream
journalctl -u pdns-pf-oxfeed-commandsource@my-feed -f

# Restart after a config change
systemctl restart pdns-pf-oxfeed-commandsource@my-feed

The service does not watch its config file for changes; restart the instance after editing.

Config location

Each instance reads /etc/pdns-pf/oxfeed-commandsource/<instance>.yml. The RPM ships a commented template at /etc/pdns-pf/oxfeed-commandsource/example.yml but does not install a ready-to-use per-instance config. See Configuration for the full reference.

Command-line flags

Flag Default Purpose
-config Path to the YAML config file. The packaged unit passes the per-instance file.
-expand-env false Expand ${VAR} references inside the YAML file.
-strict false Reject unknown YAML fields instead of ignoring them.
-o Override feed.root with a filesystem path or simpleblob:// URI.
-http-addr (config) Override http.address.
-http-serve-feed false Override http.serve_feed.
-debug false Shortcut for -log-level=debug.
-cpuprofile Write a CPU pprof to this file when the process exits.
-memprofile Write a heap profile to this file when the process exits.
-log-level (config) Override log.level.
-log-format (config) Override log.format.
-log-timestamp (config) Override log.timestamp.

The service needs a configured feed.command_source.command before it can start; there is no positional command argument or flag that sets it. When that command is supplied by configuration, run_once defaults to false for long-lived daemon operation and can be set to true for a single update cycle.

HTTP endpoints

The HTTP server bound to http.address exposes:

  • Status page (/). HTML summary of the running feed: feed UUID, whether snapshots are LMDB-sorted, whether namespace_per_code is active, current source version, total feed size, and per-snapshot / per-delta tables.
  • Metrics (/metrics). Prometheus endpoint. See Metrics.
  • Healthz (/healthz). JSON response from the embedded go-healthz library. See Healthz checks below.
  • pprof (/debug/pprof/...). Go net/http/pprof handlers for CPU, heap, goroutine, and block profiles.
  • Feed tree (/feed/). Only when http.serve_feed is set. Intended for development and testing only.

Healthz checks

The service registers three checks that share a single lifecycle: all three return OK until the first successful update lands, then switch to reflecting the real feed state.

Check Warn / errors when
feed_size Warns when the published feed contains no data.
feed_version Errors when no feed version exists (snapshots and deltas are both empty).
feed_source_version Errors when the last accepted source version is empty.

The "passive until first update" behaviour means a freshly started instance does not page during warm-up, but a stuck instance — one that never produces a first successful update — will not page either. Pair healthz with the oxfeed_source_command_exec_success_last_time_seconds metric to alert on warm-up failures.

Writing a source command

The command contract is documented under Architecture → The command contract. A minimal /bin/sh skeleton looks like:

#!/bin/sh
set -eu

# OXFEED_TMPDIR is provided by the service and cleaned up on exit.
csv="$OXFEED_TMPDIR/feed.csv"
codes="$OXFEED_TMPDIR/feed-codes.json"

# Bail out early if nothing changed since the last accepted version.
if my-source --version-only | grep -qxF "${OXFEED_LAST_VERSION-}"; then
    exit 11   # "not modified"
fi

# Produce deterministic output: no timestamps, fixed sort order.
my-source --emit-csv   > "$csv"
my-source --emit-codes > "$codes"

# Hand the files off to the service. The version field is optional
# but lets the service feed it back in OXFEED_LAST_VERSION next time.
printf 'OXFEED_GENERATOR_RESULT: {"v":1,"csv_file":%s,"codes_file":%s,"version":%s}\n' \
    "\"$csv\"" "\"$codes\"" "\"$(my-source --version-only)\""

The service reads csv_file and codes_file, hashes them, and only emits a delta when the contents actually changed. Tools like the admin's pdns-pf-admin-manage export_oxfeed subcommand follow this contract.

Profiling

-cpuprofile <path> writes a CPU profile and -memprofile <path> writes a heap profile when the process exits, including on the next systemctl stop. Combine with -once for short, bounded profiling runs.

Live profiling is available via the pprof endpoints under /debug/pprof/ on the status server. For example:

go tool pprof http://127.0.0.1:9605/debug/pprof/heap