Skip to content

Commit

Permalink
Merge branch 'main' into bluechi-is-online-agent-with-wait
Browse files Browse the repository at this point in the history
  • Loading branch information
DanaOrr committed Dec 16, 2024
2 parents e41ad04 + de238cc commit e6d8fe4
Show file tree
Hide file tree
Showing 43 changed files with 989 additions and 167 deletions.
1 change: 1 addition & 0 deletions bluechi.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ This package contains the controller service.
%ghost %{_sysconfdir}/bluechi/controller.conf
%dir %{_sysconfdir}/bluechi
%dir %{_sysconfdir}/bluechi/controller.conf.d
%dir %{_rundir}/bluechi
%doc README.md
%doc README.developer.md
%license LICENSE
Expand Down
11 changes: 11 additions & 0 deletions config/controller/controller.conf
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,14 @@
# Number of keepalive packets without ACK from the agent till the peer connection is dropped. Value is
# set to socket option TCP_KEEPCNT.
#TCPKeepAliveCount=6

#
# Enables or disables the connection handler for agents to connect remotely via TCP/IP. If disabled,
# all other TCP options including the ControllerPort are not used.
# The TCP handler can run alongside the UDS handler and the systemd socket activated handler.
#UseTCP=true

#
# Enables or disables the connection handler for agents to connect locally via Unix Domain Socket (UDS).
# The UDS handler can run alongside the TCP handler and the systemd socket activated handler.
#UseUDS=true
2 changes: 2 additions & 0 deletions doc/docs/resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
Paul Wallrabe, Michael Engel - Eclipse Newsletter - November 2023 <br>
- [Eclipse BlueChi - A deterministic multi-node service controller for automotive and edge](https://www.youtube.com/watch?v=EMaNJEKEgZ8) <br>
Michael Engel - DevConf.cz - June 2024 <br>
- [Eclipse BlueChi - A deterministic multi-node service controller for automotive](https://www.youtube.com/watch?v=p0PCESqUrPM&list=PLXGqib0ZinZFw1NXGzfLxTXF8DfpzkAb5&index=17&pp=iAQB) <br>
Michael Engel - Open Community for Automotive (OCA) - October 2024 <br>
- [Eclipse BlueChi Workshop](https://github.com/eclipse-bluechi/bluechi-demos/tree/main/workshop-devconf-cz-2024) <br>
Mark Kemel, Michael Engel - DevConf.cz - June 2024 <br>
- [Executing Container Orchestration with Eclipse BlueChi on the RedHat In-Vehicle Operating System in the AWS Cloud – Part 1](https://aws.amazon.com/blogs/industries/executing-container-orchestration-with-eclipse-bluechi-on-the-redhat-in-vehicle-operating-system-in-the-aws-cloud-part-1/) <br>
Expand Down
24 changes: 20 additions & 4 deletions doc/man/bluechi-controller.conf.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,31 @@ The bluechi-controller configuration file is using the

All fields to bootstrap the bluechi controller are contained in the **bluechi-controller** section. The following keys are understood by `bluechi-controller`.

#### **UseTCP** (string)

If this flag is set to `true`, it enables the connection handler for agents to connect
remotely via TCP/IP to the controller. If disabled, all other TCP options such as the
ControllerPort or TCPKeepAliveTime are not used.
The TCP handler can run alongside the handler for local connections (Unix Domain Socket)
as well as the systemd socket activated handler.
Default: true.

#### **UseUDS** (string)

If this flag is set to `true`, it enables the connection handler for agents to connect
locally via Unix Domain Socket (UDS) to the controller.
The UDS handler can run alongside the handler for remote connections (TCP/IP) as well as
the systemd socket activated handler.
Default: true.

#### **ControllerPort** (uint16_t)

The port the bluechi-controller listens on to establish connections with the `bluechi-agent`. By default port `842` is used.

#### **AllowedNodeNames** (string)

A comma separated list of unique bluechi-agent names. It's mandatory to set the option, only nodes with names mentioned
in the list can connect to `bluechi-controller'. These names are defined in the agent's configuration file under `NodeName`
in the list can connect to `bluechi-controller`. These names are defined in the agent's configuration file under `NodeName`
option (see `bluechi-agent.conf(5)`).

#### **HeartbeatInterval** (long)
Expand Down Expand Up @@ -117,10 +134,9 @@ LogIsQuiet=false

## FILES

Distributions provide the __/usr/share/bluechi/config/controller.conf__ file which defines bluechi configuration defaults. Administrators can copy this file to __/etc/bluechi/controller.conf__ and specify their own configuration.

Administrators can also use a "drop-in" directory __/etc/bluechi/controller.conf.d__ to drop their configuration changes.
Distributions provide the **/usr/share/bluechi/config/controller.conf** file which defines bluechi configuration defaults. Administrators can copy this file to **/etc/bluechi/controller.conf** and specify their own configuration.

Administrators can also use a "drop-in" directory **/etc/bluechi/controller.conf.d** to drop their configuration changes.

## SEE ALSO

Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ conf.set('_GNU_SOURCE', true)

prefixdir = get_option('prefix')

conf.set_quoted('CONFIG_H_UDS_SOCKET_PATH', get_option('unix_domain_socket_path'))
conf.set_quoted('CONFIG_H_SYSCONFDIR', join_paths(prefixdir, get_option('sysconfdir')))
conf.set_quoted('CONFIG_H_DATADIR', join_paths(prefixdir, get_option('datadir')))
conf.set_quoted('CONFIG_H_BC_VERSION', run_command(
Expand Down
3 changes: 3 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ option('with_man_pages', type : 'boolean', value : true,
option('with_selinux', type : 'boolean', value : true,
description : 'Include the build and install of bluechi-selinux')

option('unix_domain_socket_path', type : 'string',
description: 'The path of the Unix Domain Socket for BlueChi',
value: '/run/bluechi/bluechi.sock')
202 changes: 181 additions & 21 deletions src/controller/controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ Controller *controller_new(void) {
controller->number_of_nodes = 0;
controller->number_of_nodes_online = 0;
controller->peer_socket_options = steal_pointer(&socket_opts);
controller->node_connection_tcp_socket_source = NULL;
controller->node_connection_uds_socket_source = NULL;
controller->node_connection_systemd_socket_source = NULL;
LIST_HEAD_INIT(controller->nodes);
LIST_HEAD_INIT(controller->anonymous_nodes);
LIST_HEAD_INIT(controller->jobs);
Expand Down Expand Up @@ -91,7 +94,26 @@ void controller_unref(Controller *controller) {
free_and_null(controller->api_bus_service_name);
free_and_null(controller->peer_socket_options);

sd_event_source_unrefp(&controller->node_connection_source);
if (controller->node_connection_tcp_socket_source != NULL) {
sd_event_source_unrefp(&controller->node_connection_tcp_socket_source);
controller->node_connection_tcp_socket_source = NULL;
}
if (controller->node_connection_uds_socket_source != NULL) {
sd_event_source_unrefp(&controller->node_connection_uds_socket_source);
controller->node_connection_uds_socket_source = NULL;

/* Remove UDS socket for proper cleanup and not cause an address in use error */
unlink(CONFIG_H_UDS_SOCKET_PATH);
}
if (controller->node_connection_systemd_socket_source != NULL) {
sd_event_source_unrefp(&controller->node_connection_systemd_socket_source);
controller->node_connection_systemd_socket_source = NULL;

/* Remove UDS socket for proper cleanup and not cause an address in use error even
* though the systemd socket might have been changed to listen on different socket
*/
unlink(CONFIG_H_UDS_SOCKET_PATH);
}

sd_bus_slot_unrefp(&controller->name_owner_changed_slot);
sd_bus_slot_unrefp(&controller->filter_slot);
Expand Down Expand Up @@ -266,6 +288,17 @@ Node *controller_add_node(Controller *controller, const char *name) {
return steal_pointer(&node);
}

bool controller_set_use_tcp(Controller *controller, bool use_tcp) {
controller->use_tcp = use_tcp;
return true;
}

bool controller_set_use_uds(Controller *controller, bool use_uds) {
controller->use_uds = use_uds;
return true;
}


bool controller_set_port(Controller *controller, const char *port_s) {
uint16_t port = 0;

Expand Down Expand Up @@ -327,6 +360,17 @@ bool controller_parse_config(Controller *controller, const char *configfile) {
}

bool controller_apply_config(Controller *controller) {
if (!controller_set_use_tcp(
controller, cfg_get_bool_value(controller->config, CFG_CONTROLLER_USE_TCP))) {
bc_log_error("Failed to set USE TCP");
return false;
}
if (!controller_set_use_uds(
controller, cfg_get_bool_value(controller->config, CFG_CONTROLLER_USE_UDS))) {
bc_log_error("Failed to set USE UDS");
return false;
}

const char *port = NULL;
port = cfg_get_value(controller->config, CFG_CONTROLLER_PORT);
if (port) {
Expand Down Expand Up @@ -403,9 +447,9 @@ static int controller_accept_node_connection(
UNUSED sd_event_source *source, int fd, UNUSED uint32_t revents, void *userdata) {
Controller *controller = userdata;
Node *node = NULL;
_cleanup_fd_ int nfd = accept_tcp_connection_request(fd);
_cleanup_fd_ int nfd = accept_connection_request(fd);
if (nfd < 0) {
bc_log_errorf("Failed to accept TCP connection request: %s", strerror(-nfd));
bc_log_errorf("Failed to accept connection request: %s", strerror(-nfd));
return -1;
}

Expand All @@ -431,53 +475,169 @@ static int controller_accept_node_connection(
return 0;
}

static bool controller_setup_node_connection_handler(Controller *controller) {
static bool controller_setup_systemd_socket_connection_handler(Controller *controller) {
int r = 0;
int accept_fd = -1;
_cleanup_fd_ int tcp_fd = -1;
_cleanup_sd_event_source_ sd_event_source *event_source = NULL;

int n = sd_listen_fds(0);
if (n < 1) {
bc_log_debug("No socket unit file descriptor has been passed");
return true;
}
if (n > 1) {
bc_log_errorf("Received too many file descriptors - %d", n);
bc_log_errorf("Received too many file descriptors from socket unit - %d", n);
return false;
}

if (n == 1) {
accept_fd = SD_LISTEN_FDS_START;
} else {
tcp_fd = create_tcp_socket(controller->port);
if (tcp_fd < 0) {
bc_log_errorf("Failed to create TCP socket: %s", strerror(errno));
r = sd_event_add_io(
controller->event,
&event_source,
SD_LISTEN_FDS_START,
EPOLLIN,
controller_accept_node_connection,
controller);
if (r < 0) {
bc_log_errorf("Failed to add io event source for systemd socket unit: %s", strerror(-r));
return false;
}
r = sd_event_source_set_io_fd_own(event_source, true);
if (r < 0) {
bc_log_errorf("Failed to set io fd own for systemd socket unit: %s", strerror(-r));
return false;
}

(void) sd_event_source_set_description(event_source, "node-accept-systemd-socket");
controller->node_connection_systemd_socket_source = steal_pointer(&event_source);

bc_log_info("Waiting for connection requests on configured socket unit...");
return true;
}

static bool controller_setup_tcp_connection_handler(Controller *controller) {
int r = 0;
_cleanup_fd_ int tcp_fd = -1;
_cleanup_sd_event_source_ sd_event_source *event_source = NULL;

tcp_fd = create_tcp_socket(controller->port);
if (tcp_fd < 0) {
/*
* Check if the address is already in use and if the systemd file descriptor already uses it.
* In case both conditions are true, only log a warning and proceed as successful since a
* proper TCP socket incl. handler has already been set up.
*/
if (tcp_fd == -EADDRINUSE && controller->node_connection_systemd_socket_source != NULL &&
sd_is_socket_inet(SD_LISTEN_FDS_START, AF_UNSPEC, SOCK_STREAM, 1, controller->port) > 0) {
bc_log_warnf("TCP socket for port %d already setup with systemd socket unit",
controller->port);
return true;
}

bc_log_errorf("Failed to create TCP socket: %s", strerror(-tcp_fd));
return false;
}

r = sd_event_add_io(
controller->event,
&event_source,
tcp_fd,
EPOLLIN,
controller_accept_node_connection,
controller);
if (r < 0) {
bc_log_errorf("Failed to add io event for tcp socket: %s", strerror(-r));
return false;
}
r = sd_event_source_set_io_fd_own(event_source, true);
if (r < 0) {
bc_log_errorf("Failed to set io fd own for tcp socket: %s", strerror(-r));
return false;
}
// sd_event_set_io_fd_own takes care of closing tcp_fd
steal_fd(&tcp_fd);

(void) sd_event_source_set_description(event_source, "node-accept-tcp-socket");
controller->node_connection_tcp_socket_source = steal_pointer(&event_source);

bc_log_infof("Waiting for connection requests on port %d...", controller->port);
return true;
}


static bool controller_setup_uds_connection_handler(Controller *controller) {
int r = 0;
_cleanup_fd_ int uds_fd = -1;
_cleanup_sd_event_source_ sd_event_source *event_source = NULL;

uds_fd = create_uds_socket(CONFIG_H_UDS_SOCKET_PATH);
if (uds_fd < 0) {
/*
* Check if the uds path is already in use and if the systemd file descriptor already uses
* it. In case both conditions are true, only log a warning and proceed as successful since a
* proper UDS incl. handler has already been set up.
*/
if (uds_fd == -EADDRINUSE && controller->node_connection_systemd_socket_source != NULL &&
sd_is_socket_unix(SD_LISTEN_FDS_START, AF_UNIX, 1, CONFIG_H_UDS_SOCKET_PATH, 0) > 0) {
bc_log_warnf("UDS socket for path %s already setup with systemd socket unit",
CONFIG_H_UDS_SOCKET_PATH);
return true;
} else if (uds_fd == -EADDRINUSE) {
/* If address is in use, remove socket file and retry again */
unlink(CONFIG_H_UDS_SOCKET_PATH);
uds_fd = create_uds_socket(CONFIG_H_UDS_SOCKET_PATH);
if (uds_fd < 0) {
bc_log_errorf("Failed to create UDS socket: %s", strerror(-uds_fd));
return false;
}
} else {
bc_log_errorf("Failed to create UDS socket: %s", strerror(-uds_fd));
return false;
}
accept_fd = tcp_fd;
}

r = sd_event_add_io(
controller->event,
&event_source,
accept_fd,
uds_fd,
EPOLLIN,
controller_accept_node_connection,
controller);
if (r < 0) {
bc_log_errorf("Failed to add io event: %s", strerror(-r));
bc_log_errorf("Failed to add io event for uds socket: %s", strerror(-r));
return false;
}
r = sd_event_source_set_io_fd_own(event_source, true);
if (r < 0) {
bc_log_errorf("Failed to set io fd own: %s", strerror(-r));
bc_log_errorf("Failed to set io fd own for uds socket: %s", strerror(-r));
return false;
}
// sd_event_set_io_fd_own takes care of closing uds_fd
steal_fd(&uds_fd);

// sd_event_set_io_fd_own takes care of closing accept_fd
steal_fd(&tcp_fd);
(void) sd_event_source_set_description(event_source, "node-accept-uds-socket");
controller->node_connection_uds_socket_source = steal_pointer(&event_source);

(void) sd_event_source_set_description(event_source, "node-accept-socket");
bc_log_infof("Waiting for connection requests on port %s...", CONFIG_H_UDS_SOCKET_PATH);
return true;
}

controller->node_connection_source = steal_pointer(&event_source);

static bool controller_setup_node_connection_handler(Controller *controller) {
if (!controller_setup_systemd_socket_connection_handler(controller)) {
return false;
}
if (controller->use_tcp && !controller_setup_tcp_connection_handler(controller)) {
return false;
}
if (controller->use_uds && !controller_setup_uds_connection_handler(controller)) {
return false;
}

if (controller->node_connection_systemd_socket_source == NULL &&
controller->node_connection_tcp_socket_source == NULL &&
controller->node_connection_uds_socket_source == NULL) {
bc_log_error("No connection request handler configured");
return false;
}
return true;
}

Expand Down
6 changes: 5 additions & 1 deletion src/controller/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
struct Controller {
int ref_count;

bool use_uds;
bool use_tcp;
uint16_t port;
char *api_bus_service_name;
long heartbeat_interval_msec;
long heartbeat_threshold_msec;

sd_event *event;
sd_event_source *node_connection_source;
sd_event_source *node_connection_tcp_socket_source;
sd_event_source *node_connection_uds_socket_source;
sd_event_source *node_connection_systemd_socket_source;

sd_bus *api_bus;
sd_bus_slot *controller_slot;
Expand Down
Loading

0 comments on commit e6d8fe4

Please sign in to comment.