$darkmode
Elektra 0.10.0
New mountpoint config structure

A mountpoint is defined by adding keys below system:/elekta/mountpoints/<mountpoint>, where <mountpoint> is the key name for the parent key of the mountpoint with slashes properly escaped. For example for the mountpoint user:/mymountpoint you have to add keys below system:/elekta/mountpoints/user:\/mymountpoint.

Every mountpoint consists of four parts:

  1. A set of plugins required for the mountpoint.
  2. A single backend plugin within the set of plugins.
  3. The mountpoint definition specific to the backend plugin.
  4. The mountpoint config available to all plugins of this mountpoint.

The set of plugins is defined below system:/elektra/mountpoints/<mountpoint>/plugins. The keys below system:/elektra/mountpoints/<mountpoint>/plugins/<ref> define a single instance of a plugin. The part <ref> will be used as name by which this plugin instance will be referenced later. The name may be arbitrary, but it must not be backend. The name backend is reserved for the backend plugin (see below).

To define a plugin instance, system:/elektra/mountpoints/<mountpoint>/plugins/<ref>/name must be set to the name of the plugin, i.e., it must be possible to open the plugin with elektraPluginOpen via this value. Optionally, the configuration keyset can be defined by the keys below system:/elektra/mountpoints/<mountpoint>/plugins/<ref>/config.

The single backend plugin is the only one that the libelektra-kdb library communicates with. It is responsible for calling other plugins when needed. A backend contract exists between this plugin and libelektra-kdb. The backend plugin alone is responsible for upholding this contract and enforcing it upon other plugins it calls.

The backend plugin is defined (like the other plugins) below system:/elektra/mountpoints/<mountpoint>/plugins. Specifically, it uses backend as <ref> and is therefore defined by the keys below system:/elektra/mountpoints/<mountpoint>/plugins/backend.

The mountpoint definition for the backend plugin is defined by the keys below system:/elektra/mountpoints/<mountpoint>/definition.

The mountpoint config is defined by the keys below system:/elektra/mountpoints/<mountpoint>/config. It is merged into the configuration keyset of every plugin of this mountpoint (including the backend plugin). Specifically, the mountpoint config is put into the user:/ namespace, while the config from system:/elektra/mountpoints/<mountpoint>/plugins/<ref>/config is put into the dir:/ namespace of the keyset passed to a plugin.

Additionally, the config/needs config from plugins' contract is moved to system:/. This config is not stored in system:/elektra/mountpoints and instead loaded at runtime by libelektra-kdb during the open operation.

This leaves the default:/ namespace for plugins to add their own defaults before calling ksLookup to access the config keyset.

Note: This mountpoint definition is separate from the normal configuration keyset passed to a plugin. The backend plugin may still have such a keyset below its system:/elektra/mountpoints/<mountpoint>/plugins/<ref>/config key. The difference between these two keyset is that the configuration keyset should be used to define the general operation of the plugin, while the mountpoint definition should specify a mountpoint.

For example, a backend plugin could support a logging mode, in which it produces a log entry every time it calls another plugin. This should be configured in the configuration keyset not in the mountpoint definition, since it doesn't change how the mountpoint works.

Additionally, the config of a plugin is always processed for all mountpoints, no matter if the mountpoint is actually accessed or the plugin actually used. This is because config is processed during the open operation, which doesn't know what parts of the whole KDB are needed for the current application. The mountpoint definition meanwhile is only processed for the mountpoints that are actually accessed. In this case the processing happens during the first get operation (within an application) that uses this mountpoint.

All other keys below system:/elektra/mountpoints/<mountpoint> are ignored.

To illustrate this structure, here is an example configuration:

# List of plugins with their config
system:/elektra/mountpoints/\/hosts/plugins/resolver/name (="resolver_fm_hpu_b")
system:/elektra/mountpoints/\/hosts/plugins/myglob/name (="glob")
system:/elektra/mountpoints/\/hosts/plugins/myglob/config/set/#0
system:/elektra/mountpoints/\/hosts/plugins/myglob/config/set/#1
system:/elektra/mountpoints/\/hosts/plugins/myglob/config/set/#2
system:/elektra/mountpoints/\/hosts/plugins/myglob/config/set/#3
system:/elektra/mountpoints/\/hosts/plugins/myglob/config/set/#4/flags
system:/elektra/mountpoints/\/hosts/plugins/store/name (="hosts")
system:/elektra/mountpoints/\/hosts/plugins/sync/name (="sync")
system:/elektra/mountpoints/\/hosts/plugins/error/name (="error")
system:/elektra/mountpoints/\/hosts/plugins/network/name (="network")
## part of the list of plugins, but also defines backend plugin
system:/elektra/mountpoints/\/hosts/plugins/backend/name (="backend")
# Configuration for backend plugin
system:/elektra/mountpoints/\/hosts/definition/path (="myhosts")
system:/elektra/mountpoints/\/hosts/definition/positions/get/resolver (="resolver")
system:/elektra/mountpoints/\/hosts/definition/positions/get/storage (="store")
system:/elektra/mountpoints/\/hosts/definition/positions/get/poststorage/#0 (="myglob")
system:/elektra/mountpoints/\/hosts/definition/positions/set/resolver (="resolver")
system:/elektra/mountpoints/\/hosts/definition/positions/set/prestorage/#0 (="myglob")
system:/elektra/mountpoints/\/hosts/definition/positions/set/prestorage/#1 (="error")
system:/elektra/mountpoints/\/hosts/definition/positions/set/prestorage/#2 (="network")
system:/elektra/mountpoints/\/hosts/definition/positions/set/storage (="store")
system:/elektra/mountpoints/\/hosts/definition/positions/set/precommit/#0 (="sync")
system:/elektra/mountpoints/\/hosts/definition/positions/set/commit (="resolver")
system:/elektra/mountpoints/\/hosts/definition/positions/set/rollback (="resolver")
# Everything else below system:/elektra/mountpoints/\/hosts is ignored

Explanation:

  • This configures a mountpoint /hosts that loads the plugins resolver_fm_hpu_b, glob, hosts, sync, error, network and backend. The plugin glob also has some configuration keys defined.
  • The backend plugin is set as the backend plugin.
  • The rest is the mountpoint definition specific to the backend plugin.

As you can see from this example, the "positions" are part of the plugin-specific mountpoint definition. This allows different backend plugins to use different "positions".

For example, there is the version backend plugin that always just provides a few keys with version information for Elektra. It doesn't need to call any other plugins and requires no configuration at all. A mountpoint with this plugin could look like this:

system:/elektra/mountpoints/\/version/plugins/backend/name (="version")

Note: The above example, is also the minimal setup for a mountpoint. The key system:/elektra/mountpoints/<mountpoint>/plugins/backend/name is the only one that must be defined.

Operations and Phases

See KDB Operations Documentation for a description of operations and phases.

In each of the phases of a get or set operation, the corresponding function of the backend plugin is called. For a description of how this works exactly read the Backend Plugins Documentation.

In the first example above, the phases were mapped one-to-one to what the plugin backend called "positions". The different terms are very much intentional, since this not a requirement.

Further Examples

We already had two examples above. Here we will look at a few more.

# List of plugins with their config
system:/elektra/mountpoints/\/hosts/plugins/resolver/name (="resolver_fm_hpu_b")
system:/elektra/mountpoints/\/hosts/plugins/glob/name (="glob")
system:/elektra/mountpoints/\/hosts/plugins/glob/config/set/#0
system:/elektra/mountpoints/\/hosts/plugins/glob/config/set/#1
system:/elektra/mountpoints/\/hosts/plugins/glob/config/set/#2
system:/elektra/mountpoints/\/hosts/plugins/glob/config/set/#3
system:/elektra/mountpoints/\/hosts/plugins/glob/config/set/#4/flags
system:/elektra/mountpoints/\/hosts/plugins/hosts/name (="hosts")
system:/elektra/mountpoints/\/hosts/plugins/sync/name (="sync")
system:/elektra/mountpoints/\/hosts/plugins/network/name (="network")
# Define backend plugin
system:/elektra/mountpoints/\/hosts/backend/name (="other_backend")
# Configuration for backend plugin
system:/elektra/mountpoints/\/hosts/definition/path (="myhosts")
system:/elektra/mountpoints/\/hosts/definition/positions/get/resolver = (="resolver")
system:/elektra/mountpoints/\/hosts/definition/positions/get/storage = (="hosts")
system:/elektra/mountpoints/\/hosts/definition/positions/get/validation/#0 (="glob")
system:/elektra/mountpoints/\/hosts/definition/positions/set/resolver = (="resolver")
system:/elektra/mountpoints/\/hosts/definition/positions/set/validation/#0 = (="glob")
system:/elektra/mountpoints/\/hosts/definition/positions/set/validation/#1 = (="network")
system:/elektra/mountpoints/\/hosts/definition/positions/set/storage = (="hosts")
system:/elektra/mountpoints/\/hosts/definition/positions/set/precommit/#0 = (="sync")
system:/elektra/mountpoints/\/hosts/definition/positions/set/commit = (="resolver")
system:/elektra/mountpoints/\/hosts/definition/positions/set/rollback (="resolver")

This example is very similar to the first one, but the plugin other_backend doesn't use the postorage and prestorage "positions". Instead, there is a validation position that is (presumably) called in the appropriate phase. The plugin other_backend may also impose its own restrictions on plugins configured for the validation position. For example, it may define that such plugins must not generate, remove or modify keys and provide a different position for plugins that do so.

system:/elektra/mountpoints/\/hosts/plugins/network/name (="network")
system:/elektra/mountpoints/\/hosts/plugins/backend/name (="db_backend")
system:/elektra/mountpoints/\/hosts/definition/db/driver (="postgres")
system:/elektra/mountpoints/\/hosts/definition/db/server (="127.0.0.1")
system:/elektra/mountpoints/\/hosts/definition/db/port (="5432")
system:/elektra/mountpoints/\/hosts/definition/db/user (="admin")
system:/elektra/mountpoints/\/hosts/definition/db/password (="supersecret")
system:/elektra/mountpoints/\/hosts/definition/phases/set/prestorage/#0 (="network")

This example shows an entirely different type of backend. The hypothetical db_backend is backed by a database. In this case it is configured for a PostgreSQL database running on 127.0.0.1:5432 to which we connect as user admin.

We also configured the network plugin to run in the prestorage phase of the set operation. Which phases can be used and how they must be configured of course depends on db_backend.

system:/elektra/mountpoints/\/hosts/plugins/yajl/name (="yajl")
system:/elektra/mountpoints/\/hosts/plugins/backend/name (="http_backend")
system:/elektra/mountpoints/\/hosts/url (="https://api.ipify.org/?format=JSON")
system:/elektra/mountpoints/\/hosts/decoder (="yajl")

The hypothetical http_backend plugin is a read-only backend plugin. In the example above, it is configured to load the URL https://api.ipify.org/?format=JSON and use the yajl plugin to parse the result into a keyset. Both the HTTP request and the decoding would likely happen in the storage phase of the get operation. The resolver phase could perform an HTTP cache check, for example.