85.1.60. pepsi-config

inspect and edit the effective pepsi configuration

Manual section:

1

85.1.60.1.1. Name

pepsi-config - look up, expand, dump and edit the merged Pepsi configuration.

85.1.60.1.2. Synopsis

pepsi-config [GLOBAL-OPTIONS] get [-f | –filename] SECTION OPTION

pepsi-config [GLOBAL-OPTIONS] pathsub PATH-EXPR

pepsi-config [GLOBAL-OPTIONS] dump [-d | –diagnostics] [–origin [–scope SCOPE]]

pepsi-config [GLOBAL-OPTIONS] set [–scope SCOPE] SECTION OPTION VALUE

pepsi-config [GLOBAL-OPTIONS] unset [–scope SCOPE] SECTION [OPTION]

pepsi-config [GLOBAL-OPTIONS] list [–scope SCOPE] [–drafts]

pepsi-config [GLOBAL-OPTIONS] export [–from DIR] [–password-file FILE] ARCHIVE

pepsi-config [GLOBAL-OPTIONS] import [–into DIR] [–force] [–password-file FILE] ARCHIVE

85.1.60.1.3. Description

pepsi-config inspects – and edits – the effective configuration shared by every Pepsi component. All components read the same INI-style configuration file (see pepsi.conf(5)) and the same database configuration overlay, so this one tool serves them all.

The reading commands report the effective configuration: the file amended by the pepsi.config_override table. For get, pathsub and dump a database that cannot be reached is not an error – the file’s configuration is reported and the run still succeeds – because an operator most often reaches for this tool when something is wrong. (A failure to connect is logged as a warning; a connection that succeeds but whose overlay cannot be read is logged as an error, and the file’s configuration is still reported. dump –origin reports the file’s configuration without a message when it cannot connect, and with a warning when the overlay cannot be read.) list is the exception: it prints the stored overrides and so has nothing to report without the database, and it exits non-zero when the connection fails or the caller does not hold the pepsi-config role.

The writing commands (set, unset) edit the database overlay only. They never modify the configuration file, which stays the operator’s own, and they are refused unless the caller holds the pepsi-config PostgreSQL role (pepsi-config adopts that account when it is started as root). That grant is the enforcement: no Pepsi component that processes mail may write the configuration that defines the pipeline it runs in.

The scope chain, and which sections may live in the database at all, are described in pepsi.conf(5).

85.1.60.1.4. Commands

get [-f | –filename] SECTION OPTION

Print the effective value of OPTION in SECTION. With –filename, the value is interpreted as a path and $-expansion is applied.

pathsub PATH-EXPR

Print PATH-EXPR with ${VAR} and $VAR placeholders substituted from the [PATHS] section and the environment.

dump [-d | –diagnostics] [–origin [–scope SCOPE]]

Print the merged configuration. With –diagnostics, also show which file and line each option came from. With –origin, annotate every value with the layer that set it (file, or the database scope) and every section with whether a change to it is applied live or needs a restart; –scope resolves the chain for a particular domain or address (default global).

–scope only has an effect together with –origin. Without it the output is the file amended by the global overlay layer alone, whatever –scope says (the value is still parsed, so a malformed scope is still an error).

Credential-bearing options are masked as ***: every option in the [pepsi-postgres] and [pepsi-admin] sections, and any option whose name contains PASSWORD, PASSPHRASE, SECRET, TOKEN, CREDENTIAL, CLIENT_ID or PEPPER — deliberately not KEY, so a TLS_KEY path is still shown. The @inline-secret@ directive merges every secrets.d/*.secret fragment into the configuration this command renders, so an unmasked dump run as root would print the SRS secret, the key-wrapping secret, the secure-link pepper and any smarthost password — and redirecting a dump into a bug report is the ordinary way an operator shares their configuration. The predicate is the one the administrative API and the settings echo use (pepsi_common::secrets::is_secret), so all three agree by construction. Read the fragment itself if you need a value.

set [–scope SCOPE] SECTION OPTION VALUE

Store one override in the database. SECTION is lower-cased and OPTION upper-cased before anything else, so the spelling used on the command line does not matter. The change is validated first by building the configuration it would produce and running the owning stage’s own parser over it; a value that stage would reject is refused, with that stage’s error, and nothing is stored. Refused likewise, and never stored: a section that may only live in the configuration file, a credential-bearing option in any section (credentials are never stored in the database), and a domain:/address: SCOPE for a section that is not [stage-*], since nothing reads other sections per domain or per address (see pepsi.conf(5)). The administrative API applies the same rule, and a row that breaks it is ignored when the overlay is read. Prints whether the change is live or needs a restart, and records the change – who, when, which scope, but not the value – in the audit log.

unset [–scope SCOPE] SECTION [OPTION]

Remove one override, or – with no OPTION – every override the scope carries for SECTION. The affected options revert to the next layer down, ultimately the configuration file. Removing something that was never set is reported and is not an error.

list [–scope SCOPE] [–drafts]

Print the stored overrides with their timestamps and authors. Unlike set and unset, –scope here has no default: with none given every scope is listed. –drafts additionally shows staged rows, which no running component reads.

export [–from DIR] [–password-file FILE] ARCHIVE

Write a password-encrypted archive of the configuration directory (by default the directory holding the loaded configuration file): the configuration file, any fragments beside it, and the secrets.d secret fragments. Each file’s permission bits are recorded numerically and its owner and group by name (falling back to the numeric id when the account no longer resolves). ARCHIVE may be - for standard output; the progress and summary lines go to standard error, so that stays usable. The archive file itself is created mode 0600. Only regular files are archived – symbolic links are not followed and anything else is skipped with a warning – and a single file larger than 32 MiB, an empty password, or a directory holding no regular file at all is refused. This deliberately does not cover the database overlay, which pg_dump already backs up properly.

import [–into DIR] [–force] [–password-file FILE] ARCHIVE

Restore an archive written by export. ARCHIVE may be - to read standard input. Ownership is restored, so this normally needs root; a file whose recorded owner does not exist on this machine is refused, not guessed, and so is one owned by another account when the command is not run as root. Those ownership checks run over the whole archive before a single file is written, so a restore that fails on them writes nothing. An entry whose target already exists is refused too, but that check happens as the entry is reached, so it stops the restore rather than skipping the file — the entries before it are already written and the ones after it are not. Pass –force to overwrite instead. Restoring into a directory that already holds a pepsi.conf therefore wants either –force or an empty –into directory. Archive entries naming an absolute path or a .. component are rejected outright.

Both export and import need the archive password. With –password-file it is read from FILE, which must not be readable by others (chmod 600) and must not be empty; otherwise it is prompted for on the terminal without echo, and export asks twice and refuses a mismatch. When no configuration file was found at all there is no directory to default to, and –from/–into becomes mandatory.

85.1.60.1.5. Scopes

SCOPE is one of:

global

The whole deployment. The default for set and unset.

domain:DOMAIN

Messages whose relevant address is at DOMAIN.

address:ADDRESS

Messages whose relevant address is exactly ADDRESS.

The relevant address is the envelope sender for a locally-originated message, otherwise each envelope recipient – the same rule the per-address settings layer uses (pepsi-settings(1)).

85.1.60.1.6. Global Options

These global options precede the subcommand (a trailing flag is rejected).

-c FILE, –config FILE

Read the configuration from FILE instead of searching the default locations.

-L LOGLEVEL, –log LOGLEVEL

Set the logging verbosity. LOGLEVEL is one of error, warn, info, debug or trace. When the flag is absent the global [pepsi] LOG option applies, and failing that info.

-v, –verbose

Show log messages from all sources, including third-party libraries.

-h, –help

Print a usage summary and exit.

-V, –version

Print the version and exit.

85.1.60.1.7. Exit Status

0

Successful completion.

1

An error occurred, for example a malformed configuration file, a missing SECTION/OPTION, a rejected override value, a section that may only live in the configuration file, a wrong archive password, or insufficient database privileges for a write. The reason is written to the log.

2

The command line itself was wrong (an unknown option, a global option written after the subcommand, a missing argument).

85.1.60.1.8. Files

When –config is not given, the first existing file from the following list is used. Every Pepsi component shares the same configuration file, so this is the same list each one searches:

  • $XDG_CONFIG_HOME/pepsi.conf

  • $HOME/.config/pepsi.conf

  • /etc/pepsi/pepsi.conf

  • /etc/pepsi.conf

85.1.60.1.9. Examples

Check which domains mail is accepted for:

pepsi-config -c /etc/pepsi/pepsi.conf get pepsi-ingress ACCEPTED_DOMAINS

Dump the merged configuration with source annotations:

pepsi-config -c /etc/pepsi/pepsi.conf dump --diagnostics

Show where every effective value came from:

pepsi-config dump --origin

Raise one stage’s queue lifetime without editing a file or restarting anything:

pepsi-config set stage-relay MAX_LIFETIME '48 h'

Give one domain a different setting, and take it away again:

pepsi-config set --scope domain:example.org stage-relay DELAY_DSN_AFTER '4 h'
pepsi-config unset --scope domain:example.org stage-relay DELAY_DSN_AFTER

Back up everything that is not in the database:

pepsi-config export /root/pepsi-config-backup.pca

85.1.60.1.10. See Also

pepsi.conf(5), pepsi-setup(1), pepsi-settings(1)

85.1.60.1.11. Bugs

Report bugs to the Pepsi issue tracker.