From 65ee2fb56d6fc26d334881d0cf0300842acbfa3f Mon Sep 17 00:00:00 2001 From: Michael Engel Date: Thu, 12 Sep 2024 18:32:44 +0200 Subject: [PATCH] Split up method-unit-actions Relates to: https://github.com/eclipse-bluechi/bluechi/issues/691 The method-unit-actions file collects a lot of different operations. These have been split up into multiple files based on semantically coherent functionality. Also, usage functions for the various commands have been added. Signed-off-by: Michael Engel --- src/client/method-daemon-reload.c | 47 ++ src/client/method-daemon-reload.h | 11 + src/client/method-enable-disable.c | 226 ++++++++ src/client/method-enable-disable.h | 14 + src/client/method-freeze-thaw.c | 90 ++++ ...od-unit-actions.h => method-freeze-thaw.h} | 0 src/client/method-reset-failed.c | 134 +++++ src/client/method-reset-failed.h | 11 + src/client/method-unit-actions.c | 499 ------------------ src/client/method-unit-lifecycle.c | 103 ++++ src/client/method-unit-lifecycle.h | 14 + 11 files changed, 650 insertions(+), 499 deletions(-) create mode 100644 src/client/method-daemon-reload.c create mode 100644 src/client/method-daemon-reload.h create mode 100644 src/client/method-enable-disable.c create mode 100644 src/client/method-enable-disable.h create mode 100644 src/client/method-freeze-thaw.c rename src/client/{method-unit-actions.h => method-freeze-thaw.h} (100%) create mode 100644 src/client/method-reset-failed.c create mode 100644 src/client/method-reset-failed.h delete mode 100644 src/client/method-unit-actions.c create mode 100644 src/client/method-unit-lifecycle.c create mode 100644 src/client/method-unit-lifecycle.h diff --git a/src/client/method-daemon-reload.c b/src/client/method-daemon-reload.c new file mode 100644 index 0000000000..ed75afc612 --- /dev/null +++ b/src/client/method-daemon-reload.c @@ -0,0 +1,47 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#include "method-daemon-reload.h" +#include "client.h" + +#include "libbluechi/common/opt.h" + +static int method_daemon_reload_on(Client *client, char *node_name) { + int r = 0; + _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_sd_bus_message_ sd_bus_message *result = NULL; + + r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); + if (r < 0) { + return r; + } + + r = sd_bus_call_method( + client->api_bus, + BC_INTERFACE_BASE_NAME, + client->object_path, + NODE_INTERFACE, + "Reload", + &error, + &result, + ""); + if (r < 0) { + fprintf(stderr, "Failed to issue method call: %s\n", error.message); + return r; + } + + return 0; +} + +int method_daemon_reload(Command *command, void *userdata) { + return method_daemon_reload_on(userdata, command->opargv[0]); +} + + +void usage_method_daemon_reload() { + usage_print_header(); + usage_print_description("Reload all units on a node"); + usage_print_usage("bluechictl daemon-reload [nodename]"); +} diff --git a/src/client/method-daemon-reload.h b/src/client/method-daemon-reload.h new file mode 100644 index 0000000000..f4fa2d7bcb --- /dev/null +++ b/src/client/method-daemon-reload.h @@ -0,0 +1,11 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#pragma once + +#include "libbluechi/cli/command.h" + +int method_daemon_reload(Command *command, void *userdata); +void usage_method_daemon_reload(); diff --git a/src/client/method-enable-disable.c b/src/client/method-enable-disable.c new file mode 100644 index 0000000000..3778fb5b98 --- /dev/null +++ b/src/client/method-enable-disable.c @@ -0,0 +1,226 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#include "method-enable-disable.h" +#include "client.h" +#include "method-daemon-reload.h" + +#include "libbluechi/common/opt.h" + +static int add_string_array_to_message(sd_bus_message *m, char **units, size_t units_count) { + _cleanup_free_ char **units_array = NULL; + int r = 0; + + units_array = malloc0_array(0, sizeof(char *), units_count + 1); + if (units_array == NULL) { + fprintf(stderr, "Failed to allocate memory\n"); + return -ENOMEM; + } + size_t i = 0; + for (i = 0; i < units_count; i++) { + units_array[i] = units[i]; + } + + r = sd_bus_message_append_strv(m, units_array); + if (r < 0) { + fprintf(stderr, "Failed to append the list of units to the message: %s\n", strerror(-r)); + return r; + } + + return 0; +} + +static int parse_enable_disable_response_from_message(sd_bus_message *m) { + int r = 0; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)"); + if (r < 0) { + fprintf(stderr, "Failed to open the strings array container: %s\n", strerror(-r)); + return r; + } + + for (;;) { + const char *op_type = NULL; + const char *symlink_file = NULL; + const char *symlink_dest = NULL; + + r = sd_bus_message_read(m, "(sss)", &op_type, &symlink_file, &symlink_dest); + if (r < 0) { + fprintf(stderr, "Failed to read enabled unit file information: %s\n", strerror(-r)); + return r; + } + if (r == 0) { + break; + } + if (streq(op_type, "symlink")) { + fprintf(stderr, "Created symlink %s -> %s\n", symlink_file, symlink_dest); + } else if (streq(op_type, "unlink")) { + fprintf(stderr, "Removed \"%s\".\n", symlink_file); + } else { + fprintf(stderr, "Unknown operation: %s\n", op_type); + } + } + + return 0; +} + +static int method_enable_unit_on( + Client *client, char *node_name, char **units, size_t units_count, int runtime, int force) { + int r = 0; + _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_sd_bus_message_ sd_bus_message *result = NULL; + _cleanup_sd_bus_message_ sd_bus_message *outgoing_message = NULL; + + r = client_create_message_new_method_call(client, node_name, "EnableUnitFiles", &outgoing_message); + if (r < 0) { + fprintf(stderr, "Failed to create a new message: %s\n", strerror(-r)); + return r; + } + + r = add_string_array_to_message(outgoing_message, units, units_count); + if (r < 0) { + fprintf(stderr, "Failed to append the string array to the message: %s\n", strerror(-r)); + } + + r = sd_bus_message_append(outgoing_message, "bb", runtime, force); + if (r < 0) { + fprintf(stderr, "Failed to append runtime and force to the message: %s\n", strerror(-r)); + return r; + } + + r = sd_bus_call(client->api_bus, outgoing_message, BC_DEFAULT_DBUS_TIMEOUT, &error, &result); + if (r < 0) { + fprintf(stderr, "Failed to issue call: %s\n", error.message); + return r; + } + + int carries_install_info = 0; + r = sd_bus_message_read(result, "b", &carries_install_info); + if (r < 0) { + fprintf(stderr, "Failed to read carries_install_info from the message: %s\n", strerror(-r)); + return r; + } + + if (carries_install_info) { + fprintf(stderr, "The unit files included enablement information\n"); + } else { + fprintf(stderr, "The unit files did not include any enablement information\n"); + } + + r = parse_enable_disable_response_from_message(result); + if (r < 0) { + fprintf(stderr, "Failed to parse the response strings array: %s\n", error.message); + return r; + } + + return 0; +} + +static int method_disable_unit_on(Client *client, char *node_name, char **units, size_t units_count, int runtime) { + int r = 0; + _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_sd_bus_message_ sd_bus_message *result = NULL; + _cleanup_sd_bus_message_ sd_bus_message *outgoing_message = NULL; + + r = client_create_message_new_method_call(client, node_name, "DisableUnitFiles", &outgoing_message); + if (r < 0) { + fprintf(stderr, "Failed to create a new message: %s\n", strerror(-r)); + return r; + } + + r = add_string_array_to_message(outgoing_message, units, units_count); + if (r < 0) { + fprintf(stderr, "Failed to append the string array to the message: %s\n", strerror(-r)); + } + + r = sd_bus_message_append(outgoing_message, "b", runtime); + if (r < 0) { + fprintf(stderr, "Failed to append runtime to the message: %s\n", strerror(-r)); + return r; + } + + r = sd_bus_call(client->api_bus, outgoing_message, BC_DEFAULT_DBUS_TIMEOUT, &error, &result); + if (r < 0) { + fprintf(stderr, "Failed to issue call: %s\n", error.message); + return r; + } + + r = parse_enable_disable_response_from_message(result); + if (r < 0) { + fprintf(stderr, "Failed to parse the response strings array: %s\n", error.message); + return r; + } + + return 0; +} + +int method_enable(Command *command, void *userdata) { + int r = 0; + r = method_enable_unit_on( + userdata, + command->opargv[0], + &command->opargv[1], + command->opargc - 1, + command_flag_exists(command, ARG_RUNTIME_SHORT), + command_flag_exists(command, ARG_FORCE_SHORT)); + if (r < 0) { + fprintf(stderr, + "Failed to enable the units on node [%s] - %s", + command->opargv[0], + strerror(-r)); + return r; + } + + if (!command_flag_exists(command, ARG_NO_RELOAD_SHORT)) { + r = method_daemon_reload_on(userdata, command->opargv[0]); + } + + return r; +} + +int method_disable(Command *command, void *userdata) { + int r = 0; + r = method_disable_unit_on( + userdata, + command->opargv[0], + &command->opargv[1], + command->opargc - 1, + command_flag_exists(command, ARG_RUNTIME_SHORT)); + if (r < 0) { + fprintf(stderr, + "Failed to disable the units on node [%s] - %s", + command->opargv[0], + strerror(-r)); + } + if (!command_flag_exists(command, ARG_NO_RELOAD_SHORT)) { + r = method_daemon_reload_on(userdata, command->opargv[0]); + } + + return r; +} + + +void usage_method_enable() { + usage_print_header(); + usage_print_description("Enable a unit on a node"); + usage_print_usage("bluechictl enable [nodename] [unit1, unit2, ...] [options]"); + printf("\n"); + printf("Available options:\n"); + printf(" --%s \t shows this help message\n", ARG_HELP); + printf(" --%s \t if set, the changes don't persist after reboot \n", ARG_RUNTIME); + printf(" --%s \t if set, symlinks pointing to other units are replaced \n", ARG_FORCE); + printf(" --%s \t if set, no daemon-reload is triggered \n", ARG_NO_RELOAD); +} + +void usage_method_disable() { + usage_print_header(); + usage_print_description("Disable a unit on a node"); + usage_print_usage("bluechictl disable [nodename] [unit1, unit2, ...] [options]"); + printf("\n"); + printf("Available options:\n"); + printf(" --%s \t shows this help message\n", ARG_HELP); + printf(" --%s \t if set, the changes don't persist after reboot \n", ARG_RUNTIME); + printf(" --%s \t if set, no daemon-reload is triggered \n", ARG_NO_RELOAD); +} diff --git a/src/client/method-enable-disable.h b/src/client/method-enable-disable.h new file mode 100644 index 0000000000..561a29a500 --- /dev/null +++ b/src/client/method-enable-disable.h @@ -0,0 +1,14 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#pragma once + +#include "libbluechi/cli/command.h" + +int method_enable(Command *command, void *userdata); +void usage_method_enable(); + +int method_disable(Command *command, void *userdata); +void usage_method_disable(); diff --git a/src/client/method-freeze-thaw.c b/src/client/method-freeze-thaw.c new file mode 100644 index 0000000000..d9e1eab4f2 --- /dev/null +++ b/src/client/method-freeze-thaw.c @@ -0,0 +1,90 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#include "method-freeze-thaw.h" +#include "client.h" + +#include "libbluechi/common/opt.h" + +static int method_freeze_unit_on(Client *client, char *node_name, char *unit) { + int r = 0; + _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_sd_bus_message_ sd_bus_message *result = NULL; + + r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); + if (r < 0) { + return r; + } + + r = sd_bus_call_method( + client->api_bus, + BC_INTERFACE_BASE_NAME, + client->object_path, + NODE_INTERFACE, + "FreezeUnit", + &error, + &result, + "s", + unit); + if (r < 0) { + fprintf(stderr, "Failed to issue method call: %s\n", error.message); + return r; + } + + printf("Unit %s freeze operation done\n", unit); + + return 0; +} + +static int method_thaw_unit_on(Client *client, char *node_name, char *unit) { + int r = 0; + _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_sd_bus_message_ sd_bus_message *result = NULL; + + r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); + if (r < 0) { + return r; + } + + r = sd_bus_call_method( + client->api_bus, + BC_INTERFACE_BASE_NAME, + client->object_path, + NODE_INTERFACE, + "ThawUnit", + &error, + &result, + "s", + unit); + if (r < 0) { + fprintf(stderr, "Failed to issue method call: %s\n", error.message); + return r; + } + + printf("Unit %s thaw operation done\n", unit); + + return 0; +} + +int method_freeze(Command *command, void *userdata) { + return method_freeze_unit_on(userdata, command->opargv[0], command->opargv[1]); +} + +int method_thaw(Command *command, void *userdata) { + return method_thaw_unit_on(userdata, command->opargv[0], command->opargv[1]); +} + + +void usage_method_freeze() { + usage_print_header(); + usage_print_description("Freeze a unit on a node"); + usage_print_usage("bluechictl freeze [nodename] [unit]"); +} + +void usage_method_thaw() { + usage_print_header(); + usage_print_description("Thaw a previously frozen unit on a node"); + usage_print_usage("bluechictl freeze [nodename] [unit]"); +} diff --git a/src/client/method-unit-actions.h b/src/client/method-freeze-thaw.h similarity index 100% rename from src/client/method-unit-actions.h rename to src/client/method-freeze-thaw.h diff --git a/src/client/method-reset-failed.c b/src/client/method-reset-failed.c new file mode 100644 index 0000000000..4a1167c4da --- /dev/null +++ b/src/client/method-reset-failed.c @@ -0,0 +1,134 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#include "method-reset-failed.h" +#include "client.h" + +#include "libbluechi/common/opt.h" + +static int method_reset_failed_on_units(Client *client, Command *commands) { + char *node_name = commands->opargv[0]; + int units_count = 1; + int r = 0; + _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_sd_bus_message_ sd_bus_message *result = NULL; + + r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); + if (r < 0) { + return r; + } + + while (commands->opargv[units_count] != NULL) { + printf("%i %s\n", units_count, commands->opargv[units_count]); + r = sd_bus_call_method( + client->api_bus, + BC_INTERFACE_BASE_NAME, + client->object_path, + NODE_INTERFACE, + "ResetFailedUnit", + &error, + &result, + "s", + commands->opargv[units_count]); + + if (r < 0) { + fprintf(stderr, "Failed to issue method call: %s\n", error.message); + return r; + } + units_count++; + } + return r; +} + +static int method_reset_failed_on_node(Client *client, char *node_name) { + + _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_sd_bus_message_ sd_bus_message *result = NULL; + int r = 0; + + r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); + if (r < 0) { + return r; + } + + r = sd_bus_call_method( + client->api_bus, + BC_INTERFACE_BASE_NAME, + client->object_path, + NODE_INTERFACE, + "ResetFailed", + &error, + &result, + ""); + if (r < 0) { + fprintf(stderr, + "Couldn't reset failed state of all units on node '%s': %s\n", + node_name, + error.message); + return r; + } + + return r; +} + +static int method_reset_failed_on_all_nodes(Client *client) { + + int r = 0; + + _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_sd_bus_message_ sd_bus_message *result = NULL; + r = sd_bus_call_method( + client->api_bus, + BC_INTERFACE_BASE_NAME, + BC_OBJECT_PATH, + CONTROLLER_INTERFACE, + "ListNodes", + &error, + &result, + "", + NULL); + if (r < 0) { + fprintf(stderr, "Failed to issue method call: %s\n", error.message); + return r; + } + + r = sd_bus_message_enter_container(result, SD_BUS_TYPE_ARRAY, "(soss)"); + if (r < 0) { + fprintf(stderr, "Failed to open result array: %s\n", strerror(-r)); + return r; + } + while (sd_bus_message_at_end(result, false) == 0) { + const char *name = NULL; + + r = sd_bus_message_read(result, "(soss)", &name, NULL, NULL, NULL); + if (r < 0) { + fprintf(stderr, "Failed to read node information: %s\n", strerror(-r)); + return r; + } + + _cleanup_free_ char *node_name = strdup(name); + r = method_reset_failed_on_node(client, node_name); + } + + return r; +} + +int method_reset_failed(Command *command, void *userdata) { + if (command->opargv[0] != NULL) { + if (command->opargv[1] != NULL) { + return method_reset_failed_on_units(userdata, command); + } + return method_reset_failed_on_node(userdata, command->opargv[0]); + } + return method_reset_failed_on_all_nodes(userdata); +} + +void usage_method_reset_failed() { + usage_print_header(); + usage_print_description("Reset the failed state of units"); + usage_print_usage("bluechictl reset-failed [nodename] [unit1, unit2, ...]"); + printf(" If [nodename] and unit(s) are not given, the failed state is reset for all units on all nodes.\n"); + printf(" If no unit(s) are given, the failed state is reset for all units on the given node.\n"); +} diff --git a/src/client/method-reset-failed.h b/src/client/method-reset-failed.h new file mode 100644 index 0000000000..cd78c54521 --- /dev/null +++ b/src/client/method-reset-failed.h @@ -0,0 +1,11 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#pragma once + +#include "libbluechi/cli/command.h" + +int method_reset_failed(Command *command, void *userdata); +void usage_method_reset_failed(); diff --git a/src/client/method-unit-actions.c b/src/client/method-unit-actions.c deleted file mode 100644 index d0f8599c1b..0000000000 --- a/src/client/method-unit-actions.c +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright Contributors to the Eclipse BlueChi project - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ -#include "method-unit-actions.h" -#include "client.h" - -#include "libbluechi/common/opt.h" - -static int method_lifecycle_action_on(Client *client, char *node_name, char *unit, char *method) { - _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_sd_bus_message_ sd_bus_message *message = NULL; - _cleanup_sd_bus_message_ sd_bus_message *job_result = NULL; - char *job_path = NULL, *result = NULL, *node = NULL; - uint32_t id = 0; - int r = 0; - - r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); - if (r < 0) { - return r; - } - - r = sd_bus_match_signal( - client->api_bus, - NULL, - BC_INTERFACE_BASE_NAME, - BC_CONTROLLER_OBJECT_PATH, - CONTROLLER_INTERFACE, - "JobRemoved", - match_job_removed_signal, - client); - - if (r < 0) { - fprintf(stderr, "Failed to match signal\n"); - return r; - } - - r = sd_bus_call_method( - client->api_bus, - BC_INTERFACE_BASE_NAME, - client->object_path, - NODE_INTERFACE, - method, - &error, - &message, - "ss", - unit, - "replace"); - if (r < 0) { - fprintf(stderr, "Failed to issue method call: %s\n", error.message); - return r; - } - - r = sd_bus_message_read(message, "o", &job_path); - if (r < 0) { - fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r)); - return r; - } - - job_result = client_wait_for_job(client, job_path); - if (job_result == NULL) { - return -EIO; - } - - r = sd_bus_message_read(job_result, "uosss", &id, &job_path, &node, &unit, &result); - if (r < 0) { - fprintf(stderr, "Can't parse job result\n"); - return r; - } - - printf("Unit %s %s operation result: %s\n", unit, method, result); - - return r; -} - -static int add_string_array_to_message(sd_bus_message *m, char **units, size_t units_count) { - _cleanup_free_ char **units_array = NULL; - int r = 0; - - units_array = malloc0_array(0, sizeof(char *), units_count + 1); - if (units_array == NULL) { - fprintf(stderr, "Failed to allocate memory\n"); - return -ENOMEM; - } - size_t i = 0; - for (i = 0; i < units_count; i++) { - units_array[i] = units[i]; - } - - r = sd_bus_message_append_strv(m, units_array); - if (r < 0) { - fprintf(stderr, "Failed to append the list of units to the message: %s\n", strerror(-r)); - return r; - } - - return 0; -} - -static int parse_enable_disable_response_from_message(sd_bus_message *m) { - int r = 0; - - r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)"); - if (r < 0) { - fprintf(stderr, "Failed to open the strings array container: %s\n", strerror(-r)); - return r; - } - - for (;;) { - const char *op_type = NULL; - const char *symlink_file = NULL; - const char *symlink_dest = NULL; - - r = sd_bus_message_read(m, "(sss)", &op_type, &symlink_file, &symlink_dest); - if (r < 0) { - fprintf(stderr, "Failed to read enabled unit file information: %s\n", strerror(-r)); - return r; - } - if (r == 0) { - break; - } - if (streq(op_type, "symlink")) { - fprintf(stderr, "Created symlink %s -> %s\n", symlink_file, symlink_dest); - } else if (streq(op_type, "unlink")) { - fprintf(stderr, "Removed \"%s\".\n", symlink_file); - } else { - fprintf(stderr, "Unknown operation: %s\n", op_type); - } - } - - return 0; -} - -static int method_enable_unit_on( - Client *client, char *node_name, char **units, size_t units_count, int runtime, int force) { - int r = 0; - _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_sd_bus_message_ sd_bus_message *result = NULL; - _cleanup_sd_bus_message_ sd_bus_message *outgoing_message = NULL; - - r = client_create_message_new_method_call(client, node_name, "EnableUnitFiles", &outgoing_message); - if (r < 0) { - fprintf(stderr, "Failed to create a new message: %s\n", strerror(-r)); - return r; - } - - r = add_string_array_to_message(outgoing_message, units, units_count); - if (r < 0) { - fprintf(stderr, "Failed to append the string array to the message: %s\n", strerror(-r)); - } - - r = sd_bus_message_append(outgoing_message, "bb", runtime, force); - if (r < 0) { - fprintf(stderr, "Failed to append runtime and force to the message: %s\n", strerror(-r)); - return r; - } - - r = sd_bus_call(client->api_bus, outgoing_message, BC_DEFAULT_DBUS_TIMEOUT, &error, &result); - if (r < 0) { - fprintf(stderr, "Failed to issue call: %s\n", error.message); - return r; - } - - int carries_install_info = 0; - r = sd_bus_message_read(result, "b", &carries_install_info); - if (r < 0) { - fprintf(stderr, "Failed to read carries_install_info from the message: %s\n", strerror(-r)); - return r; - } - - if (carries_install_info) { - fprintf(stderr, "The unit files included enablement information\n"); - } else { - fprintf(stderr, "The unit files did not include any enablement information\n"); - } - - r = parse_enable_disable_response_from_message(result); - if (r < 0) { - fprintf(stderr, "Failed to parse the response strings array: %s\n", error.message); - return r; - } - - return 0; -} - -static int method_disable_unit_on(Client *client, char *node_name, char **units, size_t units_count, int runtime) { - int r = 0; - _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_sd_bus_message_ sd_bus_message *result = NULL; - _cleanup_sd_bus_message_ sd_bus_message *outgoing_message = NULL; - - r = client_create_message_new_method_call(client, node_name, "DisableUnitFiles", &outgoing_message); - if (r < 0) { - fprintf(stderr, "Failed to create a new message: %s\n", strerror(-r)); - return r; - } - - r = add_string_array_to_message(outgoing_message, units, units_count); - if (r < 0) { - fprintf(stderr, "Failed to append the string array to the message: %s\n", strerror(-r)); - } - - r = sd_bus_message_append(outgoing_message, "b", runtime); - if (r < 0) { - fprintf(stderr, "Failed to append runtime to the message: %s\n", strerror(-r)); - return r; - } - - r = sd_bus_call(client->api_bus, outgoing_message, BC_DEFAULT_DBUS_TIMEOUT, &error, &result); - if (r < 0) { - fprintf(stderr, "Failed to issue call: %s\n", error.message); - return r; - } - - r = parse_enable_disable_response_from_message(result); - if (r < 0) { - fprintf(stderr, "Failed to parse the response strings array: %s\n", error.message); - return r; - } - - return 0; -} - -static int method_daemon_reload_on(Client *client, char *node_name) { - int r = 0; - _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_sd_bus_message_ sd_bus_message *result = NULL; - - r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); - if (r < 0) { - return r; - } - - r = sd_bus_call_method( - client->api_bus, - BC_INTERFACE_BASE_NAME, - client->object_path, - NODE_INTERFACE, - "Reload", - &error, - &result, - ""); - if (r < 0) { - fprintf(stderr, "Failed to issue method call: %s\n", error.message); - return r; - } - - return 0; -} - -static int method_freeze_unit_on(Client *client, char *node_name, char *unit) { - int r = 0; - _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_sd_bus_message_ sd_bus_message *result = NULL; - - r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); - if (r < 0) { - return r; - } - - r = sd_bus_call_method( - client->api_bus, - BC_INTERFACE_BASE_NAME, - client->object_path, - NODE_INTERFACE, - "FreezeUnit", - &error, - &result, - "s", - unit); - if (r < 0) { - fprintf(stderr, "Failed to issue method call: %s\n", error.message); - return r; - } - - printf("Unit %s freeze operation done\n", unit); - - return 0; -} - -static int method_thaw_unit_on(Client *client, char *node_name, char *unit) { - int r = 0; - _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_sd_bus_message_ sd_bus_message *result = NULL; - - r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); - if (r < 0) { - return r; - } - - r = sd_bus_call_method( - client->api_bus, - BC_INTERFACE_BASE_NAME, - client->object_path, - NODE_INTERFACE, - "ThawUnit", - &error, - &result, - "s", - unit); - if (r < 0) { - fprintf(stderr, "Failed to issue method call: %s\n", error.message); - return r; - } - - printf("Unit %s thaw operation done\n", unit); - - return 0; -} - -static int method_reset_failed_on_units(Client *client, Command *commands) { - char *node_name = commands->opargv[0]; - int units_count = 1; - int r = 0; - _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_sd_bus_message_ sd_bus_message *result = NULL; - - r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); - if (r < 0) { - return r; - } - - while (commands->opargv[units_count] != NULL) { - printf("%i %s\n", units_count, commands->opargv[units_count]); - r = sd_bus_call_method( - client->api_bus, - BC_INTERFACE_BASE_NAME, - client->object_path, - NODE_INTERFACE, - "ResetFailedUnit", - &error, - &result, - "s", - commands->opargv[units_count]); - - if (r < 0) { - fprintf(stderr, "Failed to issue method call: %s\n", error.message); - return r; - } - units_count++; - } - return r; -} - -static int method_reset_failed_on_node(Client *client, char *node_name) { - - _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_sd_bus_message_ sd_bus_message *result = NULL; - int r = 0; - - r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); - if (r < 0) { - return r; - } - - r = sd_bus_call_method( - client->api_bus, - BC_INTERFACE_BASE_NAME, - client->object_path, - NODE_INTERFACE, - "ResetFailed", - &error, - &result, - ""); - if (r < 0) { - fprintf(stderr, - "Couldn't reset failed state of all units on node '%s': %s\n", - node_name, - error.message); - return r; - } - - return r; -} - -static int method_reset_failed_on_all_nodes(Client *client) { - - int r = 0; - - _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_sd_bus_message_ sd_bus_message *result = NULL; - r = sd_bus_call_method( - client->api_bus, - BC_INTERFACE_BASE_NAME, - BC_OBJECT_PATH, - CONTROLLER_INTERFACE, - "ListNodes", - &error, - &result, - "", - NULL); - if (r < 0) { - fprintf(stderr, "Failed to issue method call: %s\n", error.message); - return r; - } - - r = sd_bus_message_enter_container(result, SD_BUS_TYPE_ARRAY, "(soss)"); - if (r < 0) { - fprintf(stderr, "Failed to open result array: %s\n", strerror(-r)); - return r; - } - while (sd_bus_message_at_end(result, false) == 0) { - const char *name = NULL; - - r = sd_bus_message_read(result, "(soss)", &name, NULL, NULL, NULL); - if (r < 0) { - fprintf(stderr, "Failed to read node information: %s\n", strerror(-r)); - return r; - } - - _cleanup_free_ char *node_name = strdup(name); - r = method_reset_failed_on_node(client, node_name); - } - - return r; -} - -int method_start(Command *command, void *userdata) { - return method_lifecycle_action_on(userdata, command->opargv[0], command->opargv[1], "StartUnit"); -} - -int method_stop(Command *command, void *userdata) { - return method_lifecycle_action_on(userdata, command->opargv[0], command->opargv[1], "StopUnit"); -} - -int method_restart(Command *command, void *userdata) { - return method_lifecycle_action_on(userdata, command->opargv[0], command->opargv[1], "RestartUnit"); -} - -int method_reload(Command *command, void *userdata) { - return method_lifecycle_action_on(userdata, command->opargv[0], command->opargv[1], "ReloadUnit"); -} - -int method_freeze(Command *command, void *userdata) { - return method_freeze_unit_on(userdata, command->opargv[0], command->opargv[1]); -} - -int method_thaw(Command *command, void *userdata) { - return method_thaw_unit_on(userdata, command->opargv[0], command->opargv[1]); -} - -int method_reset_failed(Command *command, void *userdata) { - if (command->opargv[0] != NULL) { - if (command->opargv[1] != NULL) { - return method_reset_failed_on_units(userdata, command); - } - return method_reset_failed_on_node(userdata, command->opargv[0]); - } - return method_reset_failed_on_all_nodes(userdata); -} - -int method_enable(Command *command, void *userdata) { - int r = 0; - r = method_enable_unit_on( - userdata, - command->opargv[0], - &command->opargv[1], - command->opargc - 1, - command_flag_exists(command, ARG_RUNTIME_SHORT), - command_flag_exists(command, ARG_FORCE_SHORT)); - if (r < 0) { - fprintf(stderr, - "Failed to enable the units on node [%s] - %s", - command->opargv[0], - strerror(-r)); - return r; - } - - if (!command_flag_exists(command, ARG_NO_RELOAD_SHORT)) { - r = method_daemon_reload_on(userdata, command->opargv[0]); - } - - return r; -} - -int method_disable(Command *command, void *userdata) { - int r = 0; - r = method_disable_unit_on( - userdata, - command->opargv[0], - &command->opargv[1], - command->opargc - 1, - command_flag_exists(command, ARG_RUNTIME_SHORT)); - if (r < 0) { - fprintf(stderr, - "Failed to disable the units on node [%s] - %s", - command->opargv[0], - strerror(-r)); - } - if (!command_flag_exists(command, ARG_NO_RELOAD_SHORT)) { - r = method_daemon_reload_on(userdata, command->opargv[0]); - } - - return r; -} - -int method_daemon_reload(Command *command, void *userdata) { - return method_daemon_reload_on(userdata, command->opargv[0]); -} diff --git a/src/client/method-unit-lifecycle.c b/src/client/method-unit-lifecycle.c new file mode 100644 index 0000000000..60764dcc6d --- /dev/null +++ b/src/client/method-unit-lifecycle.c @@ -0,0 +1,103 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#include "method-unit-lifecycle.h" +#include "client.h" + +#include "libbluechi/common/opt.h" + +static int method_lifecycle_action_on(Client *client, char *node_name, char *unit, char *method) { + _cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_sd_bus_message_ sd_bus_message *message = NULL; + _cleanup_sd_bus_message_ sd_bus_message *job_result = NULL; + char *job_path = NULL, *result = NULL, *node = NULL; + uint32_t id = 0; + int r = 0; + + r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path); + if (r < 0) { + return r; + } + + r = sd_bus_match_signal( + client->api_bus, + NULL, + BC_INTERFACE_BASE_NAME, + BC_CONTROLLER_OBJECT_PATH, + CONTROLLER_INTERFACE, + "JobRemoved", + match_job_removed_signal, + client); + + if (r < 0) { + fprintf(stderr, "Failed to match signal\n"); + return r; + } + + r = sd_bus_call_method( + client->api_bus, + BC_INTERFACE_BASE_NAME, + client->object_path, + NODE_INTERFACE, + method, + &error, + &message, + "ss", + unit, + "replace"); + if (r < 0) { + fprintf(stderr, "Failed to issue method call: %s\n", error.message); + return r; + } + + r = sd_bus_message_read(message, "o", &job_path); + if (r < 0) { + fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r)); + return r; + } + + job_result = client_wait_for_job(client, job_path); + if (job_result == NULL) { + return -EIO; + } + + r = sd_bus_message_read(job_result, "uosss", &id, &job_path, &node, &unit, &result); + if (r < 0) { + fprintf(stderr, "Can't parse job result\n"); + return r; + } + + printf("Unit %s %s operation result: %s\n", unit, method, result); + + return r; +} + +int method_start(Command *command, void *userdata) { + return method_lifecycle_action_on(userdata, command->opargv[0], command->opargv[1], "StartUnit"); +} + +int method_stop(Command *command, void *userdata) { + return method_lifecycle_action_on(userdata, command->opargv[0], command->opargv[1], "StopUnit"); +} + +int method_restart(Command *command, void *userdata) { + return method_lifecycle_action_on(userdata, command->opargv[0], command->opargv[1], "RestartUnit"); +} + +int method_reload(Command *command, void *userdata) { + return method_lifecycle_action_on(userdata, command->opargv[0], command->opargv[1], "ReloadUnit"); +} + +void usage_method_lifecycle() { + usage_print_header(); + usage_print_description("Start/Stop/Restart/Reload a unit on a node"); + usage_print_usage("bluechictl [start|stop|restart|reload] [nodename] [unitname]"); + printf("\n"); + printf("Examples:\n"); + printf(" bluechictl start primary interesting.service\n"); + printf(" bluechictl stop primary interesting.service\n"); + printf(" bluechictl restart primary interesting.service\n"); + printf(" bluechictl reload primary interesting.service\n"); +} diff --git a/src/client/method-unit-lifecycle.h b/src/client/method-unit-lifecycle.h new file mode 100644 index 0000000000..2397295f24 --- /dev/null +++ b/src/client/method-unit-lifecycle.h @@ -0,0 +1,14 @@ +/* + * Copyright Contributors to the Eclipse BlueChi project + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#pragma once + +#include "libbluechi/cli/command.h" + +int method_start(Command *command, void *userdata); +int method_stop(Command *command, void *userdata); +int method_restart(Command *command, void *userdata); +int method_reload(Command *command, void *userdata); +void usage_method_lifecycle();