diff --git a/daemons/based/based_messages.c b/daemons/based/based_messages.c index d8ab5d788a..d15dde7ae3 100644 --- a/daemons/based/based_messages.c +++ b/daemons/based/based_messages.c @@ -1,532 +1,531 @@ /* * Copyright 2004-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Maximum number of diffs to ignore while waiting for a resync */ #define MAX_DIFF_RETRY 5 bool based_is_primary = false; xmlNode *the_cib = NULL; int cib_process_shutdown_req(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer) { const char *host = crm_element_value(req, PCMK__XA_SRC); *answer = NULL; if (crm_element_value(req, PCMK__XA_CIB_ISREPLYTO) == NULL) { crm_info("Peer %s is requesting to shut down", host); return pcmk_ok; } if (cib_shutdown_flag == FALSE) { crm_err("Peer %s mistakenly thinks we wanted to shut down", host); return -EINVAL; } crm_info("Peer %s has acknowledged our shutdown request", host); terminate_cib(__func__, 0); return pcmk_ok; } // @COMPAT: Remove when PCMK__CIB_REQUEST_NOOP is removed int cib_process_noop(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { crm_trace("Processing \"%s\" event", op); *answer = NULL; return pcmk_ok; } int cib_process_readwrite(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer) { int result = pcmk_ok; crm_trace("Processing \"%s\" event", op); if (pcmk__str_eq(op, PCMK__CIB_REQUEST_IS_PRIMARY, pcmk__str_none)) { if (based_is_primary) { result = pcmk_ok; } else { result = -EPERM; } return result; } if (pcmk__str_eq(op, PCMK__CIB_REQUEST_PRIMARY, pcmk__str_none)) { if (!based_is_primary) { crm_info("We are now in R/W mode"); based_is_primary = true; } else { crm_debug("We are still in R/W mode"); } } else if (based_is_primary) { crm_info("We are now in R/O mode"); based_is_primary = false; } return result; } /* Set to 1 when a sync is requested, incremented when a diff is ignored, * reset to 0 when a sync is received */ static int sync_in_progress = 0; void send_sync_request(const char *host) { xmlNode *sync_me = create_xml_node(NULL, "sync-me"); crm_node_t *peer = NULL; crm_info("Requesting re-sync from %s", (host? host : "all peers")); sync_in_progress = 1; crm_xml_add(sync_me, PCMK__XA_T, T_CIB); crm_xml_add(sync_me, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_SYNC_TO_ONE); crm_xml_add(sync_me, PCMK__XA_CIB_DELEGATED_FROM, stand_alone? "localhost" : crm_cluster->uname); if (host != NULL) { peer = pcmk__get_node(0, host, NULL, pcmk__node_search_cluster); } send_cluster_message(peer, crm_msg_cib, sync_me, FALSE); free_xml(sync_me); } int cib_process_ping(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer) { const char *host = crm_element_value(req, PCMK__XA_SRC); const char *seq = crm_element_value(req, F_CIB_PING_ID); char *digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET); crm_trace("Processing \"%s\" event %s from %s", op, seq, host); *answer = create_xml_node(NULL, PCMK__XE_PING_RESPONSE); crm_xml_add(*answer, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET); crm_xml_add(*answer, PCMK__XA_DIGEST, digest); crm_xml_add(*answer, F_CIB_PING_ID, seq); pcmk__if_tracing( { // Append additional detail so the receiver can log the differences add_message_xml(*answer, PCMK__XA_CIB_CALLDATA, the_cib); }, if (the_cib != NULL) { // Always include at least the version details xmlNode *shallow = create_xml_node(NULL, (const char *) the_cib->name); copy_in_properties(shallow, the_cib); add_message_xml(*answer, PCMK__XA_CIB_CALLDATA, shallow); free_xml(shallow); } ); crm_info("Reporting our current digest to %s: %s for %s.%s.%s", host, digest, crm_element_value(existing_cib, PCMK_XA_ADMIN_EPOCH), crm_element_value(existing_cib, PCMK_XA_EPOCH), crm_element_value(existing_cib, PCMK_XA_NUM_UPDATES)); free(digest); return pcmk_ok; } int cib_process_sync(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer) { return sync_our_cib(req, TRUE); } int cib_process_upgrade_server(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer) { int rc = pcmk_ok; *answer = NULL; if(crm_element_value(req, F_CIB_SCHEMA_MAX)) { /* The originator of an upgrade request sends it to the DC, without * F_CIB_SCHEMA_MAX. If an upgrade is needed, the DC re-broadcasts the * request with F_CIB_SCHEMA_MAX, and each node performs the upgrade * (and notifies its local clients) here. */ return cib_process_upgrade( op, options, section, req, input, existing_cib, result_cib, answer); } else { int new_version = 0; int current_version = 0; xmlNode *scratch = copy_xml(existing_cib); const char *host = crm_element_value(req, PCMK__XA_SRC); const char *value = crm_element_value(existing_cib, PCMK_XA_VALIDATE_WITH); const char *client_id = crm_element_value(req, PCMK__XA_CIB_CLIENTID); const char *call_opts = crm_element_value(req, PCMK__XA_CIB_CALLOPT); const char *call_id = crm_element_value(req, PCMK__XA_CIB_CALLID); crm_trace("Processing \"%s\" event", op); if (value != NULL) { current_version = get_schema_version(value); } rc = update_validation(&scratch, &new_version, 0, TRUE, TRUE); if (new_version > current_version) { xmlNode *up = create_xml_node(NULL, __func__); rc = pcmk_ok; crm_notice("Upgrade request from %s verified", host); crm_xml_add(up, PCMK__XA_T, T_CIB); crm_xml_add(up, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_UPGRADE); crm_xml_add(up, F_CIB_SCHEMA_MAX, get_schema_name(new_version)); crm_xml_add(up, PCMK__XA_CIB_DELEGATED_FROM, host); crm_xml_add(up, PCMK__XA_CIB_CLIENTID, client_id); crm_xml_add(up, PCMK__XA_CIB_CALLOPT, call_opts); crm_xml_add(up, PCMK__XA_CIB_CALLID, call_id); if (cib_legacy_mode() && based_is_primary) { rc = cib_process_upgrade( op, options, section, up, input, existing_cib, result_cib, answer); } else { send_cluster_message(NULL, crm_msg_cib, up, FALSE); } free_xml(up); } else if(rc == pcmk_ok) { rc = -pcmk_err_schema_unchanged; } if (rc != pcmk_ok) { // Notify originating peer so it can notify its local clients crm_node_t *origin = NULL; origin = pcmk__search_node_caches(0, host, pcmk__node_search_cluster); crm_info("Rejecting upgrade request from %s: %s " CRM_XS " rc=%d peer=%s", host, pcmk_strerror(rc), rc, (origin? origin->uname : "lost")); if (origin) { xmlNode *up = create_xml_node(NULL, __func__); crm_xml_add(up, PCMK__XA_T, T_CIB); crm_xml_add(up, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_UPGRADE); crm_xml_add(up, PCMK__XA_CIB_DELEGATED_FROM, host); crm_xml_add(up, PCMK__XA_CIB_ISREPLYTO, host); crm_xml_add(up, PCMK__XA_CIB_CLIENTID, client_id); crm_xml_add(up, PCMK__XA_CIB_CALLOPT, call_opts); crm_xml_add(up, PCMK__XA_CIB_CALLID, call_id); crm_xml_add_int(up, PCMK__XA_CIB_UPGRADE_RC, rc); if (send_cluster_message(origin, crm_msg_cib, up, TRUE) == FALSE) { crm_warn("Could not send CIB upgrade result to %s", host); } free_xml(up); } } free_xml(scratch); } return rc; } int cib_process_sync_one(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer) { return sync_our_cib(req, FALSE); } int cib_server_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer) { int rc = pcmk_ok; if (sync_in_progress > MAX_DIFF_RETRY) { /* Don't ignore diffs forever; the last request may have been lost. * If the diff fails, we'll ask for another full resync. */ sync_in_progress = 0; } // The primary instance should never ignore a diff if (sync_in_progress && !based_is_primary) { int diff_add_updates = 0; int diff_add_epoch = 0; int diff_add_admin_epoch = 0; int diff_del_updates = 0; int diff_del_epoch = 0; int diff_del_admin_epoch = 0; cib_diff_version_details(input, &diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, &diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates); sync_in_progress++; crm_notice("Not applying diff %d.%d.%d -> %d.%d.%d (sync in progress)", diff_del_admin_epoch, diff_del_epoch, diff_del_updates, diff_add_admin_epoch, diff_add_epoch, diff_add_updates); return -pcmk_err_diff_resync; } rc = cib_process_diff(op, options, section, req, input, existing_cib, result_cib, answer); crm_trace("result: %s (%d), %s", pcmk_strerror(rc), rc, (based_is_primary? "primary": "secondary")); if ((rc == -pcmk_err_diff_resync) && !based_is_primary) { free_xml(*result_cib); *result_cib = NULL; send_sync_request(NULL); } else if (rc == -pcmk_err_diff_resync) { rc = -pcmk_err_diff_failed; if (options & cib_force_diff) { crm_warn("Not requesting full refresh in R/W mode"); } } else if ((rc != pcmk_ok) && !based_is_primary && cib_legacy_mode()) { crm_warn("Requesting full CIB refresh because update failed: %s" CRM_XS " rc=%d", pcmk_strerror(rc), rc); pcmk__log_xml_patchset(LOG_INFO, input); free_xml(*result_cib); *result_cib = NULL; send_sync_request(NULL); } return rc; } int cib_process_replace_svr(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer) { int rc = cib_process_replace(op, options, section, req, input, existing_cib, result_cib, answer); if ((rc == pcmk_ok) && pcmk__xe_is(input, PCMK_XE_CIB)) { sync_in_progress = 0; } return rc; } // @COMPAT: Remove when PCMK__CIB_REQUEST_ABS_DELETE is removed int cib_process_delete_absolute(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer) { return -EINVAL; } static xmlNode * cib_msg_copy(xmlNode *msg) { static const char *field_list[] = { PCMK__XA_T, PCMK__XA_CIB_CLIENTID, PCMK__XA_CIB_CALLOPT, PCMK__XA_CIB_CALLID, PCMK__XA_CIB_OP, PCMK__XA_CIB_ISREPLYTO, PCMK__XA_CIB_SECTION, PCMK__XA_CIB_HOST, PCMK__XA_CIB_RC, PCMK__XA_CIB_DELEGATED_FROM, PCMK__XA_CIB_OBJECT, PCMK__XA_CIB_OBJECT_TYPE, - F_CIB_TIMEOUT, F_CIB_GLOBAL_UPDATE, PCMK__XA_CIB_CLIENTNAME, F_CIB_USER, F_CIB_NOTIFY_TYPE, F_CIB_NOTIFY_ACTIVATE }; xmlNode *copy = create_xml_node(NULL, "copy"); CRM_ASSERT(copy != NULL); for (int lpc = 0; lpc < PCMK__NELEM(field_list); lpc++) { const char *field = field_list[lpc]; const char *value = crm_element_value(msg, field); if (value != NULL) { crm_xml_add(copy, field, value); } } return copy; } int sync_our_cib(xmlNode * request, gboolean all) { int result = pcmk_ok; char *digest = NULL; const char *host = crm_element_value(request, PCMK__XA_SRC); const char *op = crm_element_value(request, PCMK__XA_CIB_OP); crm_node_t *peer = NULL; xmlNode *replace_request = NULL; CRM_CHECK(the_cib != NULL, return -EINVAL); CRM_CHECK(all || (host != NULL), return -EINVAL); crm_debug("Syncing CIB to %s", all ? "all peers" : host); replace_request = cib_msg_copy(request); if (host != NULL) { crm_xml_add(replace_request, PCMK__XA_CIB_ISREPLYTO, host); } if (all) { xml_remove_prop(replace_request, PCMK__XA_CIB_HOST); } crm_xml_add(replace_request, PCMK__XA_CIB_OP, PCMK__CIB_REQUEST_REPLACE); // @TODO Keep for tracing, or drop? crm_xml_add(replace_request, PCMK__XA_ORIGINAL_CIB_OP, op); pcmk__xe_set_bool_attr(replace_request, F_CIB_GLOBAL_UPDATE, true); crm_xml_add(replace_request, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET); digest = calculate_xml_versioned_digest(the_cib, FALSE, TRUE, CRM_FEATURE_SET); crm_xml_add(replace_request, PCMK__XA_DIGEST, digest); add_message_xml(replace_request, PCMK__XA_CIB_CALLDATA, the_cib); if (!all) { peer = pcmk__get_node(0, host, NULL, pcmk__node_search_cluster); } if (!send_cluster_message(peer, crm_msg_cib, replace_request, FALSE)) { result = -ENOTCONN; } free_xml(replace_request); free(digest); return result; } int cib_process_commit_transaction(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { /* On success, our caller will activate *result_cib locally, trigger a * replace notification if appropriate, and sync *result_cib to all nodes. * On failure, our caller will free *result_cib. */ int rc = pcmk_rc_ok; const char *client_id = crm_element_value(req, PCMK__XA_CIB_CLIENTID); const char *origin = crm_element_value(req, PCMK__XA_SRC); pcmk__client_t *client = pcmk__find_client_by_id(client_id); rc = based_commit_transaction(input, client, origin, result_cib); if (rc != pcmk_rc_ok) { char *source = based_transaction_source_str(client, origin); crm_err("Could not commit transaction for %s: %s", source, pcmk_rc_str(rc)); free(source); } return pcmk_rc2legacy(rc); } int cib_process_schemas(const char *op, int options, const char *section, xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode **answer) { xmlNode *data = NULL; const char *after_ver = NULL; GList *schemas = NULL; GList *already_included = NULL; *answer = create_xml_node(NULL, PCMK__XA_SCHEMAS); data = get_message_xml(req, PCMK__XA_CIB_CALLDATA); if (data == NULL) { crm_warn("No data specified in request"); return -EPROTO; } after_ver = crm_element_value(data, PCMK_XA_VERSION); if (after_ver == NULL) { crm_warn("No version specified in request"); return -EPROTO; } /* The client requested all schemas after the latest one we know about, which * means the client is fully up-to-date. Return a properly formatted reply * with no schemas. */ if (pcmk__str_eq(after_ver, xml_latest_schema(), pcmk__str_none)) { return pcmk_ok; } schemas = pcmk__schema_files_later_than(after_ver); for (GList *iter = schemas; iter != NULL; iter = iter->next) { pcmk__build_schema_xml_node(*answer, iter->data, &already_included); } g_list_free_full(schemas, free); g_list_free_full(already_included, free); return pcmk_ok; } diff --git a/include/crm/cib/internal.h b/include/crm/cib/internal.h index 3b800c3057..c2f37bccc9 100644 --- a/include/crm/cib/internal.h +++ b/include/crm/cib/internal.h @@ -1,329 +1,328 @@ /* * Copyright 2004-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef CIB_INTERNAL__H # define CIB_INTERNAL__H # include # include # include // Request types for CIB manager IPC/CPG #define PCMK__CIB_REQUEST_SECONDARY "cib_slave" #define PCMK__CIB_REQUEST_PRIMARY "cib_master" #define PCMK__CIB_REQUEST_SYNC_TO_ALL "cib_sync" #define PCMK__CIB_REQUEST_SYNC_TO_ONE "cib_sync_one" #define PCMK__CIB_REQUEST_IS_PRIMARY "cib_ismaster" #define PCMK__CIB_REQUEST_BUMP "cib_bump" #define PCMK__CIB_REQUEST_QUERY "cib_query" #define PCMK__CIB_REQUEST_CREATE "cib_create" #define PCMK__CIB_REQUEST_MODIFY "cib_modify" #define PCMK__CIB_REQUEST_DELETE "cib_delete" #define PCMK__CIB_REQUEST_ERASE "cib_erase" #define PCMK__CIB_REQUEST_REPLACE "cib_replace" #define PCMK__CIB_REQUEST_APPLY_PATCH "cib_apply_diff" #define PCMK__CIB_REQUEST_UPGRADE "cib_upgrade" #define PCMK__CIB_REQUEST_ABS_DELETE "cib_delete_alt" #define PCMK__CIB_REQUEST_NOOP "noop" #define PCMK__CIB_REQUEST_SHUTDOWN "cib_shutdown_req" #define PCMK__CIB_REQUEST_COMMIT_TRANSACT "cib_commit_transact" #define PCMK__CIB_REQUEST_SCHEMAS "cib_schemas" -# define F_CIB_TIMEOUT "cib_timeout" # define F_CIB_GLOBAL_UPDATE "cib_update" # define F_CIB_UPDATE_RESULT "cib_update_result" # define F_CIB_NOTIFY_TYPE "cib_notify_type" # define F_CIB_NOTIFY_ACTIVATE "cib_notify_activate" # define F_CIB_UPDATE_DIFF "cib_update_diff" # define F_CIB_USER "cib_user" # define F_CIB_LOCAL_NOTIFY_ID "cib_local_notify_id" # define F_CIB_PING_ID "cib_ping_id" # define F_CIB_SCHEMA_MAX "cib_schema_max" # define T_CIB "cib" # define T_CIB_COMMAND "cib_command" # define T_CIB_NOTIFY "cib_notify" /* notify sub-types */ # define T_CIB_PRE_NOTIFY "cib_pre_notify" # define T_CIB_POST_NOTIFY "cib_post_notify" # define T_CIB_TRANSACTION "cib_transaction" # define T_CIB_UPDATE_CONFIRM "cib_update_confirmation" /*! * \internal * \enum cib__op_attr * \brief Flags for CIB operation attributes */ enum cib__op_attr { cib__op_attr_none = 0, //!< No special attributes cib__op_attr_modifies = (1 << 1), //!< Modifies CIB cib__op_attr_privileged = (1 << 2), //!< Requires privileges cib__op_attr_local = (1 << 3), //!< Must only be processed locally cib__op_attr_replaces = (1 << 4), //!< Replaces CIB cib__op_attr_writes_through = (1 << 5), //!< Writes to disk on success cib__op_attr_transaction = (1 << 6), //!< Supported in a transaction }; /*! * \internal * \enum cib__op_type * \brief Types of CIB operations */ enum cib__op_type { cib__op_abs_delete, cib__op_apply_patch, cib__op_bump, cib__op_commit_transact, cib__op_create, cib__op_delete, cib__op_erase, cib__op_is_primary, cib__op_modify, cib__op_noop, cib__op_ping, cib__op_primary, cib__op_query, cib__op_replace, cib__op_secondary, cib__op_shutdown, cib__op_sync_all, cib__op_sync_one, cib__op_upgrade, cib__op_schemas, }; gboolean cib_diff_version_details(xmlNode * diff, int *admin_epoch, int *epoch, int *updates, int *_admin_epoch, int *_epoch, int *_updates); gboolean cib_read_config(GHashTable * options, xmlNode * current_cib); typedef int (*cib__op_fn_t)(const char *, int, const char *, xmlNode *, xmlNode *, xmlNode *, xmlNode **, xmlNode **); typedef struct cib__operation_s { const char *name; enum cib__op_type type; uint32_t flags; //!< Group of enum cib__op_attr flags } cib__operation_t; typedef struct cib_notify_client_s { const char *event; const char *obj_id; /* implement one day */ const char *obj_type; /* implement one day */ void (*callback) (const char *event, xmlNode * msg); } cib_notify_client_t; typedef struct cib_callback_client_s { void (*callback) (xmlNode *, int, int, xmlNode *, void *); const char *id; void *user_data; gboolean only_success; struct timer_rec_s *timer; void (*free_func)(void *); } cib_callback_client_t; struct timer_rec_s { int call_id; int timeout; guint ref; cib_t *cib; }; #define cib__set_call_options(cib_call_opts, call_for, flags_to_set) do { \ cib_call_opts = pcmk__set_flags_as(__func__, __LINE__, \ LOG_TRACE, "CIB call", (call_for), (cib_call_opts), \ (flags_to_set), #flags_to_set); \ } while (0) #define cib__clear_call_options(cib_call_opts, call_for, flags_to_clear) do { \ cib_call_opts = pcmk__clear_flags_as(__func__, __LINE__, \ LOG_TRACE, "CIB call", (call_for), (cib_call_opts), \ (flags_to_clear), #flags_to_clear); \ } while (0) cib_t *cib_new_variant(void); /*! * \internal * \brief Check whether a given CIB client's update should trigger a refresh * * Here, "refresh" means that Pacemaker daemons write out their current state. * * If a Pacemaker daemon or one of certain Pacemaker CLI tools modifies the CIB, * we can assume that the CIB hasn't diverged from the true cluster state. A * "safe" CLI tool requests that all relevant daemons update their state before * the tool requests any CIB modifications directly. * * In contrast, other "unsafe" tools (for example, \c cibadmin and external * tools) may request arbitrary CIB changes. * * A Pacemaker daemon can write out its current state to the CIB when it's * notified of an update from an unsafe client, to ensure the CIB still contains * the daemon's correct state. * * \param[in] name CIB client name * * \return \c true if the CIB client should trigger a refresh, or \c false * otherwise */ static inline bool cib__client_triggers_refresh(const char *name) { return !crm_is_daemon_name(name) && !pcmk__str_any_of(name, "attrd_updater", "crm_attribute", "crm_node", "crm_resource", "crm_ticket", NULL); } int cib__get_notify_patchset(const xmlNode *msg, const xmlNode **patchset); bool cib__element_in_patchset(const xmlNode *patchset, const char *element); int cib_perform_op(cib_t *cib, const char *op, int call_options, cib__op_fn_t fn, bool is_query, const char *section, xmlNode *req, xmlNode *input, bool manage_counters, bool *config_changed, xmlNode **current_cib, xmlNode **result_cib, xmlNode **diff, xmlNode **output); int cib__create_op(cib_t *cib, const char *op, const char *host, const char *section, xmlNode *data, int call_options, const char *user_name, const char *client_name, xmlNode **op_msg); int cib__extend_transaction(cib_t *cib, xmlNode *request); void cib_native_callback(cib_t * cib, xmlNode * msg, int call_id, int rc); void cib_native_notify(gpointer data, gpointer user_data); int cib__get_operation(const char *op, const cib__operation_t **operation); int cib_process_query(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_erase(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_bump(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_replace(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_create(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_modify(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_delete(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_diff(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); int cib_process_upgrade(const char *op, int options, const char *section, xmlNode * req, xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib, xmlNode ** answer); /*! * \internal * \brief Query or modify a CIB * * \param[in] op PCMK__CIB_REQUEST_* operation to be performed * \param[in] options Flag set of \c cib_call_options * \param[in] section XPath to query or modify * \param[in] req unused * \param[in] input Portion of CIB to modify (used with * PCMK__CIB_REQUEST_CREATE, * PCMK__CIB_REQUEST_MODIFY, and * PCMK__CIB_REQUEST_REPLACE) * \param[in,out] existing_cib Input CIB (used with PCMK__CIB_REQUEST_QUERY) * \param[in,out] result_cib CIB copy to make changes in (used with * PCMK__CIB_REQUEST_CREATE, * PCMK__CIB_REQUEST_MODIFY, * PCMK__CIB_REQUEST_DELETE, and * PCMK__CIB_REQUEST_REPLACE) * \param[out] answer Query result (used with PCMK__CIB_REQUEST_QUERY) * * \return Legacy Pacemaker return code */ int cib_process_xpath(const char *op, int options, const char *section, const xmlNode *req, xmlNode *input, xmlNode *existing_cib, xmlNode **result_cib, xmlNode ** answer); bool cib__config_changed_v1(xmlNode *last, xmlNode *next, xmlNode **diff); int cib_internal_op(cib_t * cib, const char *op, const char *host, const char *section, xmlNode * data, xmlNode ** output_data, int call_options, const char *user_name); int cib_file_read_and_verify(const char *filename, const char *sigfile, xmlNode **root); int cib_file_write_with_digest(xmlNode *cib_root, const char *cib_dirname, const char *cib_filename); void cib__set_output(cib_t *cib, pcmk__output_t *out); cib_callback_client_t* cib__lookup_id (int call_id); /*! * \internal * \brief Connect to, query, and optionally disconnect from the CIB * * Open a read-write connection to the CIB manager if an already connected * client is not passed in. Then query the CIB and store the resulting XML. * Finally, disconnect if the CIB connection isn't being returned to the caller. * * \param[in,out] out Output object (may be \p NULL) * \param[in,out] cib If not \p NULL, where to store CIB connection * \param[out] cib_object Where to store query result * * \return Standard Pacemaker return code * * \note If \p cib is not \p NULL, the caller is responsible for freeing \p *cib * using \p cib_delete(). * \note If \p *cib points to an existing \p cib_t object, this function will * reuse it instead of creating a new one. If the existing client is * already connected, the connection will be reused, even if it's * read-only. */ int cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object); int cib__clean_up_connection(cib_t **cib); int cib__update_node_attr(pcmk__output_t *out, cib_t *cib, int call_options, const char *section, const char *node_uuid, const char *set_type, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value, const char *user_name, const char *node_type); int cib__get_node_attrs(pcmk__output_t *out, cib_t *cib, const char *section, const char *node_uuid, const char *set_type, const char *set_name, const char *attr_id, const char *attr_name, const char *user_name, xmlNode **result); int cib__delete_node_attr(pcmk__output_t *out, cib_t *cib, int options, const char *section, const char *node_uuid, const char *set_type, const char *set_name, const char *attr_id, const char *attr_name, const char *attr_value, const char *user_name); #endif