Technical proposal

Technical proposal

The idea behind chantico is to use the kubernetes control plane as a basis to have a fully declarative approach to the energy domain control. To make this happen Chantico is built as a kubernetes controller operating over a set custom resources.

Aside from the controller, additional components are deployed to provide a complete solution for the energy domain. The components can be enabled or disabled during installation.

Components

chantico-filebrowser

The chantico-filebrowser is a kubernetes deployment living in the chantico namespace. It hosts a File Browser instance that allows to add configuration files via drag and drop (e.g. uploading MIB files for the registration of a PDU).

chantico-snmp

The chantico-snmp is a kubernetes deployment living in the chantico namespace. It hosts a Prometheus SNMP Exporter instance that query devices using the SNMP format and exposes a prometheus compatible format.

chantico-prometheus

The chantico-snmp is a kubernetes service living in the chantico namespace. It hosts a Prometheus deployment that scrapes devices via chantico-snmp.

chantico-victoriametrics

The chantico-victoriametrics is a kubernetes service living in the chantico namespace. It hosts a VictoriaMetrics instance that stores the metrics scraped by chantico-prometheus for long-term retention.

chantico-grafana

The chantico-grafana is a kubernetes service living in the chantico namespace. It hosts a Grafana instance that allows to visualize the metrics stored in chantico-prometheus and chantico-victoriametrics to provide a user-facing dashboard for reporting and analysis of the metrics out of the energy domain.

Technical choices

The backbone of chantico was implemented using operator-sdk.

Documentation

This repository aims to be stand-alone. This is why we use plantuml to write diagrams, as its text-based approach allows to store directly in this repository and iterate over design with gitlab project management tooling (issues, merge requests…)

Programming language

To seamlessly interoperate with kubernetes the go programming language was chosen.

That does not work on my machine

To avoid the “it does not work” on my machine, consider using nix-flake to set-up your development environment. Although this is not strictly required this is encouraged to work on the project.

Testing

Philosophy

Chantico is designed to serve as the glue between many components that run on and depend on Kubernetes. Because of this, integration and end-to-end testing can be costly and significantly slow down the development cycle, due to long-running CI jobs and the complexity of setting up a proper development environment.

To address bugs that go beyond the scope of unit testing, we aim to invest in robust automatic logging that will be explained in its own section.

To keep testing lightweight and efficient, we follow these rules regarding what is allowed and disallowed in tests:

Allowed in tests:

  • Creation of temporary directories and files
  • Mocking the Kubernetes client
  • Modifying OS environment variables

Disallowed in tests:

  • Spinning up a Kubernetes instance
  • Spinning up service instances

Table-Driven Testing

In line with Go’s philosophy of simplicity, we use the standard testing package from the Go library. When appropriate, we design tests using table-driven testing, following this format:

func TestInitializeFinalizer(t *testing.T) {
    testCases := map[string]struct {
        Case     *chantico.MeasurementDevice
        Expected []string
    }{
        "empty finalizer": {
            Case: &chantico.MeasurementDevice{
                ObjectMeta: metav1.ObjectMeta{
                    Finalizers: []string{},
                }},
            Expected: []string{chantico.SNMPUpdateFinalizer},
        },
        "already initialized": {
            Case: &chantico.MeasurementDevice{
                ObjectMeta: metav1.ObjectMeta{
                    Finalizers: []string{"test"},
                }},
            Expected: []string{"test", chantico.SNMPUpdateFinalizer},
        },
    }

    for name, tc := range testCases {
        t.Run(name, func(t *testing.T) {
            InitializeFinalizer(tc.Case, nil)
            if !equalStringSlices(tc.Expected, tc.Case.ObjectMeta.Finalizers) {
                t.Errorf("InitializeFinalizer(%#v) = %#v, want %#v\n", tc, tc.Case.ObjectMeta.Finalizers, tc.Expected)
            }
        })
    }
}

Running the tests

To run the tests just launch the following command:

 go test -v ./internal/...

Logging

Coming soon.

CI/CD

We use GitHub CI to build Docker images for Chantico components, including the manager and SNMP mock. Additionally, formatting, tests and coverage are run. Pages are also deployed via GitHub CI.