//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

=== Configuration

==== Environment Variables & System Properties

Apache Karaf uses default configuration properties location in `etc` folder (`KARAF_ETC`).

You can override any configuration using either environment variables or system properties.

Basically, Apache Karaf is looking for property in env and system properties.

You can use `PID_PROPERTY=VALUE` syntax for environment variable and `pid.property=value` for system properties.

For instance, the following statement will override value `sshPort` in `etc/org.apache.karaf.shell.cfg`:

```
# environment variable
export ORG_APACHE_KARAF_SHELL_SSHPORT=8102
```

```
# system property
-Dorg.apache.karaf.shell.sshPort=8102
```

You can override any configuration property using this mechanism.

It's possible to "append" a new value based on the content of a configuration property.
For instance, you want to add a new features repository to the default value (define the `etc/org.apache.karaf.features.cfg` config file `featuresRepositories` property.
You can use the following env variable:

----
export ORG_APACHE_KARAF_FEATURES_FEATURESREPOSITORIES='${featuresRepositories},mvn:org.apache.karaf.decanter/apache-karaf-decanter/2.5.0/xml/features'
----

It means that Karaf will take value of `featuresRepositories` property contained in the `etc/org.apache.karaf.features.cfg` configuration file and add
`mvn:org.apache.karaf.decanter/apache-karaf-decanter/2.5.0/xml/features`.

==== Files

Apache Karaf stores and loads all configuration in files located in the `etc` folder.

By default, the `etc` folder is relative to the `KARAF_BASE` folder. You can define another location
using the `KARAF_ETC` variable.

Each configuration is identified by a ID (the ConfigAdmin PID). The configuration file names follow the `pid.cfg`
name convention.

For instance, `etc/org.apache.karaf.shell.cfg` means that this file is the file used by the configuration with
`org.apache.karaf.shell` as PID.

A configuration file is a properties file containing key/value pairs:

----
property=value
----

Properties can be referenced inside configuration files using the syntax `${<name>}`. Default and alternate
values can be specified using `${<name>:-<default_value>}` and `${<name>:+<alternate_value>}` syntaxes respectively.

----
existing_property=baz
property1=${missing_property:-foo}   # "foo"
property2=${missing_property:+foo}   # empty string
property3=${existing_property:-bar}  # "baz"
property4=${existing_property:+bar}  # "bar"
----

Apache Karaf will look for system property as well. For instance, the following:

----
key=${foo}
----

means that `key` will contain `bar` if you start Karaf with `-Dfoo=bar`.

Environment variables can be referenced inside configuration files using the syntax `${env:<name>}` (e.g.
`property=${env:FOO}` will set "property" to the value of the enviroment variable "FOO"). Default and alternate
values can be defined for them as well using the same syntax as above.

Apache Karaf also supports other syntax, supporting:

* files on disk, for example to be used with Kubernetes secrets
* environment variables
* properties defined in `etc/config.properties`
* system properties

===== Secret Files

Usually secrets (for example when provided by Kubernetes) will surface as files in a location.
By default, the location is `etc` folder. However, you can point to any folder. The configuration
is located in `etc/config.properties`:

----
org.apache.felix.configadmin.plugin.interpolation.secretsdir=${karaf.etc}
----

The file contents are opaque and contain the secret value as-is. To use content of a secret file in a
configuration property, you can do:

----
user=my-user
password=$[secret:db.password]
----

The content of `etc/db.password` will by used as value for `password` property.

===== Environment variables

Exactly the same as `${env:USER}`, you can use `$[env:USER]` syntax in a property:

----
greeting="Hello $[env:USER]"
----

With this syntax, default value is passed like this:

----
greeting="Hello $[env:USER;default=John]"
----

It's also possible to define the type of the property:

----
port=$[env:PORT;type=Integer]
----

===== System properties

System property can be passed with `-Dfoo=bar` to the Karaf process or define in `etc/config.properties`.

You can use these properties using the following syntax:

----
port=$[prop:my.port;default=8080]
----

===== cfg files

In Apache Karaf, a configuration is a PID with a set of properties attached.

Apache Karaf automatically loads all `*.cfg` files from the `etc` folder.

You can configure the behaviour of the configuration files using some dedicated properties in the
`etc/config.properties` configuration file:

----
...
#
# Configuration FileMonitor properties
#
felix.fileinstall.enableConfigSave = true
felix.fileinstall.dir    = ${karaf.etc}
felix.fileinstall.filter = .*\\.(cfg|config)
felix.fileinstall.poll   = 1000
felix.fileinstall.noInitialDelay = true
felix.fileinstall.log.level = 3
felix.fileinstall.log.default = jul
...
----

* `felix.fileinstall.enableConfigSave` flush back in the configuration file the changes performed directly on the
configuration service (ConfigAdmin). If `true`, any change (using `config:*` commands, MBeans, OSGi service) is
persisted back in the configuration false. Default is `true`.
* `felix.fileinstall.dir` is the directory where Apache Karaf is looking for configuration files. Default is `${karaf.etc}`
meaning the value of the `KARAF_ETC` variable.
* `felix.fileinstall.filter` is the file name pattern used to load only some configuration files. Only files matching
the pattern will be loaded. Default value is `.*\\.(cfg|config)` meaning *.cfg and *.config files.
* `felix.fileinstall.poll` is the polling interval (in milliseconds). Default value is `1000` meaning that Apache
Karaf "re-loads" the configuration files every second.
* `felix.fileinstall.noInitialDelay` is a flag indicating if the configuration file polling starts as soon as Apache
Karaf starts or wait for a certain time. If `true`, Apache Karaf polls the configuration files as soon as the configuration
service starts.
* `felix.fileinstall.log.level` is the log message verbosity level of the configuration polling service. The
higher this value, the more verbose the configuration service is.
* `felix.fileinstall.log.default` is the logging framework to use, `jul` meaning Java Util Logging.

You can change the configuration at runtime by directly editing the configuration file.

You can also do the same using the `config:*` commands or the ConfigMBean.

Apache Karaf persists configuration using its own persistence manager in the case of when available persistence managers do not support that.
Configuration files are placed by default in `KARAF_ETC`, but it could be overridden via variable `storage` in `etc/org.apache.karaf.config.cfg`.
If you want to disable the Karaf persistence manager, set the storage variable to an empty string (`storage=`).

==== `config:*` commands

Apache Karaf provides a set of commands to manage the configuration.

===== `config:list`

`config:list` displays the list of all configurations available, or the properties in a given configuration (PID).

Without the `query` argument, the `config:list` command display all configurations, with PID, attached bundle and
properties defined in the configuration:

----
karaf@root()> config:list
----------------------------------------------------------------
Pid:            org.apache.karaf.service.acl.command.system.start-level
BundleLocation: mvn:org.apache.karaf.shell/org.apache.karaf.shell.console/4.0.0
Properties:
   service.guard = (&(osgi.command.scope=system)(osgi.command.function=start-level))
   * = *
   start-level = admin                           # admin can set any start level, including < 100
   start-level[/[^0-9]*/] = viewer               # viewer can obtain the current start level
   execute[/.*/,/[^0-9]*/] = viewer               # viewer can obtain the current start level
   execute = admin                           # admin can set any start level, including < 100
   service.pid = org.apache.karaf.service.acl.command.system.start-level
   start-level[/.*[0-9][0-9][0-9]+.*/] = manager # manager can set startlevels above 100
   execute[/.*/,/.*[0-9][0-9][0-9]+.*/] = manager # manager can set startlevels above 100
----------------------------------------------------------------
Pid:            org.apache.karaf.log
BundleLocation: mvn:org.apache.karaf.log/org.apache.karaf.log.core/4.0.0
Properties:
   service.pid = org.apache.karaf.log
   size = 500
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
...
----

The `query` argument accepts a query using a LDAP syntax.

For instance, you can display details on one specific configuration using the following filter:

----
karaf@root()> config:list "(service.pid=org.apache.karaf.log)"
----------------------------------------------------------------
Pid:            org.apache.karaf.log
BundleLocation: mvn:org.apache.karaf.log/org.apache.karaf.log.core/4.0.0
Properties:
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   service.pid = org.apache.karaf.log
   size = 500
----

===== `config:edit`

`config:edit` is the first command to do when you want to change a configuration. `config:edit` command put you
in edit mode for a given configuration.

For instance, you can edit the `org.apache.karaf.log` configuration:

----
karaf@root()> config:edit org.apache.karaf.log
----

The `config:edit` command doesn't display anything, it just puts you in configuration edit mode. You are now ready
to use other config commands (like `config:property-append`, `config:property-delete`, `config:property-set`, ...).

If you provide a configuration PID that doesn't exist yet, Apache Karaf will create a new configuration (and so a new
configuration file) automatically.

All changes that you do in configuration edit mode are stored in your console session: the changes are not directly
applied in the configuration. It allows you to "commit" the changes (see `config:update` command) or "rollback" and
cancel your changes (see `config:cancel` command).

===== `config:property-list`

The `config:property-list` lists the properties for the currently edited configuration.

Assuming that you edited the `org.apache.karaf.log` configuration, you can do:

----
karaf@root()> config:property-list
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   service.pid = org.apache.karaf.log
   size = 500
----

===== `config:property-set`

The `config:property-set` command updates the value of a given property in the currently edited configuration.

For instance, to change the value of the `size` property of the previously edited `org.apache.karaf.log` configuration,
you can do:

----
karaf@root()> config:property-set size 1000
karaf@root()> config:property-list
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   service.pid = org.apache.karaf.log
   size = 1000
----

If the property doesn't exist, the `config:property-set` command creates the property.

You can use `config:property-set` command outside the configuration edit mode, by specifying the `-p` (for configuration pid) option:

----
karaf@root()> config:property-set -p org.apache.karaf.log size 1000
karaf@root()> config:list "(service.pid=org.apache.karaf.log)"
----------------------------------------------------------------
Pid:            org.apache.karaf.log
BundleLocation: mvn:org.apache.karaf.log/org.apache.karaf.log.core/4.0.0
Properties:
   service.pid = org.apache.karaf.log
   size = 1000
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
----

[NOTE]
====
Using the `pid` option, you bypass the configuration commit and rollback mechanism.
====

===== `config:property-append`

The `config:property-append` is similar to `config:property-set` command, but instead of completely replacing the
property value, it appends a string at the end of the property value.

For instance, to add 1 at the end of the value of the `size` property in `org.apache.karaf.log` configuration
(and so have 5001 for the value instead of 500), you can do:

----
karaf@root()> config:property-append size 1
karaf@root()> config:property-list
   service.pid = org.apache.karaf.log
   size = 5001
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
----

Like the `config:property-set` command, if the property doesn't exist, the `config:property-set` command creates
the property.

You can use the `config:property-append` command outside the configuration edit mode, by specifying the `-p` (for configuration pid) option:

----
karaf@root()> config:property-append -p org.apache.karaf.log size 1
karaf@root()> config:list "(service.pid=org.apache.karaf.log)"
----------------------------------------------------------------
Pid:            org.apache.karaf.log
BundleLocation: mvn:org.apache.karaf.log/org.apache.karaf.log.core/4.0.0
Properties:
   service.pid = org.apache.karaf.log
   size = 5001
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
----

[NOTE]
====
Using the `pid` option, you bypass the configuration commit and rollback mechanism.
====

===== `config:property-delete`

The `config:property-delete` command deletes a property in the currently edited configuration.

For instance, you previously added a `test` property in `org.apache.karaf.log` configuration. To delete this `test`
property, you do:

----
karaf@root()> config:property-set test test
karaf@root()> config:property-list
   service.pid = org.apache.karaf.log
   size = 500
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
   test = test
karaf@root()> config:property-delete test
karaf@root()> config:property-list
   service.pid = org.apache.karaf.log
   size = 500
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
----

You can use the `config:property-delete` command outside the configuration edit mode, by specifying the `-p` (for configuration pid) option:

----
karaf@root()> config:property-delete -p org.apache.karaf.log test
----

===== `config:update` and `config:cancel`

When you are in the configuration edit mode, all changes that you do using `config:property*` commands are stored in "memory"
(actually in the console session).

Thanks to that, you can "commit" your changes using the `config:update` command. The `config:update` command will
commit your changes, update the configuration, and (if possible) update the configuration files.

For instance, after changing `org.apache.karaf.log` configuration with some `config:property*` commands, you have
to commit your change like this:

----
karaf@root()> config:edit org.apache.karaf.log
karaf@root()> config:property-set test test
karaf@root()> config:update
karaf@root()> config:list "(service.pid=org.apache.karaf.log)"
----------------------------------------------------------------
Pid:            org.apache.karaf.log
BundleLocation: mvn:org.apache.karaf.log/org.apache.karaf.log.core/4.0.0
Properties:
   service.pid = org.apache.karaf.log
   size = 500
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
   test = test
----

On the other hand, if you want to "rollback" your changes, you can use the `config:cancel` command. It will cancel all
changes that you did, and return to the configuration state just before the `config:edit` command. The `config:cancel`
exits from the edit mode.

For instance, you added the test property in the `org.apache.karaf.log` configuration, but it was a mistake:

----
karaf@root()> config:edit org.apache.karaf.log
karaf@root()> config:property-set test test
karaf@root()> config:cancel
karaf@root()> config:list "(service.pid=org.apache.karaf.log)"
----------------------------------------------------------------
Pid:            org.apache.karaf.log
BundleLocation: mvn:org.apache.karaf.log/org.apache.karaf.log.core/4.0.0
Properties:
   service.pid = org.apache.karaf.log
   size = 500
   pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
   felix.fileinstall.filename = file:/opt/apache-karaf-4.0.0/etc/org.apache.karaf.log.cfg
----

===== `config:delete`

The `config:delete` command completely deletes an existing configuration. You don't have to be in edit mode to delete
a configuration.

For instance, you added `my.config` configuration:

----
karaf@root()> config:edit my.config
karaf@root()> config:property-set test test
karaf@root()> config:update
karaf@root()> config:list "(service.pid=my.config)"
----------------------------------------------------------------
Pid:            my.config
BundleLocation: null
Properties:
   service.pid = my.config
   test = test
----

You can delete the `my.config` configuration (including all properties in the configuration) using the `config:delete`
command:

----
karaf@root()> config:delete my.config
karaf@root()> config:list "(service.pid=my.config)"
karaf@root()>
----

===== `config:meta`

The `config:meta` command lists the meta type information related to a given configuration.

It allows you to get details about the configuration properties: key, name, type, default value, and description:

----
karaf@root()> config:meta -p org.apache.karaf.log
Meta type informations for pid: org.apache.karaf.log
key     | name    | type   | default                                                              | description
---------------------------------------------------------------------------------------------------------------------------------------
size    | Size    | int    | 500                                                                  | size of the log to keep in memory
pattern | Pattern | String | %d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n | Pattern used to display log entries
---- 

==== JMX ConfigMBean

On the JMX layer, you have a MBean dedicated to the management of the configurations: the ConfigMBean.

The ConfigMBean object name is: `org.apache.karaf:type=config,name=*`.

===== Attributes

The `Configs` attribute is a list of all configuration PIDs.

===== Operations

* `listProperties(pid)` returns the list of properties (property=value formatted) for the configuration `pid`.
* `deleteProperty(pid, property)` deletes the `property` from the configuration `pid`.
* `appendProperty(pid, property, value)` appends `value` at the end of the value of the `property` of the configuration `pid`.
* `setProperty(pid, property, value)` sets `value` for the value of the `property` of the configuration `pid`.
* `delete(pid)` deletes the configuration identified by the `pid`.
* `create(pid)` creates an empty (without any property) configuration with `pid`.
* `update(pid, properties)` updates a configuration identified with `pid` with the provided `properties` map.

