From f43885b47d8d632043c50d8500bf9d1ce8206d77 Mon Sep 17 00:00:00 2001 From: Amin Ben Romdhane Date: Tue, 28 Nov 2023 14:47:36 +0000 Subject: [PATCH] T#11633: bbfdm: Support transaction commit/abort for microservices --- bbfdmd/ubus/bbfdmd.c | 33 ++++++++++++------ bbfdmd/ubus/get_helper.c | 37 ++++++++++++++++---- bbfdmd/ubus/get_helper.h | 6 ++-- libbbfdm-api/dmapi.h | 1 + libbbfdm-api/dmbbf.c | 3 ++ libbbfdm-api/dmentry.c | 10 ------ libbbfdm-api/dmentry.h | 3 ++ libbbfdm-api/dmplugin.c | 75 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 138 insertions(+), 30 deletions(-) diff --git a/bbfdmd/ubus/bbfdmd.c b/bbfdmd/ubus/bbfdmd.c index 42182e85..898f62a7 100644 --- a/bbfdmd/ubus/bbfdmd.c +++ b/bbfdmd/ubus/bbfdmd.c @@ -562,6 +562,7 @@ int bbfdm_set_handler(struct ubus_context *ctx, struct ubus_object *obj, blob_buf_init(&data.bb, 0); bbf_init(&data.bbf_ctx); + data.ctx = ctx; data.bbf_ctx.in_param = path; fault = fill_pvlist_set(&data, path, tb[DM_SET_VALUE] ? blobmsg_get_string(tb[DM_SET_VALUE]) : NULL, tb[DM_SET_OBJ_PATH], &pv_list); @@ -584,11 +585,13 @@ int bbfdm_set_handler(struct ubus_context *ctx, struct ubus_object *obj, WARNING("Transaction not started yet"); fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); goto end; + } else { + data.bbf_ctx.trans_id = data.trans_id; } if (data.trans_id == 0) { // Transaction-id is not defined so create an internal transaction - trans_id = transaction_start("INT_SET", 0); + trans_id = transaction_start(&data, "INT_SET", 0); if (trans_id == 0) { WARNING("Failed to get the lock for the transaction"); fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); @@ -600,7 +603,7 @@ int bbfdm_set_handler(struct ubus_context *ctx, struct ubus_object *obj, if (data.trans_id == 0) { // Internal transaction: need to commit the changes - transaction_commit(trans_id, NULL, true); + transaction_commit(NULL, trans_id, true); } end: @@ -687,6 +690,7 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj, snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[DM_ADD_PATH])); + data.ctx = ctx; data.bbf_ctx.in_param = path; fill_optional_data(&data, tb[DM_ADD_OPTIONAL]); @@ -701,11 +705,13 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj, WARNING("Transaction not started yet"); fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); goto end; + } else { + data.bbf_ctx.trans_id = data.trans_id; } if (data.trans_id == 0) { // Transaction-id is not defined so create an internal transaction - trans_id = transaction_start("INT_ADD", 0); + trans_id = transaction_start(&data, "INT_ADD", 0); if (trans_id == 0) { ERR("Failed to get the lock for the transaction"); fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); @@ -719,7 +725,7 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj, if (data.trans_id == 0) { // Internal transaction: need to abort the changes - transaction_abort(trans_id, NULL); + transaction_abort(NULL, trans_id); } goto end; @@ -737,7 +743,7 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj, if (data.trans_id == 0) { // Internal transaction: need to abort the changes - transaction_abort(trans_id, NULL); + transaction_abort(NULL, trans_id); } free_pv_list(&pv_list); @@ -753,7 +759,7 @@ int bbfdm_add_handler(struct ubus_context *ctx, struct ubus_object *obj, if (data.trans_id == 0) { // Internal transaction: need to commit the changes - transaction_commit(trans_id, NULL, true); + transaction_commit(NULL, trans_id, true); } end: @@ -805,6 +811,7 @@ int bbfdm_del_handler(struct ubus_context *ctx, struct ubus_object *obj, } } + data.ctx = ctx; data.plist = &paths_list; fill_optional_data(&data, tb[DM_DEL_OPTIONAL]); @@ -821,11 +828,13 @@ int bbfdm_del_handler(struct ubus_context *ctx, struct ubus_object *obj, WARNING("Transaction not started yet"); fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); goto end; + } else { + data.bbf_ctx.trans_id = data.trans_id; } if (data.trans_id == 0) { // Transaction-id is not defined so create an internal transaction - trans_id = transaction_start("INT_DEL", 0); + trans_id = transaction_start(&data, "INT_DEL", 0); if (trans_id == 0) { WARNING("Failed to get the lock for the transaction"); fill_err_code_array(&data, USP_FAULT_INTERNAL_ERROR); @@ -837,7 +846,7 @@ int bbfdm_del_handler(struct ubus_context *ctx, struct ubus_object *obj, if (data.trans_id == 0) { // Internal transaction: need to commit the changes - transaction_commit(trans_id, NULL, true); + transaction_commit(NULL, trans_id, true); } end: @@ -901,9 +910,11 @@ static int bbfdm_transaction_handler(struct ubus_context *ctx, struct ubus_objec bbf_init(&data.bbf_ctx); blob_buf_init(&data.bb, 0); + data.ctx = ctx; + if (is_str_eq(trans_cmd, "start")) { cancel_periodic_timers(ctx); - ret = transaction_start("API", max_timeout); + ret = transaction_start(&data, "API", max_timeout); if (ret) { blobmsg_add_u8(&data.bb, "status", true); blobmsg_add_u32(&data.bb, "transaction_id", ret); @@ -913,11 +924,11 @@ static int bbfdm_transaction_handler(struct ubus_context *ctx, struct ubus_objec } } else if (is_str_eq(trans_cmd, "commit")) { register_periodic_timers(ctx); - ret = transaction_commit(data.trans_id, &data.bb, is_service_restart); + ret = transaction_commit(&data, data.trans_id, is_service_restart); blobmsg_add_u8(&data.bb, "status", (ret == 0)); } else if (is_str_eq(trans_cmd, "abort")) { register_periodic_timers(ctx); - ret = transaction_abort(data.trans_id, &data.bb); + ret = transaction_abort(&data, data.trans_id); blobmsg_add_u8(&data.bb, "status", (ret == 0)); } else if (is_str_eq(trans_cmd, "status")) { transaction_status(&data.bb); diff --git a/bbfdmd/ubus/get_helper.c b/bbfdmd/ubus/get_helper.c index a37c3e52..5c304901 100644 --- a/bbfdmd/ubus/get_helper.c +++ b/bbfdmd/ubus/get_helper.c @@ -18,6 +18,8 @@ #include "common.h" #include "pretty_print.h" +extern struct list_head head_registered_service; + DMOBJ *DEAMON_DM_ROOT_OBJ = NULL; DM_MAP_VENDOR *DEAMON_DM_VENDOR_EXTENSION[2] = {0}; DM_MAP_VENDOR_EXCLUDE *DEAMON_DM_VENDOR_EXTENSION_EXCLUDE = NULL; @@ -187,7 +189,7 @@ void fill_err_code_array(bbfdm_data_t *data, int fault) static void transaction_timeout_handler(struct uloop_timeout *t __attribute__((unused))) { INFO("Transaction timeout called, aborting tid %d", g_current_trans.trans_id); - transaction_abort(g_current_trans.trans_id, NULL); + transaction_abort(NULL, g_current_trans.trans_id); } static int get_random_id(void) @@ -269,7 +271,7 @@ static int compare_path(const void *arg1, const void *arg2) } // Returns transaction id if successful, otherwise 0 -int transaction_start(char *app, uint32_t max_timeout) +int transaction_start(bbfdm_data_t *data, char *app, uint32_t max_timeout) { int ret = 0; uint32_t timeout; @@ -280,12 +282,12 @@ int transaction_start(char *app, uint32_t max_timeout) } if (max_timeout > 0) { - timeout = max_timeout; + timeout = max_timeout * 1000; } else { timeout = g_current_trans.timeout_ms; } - ret = get_random_id(); + ret = data->trans_id ? data->trans_id : get_random_id(); strncpyt(g_current_trans.app, app, 32); g_current_trans.trans_id = ret; @@ -293,6 +295,11 @@ int transaction_start(char *app, uint32_t max_timeout) uloop_timeout_set(&g_current_trans.trans_timeout, timeout); INFO("Transaction created by [%s] id %d, timeout %zd", g_current_trans.app, g_current_trans.trans_id, timeout); + if (data->trans_id) { + // Call transaction for registered services only if transaction id is defined + handle_transaction_of_registered_service(data->ctx, NULL, &head_registered_service, "start", ret, timeout/1000, 0); + } + return ret; } @@ -323,17 +330,26 @@ bool is_transaction_valid(int trans_id) return (trans_id == g_current_trans.trans_id); } -int transaction_commit(int trans_id, struct blob_buf *bb, bool is_service_restart) +int transaction_commit(bbfdm_data_t *data, int trans_id, bool is_service_restart) { int ret = -1; if (is_transaction_valid(trans_id)) { + struct blob_buf *bb = data ? &data->bb : NULL; + void *arr = NULL; + INFO("Commit on-going transaction by %s", g_current_trans.app); uloop_timeout_cancel(&g_current_trans.trans_timeout); g_current_trans.trans_id = 0; g_current_trans.app[0] = '\0'; + if (bb) arr = blobmsg_open_array(bb, "updated_services"); bbf_entry_restart_services(bb, is_service_restart); + if (data && data->trans_id) { + // Call transaction for registered services only if transaction id is defined + handle_transaction_of_registered_service(data->ctx, bb, &head_registered_service, "commit", data->trans_id, 0, is_service_restart); + } + if (bb) blobmsg_close_array(bb, arr); ret = 0; } else { @@ -343,17 +359,26 @@ int transaction_commit(int trans_id, struct blob_buf *bb, bool is_service_restar return ret; } -int transaction_abort(int trans_id, struct blob_buf *bb) +int transaction_abort(bbfdm_data_t *data, int trans_id) { int ret = -1; if (is_transaction_valid(trans_id)) { + struct blob_buf *bb = data ? &data->bb : NULL; + void *arr = NULL; + INFO("Abort on-going transaction by %s", g_current_trans.app); uloop_timeout_cancel(&g_current_trans.trans_timeout); g_current_trans.trans_id = 0; g_current_trans.app[0] = '\0'; + if (bb) arr = blobmsg_open_array(bb, "reverted_configs"); bbf_entry_revert_changes(bb); + if (data && data->trans_id) { + // Call transaction for registered services only if transaction id is defined + handle_transaction_of_registered_service(data->ctx, bb, &head_registered_service, "abort", data->trans_id, 0, 0); + } + if (bb) blobmsg_close_array(bb, arr); ret = 0; } else { diff --git a/bbfdmd/ubus/get_helper.h b/bbfdmd/ubus/get_helper.h index b2896c0a..4eef1da0 100644 --- a/bbfdmd/ubus/get_helper.h +++ b/bbfdmd/ubus/get_helper.h @@ -40,9 +40,9 @@ void fill_err_code_array(bbfdm_data_t *data, int fault); void bb_add_string(struct blob_buf *bb, const char *name, const char *value); -int transaction_start(char *app, uint32_t max_timeout); -int transaction_commit(int trans_id, struct blob_buf *bb, bool is_service_restart); -int transaction_abort(int trans_id, struct blob_buf *bb); +int transaction_start(bbfdm_data_t *data, char *app, uint32_t max_timeout); +int transaction_commit(bbfdm_data_t *data, int trans_id, bool is_service_restart); +int transaction_abort(bbfdm_data_t *data, int trans_id); int transaction_status(struct blob_buf *bb); bool is_transaction_running(void); bool is_transaction_valid(int trans_id); diff --git a/libbbfdm-api/dmapi.h b/libbbfdm-api/dmapi.h index 5d914a32..b3db4941 100644 --- a/libbbfdm-api/dmapi.h +++ b/libbbfdm-api/dmapi.h @@ -206,6 +206,7 @@ struct dmctx { bool isevent; bool isinfo; bool disable_mservice_browse; + int trans_id; }; typedef struct dmnode { diff --git a/libbbfdm-api/dmbbf.c b/libbbfdm-api/dmbbf.c index 6da35fc5..2170b4f3 100644 --- a/libbbfdm-api/dmbbf.c +++ b/libbbfdm-api/dmbbf.c @@ -1291,6 +1291,7 @@ static int add_ubus_object(struct dmctx *dmctx, struct dmnode *node) json_object_object_add(in_args, "proto", json_object_new_string((dmctx->dm_type == BBFDM_BOTH) ? "both" : (dmctx->dm_type == BBFDM_CWMP) ? "cwmp" : "usp")); json_object_object_add(in_args, "instance_mode", json_object_new_string(dmctx->instance_mode ? "1" : "0")); json_object_object_add(in_args, "format", json_object_new_string("raw")); + json_object_object_add(in_args, "transaction_id", json_object_new_int(dmctx->trans_id)); dmubus_call(ubus_name, "add", UBUS_ARGS{ @@ -1337,6 +1338,7 @@ static int del_ubus_object(struct dmctx *dmctx, struct dmnode *node) json_object_object_add(in_args, "proto", json_object_new_string((dmctx->dm_type == BBFDM_BOTH) ? "both" : (dmctx->dm_type == BBFDM_CWMP) ? "cwmp" : "usp")); json_object_object_add(in_args, "instance_mode", json_object_new_string(dmctx->instance_mode ? "1" : "0")); json_object_object_add(in_args, "format", json_object_new_string("raw")); + json_object_object_add(in_args, "transaction_id", json_object_new_int(dmctx->trans_id)); dmubus_call(ubus_name, "del", UBUS_ARGS{ @@ -1408,6 +1410,7 @@ static int set_ubus_value(struct dmctx *dmctx, struct dmnode *node) json_object_object_add(in_args, "proto", json_object_new_string((dmctx->dm_type == BBFDM_BOTH) ? "both" : (dmctx->dm_type == BBFDM_CWMP) ? "cwmp" : "usp")); json_object_object_add(in_args, "instance_mode", json_object_new_string(dmctx->instance_mode ? "1" : "0")); json_object_object_add(in_args, "format", json_object_new_string("raw")); + json_object_object_add(in_args, "transaction_id", json_object_new_int(dmctx->trans_id)); if (is_reference_parameter(ubus_name, dmctx->in_param, in_args)) { get_reference_paramater_value(dmctx, dmctx->in_value, param_value, sizeof(param_value)); diff --git a/libbbfdm-api/dmentry.c b/libbbfdm-api/dmentry.c index c780d978..c113e14d 100644 --- a/libbbfdm-api/dmentry.c +++ b/libbbfdm-api/dmentry.c @@ -439,9 +439,6 @@ bool adm_entry_object_exists(struct dmctx *ctx, char *param) void bbf_entry_restart_services(struct blob_buf *bb, bool restart_services) { struct package_change *pc = NULL; - void *arr = NULL; - - if (bb) arr = blobmsg_open_array(bb, "updated_services"); list_for_each_entry(pc, &head_package_change, list) { @@ -454,8 +451,6 @@ void bbf_entry_restart_services(struct blob_buf *bb, bool restart_services) } } - if (bb) blobmsg_close_array(bb, arr); - dmuci_commit_bbfdm(); free_all_list_package_change(&head_package_change); @@ -464,9 +459,6 @@ void bbf_entry_restart_services(struct blob_buf *bb, bool restart_services) void bbf_entry_revert_changes(struct blob_buf *bb) { struct package_change *pc = NULL; - void *arr = NULL; - - if (bb) arr = blobmsg_open_array(bb, "reverted_configs"); list_for_each_entry(pc, &head_package_change, list) { @@ -475,8 +467,6 @@ void bbf_entry_revert_changes(struct blob_buf *bb) dmubus_call_set("uci", "revert", UBUS_ARGS{{"config", pc->package, String}}, 1); } - if (bb) blobmsg_close_array(bb, arr); - dmuci_revert_bbfdm(); free_all_list_package_change(&head_package_change); diff --git a/libbbfdm-api/dmentry.h b/libbbfdm-api/dmentry.h index 914ecf93..d312eb7d 100644 --- a/libbbfdm-api/dmentry.h +++ b/libbbfdm-api/dmentry.h @@ -48,4 +48,7 @@ void get_list_of_registered_service(struct list_head *srvlist, struct blob_buf * bool load_service(DMOBJ *main_dm, struct list_head *srv_list, char *srv_name, char *srv_parent_dm, char *srv_obj); void free_services_from_list(struct list_head *clist); +int handle_transaction_of_registered_service(struct ubus_context *ctx, struct blob_buf *trans_bb, struct list_head *srvlist, + const char *trans_cmd, int trans_id, uint32_t max_timeout, bool service_restart); + #endif //__DMENTRY_H__ diff --git a/libbbfdm-api/dmplugin.c b/libbbfdm-api/dmplugin.c index 2aab173f..cf5dbad6 100644 --- a/libbbfdm-api/dmplugin.c +++ b/libbbfdm-api/dmplugin.c @@ -134,6 +134,81 @@ bool load_service(DMOBJ *main_dm, struct list_head *srv_list, char *srv_name, ch return true; } +static void ubus_transaction_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg) +{ + struct blob_attr *tb[2] = {0}; + const struct blobmsg_policy p[2] = { + { "updated_services", BLOBMSG_TYPE_ARRAY }, + { "reverted_configs", BLOBMSG_TYPE_ARRAY } + }; + + if (msg == NULL || req == NULL) + return; + + struct blob_buf *bb = (struct blob_buf *)req->priv; + if (bb == NULL) + return; + + blobmsg_parse(p, 2, tb, blobmsg_data(msg), blobmsg_len(msg)); + + if (tb[0]) { + struct blob_attr *service = NULL; + size_t rem; + + blobmsg_for_each_attr(service, tb[0], rem) { + blobmsg_add_string(bb, NULL, blobmsg_get_string(service)); + } + } + + if (tb[1]) { + struct blob_attr *config = NULL; + size_t rem; + + blobmsg_for_each_attr(config, tb[1], rem) { + blobmsg_add_string(bb, NULL, blobmsg_get_string(config)); + } + } +} + +int handle_transaction_of_registered_service(struct ubus_context *ctx, struct blob_buf *trans_bb, struct list_head *srvlist, + const char *trans_cmd, int trans_id, uint32_t max_timeout, bool service_restart) +{ + struct service *srv = NULL; + + if (is_micro_service == true) // This should be called only from main daemon + return -1; + + if (ctx == NULL || trans_id == 0) + return -1; + + list_for_each_entry(srv, srvlist, list) { + struct blob_buf bb = {0}; + void *table = NULL; + uint32_t ubus_id; + + // check if object already present + int ret = ubus_lookup_id(ctx, srv->name, &ubus_id); + if (ret != 0) + continue; + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + blobmsg_add_string(&bb, "cmd", trans_cmd); + blobmsg_add_u8(&bb, "restart_services", service_restart); + blobmsg_add_u32(&bb, "timeout", max_timeout); + + table = blobmsg_open_table(&bb, "optional"); + blobmsg_add_u32(&bb, "transaction_id", trans_id); + blobmsg_close_table(&bb, table); + + ubus_invoke(ctx, ubus_id, "transaction", bb.head, ubus_transaction_callback, (void *)trans_bb, 5000); + blob_buf_free(&bb); + } + + return 0; +} + void get_list_of_registered_service(struct list_head *srvlist, struct blob_buf *bb) { struct service *srv = NULL;