Component Configuration

Configuration of the cobald.daemon is performed at startup via one of two methods: a YAML file or Python code. While the former is more structured and easier to verify, the latter allows for greater freedom.

The configuration file is the only positional argument when launching the cobald.daemon. The file extension determines the type of configuration interface to use - .py for Python files and .yaml for YAML files.

$ python3 -m cobald.daemon /etc/cobald/config.yaml
$ python3 -m cobald.daemon /etc/cobald/config.py

The YAML Interface

The top level of a YAML configuration file is a mapping with two sections: the pipeline section setting up a pool control pipeline, and the logging section setting up the logging facilities. The logging section is optional and follows the standard configuration dictionary schema. [1]

The pipeline section must contain a sequence of Controllers, Decorators and Pools. Each pipeline is constructed in reverse order: the last element should be a Pool and is constructed first, then recursively passed to its predecessor for construction.

# pool becomes the target of the controller
pipeline:
    - !LinearController
      low_utilisation: 0.9
      high_utilisation: 1.1
    - !CpuPool
      interval: 1

Object References

YAML configurations support !! tag and ! constructor syntax. These allow to use arbitrary Python objects and registered plugins, respectively. Both support keyword and positional arguments.

# generic python tag for arbitrary objects
!!python/object:cobald.controller.linear.LinearController {low_utilisation: 0.9}
# constructor tag for registered plugin
!LinearController
low_utilisation: 0.9

Added in version 0.9.3.

Note

The YAML configuration is read using yaml.SafeLoader to avoid arbitrary code execution. Objects must be marked as safe for loading, either as COBalD plugins or using PyYAML directly.

A legacy format using explicit type references is available, but discouraged. This uses an invocation mechanism that can use arbitrary callables to construct objects: each mapping with a __type__ key is invoked with its items as keyword arguments, and the optional __args__ as positional arguments.

pipeline:
    # same as ``package.module.callable(a, b, keyword1="one", keyword2="two")
    - __type__: package.module.callable
      __args__:
        - a
        - b
      keyword1: one
      keyword2: two

Deprecated since version 0.9.3: Use YAML tags and constructors instead.

Python Code Inclusion

Python configuration files are loaded like regular modules. This allows to define arbitrary types and functions, and directly chain components or configure logging. At least one pipeline of Controllers, Decorators and Pools should be instantiated.

from cobald.controller.linear import LinearController

from cobald_demo.cpu_pool import CpuPool
from cobald_demo.draw_line import DrawLineHook

pipeline = LinearController.s(
    low_utilisation=0.9, high_allocation=1.1
) >> CpuPool()

As regular modules, Python configurations must explicitly import the components they use. In addition, everything not bound to a name will be garbage collected. This allows configurations to use temporary objects, e.g. reading from files or sockets, but means persistent objects (such as a pipeline) must be bound to a name.