Documentation
¶
Overview ¶
Package configfilekv reads a directory of single-value files as a configuration layer: each file's name is a key and its contents are the value.
Three unrelated systems present configuration exactly this way — a Kubernetes ConfigMap or Secret mounted as a volume, Docker and Podman secrets under /run/secrets, and systemd credentials under $CREDENTIALS_DIRECTORY — so this is named for the shape rather than for any one of them.
store, err := config.NewStore(ctx,
config.WithBackend(configfilekv.New(config.OS(), "/etc/config")),
)
It adds no third-party dependency.
Why this is not a directory glob ¶
A mounted ConfigMap does not contain plain files. The kubelet writes a timestamped directory and atomically repoints a "..data" symlink at it, which is what makes an update impossible to observe half-applied:
..2026_07_29_10_00_00.1234/ real directory ..data -> ..2026_07_29_.../ repointed atomically on update database.host -> ..data/database.host
Listing that naively yields "..data" and a timestamped directory alongside the real keys, so a consumer who did not know would invent two configuration keys out of the update mechanism. Dot-prefixed entries are therefore skipped.
Index ¶
Constants ¶
const DefaultFileMode fs.FileMode = 0o600
DefaultFileMode is the mode a newly written file gets.
Owner-only, because a writable directory of single-value files may well be holding credentials. The looser default fails silently — nobody notices their secrets are world-readable — while this one fails visibly, as a sibling process unable to read what it expected.
const DefaultPollInterval = 30 * time.Second
DefaultPollInterval is how often the watcher re-examines the directory when the caller does not say.
const SourceKind = config.SourceKind("filekv")
SourceKind identifies layers this backend contributes.
Variables ¶
var ( // ErrNotListable is returned when the filesystem cannot enumerate a // directory, which this backend has no way to work without. // // Reported at construction rather than as an empty layer at load: a backend // whose whole job is enumeration silently contributing nothing is the worst // available outcome, because the configuration merely appears to be missing. ErrNotListable = errors.NewSentinel("config-filekv.not_listable", "configfilekv: filesystem cannot list directories") // ErrUnwritableValue is returned when a write carries something a single // file cannot hold — a map or a slice, which has no one-file representation. ErrUnwritableValue = errors.NewSentinel("config-filekv.unwritable_value", "configfilekv: value cannot be written to a single file") )
Errors this backend returns. Callers should branch on these with errors.Is.
Functions ¶
Types ¶
type Option ¶
type Option func(*backend)
Option configures a backend.
func WithFileMode ¶
WithFileMode sets the mode of files this backend creates.
Defaults to DefaultFileMode, which is owner-only.
func WithPollInterval ¶
WithPollInterval overrides how often the watcher re-examines the directory.
func WithPrefix ¶
WithPrefix nests every key under a path.
Without it the directory's keys sit at the root, which is right for a ConfigMap that *is* the configuration and wrong for a secrets directory sharing a store with everything else.
func WithSensitive ¶
func WithSensitive() Option
WithSensitive marks the layer as holding secret material.
Two of the three systems this serves deliver secrets. Marking the layer means the core refuses to write one of these values into a layer that is not itself sensitive — the same protection a secrets manager gets, over a local directory.
Off by default, because a mounted ConfigMap usually is not secret and marking it so would refuse ordinary writes to the file beneath it.
func WithTrimTrailingNewline ¶
func WithTrimTrailingNewline() Option
WithTrimTrailingNewline strips one trailing newline from each value.
Off by default, and deliberately so. Kubernetes, Docker and systemd all write a value byte-exact, so a trailing newline only appears when a human created the file with echo. Trimming by default would silently alter a value that legitimately ends in whitespace — and when that value is a credential, the result is an authentication failure with nothing to point at. A stray newline shows up in the first log line and can be diagnosed; a mangled secret cannot.
func WithValueCodec ¶
WithValueCodec decodes each file's contents through a codec.
For a directory whose files hold JSON or YAML rather than scalars. A value that decodes to a mapping becomes a subtree; anything else falls back to the string, so a directory mixing the two works.
func WithWritable ¶
func WithWritable() Option
WithWritable allows changes to be written into the directory.
Off by default because every layout this adapter was built for is read-only — a ConfigMap volume is mounted read-only, Docker secrets are 0444, systemd credentials 0400 — so a writable default would fail on the filesystem for all three real consumers.
A plain directory of files is a perfectly good small writable store, which is why the option exists at all.