Skip to content

Commit

Permalink
Added StartTransientUnit API to BlueChi
Browse files Browse the repository at this point in the history
Relates to: #1033

In order to provide a more complete set of systemd APIs through BlueChi
the StartTransientUnit is being added. It also added a new integration
test for the new API method.

Signed-off-by: Michael Engel <[email protected]>
  • Loading branch information
engelmi committed Jan 29, 2025
1 parent 76b3da6 commit 3d8f3c8
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 0 deletions.
19 changes: 19 additions & 0 deletions data/org.eclipse.bluechi.Node.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,25 @@
<arg name="job" type="o" direction="out" />
</method>

<!--
StartTransientUnit:
@name: The name of the transient unit to start, incl. suffix such as .service
@mode: The mode used to start the unit
@props: List of key-value pairs of the systemd unit, e.g. ExecStart=/bin/true
@aux: Currently unused in systemd. Pass an empty list to it.
@job: The path for the job associated with the start operation
StartTransientUnit may be used to create and start a transient unit, which will be released as soon as it is not running or referenced anymore or the
system is rebooted.
-->
<method name="StartTransientUnit">
<arg name="name" type="s" direction="in" />
<arg name="mode" type="s" direction="in" />
<arg name="props" type="a(sv)" direction="in" />
<arg name="aux" type="a(sa(sv))" direction="in" />
<arg name="job" type="o" direction="out" />
</method>

<!--
StopUnit:
@name: The name of the unit to stop
Expand Down
7 changes: 7 additions & 0 deletions data/org.eclipse.bluechi.internal.Agent.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
<arg name="mode" type="s" direction="in" />
<arg name="jobid" type="u" direction="in" />
</method>
<method name="StartTransientUnit">
<arg name="name" type="s" direction="in" />
<arg name="mode" type="s" direction="in" />
<arg name="props" type="a(sv)" direction="in" />
<arg name="aux" type="a(sa(sv))" direction="in" />
<arg name="job" type="o" direction="out" />
</method>
<method name="StopUnit">
<arg name="name" type="s" direction="in" />
<arg name="mode" type="s" direction="in" />
Expand Down
8 changes: 8 additions & 0 deletions doc/docs/api/description.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ Object path: `/org/eclipse/bluechi/node/$name`
The job returned is an object path for an object implementing `org.eclipse.bluechi.Job`, and which be monitored for
the progress of the job, or used to cancel the job. To track the result of the job, follow the `JobRemoved` signal
on the Controller.

* `StartTransientUnit(in s name, in s mode, in a(sv) properties, in a(sa(sv)) aux, out o job)`

`StartTransientUnit()` may be used to create and start a transient unit, which will be released as soon as it is not
running or referenced anymore or the system is rebooted. name is the unit name including suffix, and must be unique.
`mode` is the same as in `StartUnit()`, properties contains properties of the unit, specified like in SetUnitProperties().
`aux` is currently unused and should be passed as empty array. See the New Control Group Interfaces for more information
how to make use of this functionality for resource control purposes.

* `StopUnit(in s name, in s mode, out o job)`

Expand Down
1 change: 1 addition & 0 deletions src/agent/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -1783,6 +1783,7 @@ static const sd_bus_vtable internal_agent_vtable[] = {
SD_BUS_METHOD("GetUnitProperty", "sss", "v", agent_method_get_unit_property, 0),
SD_BUS_METHOD("SetUnitProperties", "sba(sv)", "", agent_method_set_unit_properties, 0),
SD_BUS_METHOD("StartUnit", "ssu", "", agent_method_start_unit, 0),
SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", agent_method_passthrough_to_systemd, 0),
SD_BUS_METHOD("StopUnit", "ssu", "", agent_method_stop_unit, 0),
SD_BUS_METHOD("FreezeUnit", "s", "", agent_method_freeze_unit, 0),
SD_BUS_METHOD("ThawUnit", "s", "", agent_method_thaw_unit, 0),
Expand Down
25 changes: 25 additions & 0 deletions src/bindings/python/bluechi/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,31 @@ def set_unit_properties(
keyvalues,
)

def start_transient_unit(
self,
name: str,
mode: str,
props: List[Tuple[str, Variant]],
aux: List[Tuple[str, List[Tuple[str, Variant]]]],
) -> ObjPath:
"""
StartTransientUnit:
@name: The name of the transient unit to start, incl. suffix such as .service
@mode: The mode used to start the unit
@props: List of key-value pairs of the systemd unit, e.g. ExecStart=/bin/true
@aux: Currently unused in systemd. Pass an empty list to it.
@job: The path for the job associated with the start operation
StartTransientUnit may be used to create and start a transient unit, which will be released as soon as it is not running or referenced anymore or the
system is rebooted.
"""
return self.get_proxy().StartTransientUnit(
name,
mode,
props,
aux,
)

def start_unit(self, name: str, mode: str) -> ObjPath:
"""
StartUnit:
Expand Down
1 change: 1 addition & 0 deletions src/controller/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ static const sd_bus_vtable node_vtable[] = {
SD_BUS_METHOD("ListUnitFiles", "", UNIT_FILE_INFO_STRUCT_ARRAY_TYPESTRING, node_method_list_unit_files, 0),
SD_BUS_METHOD("GetUnitFileState", "s", "s", node_method_passthrough_to_agent, 0),
SD_BUS_METHOD("StartUnit", "ss", "o", node_method_start_unit, 0),
SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", node_method_passthrough_to_agent, 0),
SD_BUS_METHOD("StopUnit", "ss", "o", node_method_stop_unit, 0),
SD_BUS_METHOD("FreezeUnit", "s", "", node_method_passthrough_to_agent, 0),
SD_BUS_METHOD("ThawUnit", "s", "", node_method_passthrough_to_agent, 0),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
summary: Test starting a transient unit
id: c683d707-9e11-49e2-8b87-d759ae676f52
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#
# Copyright Contributors to the Eclipse BlueChi project
#
# SPDX-License-Identifier: LGPL-2.1-or-later

import unittest

from dasbus.typing import Variant
from dasbus.loop import EventLoop

from bluechi.api import Controller, Monitor, Node


class TestStartTransientUnit(unittest.TestCase):

def __init__(self, methodName="runTest"):
super().__init__(methodName)

self.transient_unit = "transient.service"
self.received_new_signal = False
self.received_removed_signal = False

def test_start_transient_unit(self):
loop = EventLoop()

controller = Controller()
monitor_path = controller.create_monitor()
monitor = Monitor(monitor_path)
monitor.subscribe("node-foo", self.transient_unit)

def on_new_unit(node, unit, reason):
if unit == self.transient_unit:
self.received_new_signal = True

def on_removed_unit(node, unit, reason):
if unit == self.transient_unit:
self.received_removed_signal = True
loop.quit()

monitor.on_unit_new(on_new_unit)
monitor.on_unit_removed(on_removed_unit)

node = Node("localhost")
node.start_transient_unit(
TestStartTransientUnit.transient_unit,
"replace",
[
("Description", Variant("s", "My Test Transient Service")),
(
"ExecStart",
Variant(
"a(sasb)",
[
(
"/usr/bin/sleep",
["/usr/bin/sleep", "1"],
False,
)
],
),
),
],
[],
)

loop.run()

assert self.received_new_signal, "Did not receive new signal"
assert self.received_removed_signal, "Did not receive remove signal"


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#
# Copyright Contributors to the Eclipse BlueChi project
#
# SPDX-License-Identifier: LGPL-2.1-or-later

import os
from typing import Dict

from bluechi_test.config import BluechiControllerConfig, BluechiAgentConfig
from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine
from bluechi_test.test import BluechiTest


def exec(ctrl: BluechiControllerMachine, _: Dict[str, BluechiAgentMachine]):
result, output = ctrl.run_python(os.path.join("python", "start_transient.py"))
if result != 0:
raise Exception(output)


def test_bluechi_controller_start_transient_unit(
bluechi_test: BluechiTest,
bluechi_ctrl_default_config: BluechiControllerConfig,
bluechi_node_default_config: BluechiAgentConfig,
):
node_foo_cfg = bluechi_node_default_config.deep_copy()
node_foo_cfg.node_name = "node-foo"

bluechi_ctrl_default_config.allowed_node_names = ["node-foo"]

bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config)
bluechi_test.add_bluechi_agent_config(node_foo_cfg)

bluechi_test.run(exec)

0 comments on commit 3d8f3c8

Please sign in to comment.