ConfigCascade

From Open-Xchange

Introduction to the config cascade

The config cascade is a configuration system that allows administrators to selectively override configuration parameters on context and user level. This means a configuration option can vary between groups of contexts, specific contexts or users.

Who should read this document?

If you are tasked with designing and maintaining the configuration of an OX server or cluster, information contained in this document will acquaint you with options in OX configuration design.

Core Concepts - Configuration Scope

The config cascade differentiates between 4 scopes of configuration: Server, ContextSet, Context and User, with the latter always overriding the configuration of the one before it. To determine the active value of a certain parameter, the config cascade looks whether the parameter is defined in a certain scope before falling back to the next scope to the left to determine if a value is defined there. This means, that a value in the User scope can override the more general value from the Context scope, which in turn overrides the value of a context set configuration, which itself overrides a server wide configuration.

Core Concepts - Context Taxonomy

When deciding on configuration options it usually makes sense to group contexts according to a certain criterion. Typical uses would be to group contexts by offering (webmail, groupware_standard, groupware_plus), or country (de, fr, es) or brand (coolhosting, supremehosting) or if they are part of a "friendly users" group you sometimes give access to features to deem whether they are appropriate for rollout (beta). You can then specify configuration options that only take effect if a context is part of one of these groups. For example, the default hostname varies by both country and brand, with the french coolhosting domain name being "coolhosting.fr", while the spanish one is "coolhosting.es", or, for the second brand "supremehosting.fr" or "supremehosting.es" respectively. How can you go about classifying a context?

Using the command line tools you can specifiy the taxonomy/types parameter:

createcontext ... -i 12 --taxonomy/types=webmail,coolhosting,de

which would tag context 12 with the types webmail, coolhosting and de. This is also available in "changecontext". In RMI the equivalent is to call Context#setUserAttribute("taxonomy", "types", "webmail,coolhosting,de"). We will later see how configuration options can be specified for these types of contexts.

Specifying Configuration - Server Scope

The most general scope is the Server scope. Every value that can be overridden along the config cascade should also be defined with a default value in the Server scope. This is done using the usual configuration methods of the server: .properties files in the config directory (usually /opt/openexchange/etc, or /opt/openexchange/etc/groupware in versions up to 6.20.7). Let's consider the properties "com.openexchange.messaging.facebook", which governs whether facebook messaging should be available in a given installation. Since we consider this to be a premium feature, we'll disable this on the server level:

 facebookmessaging.properties:
 com.openexchange.messaging.facebook=false

Later we will see how to enable it for certain groups of contexts.

Specifying Configuration - Context Set Scope

As we saw, you can classify contexts into groups. These groups will now be used to specify certain configuration options. Let's consider this setup:


 Context 12: webmail,de,beta
 Context 13: groupware_plus,es
 Context 14: groupware_plus,fr,beta


Let's say, we want to roll out the facebook functionality to those contexts, that have the groupware_plus product and are part of our "friendly users". For this, you can specify a configuration that overrides the server setting like this:

Create a file called /opt/openexchange/etc/contextSets/messaging.yml and add the following block:

  experimental_gw_plus:
      withTags: groupware_plus & beta
      com.openexchange.messaging.facebook: true

Let's go through this line by line. The first line introduces a configuration block that will be used for certain contexts. The name doesn't matter, only insofar as that it may only be used once per file. Choose a good mnemonic here, so a future you or someone else can guess at what is going on in this configuration block.

The second line specifies the criterion to use to find out whether a context belongs in this group of contexts. In this case, a context having both the groupware_plus and beta tags will be considered to be a part of this group. In the withTags expression you can use boolean logic (with & for and, | for or and brackets to group the expressions). It's best to not go overboard with this, though. If the boolean expressions here become too complex it's usually an indication that you could use another classification for the contexts. Which tags does a context have? Firstly, and most obviously, those specified as its taxonomy/types list. But that is not the whole story. The /users/ module access permissions are also transformed into tags and applied to the context (at runtime). So if a user has access to the tasks module and the infostore module, the context will be considered to be tagged with ucTask and ucInfostore as well. This is sometimes enough to determine if a context is part of a certain offering, but more explicit tagging of contexts according to the offering keeps things readable. Lastly the configuration parameter "com.openexchange.config.cascade.types" (which is itself config cascade enabled) adds its value to the tag list, so, for example:

  friendly_users:
      withTags: groupware_plus & beta
      com.openexchange.config.cascade.types: friendly_and_paying

Would add the friendly_and_paying tag to all contexts already classified as groupware_plus and beta. Also since this value can also be specified on user level, you could classify users irrespective of their contexts, should the need arise.

The third line then specifies the setting to override. You can specify all properties to override in this block, so if we wanted to enable both facebook and twitter messaging for these contexts, we'd use the following configuration:

  experimental_gw_plus:
      withTags: groupware_plus & beta
      com.openexchange.messaging.facebook: true
      com.openexchange.messaging.twitter: true

Most configuration use cases can probably be handled with the context sets system. Only if a configuration is truly unique for just one context or user should the other options be pursued.

Specifying Configuration - Context Scope and User Scope

Configuration options can be overridden on user and context level, using a dynamic property. For example:

$ createcontext [...] --config/com.openexchange.messaging.facebook=true
$ changecontext [...] --config/com.openexchange.messaging.facebook=true

$ createuser [...] --config/com.openexchange.messaging.facebook=true
$ changeuser [...] --config/com.openexchange.messaging.facebook=true

Depending on the number of users and contexts in your system, this could pose a problem further down the road when you need to update this value for a large number of users.

UI Properties

A common use case for the OX configuration system is to allow fine-tuning of the UI by providing configuration data on the backend. All properties defined in properties files below /opt/open-xchange/etc/groupware/settings are transported to the UI and are config cascade enabled. So every customization you can specify for the UI using these settings, can also be selectively overridden with the config cascade.

Since the config cascade only overrides existing settings, whether a property is a UI property or a server property is automatically determined by the directory in which the corresponding .properties file is found. For example if /opt/open-xchange/etc/settings/appsuite.properties contains the setting

io.ox/core//theme=default

Then you can overwrite it for any context (or user, context set, etc.):

$ changecontext [...] --config/io.ox/core//theme=org.example.theme

Further Reading

ConfigCascadeCookbook - Collects typical configuration scenarios and how to handle them using the config cascade.