Skip to content

Commit

Permalink
extended monitor API by adding and removing peers
Browse files Browse the repository at this point in the history
Relates to: #187

Monitor signals are only sent to the creator of the monitor. The
new Peer API enables to add and remove additional listener on the
same monitor with its subscriptions.
A user with sufficient priviledges to make methods calls to BlueChi's
API can add and remove peers. The processes for the peers can be run
by a different user with no access to BlueChi's API, but will still
be able to receive events if added by a privileged process.

Signed-off-by: Michael Engel <mengel@redhat.com>
  • Loading branch information
engelmi committed Dec 6, 2023
1 parent 55312a0 commit 43643bf
Show file tree
Hide file tree
Showing 12 changed files with 577 additions and 60 deletions.
34 changes: 34 additions & 0 deletions data/org.eclipse.bluechi.Monitor.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,30 @@
<arg name="id" type="u" direction="out" />
</method>

<!--
AddPeer:
@name: The name of the peer to add as listener to all monitor events. Needs to be unique name on the bus.
@id: The id of the created peer
Add a new peer to the monitor. A peer will receive all events that the monitor subscribes to.
-->
<method name="AddPeer">
<arg name="name" type="s" direction="in" />
<arg name="id" type="u" direction="out" />
</method>

<!--
RemovePeer:
@id: The id of the peer to remove
@reason: The reason for removing the peer
Remove a previously added peer from the monitor. The reason will be part of the PeerRemoved signal, which is only sent to the respective peer.
-->
<method name="RemovePeer">
<arg name="id" type="u" direction="in" />
<arg name="reason" type="s" direction="in" />
</method>


<!--
UnitPropertiesChanged:
Expand Down Expand Up @@ -122,5 +146,15 @@
<arg name="unit" type="s" />
<arg name="reason" type="s" />
</signal>

<!--
PeerRemoved:
@reason: The reason the peer got removed from the monitor.
Emitted when a peer is removed from the monitor, e.g. when the monitor has been closed, and only sent to the respective peer.
-->
<signal name="PeerRemoved">
<arg name="reason" type="s" />
</signal>
</interface>
</node>
42 changes: 42 additions & 0 deletions src/bindings/python/bluechi/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,31 @@ def subscribe_list(self, node: str, units: List[str]) -> UInt32:
units,
)

def add_peer(self, name: str) -> UInt32:
"""
AddPeer:
@name: The name of the peer to add as listener to all monitor events. Needs to be unique name on the bus.
@id: The id of the created peer
Add a new peer to the monitor. A peer will receive all events that the monitor subscribes to.
"""
return self.get_proxy().AddPeer(
name,
)

def remove_peer(self, id: UInt32, reason: str) -> None:
"""
RemovePeer:
@id: The id of the peer to remove
@reason: The reason for removing the peer
Remove a previously added peer from the monitor. The reason will be part of the PeerRemoved signal, which is only sent to the respective peer.
"""
self.get_proxy().RemovePeer(
id,
reason,
)

def on_unit_properties_changed(
self,
callback: Callable[
Expand Down Expand Up @@ -246,6 +271,23 @@ def on_unit_removed(
"""
self.get_proxy().UnitRemoved.connect(callback)

def on_peer_removed(
self,
callback: Callable[
[
str,
],
None,
],
) -> None:
"""
PeerRemoved:
@reason: The reason the peer got removed from the monitor.
Emitted when a peer is removed from the monitor, e.g. when the monitor has been closed, and only sent to the respective peer.
"""
self.get_proxy().PeerRemoved.connect(callback)


class Metrics(ApiBase):
"""
Expand Down
41 changes: 41 additions & 0 deletions src/libbluechi/bus/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include "utils.h"

#include "libbluechi/common/string-util.h"

/* Number of seconds idle before sending keepalive packets */
#define AGENT_KEEPALIVE_SOCKET_KEEPIDLE_SECS 1

Expand Down Expand Up @@ -336,3 +338,42 @@ int bus_socket_set_keepalive(sd_bus *bus) {

return 0;
}

/*
* Copied from libsystemd/sd-bus/bus-internal.c service_name_is_valid and adjusted to
* exclude the well-known service names. Also does not support '_' and '-' characters.
*/
bool bus_id_is_valid(const char *name) {
if (isempty(name) || name[0] != ':') {
return false;
}

const char *i = name + 1;
bool dot = true;
bool found_dot = false;
for (; *i; i++) {
if (*i == '.') {
if (dot) {
return false;
}
found_dot = true;
dot = true;
continue;
}
dot = false;

if (!ascii_isalpha(*i) && !ascii_isdigit(*i)) {
return false;
}
}

if (i - name > SD_BUS_MAXIMUM_NAME_LENGTH) {
return false;
}

if (dot || !found_dot) {
return false;
}

return true;
}
2 changes: 2 additions & 0 deletions src/libbluechi/bus/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ int bus_parse_unit_on_node_info(sd_bus_message *message, UnitInfo *u);
int bus_socket_set_no_delay(sd_bus *bus);
int bus_socket_set_keepalive(sd_bus *bus);

bool bus_id_is_valid(const char *name);

int assemble_object_path_string(const char *prefix, const char *name, char **res);

DEFINE_CLEANUP_FUNC(UnitInfo, unit_unref)
Expand Down
3 changes: 3 additions & 0 deletions src/libbluechi/test/bus/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: LGPL-2.1-or-later

subdir('utils')
49 changes: 49 additions & 0 deletions src/libbluechi/test/bus/utils/bus_id_is_valid_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#include "libbluechi/bus/utils.h"
#include "libbluechi/common/string-util.h"

bool test_bus_id_is_valid(const char *name, bool expected_is_valid) {
bool got_is_valid = bus_id_is_valid(name);
if (got_is_valid != expected_is_valid) {
fprintf(stderr,
"FAILED: expected bus name '%s' to be %s, but got %s\n",
name,
bool_to_str(expected_is_valid),
bool_to_str(got_is_valid));
return false;
}
return true;
}

int main() {
bool result = true;

result = result && test_bus_id_is_valid(NULL, false);
result = result && test_bus_id_is_valid("", false);
result = result && test_bus_id_is_valid(":", false);
result = result && test_bus_id_is_valid(":.", false);
result = result && test_bus_id_is_valid(":1.", false);
result = result && test_bus_id_is_valid(":1.3.", false);
result = result && test_bus_id_is_valid("1", false);
result = result && test_bus_id_is_valid("1.", false);
result = result && test_bus_id_is_valid("1.3", false);
result = result && test_bus_id_is_valid(":1..3", false);
result = result && test_bus_id_is_valid("org.eclipse.bluechi", false);
result = result &&
test_bus_id_is_valid(
":1.1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
false);

result = result && test_bus_id_is_valid(":1.1", true);
result = result && test_bus_id_is_valid(":1.12345", true);
result = result && test_bus_id_is_valid(":1.123.45", true);

if (result) {
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
15 changes: 15 additions & 0 deletions src/libbluechi/test/bus/utils/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SPDX-License-Identifier: LGPL-2.1-or-later

bus_src = [
'bus_id_is_valid_test',
]

foreach src : bus_src
exec_test = executable(src, src + '.c',
link_with: [
bluechi_lib,
],
include_directories: include_directories('../../../..'),
)
test(src, exec_test)
endforeach
1 change: 1 addition & 0 deletions src/libbluechi/test/meson.build
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: LGPL-2.1-or-later

subdir('bus')
subdir('common')
subdir('log')
2 changes: 1 addition & 1 deletion src/manager/manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ static void manager_client_disconnected(Manager *manager, const char *client_id)
Monitor *monitor = NULL;
Monitor *next_monitor = NULL;
LIST_FOREACH_SAFE(monitors, monitor, next_monitor, manager->monitors) {
if (streq(monitor->client, client_id)) {
if (streq(monitor->owner, client_id)) {
monitor_close(monitor);
manager_remove_monitor(manager, monitor);
}
Expand Down
Loading

0 comments on commit 43643bf

Please sign in to comment.