How configurations are stored and loaded#

This reference describes how configuration files are discovered, loaded, and merged in OrangeQS Juice and its extensions.

Note

This guide is meant as a reference, see Configuration in the Develop extensions guide for a more interactive tutorial.

Decentralized configuration schemas#

Configurations in Juice are decentralized. Each component or extension defines its own configuration schema in separate files. This modular approach allows each service or extension to specify only the configuration options it needs. This makes the system extensible and maintainable.

Configuration schemas in Juice are defined using the Configurable base class. Each component or extension that requires configuration should subclass Configurable and declare its configuration schema as class attributes using pydantic.BaseModel. For example:

from typing import ClassVar
from orangeqs.juice.settings import Configurable

class DummyConfig(Configurable):
    filename: ClassVar[str] = "dummy"

    host: str = "localhost"
    port: int = 8080
    enable_feature_x: bool = False

Each subclass of Configurable automatically has a load() method to validate and load configuration data from files. The filename class attribute determines the configuration key and the corresponding files to load.

Configurations files in OrangeQS juice are stored as TOML files. These TOML files are loaded into a Python dictionary. The dictionary will be loaded into the pydantic.BaseModel, which will handle validation.

Configuration file loading paths#

Configuration directories#

Juice loads configuration files from multiple sources.

  • System configuration directory: /etc/juice/config. Contains configuration files by the system administrator.

  • Extension entry points: Each installed extension can provide configuration files via the juice.config entry point group. These are loaded from the extension’s package resources. See Bundling configuration files with your extension in the Develop extensions guide.

Configuration file names#

Each configuration file has a filename and optional priority associated with it.

When loading a configuration for a given schema with <filename>, OrangeQS Juice follows these steps. Juice looks for files in each configuration directory: the system config, shared runtime, and extension entry points. For each configuration directory it loads:

  • All files matching <priority>-<filename>.toml or <filename>.toml in the directory.

  • All files matching <priority>-*.toml or *.toml in a subdirectory <filename>.d/ (if present).

If the priority is not specified in the file name, a default priority is assumed for each source:

Source

Default Priority

System config directory (/etc/juice/config)

0

System config subdirectory (/etc/juice/config/<filename>.d/)

10

Extension entry point directory

20

Extension entry point subdirectory (<filename>.d)

30

For example, these files could be loaded for a configuration schema with filename set to dummy (in ascending priority):

            /etc/juice/config / dummy.toml
            /etc/juice/config / 15-dummy.toml
            /etc/juice/config / dummy.d / 20-extra.toml
 <some_extension entry point> / 25-dummy.toml
<other_extension entry point> / dummy.d / extension.toml

The next section explains how these files will be combined into the configuration schema.

Warning

An exception to this rule is the orchestration.toml configuration file, which can only be loaded from /etc/juice/config. This configuration file can thus only be modified by the system administrator.

Configuration merging#

Configuration files are merged in order of ascending priority, with later files overriding earlier ones for overlapping keys. Dictionaries are merged recursively. List will not be merged, thus will be overwritten by higher priority files.

Same priority files are merged in an arbitrary order. Juice has a mechanism to ensure the order is deterministic over multiple runs, but you should not rely on this behavior!

The juice config CLI

See also the juice config CLI which provides commands to interact with the configuration.