Constellation Preview Release 0.8#

We are happy to announce the release of Constellation version 0.8, named Caelum. This is a the last release before version 1.0 and includes the last required breaking changes for the satellite API.

Breaking Changes for Operators#

None

Breaking Changes for Application Developers#

Programs written for previous versions of Constellation may not compatible with this version due to the breaking changes in the monitoring and command API in Python.

Metric Registration (Python)#

The monitoring API has been reworked to also allow for registering non-scheduled metrics. As part of this change the methods to register and reset metrics have been slightly adjusted.

Previously:

self.reset_scheduled_metrics()
self.schedule_metric("NAME", "unit", interval, self.get_metric_value)

After 0.8:

self.reset_metrics()
self.register_scheduled_metric("NAME", "unit", "description", interval, self.get_metric_value)

Command Registration (Python)#

The @cscp_requestable decorator has been adjusted to allow specifying the allowed states directly in the decorator. This requires that the decorator is now always called as a function, i.e. @cscp_requestable(). The _COMMAND_is_allowed method for specifying when a command is allowed has been removed in favor of the allowed states list. Additionally commands can now return None in order to signal that the command is currently not allowed.

Previously:

@cscp_requestable
def get_device_info(self, request: CSCP1Message) -> tuple[str, Any, dict[str, Any]]:
    ...

@cscp_requestable
def get_channel_reading(self, request: CSCP1Message) -> tuple[str, Any, dict[str, Any]]:
    ...

def _get_channel_reading_is_allowed(self, request: CSCP1Message) -> bool:
    return self.fsm.state in [SatelliteState.ORBIT, SatelliteState.RUN]

After 0.8:

@cscp_requestable()
def get_device_info(self, request: CSCP1Message) -> tuple[str, Any, dict[str, Any]]:
    ...

@cscp_requestable([SatelliteState.ORBIT, SatelliteState.RUN])
def get_channel_reading(self, request: CSCP1Message) -> tuple[str, Any, dict[str, Any]]:
    ...

Removal of the Run Identifier in do_run (Python)#

In order to align the C++ and Python satellite APIs, the run_identifier parameter has been removed from the do_run method. It is still available in do_starting or via self.run_identifier.

Previously:

    def do_run(self, run_identifier: str):
        ...

After 0.8:

    def do_run(self):
        ...

SatelliteState has been moved (Python)#

The SatelliteState enum has been moved (again) from constellation.core.message.cscp1 to constellation.core.protocol.cscp1.

Previously:

from constellation.core.message.cscp1 import SatelliteState

After 0.8:

from constellation.core.protocol.cscp1 import SatelliteState

New Features for Operators#

Python Satellite now available in Flatpak and Docker#

It is now possible to run Python satellite using Flatpak and Docker via the -t parameter. This allows for a unified deployment for example via Docker Compose or Podman Quadlets.

Running via Flatpak:

flatpak run de.desy.constellation -t Mariner -n Nine -g edda

Running via Docker:

docker run --network host \
           -it gitlab.desy.de:5555/constellation/constellation/constellation:latest \
           -t Mariner -n Nine -g edda

New Metrics#

C++ satellites now have four new metrics by default: CPU_LOAD_AVG, MEMORY_AVAIL, RUN_ID and STATE. On the Python side so far only the RUN_ID has been added, the missing metrics will be added in a future release.

Improved Python Scanning#

It is now possible to specify a telemetry condition when scanning via a Python script. This allows to scan for example until a certain number of triggers have been collected.

This requires the definition of a custom controller class inheriting from MonitoringListener as well:

# Custom controller which listens to metrics
class MyController(ScriptableController, MonitoringListener):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Subscribe to POST_VETO metric
        self.set_topics(["STAT/POST_VETO"])
        self.post_veto_triggers = 0

    def receive_metric(self, sender, metric, timestamp, value):
        if metric.name == "POST_VETO" and sender == "AidaTLU.2020":
            self.post_veto_triggers = value

With that custom controller it is then possible to wait for a telemetry condition:

# Wait until 1M triggers are collected
while ctrl.post_veto_triggers < 1000000:
    time.sleep(1)

Two additional methods have been added to the controller to help with reconfiguring. A challenge during reconfiguring is that satellite changes from the steady ORBIT state back into the ORBIT state. Using await_state can cause the controller to go ahead if the transitional reconfiguring state has not been detected yet. The new await_state_change fixes this taking a dictionary of satellites and their last state change and ensuring that they changed the state before awaiting the request state.

# Store when Sputnik.One last changed state
last_state_change = ctrl.get_last_state_change(["Sputnik.One"])

# Send reconfigure command to Sputnik.One
constellation.Sputnik.One.reconfigure(recfg)

# Wait until all states are back in the ORBIT state while ensuring Sputnik.One changed state
ctrl.await_state_change(SatelliteState.ORBIT, last_state_change)

A full example with both changes can be found in the operator guide.

New Features for Application Developers#

Emitting Metrics Manually#

Previously in Python it was only possible to emit metrics periodically. Now it is possible to emit (or β€œstat”) a metric at any time.

Non-scheduled metrics can be registered now:

self.register_metric("NAME", "unit", "description")

And the corresponding metric emitted:

self.stat("NAME", value)

It is also possible to emit scheduled metrics manually.

New get_str and get_enum Method for the Configuration#

It is possible to get strings directly without specifying the return type using get_str. There is also a new method to get enums.

For single value this can be achieved via:

config.get_enum(EnumType, "key_name", EnumType.DEFAULT_VALUE)

In a list or set, the same can be achieved via:

config.get_array("key_name", element_type=enum_type(EnumType))

Detailed Changelog#

The following changes related to satellites are included in this release:

  • MR!1071: EudaqNativeWrite: display event buffer size is kibibytes.

  • MR!1072: Mattermost: implement message sending backoff to avoid disconnects

  • MR!1075: Keithley: port to pyvisa and send metrics in each step of ramp

The following changes related to graphical user interfaces are included in this release:

  • MR!1064: Fix icons not shown under Gnome Wayland

  • MR!1059: Deactivate disallowed context menu entries in MissionControl

  • MR!1048: Fix desktop entry for TelemetryConsole opening Observatory

  • MR!1045: Fix not linking QtSvg in TelemetryConsole

The following improvements to the framework are included in this release:

  • MR!1093: Fix deadlock in data transmitter in interrupting and unrecoverable data receiver (C++)

  • MR!1092: Improve cscp_requestable and schedule_metric decorators (Python)

  • MR!1090: Implement method to wait for state change in controller (Python)

  • MR!1086: Add protocol.cscp1 module (Python)

  • MR!1085: Remove run identifier from do_run (Python)

  • MR!1082: Emit run identifier as metric in Python and increase data metric sending interval

  • MR!1079: Return error when user command throw exception instead of unknown command (C++)

  • MR!1069/MR!1087: Add get_str and get_enum method for configuration (Python)

  • MR!1063: Add CPU load average and available memory as metric (C++)

  • MR!1061: Rename files by default instead of erroring out in receiver (C++)

  • MR!1060: Check already during initializing that dependent satellites are present (C++)

  • MR!1058: Distribute state and run identifier as metric (C++)

  • MR!1057: Fix condition code handling in C++

  • MR!1054: Log WARNING instead of CRITICAL for non-allowed transitions in Python satellites

  • MR!1053: Handle more exceptions in C++ controller

  • MR!1052: Do not force lower-case keys for BOR/EOR tags in C++

  • MR!1049: Single non-list values are accepted in get_array in Python

  • MR!1046: Add possibility to load Python satellite in C++ exec API

  • MR!1012: Improve CMDP in Python and adapt monitoring API

  • MR!998: Improve quoting in C++

The following miscellaneous changes are included in this release:

  • MR!1047: Mention possibility to run Constellation under WSL on Windows in documentation

Notes#

The software is publicly available under the EUPL-1.2 from the DESY GitLab repository. In addition, the Python version is available on PyPI and the C++ version is available on Flathub for Linux.

It should be noted that this is a preview release and some interfaces and protocols might change until the first official major release.