summaryrefslogtreecommitdiffstats
path: root/daemons/based
diff options
context:
space:
mode:
Diffstat (limited to 'daemons/based')
-rw-r--r--daemons/based/Makefile.am42
-rw-r--r--daemons/based/based_callbacks.c854
-rw-r--r--daemons/based/based_common.c352
-rw-r--r--daemons/based/based_io.c22
-rw-r--r--daemons/based/based_messages.c125
-rw-r--r--daemons/based/based_notify.c99
-rw-r--r--daemons/based/based_operation.c59
-rw-r--r--daemons/based/based_remote.c29
-rw-r--r--daemons/based/based_transaction.c167
-rw-r--r--daemons/based/based_transaction.h24
-rw-r--r--daemons/based/pacemaker-based.c17
-rw-r--r--daemons/based/pacemaker-based.h45
12 files changed, 850 insertions, 985 deletions
diff --git a/daemons/based/Makefile.am b/daemons/based/Makefile.am
index 053d93c..022fc47 100644
--- a/daemons/based/Makefile.am
+++ b/daemons/based/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright 2004-2021 the Pacemaker project contributors
+# Copyright 2004-2023 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
@@ -13,35 +13,37 @@ EXTRA_DIST = cib.pam
halibdir = $(CRM_DAEMON_DIR)
-COMMONLIBS = $(top_builddir)/lib/common/libcrmcommon.la \
- $(top_builddir)/lib/cib/libcib.la
-
halib_PROGRAMS = pacemaker-based
-noinst_HEADERS = pacemaker-based.h
+noinst_HEADERS = based_transaction.h \
+ pacemaker-based.h
pacemaker_based_CFLAGS = $(CFLAGS_HARDENED_EXE)
pacemaker_based_LDFLAGS = $(LDFLAGS_HARDENED_EXE)
-pacemaker_based_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la \
- $(COMMONLIBS) $(CLUSTERLIBS)
-
-pacemaker_based_SOURCES = pacemaker-based.c \
- based_callbacks.c \
- based_common.c \
- based_io.c \
- based_messages.c \
- based_notify.c \
- based_remote.c
-
-clean-generic:
- rm -f *.log *.debug *.xml *~
-
-if BUILD_LEGACY_LINKS
+pacemaker_based_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la
+pacemaker_based_LDADD += $(top_builddir)/lib/cib/libcib.la
+pacemaker_based_LDADD += $(top_builddir)/lib/common/libcrmcommon.la
+pacemaker_based_LDADD += $(CLUSTERLIBS)
+
+pacemaker_based_SOURCES = pacemaker-based.c \
+ based_callbacks.c \
+ based_io.c \
+ based_messages.c \
+ based_notify.c \
+ based_operation.c \
+ based_remote.c \
+ based_transaction.c
+
+.PHONY: install-exec-hook
install-exec-hook:
+if BUILD_LEGACY_LINKS
$(MKDIR_P) -- $(DESTDIR)$(CRM_DAEMON_DIR)
cd $(DESTDIR)$(CRM_DAEMON_DIR) && rm -f cib && $(LN_S) pacemaker-based cib
+endif
+.PHONY: uninstall-hook
uninstall-hook:
+if BUILD_LEGACY_LINKS
cd $(DESTDIR)$(CRM_DAEMON_DIR) && rm -f cib
endif
diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c
index 3726caa..4fac222 100644
--- a/daemons/based/based_callbacks.c
+++ b/daemons/based/based_callbacks.c
@@ -20,6 +20,9 @@
#include <fcntl.h>
#include <inttypes.h> // PRIu64
+#include <glib.h>
+#include <libxml/tree.h>
+
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
@@ -31,7 +34,6 @@
#include <pacemaker-based.h>
#define EXIT_ESCALATION_MS 10000
-#define OUR_NODENAME (stand_alone? "localhost" : crm_cluster->uname)
static unsigned long cib_local_bcast_num = 0;
@@ -50,11 +52,10 @@ qb_ipcs_service_t *ipcs_ro = NULL;
qb_ipcs_service_t *ipcs_rw = NULL;
qb_ipcs_service_t *ipcs_shm = NULL;
-static void cib_process_request(xmlNode *request, gboolean privileged,
- const pcmk__client_t *cib_client);
-
-static int cib_process_command(xmlNode *request, xmlNode **reply,
- xmlNode **cib_diff, gboolean privileged);
+static int cib_process_command(xmlNode *request,
+ const cib__operation_t *operation,
+ cib__op_fn_t op_function, xmlNode **reply,
+ xmlNode **cib_diff, bool privileged);
static gboolean cib_common_callback(qb_ipcs_connection_t *c, void *data,
size_t size, gboolean privileged);
@@ -138,11 +139,130 @@ struct qb_ipcs_service_handlers ipc_rw_callbacks = {
.connection_destroyed = cib_ipc_destroy
};
+/*!
+ * \internal
+ * \brief Create reply XML for a CIB request
+ *
+ * \param[in] op CIB operation type
+ * \param[in] call_id CIB call ID
+ * \param[in] client_id CIB client ID
+ * \param[in] call_options Group of <tt>enum cib_call_options</tt> flags
+ * \param[in] rc Request return code
+ * \param[in] call_data Request output data
+ *
+ * \return Reply XML
+ *
+ * \note The caller is responsible for freeing the return value using
+ * \p free_xml().
+ */
+static xmlNode *
+create_cib_reply(const char *op, const char *call_id, const char *client_id,
+ int call_options, int rc, xmlNode *call_data)
+{
+ xmlNode *reply = create_xml_node(NULL, "cib-reply");
+
+ CRM_ASSERT(reply != NULL);
+
+ crm_xml_add(reply, F_TYPE, T_CIB);
+ crm_xml_add(reply, F_CIB_OPERATION, op);
+ crm_xml_add(reply, F_CIB_CALLID, call_id);
+ crm_xml_add(reply, F_CIB_CLIENTID, client_id);
+ crm_xml_add_int(reply, F_CIB_CALLOPTS, call_options);
+ crm_xml_add_int(reply, F_CIB_RC, rc);
+
+ if (call_data != NULL) {
+ crm_trace("Attaching reply output");
+ add_message_xml(reply, F_CIB_CALLDATA, call_data);
+ }
+
+ crm_log_xml_explicit(reply, "cib:reply");
+ return reply;
+}
+
+static void
+do_local_notify(const xmlNode *notify_src, const char *client_id,
+ bool sync_reply, bool from_peer)
+{
+ int rid = 0;
+ int call_id = 0;
+ pcmk__client_t *client_obj = NULL;
+
+ CRM_ASSERT(notify_src && client_id);
+
+ crm_element_value_int(notify_src, F_CIB_CALLID, &call_id);
+
+ client_obj = pcmk__find_client_by_id(client_id);
+ if (client_obj == NULL) {
+ crm_debug("Could not send response %d: client %s not found",
+ call_id, client_id);
+ return;
+ }
+
+ if (sync_reply) {
+ if (client_obj->ipcs) {
+ CRM_LOG_ASSERT(client_obj->request_id);
+
+ rid = client_obj->request_id;
+ client_obj->request_id = 0;
+
+ crm_trace("Sending response %d to client %s%s",
+ rid, pcmk__client_name(client_obj),
+ (from_peer? " (originator of delegated request)" : ""));
+ } else {
+ crm_trace("Sending response (call %d) to client %s%s",
+ call_id, pcmk__client_name(client_obj),
+ (from_peer? " (originator of delegated request)" : ""));
+ }
+
+ } else {
+ crm_trace("Sending event %d to client %s%s",
+ call_id, pcmk__client_name(client_obj),
+ (from_peer? " (originator of delegated request)" : ""));
+ }
+
+ switch (PCMK__CLIENT_TYPE(client_obj)) {
+ case pcmk__client_ipc:
+ {
+ int rc = pcmk__ipc_send_xml(client_obj, rid, notify_src,
+ (sync_reply? crm_ipc_flags_none
+ : crm_ipc_server_event));
+
+ if (rc != pcmk_rc_ok) {
+ crm_warn("%s reply to client %s failed: %s " CRM_XS " rc=%d",
+ (sync_reply? "Synchronous" : "Asynchronous"),
+ pcmk__client_name(client_obj), pcmk_rc_str(rc),
+ rc);
+ }
+ }
+ break;
+#ifdef HAVE_GNUTLS_GNUTLS_H
+ case pcmk__client_tls:
+#endif
+ case pcmk__client_tcp:
+ pcmk__remote_send_xml(client_obj->remote, notify_src);
+ break;
+ default:
+ crm_err("Unknown transport for client %s "
+ CRM_XS " flags=%#016" PRIx64,
+ pcmk__client_name(client_obj), client_obj->flags);
+ }
+}
+
void
cib_common_callback_worker(uint32_t id, uint32_t flags, xmlNode * op_request,
pcmk__client_t *cib_client, gboolean privileged)
{
const char *op = crm_element_value(op_request, F_CIB_OPERATION);
+ int call_options = cib_none;
+
+ crm_element_value_int(op_request, F_CIB_CALLOPTS, &call_options);
+
+ /* Requests with cib_transaction set should not be sent to based directly
+ * (outside of a commit-transaction request)
+ */
+ if (pcmk_is_set(call_options, cib_transaction)) {
+ return;
+ }
if (pcmk__str_eq(op, CRM_OP_REGISTER, pcmk__str_none)) {
if (flags & crm_ipc_client_response) {
@@ -180,9 +300,6 @@ cib_common_callback_worker(uint32_t id, uint32_t flags, xmlNode * op_request,
} else if (pcmk__str_eq(type, T_CIB_DIFF_NOTIFY, pcmk__str_casei)) {
bit = cib_notify_diff;
- } else if (pcmk__str_eq(type, T_CIB_REPLACE_NOTIFY, pcmk__str_casei)) {
- bit = cib_notify_replace;
-
} else {
status = CRM_EX_INVALID_PARAM;
}
@@ -354,9 +471,7 @@ process_ping_reply(xmlNode *reply)
if(remote_cib && remote_cib->children) {
// Additional debug
xml_calculate_changes(the_cib, remote_cib);
-
- pcmk__output_set_log_level(logger_out, LOG_INFO);
- pcmk__xml_show_changes(logger_out, remote_cib);
+ pcmk__log_xml_changes(LOG_INFO, remote_cib);
crm_trace("End of differences");
}
@@ -367,75 +482,6 @@ process_ping_reply(xmlNode *reply)
}
static void
-do_local_notify(xmlNode * notify_src, const char *client_id,
- gboolean sync_reply, gboolean from_peer)
-{
- int rid = 0;
- int call_id = 0;
- pcmk__client_t *client_obj = NULL;
-
- CRM_ASSERT(notify_src && client_id);
-
- crm_element_value_int(notify_src, F_CIB_CALLID, &call_id);
-
- client_obj = pcmk__find_client_by_id(client_id);
- if (client_obj == NULL) {
- crm_debug("Could not send response %d: client %s not found",
- call_id, client_id);
- return;
- }
-
- if (sync_reply) {
- if (client_obj->ipcs) {
- CRM_LOG_ASSERT(client_obj->request_id);
-
- rid = client_obj->request_id;
- client_obj->request_id = 0;
-
- crm_trace("Sending response %d to client %s%s",
- rid, pcmk__client_name(client_obj),
- (from_peer? " (originator of delegated request)" : ""));
- } else {
- crm_trace("Sending response (call %d) to client %s%s",
- call_id, pcmk__client_name(client_obj),
- (from_peer? " (originator of delegated request)" : ""));
- }
-
- } else {
- crm_trace("Sending event %d to client %s%s",
- call_id, pcmk__client_name(client_obj),
- (from_peer? " (originator of delegated request)" : ""));
- }
-
- switch (PCMK__CLIENT_TYPE(client_obj)) {
- case pcmk__client_ipc:
- {
- int rc = pcmk__ipc_send_xml(client_obj, rid, notify_src,
- (sync_reply? crm_ipc_flags_none
- : crm_ipc_server_event));
-
- if (rc != pcmk_rc_ok) {
- crm_warn("%s reply to client %s failed: %s " CRM_XS " rc=%d",
- (sync_reply? "Synchronous" : "Asynchronous"),
- pcmk__client_name(client_obj), pcmk_rc_str(rc),
- rc);
- }
- }
- break;
-#ifdef HAVE_GNUTLS_GNUTLS_H
- case pcmk__client_tls:
-#endif
- case pcmk__client_tcp:
- pcmk__remote_send_xml(client_obj->remote, notify_src);
- break;
- default:
- crm_err("Unknown transport for client %s "
- CRM_XS " flags=%#016" PRIx64,
- pcmk__client_name(client_obj), client_obj->flags);
- }
-}
-
-static void
local_notify_destroy_callback(gpointer data)
{
cib_local_notify_t *notify = data;
@@ -448,7 +494,7 @@ local_notify_destroy_callback(gpointer data)
static void
check_local_notify(int bcast_id)
{
- cib_local_notify_t *notify = NULL;
+ const cib_local_notify_t *notify = NULL;
if (!local_notify_queue) {
return;
@@ -483,13 +529,14 @@ queue_local_notify(xmlNode * notify_src, const char *client_id, gboolean sync_re
}
static void
-parse_local_options_v1(const pcmk__client_t *cib_client, int call_type,
- int call_options, const char *host, const char *op,
- gboolean *local_notify, gboolean *needs_reply,
- gboolean *process, gboolean *needs_forward)
+parse_local_options_v1(const pcmk__client_t *cib_client,
+ const cib__operation_t *operation, int call_options,
+ const char *host, const char *op, gboolean *local_notify,
+ gboolean *needs_reply, gboolean *process,
+ gboolean *needs_forward)
{
- if (cib_op_modifies(call_type)
- && !(call_options & cib_inhibit_bcast)) {
+ if (pcmk_is_set(operation->flags, cib__op_attr_modifies)
+ && !pcmk_is_set(call_options, cib_inhibit_bcast)) {
/* we need to send an update anyway */
*needs_reply = TRUE;
} else {
@@ -526,78 +573,87 @@ parse_local_options_v1(const pcmk__client_t *cib_client, int call_type,
}
static void
-parse_local_options_v2(const pcmk__client_t *cib_client, int call_type,
- int call_options, const char *host, const char *op,
- gboolean *local_notify, gboolean *needs_reply,
- gboolean *process, gboolean *needs_forward)
+parse_local_options_v2(const pcmk__client_t *cib_client,
+ const cib__operation_t *operation, int call_options,
+ const char *host, const char *op, gboolean *local_notify,
+ gboolean *needs_reply, gboolean *process,
+ gboolean *needs_forward)
{
- if (cib_op_modifies(call_type)) {
- if (pcmk__str_any_of(op, PCMK__CIB_REQUEST_PRIMARY,
- PCMK__CIB_REQUEST_SECONDARY, NULL)) {
- /* Always handle these locally */
- *process = TRUE;
- *needs_reply = FALSE;
- *local_notify = TRUE;
- *needs_forward = FALSE;
- return;
-
- } else {
- /* Redirect all other updates via CPG */
- *needs_reply = TRUE;
- *needs_forward = TRUE;
- *process = FALSE;
- crm_trace("%s op from %s needs to be forwarded to client %s",
- op, pcmk__client_name(cib_client),
- pcmk__s(host, "the primary instance"));
- return;
- }
- }
-
-
+ // Process locally and notify local client
*process = TRUE;
*needs_reply = FALSE;
*local_notify = TRUE;
*needs_forward = FALSE;
- if (stand_alone) {
- crm_trace("Processing %s op from client %s (stand-alone)",
+ if (pcmk_is_set(operation->flags, cib__op_attr_local)) {
+ /* Always process locally if cib__op_attr_local is set.
+ *
+ * @COMPAT: Currently host is ignored. At a compatibility break, throw
+ * an error (from cib_process_request() or earlier) if host is not NULL or
+ * OUR_NODENAME.
+ */
+ crm_trace("Processing always-local %s op from client %s",
op, pcmk__client_name(cib_client));
- } else if (host == NULL) {
- crm_trace("Processing unaddressed %s op from client %s",
- op, pcmk__client_name(cib_client));
+ if (!pcmk__str_eq(host, OUR_NODENAME,
+ pcmk__str_casei|pcmk__str_null_matches)) {
- } else if (pcmk__str_eq(host, OUR_NODENAME, pcmk__str_casei)) {
- crm_trace("Processing locally addressed %s op from client %s",
+ crm_warn("Operation '%s' is always local but its target host is "
+ "set to '%s'",
+ op, host);
+ }
+ return;
+ }
+
+ if (pcmk_is_set(operation->flags, cib__op_attr_modifies)
+ || !pcmk__str_eq(host, OUR_NODENAME,
+ pcmk__str_casei|pcmk__str_null_matches)) {
+
+ // Forward modifying and non-local requests via cluster
+ *process = FALSE;
+ *needs_reply = FALSE;
+ *local_notify = FALSE;
+ *needs_forward = TRUE;
+
+ crm_trace("%s op from %s needs to be forwarded to %s",
+ op, pcmk__client_name(cib_client),
+ pcmk__s(host, "all nodes"));
+ return;
+ }
+
+ if (stand_alone) {
+ crm_trace("Processing %s op from client %s (stand-alone)",
op, pcmk__client_name(cib_client));
} else {
- crm_trace("%s op from %s needs to be forwarded to client %s",
- op, pcmk__client_name(cib_client), host);
- *needs_forward = TRUE;
- *process = FALSE;
+ crm_trace("Processing %saddressed %s op from client %s",
+ ((host != NULL)? "locally " : "un"),
+ op, pcmk__client_name(cib_client));
}
}
static void
-parse_local_options(const pcmk__client_t *cib_client, int call_type,
- int call_options, const char *host, const char *op,
- gboolean *local_notify, gboolean *needs_reply,
- gboolean *process, gboolean *needs_forward)
+parse_local_options(const pcmk__client_t *cib_client,
+ const cib__operation_t *operation, int call_options,
+ const char *host, const char *op, gboolean *local_notify,
+ gboolean *needs_reply, gboolean *process,
+ gboolean *needs_forward)
{
if(cib_legacy_mode()) {
- parse_local_options_v1(cib_client, call_type, call_options, host,
- op, local_notify, needs_reply, process, needs_forward);
+ parse_local_options_v1(cib_client, operation, call_options, host,
+ op, local_notify, needs_reply, process,
+ needs_forward);
} else {
- parse_local_options_v2(cib_client, call_type, call_options, host,
- op, local_notify, needs_reply, process, needs_forward);
+ parse_local_options_v2(cib_client, operation, call_options, host,
+ op, local_notify, needs_reply, process,
+ needs_forward);
}
}
static gboolean
-parse_peer_options_v1(int call_type, xmlNode * request,
- gboolean * local_notify, gboolean * needs_reply, gboolean * process,
- gboolean * needs_forward)
+parse_peer_options_v1(const cib__operation_t *operation, xmlNode *request,
+ gboolean *local_notify, gboolean *needs_reply,
+ gboolean *process)
{
const char *op = NULL;
const char *host = NULL;
@@ -620,7 +676,8 @@ parse_peer_options_v1(int call_type, xmlNode * request,
}
op = crm_element_value(request, F_CIB_OPERATION);
- crm_trace("Processing %s request sent by %s", op, originator);
+ crm_trace("Processing legacy %s request sent by %s", op, originator);
+
if (pcmk__str_eq(op, PCMK__CIB_REQUEST_SHUTDOWN, pcmk__str_none)) {
/* Always process these */
*local_notify = FALSE;
@@ -693,9 +750,9 @@ parse_peer_options_v1(int call_type, xmlNode * request,
}
static gboolean
-parse_peer_options_v2(int call_type, xmlNode * request,
- gboolean * local_notify, gboolean * needs_reply, gboolean * process,
- gboolean * needs_forward)
+parse_peer_options_v2(const cib__operation_t *operation, xmlNode *request,
+ gboolean *local_notify, gboolean *needs_reply,
+ gboolean *process)
{
const char *host = NULL;
const char *delegated = crm_element_value(request, F_CIB_DELEGATED);
@@ -705,6 +762,10 @@ parse_peer_options_v2(int call_type, xmlNode * request,
gboolean is_reply = pcmk__str_eq(reply_to, OUR_NODENAME, pcmk__str_casei);
+ if (originator == NULL) { // Shouldn't be possible
+ originator = "peer";
+ }
+
if (pcmk__str_eq(op, PCMK__CIB_REQUEST_REPLACE, pcmk__str_none)) {
/* sync_our_cib() sets F_CIB_ISREPLY */
if (reply_to) {
@@ -734,10 +795,10 @@ parse_peer_options_v2(int call_type, xmlNode * request,
const char *max = crm_element_value(request, F_CIB_SCHEMA_MAX);
const char *upgrade_rc = crm_element_value(request, F_CIB_UPGRADE_RC);
- crm_trace("Parsing %s operation%s for %s with max=%s and upgrade_rc=%s",
- op, (is_reply? " reply" : ""),
+ crm_trace("Parsing upgrade %s for %s with max=%s and upgrade_rc=%s",
+ (is_reply? "reply" : "request"),
(based_is_primary? "primary" : "secondary"),
- (max? max : "none"), (upgrade_rc? upgrade_rc : "none"));
+ pcmk__s(max, "none"), pcmk__s(upgrade_rc, "none"));
if (upgrade_rc != NULL) {
// Our upgrade request was rejected by DC, notify clients of result
@@ -752,7 +813,7 @@ parse_peer_options_v2(int call_type, xmlNode * request,
goto skip_is_reply;
} else {
- // Ignore broadcast client requests when we're not DC
+ // Ignore broadcast client requests when we're not primary
return FALSE;
}
@@ -762,22 +823,25 @@ parse_peer_options_v2(int call_type, xmlNode * request,
legacy_mode = TRUE;
return FALSE;
- } else if (is_reply && cib_op_modifies(call_type)) {
+ } else if (is_reply
+ && pcmk_is_set(operation->flags, cib__op_attr_modifies)) {
crm_trace("Ignoring legacy %s reply sent from %s to local clients", op, originator);
return FALSE;
} else if (pcmk__str_eq(op, PCMK__CIB_REQUEST_SHUTDOWN, pcmk__str_none)) {
- /* Legacy handling */
- crm_debug("Legacy handling of %s message from %s", op, originator);
*local_notify = FALSE;
if (reply_to == NULL) {
*process = TRUE;
+ } else { // Not possible?
+ crm_debug("Ignoring shutdown request from %s because reply_to=%s",
+ originator, reply_to);
}
return *process;
}
- if(is_reply) {
- crm_trace("Handling %s reply sent from %s to local clients", op, originator);
+ if (is_reply) {
+ crm_trace("Will notify local clients for %s reply from %s",
+ op, originator);
*process = FALSE;
*needs_reply = FALSE;
*local_notify = TRUE;
@@ -797,62 +861,78 @@ parse_peer_options_v2(int call_type, xmlNode * request,
return TRUE;
} else if (host != NULL) {
- /* this is for a specific instance and we're not it */
- crm_trace("Ignoring %s operation for instance on %s", op, host);
+ crm_trace("Ignoring %s request intended for CIB manager on %s",
+ op, host);
return FALSE;
} else if(is_reply == FALSE && pcmk__str_eq(op, CRM_OP_PING, pcmk__str_casei)) {
*needs_reply = TRUE;
}
- crm_trace("Processing %s request sent to everyone by %s/%s on %s %s", op,
- crm_element_value(request, F_CIB_CLIENTNAME),
- crm_element_value(request, F_CIB_CALLID),
- originator, (*local_notify)?"(notify)":"");
+ crm_trace("Processing %s request broadcast by %s call %s on %s "
+ "(local clients will%s be notified)", op,
+ pcmk__s(crm_element_value(request, F_CIB_CLIENTNAME), "client"),
+ pcmk__s(crm_element_value(request, F_CIB_CALLID), "without ID"),
+ originator, (*local_notify? "" : "not"));
return TRUE;
}
static gboolean
-parse_peer_options(int call_type, xmlNode * request,
- gboolean * local_notify, gboolean * needs_reply, gboolean * process,
- gboolean * needs_forward)
+parse_peer_options(const cib__operation_t *operation, xmlNode *request,
+ gboolean *local_notify, gboolean *needs_reply,
+ gboolean *process)
{
/* TODO: What happens when an update comes in after node A
* requests the CIB from node B, but before it gets the reply (and
* sends out the replace operation)
*/
if(cib_legacy_mode()) {
- return parse_peer_options_v1(
- call_type, request, local_notify, needs_reply, process, needs_forward);
+ return parse_peer_options_v1(operation, request, local_notify,
+ needs_reply, process);
} else {
- return parse_peer_options_v2(
- call_type, request, local_notify, needs_reply, process, needs_forward);
+ return parse_peer_options_v2(operation, request, local_notify,
+ needs_reply, process);
}
}
+/*!
+ * \internal
+ * \brief Forward a CIB request to the appropriate target host(s)
+ *
+ * \param[in] request CIB request to forward
+ */
static void
-forward_request(xmlNode *request, int call_options)
+forward_request(xmlNode *request)
{
const char *op = crm_element_value(request, F_CIB_OPERATION);
+ const char *section = crm_element_value(request, F_CIB_SECTION);
const char *host = crm_element_value(request, F_CIB_HOST);
+ const char *originator = crm_element_value(request, F_ORIG);
+ const char *client_name = crm_element_value(request, F_CIB_CLIENTNAME);
+ const char *call_id = crm_element_value(request, F_CIB_CALLID);
- crm_xml_add(request, F_CIB_DELEGATED, OUR_NODENAME);
-
- if (host != NULL) {
- crm_trace("Forwarding %s op to %s", op, host);
- send_cluster_message(crm_get_peer(0, host), crm_msg_cib, request, FALSE);
+ int log_level = LOG_INFO;
- } else {
- crm_trace("Forwarding %s op to primary instance", op);
- send_cluster_message(NULL, crm_msg_cib, request, FALSE);
+ if (pcmk__str_eq(op, PCMK__CIB_REQUEST_NOOP, pcmk__str_none)) {
+ log_level = LOG_DEBUG;
}
- /* Return the request to its original state */
- xml_remove_prop(request, F_CIB_DELEGATED);
+ do_crm_log(log_level,
+ "Forwarding %s operation for section %s to %s (origin=%s/%s/%s)",
+ pcmk__s(op, "invalid"),
+ pcmk__s(section, "all"),
+ pcmk__s(host, (cib_legacy_mode()? "primary" : "all")),
+ pcmk__s(originator, "local"),
+ pcmk__s(client_name, "unspecified"),
+ pcmk__s(call_id, "unspecified"));
- if (call_options & cib_discard_reply) {
- crm_trace("Client not interested in reply");
- }
+ crm_xml_add(request, F_CIB_DELEGATED, OUR_NODENAME);
+
+ send_cluster_message(((host != NULL)? crm_get_peer(0, host) : NULL),
+ crm_msg_cib, request, FALSE);
+
+ // Return the request to its original state
+ xml_remove_prop(request, F_CIB_DELEGATED);
}
static gboolean
@@ -861,9 +941,10 @@ send_peer_reply(xmlNode * msg, xmlNode * result_diff, const char *originator, gb
CRM_ASSERT(msg != NULL);
if (broadcast) {
- /* this (successful) call modified the CIB _and_ the
- * change needs to be broadcast...
- * send via HA to other nodes
+ /* @COMPAT: Legacy code
+ *
+ * This successful call modified the CIB, and the change needs to be
+ * broadcast (sent via cluster to all nodes).
*/
int diff_add_updates = 0;
int diff_add_epoch = 0;
@@ -878,7 +959,7 @@ send_peer_reply(xmlNode * msg, xmlNode * result_diff, const char *originator, gb
CRM_LOG_ASSERT(result_diff != NULL);
digest = crm_element_value(result_diff, XML_ATTR_DIGEST);
- crm_element_value_int(result_diff, "format", &format);
+ crm_element_value_int(result_diff, PCMK_XA_FORMAT, &format);
cib_diff_version_details(result_diff,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
@@ -919,12 +1000,14 @@ send_peer_reply(xmlNode * msg, xmlNode * result_diff, const char *originator, gb
* \param[in] privileged Whether privileged commands may be run
* (see cib_server_ops[] definition)
* \param[in] cib_client IPC client that sent request (or NULL if CPG)
+ *
+ * \return Legacy Pacemaker return code
*/
-static void
+int
cib_process_request(xmlNode *request, gboolean privileged,
const pcmk__client_t *cib_client)
{
- int call_type = 0;
+ // @TODO: Break into multiple smaller functions
int call_options = 0;
gboolean process = TRUE; // Whether to process request locally now
@@ -946,12 +1029,16 @@ cib_process_request(xmlNode *request, gboolean privileged,
const char *client_name = crm_element_value(request, F_CIB_CLIENTNAME);
const char *reply_to = crm_element_value(request, F_CIB_ISREPLY);
+ const cib__operation_t *operation = NULL;
+ cib__op_fn_t op_function = NULL;
+
crm_element_value_int(request, F_CIB_CALLOPTS, &call_options);
if ((host != NULL) && (*host == '\0')) {
host = NULL;
}
+ // @TODO: Improve trace messages. Target is accurate only for legacy mode.
if (host) {
target = host;
@@ -970,72 +1057,68 @@ cib_process_request(xmlNode *request, gboolean privileged,
crm_trace("Processing local %s operation from %s/%s intended for %s", op, client_name, call_id, target);
}
- rc = cib_get_operation_id(op, &call_type);
+ rc = cib__get_operation(op, &operation);
+ rc = pcmk_rc2legacy(rc);
if (rc != pcmk_ok) {
/* TODO: construct error reply? */
crm_err("Pre-processing of command failed: %s", pcmk_strerror(rc));
- return;
+ return rc;
+ }
+
+ op_function = based_get_op_function(operation);
+ if (op_function == NULL) {
+ crm_err("Operation %s not supported by CIB manager", op);
+ return -EOPNOTSUPP;
}
if (cib_client != NULL) {
- parse_local_options(cib_client, call_type, call_options, host, op,
- &local_notify, &needs_reply, &process, &needs_forward);
+ parse_local_options(cib_client, operation, call_options, host, op,
+ &local_notify, &needs_reply, &process,
+ &needs_forward);
- } else if (parse_peer_options(call_type, request, &local_notify,
- &needs_reply, &process, &needs_forward) == FALSE) {
- return;
+ } else if (!parse_peer_options(operation, request, &local_notify,
+ &needs_reply, &process)) {
+ return rc;
+ }
+
+ if (pcmk_is_set(call_options, cib_transaction)) {
+ /* All requests in a transaction are processed locally against a working
+ * CIB copy, and we don't notify for individual requests because the
+ * entire transaction is atomic.
+ *
+ * We still call the option parser functions above, for the sake of log
+ * messages and checking whether we're the target for peer requests.
+ */
+ process = TRUE;
+ needs_reply = FALSE;
+ local_notify = FALSE;
+ needs_forward = FALSE;
}
- is_update = cib_op_modifies(call_type);
+ is_update = pcmk_is_set(operation->flags, cib__op_attr_modifies);
- if (call_options & cib_discard_reply) {
+ if (pcmk_is_set(call_options, cib_discard_reply)) {
/* If the request will modify the CIB, and we are in legacy mode, we
* need to build a reply so we can broadcast a diff, even if the
* requester doesn't want one.
*/
needs_reply = is_update && cib_legacy_mode();
local_notify = FALSE;
+ crm_trace("Client is not interested in the reply");
}
if (needs_forward) {
- const char *section = crm_element_value(request, F_CIB_SECTION);
- int log_level = LOG_INFO;
-
- if (pcmk__str_eq(op, PCMK__CIB_REQUEST_NOOP, pcmk__str_none)) {
- log_level = LOG_DEBUG;
- }
-
- do_crm_log(log_level,
- "Forwarding %s operation for section %s to %s (origin=%s/%s/%s)",
- op,
- section ? section : "'all'",
- pcmk__s(host, (cib_legacy_mode() ? "primary" : "all")),
- originator ? originator : "local",
- client_name, call_id);
-
- forward_request(request, call_options);
- return;
+ forward_request(request);
+ return rc;
}
if (cib_status != pcmk_ok) {
- const char *call = crm_element_value(request, F_CIB_CALLID);
-
rc = cib_status;
crm_err("Operation ignored, cluster configuration is invalid."
" Please repair and restart: %s", pcmk_strerror(cib_status));
- op_reply = create_xml_node(NULL, "cib-reply");
- crm_xml_add(op_reply, F_TYPE, T_CIB);
- crm_xml_add(op_reply, F_CIB_OPERATION, op);
- crm_xml_add(op_reply, F_CIB_CALLID, call);
- crm_xml_add(op_reply, F_CIB_CLIENTID, client_id);
- crm_xml_add_int(op_reply, F_CIB_CALLOPTS, call_options);
- crm_xml_add_int(op_reply, F_CIB_RC, rc);
-
- crm_trace("Attaching reply output");
- add_message_xml(op_reply, F_CIB_CALLDATA, the_cib);
-
- crm_log_xml_explicit(op_reply, "cib:reply");
+ op_reply = create_cib_reply(op, call_id, client_id, call_options, rc,
+ the_cib);
} else if (process) {
time_t finished = 0;
@@ -1043,7 +1126,8 @@ cib_process_request(xmlNode *request, gboolean privileged,
int level = LOG_INFO;
const char *section = crm_element_value(request, F_CIB_SECTION);
- rc = cib_process_command(request, &op_reply, &result_diff, privileged);
+ rc = cib_process_command(request, operation, op_function, &op_reply,
+ &result_diff, privileged);
if (!is_update) {
level = LOG_TRACE;
@@ -1120,10 +1204,9 @@ cib_process_request(xmlNode *request, gboolean privileged,
op_reply = NULL; /* the reply is queued, so don't free here */
}
- } else if (call_options & cib_discard_reply) {
- crm_trace("Caller isn't interested in reply");
+ } else if ((cib_client == NULL)
+ && !pcmk_is_set(call_options, cib_discard_reply)) {
- } else if (cib_client == NULL) {
if (is_update == FALSE || result_diff == NULL) {
crm_trace("Request not broadcast: R/O call");
@@ -1158,24 +1241,51 @@ cib_process_request(xmlNode *request, gboolean privileged,
free_xml(op_reply);
free_xml(result_diff);
- return;
+ return rc;
}
-static char *
-calculate_section_digest(const char *xpath, xmlNode * xml_obj)
+/*!
+ * \internal
+ * \brief Get a CIB operation's input from the request XML
+ *
+ * \param[in] request CIB request XML
+ * \param[in] type CIB operation type
+ * \param[out] section Where to store CIB section name
+ *
+ * \return Input XML for CIB operation
+ *
+ * \note If not \c NULL, the return value is a non-const pointer to part of
+ * \p request. The caller should not free it directly.
+ */
+static xmlNode *
+prepare_input(const xmlNode *request, enum cib__op_type type,
+ const char **section)
{
- xmlNode *xml_section = NULL;
+ xmlNode *input = NULL;
+
+ *section = NULL;
+
+ switch (type) {
+ case cib__op_apply_patch:
+ if (pcmk__xe_attr_is_true(request, F_CIB_GLOBAL_UPDATE)) {
+ input = get_message_xml(request, F_CIB_UPDATE_DIFF);
+ } else {
+ input = get_message_xml(request, F_CIB_CALLDATA);
+ }
+ break;
- if (xml_obj == NULL) {
- return NULL;
+ default:
+ input = get_message_xml(request, F_CIB_CALLDATA);
+ *section = crm_element_value(request, F_CIB_SECTION);
+ break;
}
- xml_section = get_xpath_object(xpath, xml_obj, LOG_TRACE);
- if (xml_section == NULL) {
- return NULL;
+ // Grab the specified section
+ if ((*section != NULL) && pcmk__xe_is(input, XML_TAG_CIB)) {
+ input = pcmk_find_cib_element(input, *section);
}
- return calculate_xml_versioned_digest(xml_section, FALSE, TRUE, CRM_FEATURE_SET);
+ return input;
}
// v1 and v2 patch formats
@@ -1201,14 +1311,14 @@ contains_config_change(xmlNode *diff)
}
static int
-cib_process_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff, gboolean privileged)
+cib_process_command(xmlNode *request, const cib__operation_t *operation,
+ cib__op_fn_t op_function, xmlNode **reply,
+ xmlNode **cib_diff, bool privileged)
{
xmlNode *input = NULL;
xmlNode *output = NULL;
xmlNode *result_cib = NULL;
- xmlNode *current_cib = NULL;
- int call_type = 0;
int call_options = 0;
const char *op = NULL;
@@ -1216,24 +1326,15 @@ cib_process_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff, gb
const char *call_id = crm_element_value(request, F_CIB_CALLID);
const char *client_id = crm_element_value(request, F_CIB_CLIENTID);
const char *client_name = crm_element_value(request, F_CIB_CLIENTNAME);
- const char *origin = crm_element_value(request, F_ORIG);
+ const char *originator = crm_element_value(request, F_ORIG);
int rc = pcmk_ok;
- int rc2 = pcmk_ok;
- gboolean send_r_notify = FALSE;
- gboolean config_changed = FALSE;
- gboolean manage_counters = TRUE;
+ bool config_changed = false;
+ bool manage_counters = true;
static mainloop_timer_t *digest_timer = NULL;
- char *current_nodes_digest = NULL;
- char *current_alerts_digest = NULL;
- char *current_status_digest = NULL;
- uint32_t change_section = cib_change_section_nodes
- |cib_change_section_alerts
- |cib_change_section_status;
-
CRM_ASSERT(cib_status == pcmk_ok);
if(digest_timer == NULL) {
@@ -1242,91 +1343,64 @@ cib_process_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff, gb
*reply = NULL;
*cib_diff = NULL;
- current_cib = the_cib;
/* Start processing the request... */
op = crm_element_value(request, F_CIB_OPERATION);
crm_element_value_int(request, F_CIB_CALLOPTS, &call_options);
- rc = cib_get_operation_id(op, &call_type);
- if (rc == pcmk_ok && privileged == FALSE) {
- rc = cib_op_can_run(call_type, call_options, privileged);
+ if (!privileged && pcmk_is_set(operation->flags, cib__op_attr_privileged)) {
+ rc = -EACCES;
+ crm_trace("Failed due to lack of privileges: %s", pcmk_strerror(rc));
+ goto done;
}
- rc2 = cib_op_prepare(call_type, request, &input, &section);
- if (rc == pcmk_ok) {
- rc = rc2;
- }
+ input = prepare_input(request, operation->type, &section);
- if (rc != pcmk_ok) {
- crm_trace("Call setup failed: %s", pcmk_strerror(rc));
- goto done;
-
- } else if (cib_op_modifies(call_type) == FALSE) {
- rc = cib_perform_op(op, call_options, cib_op_func(call_type), TRUE,
- section, request, input, FALSE, &config_changed,
- current_cib, &result_cib, NULL, &output);
+ if (!pcmk_is_set(operation->flags, cib__op_attr_modifies)) {
+ rc = cib_perform_op(op, call_options, op_function, true, section,
+ request, input, false, &config_changed, &the_cib,
+ &result_cib, NULL, &output);
CRM_CHECK(result_cib == NULL, free_xml(result_cib));
goto done;
}
- /* Handle a valid write action */
+ /* @COMPAT: Handle a valid write action (legacy)
+ *
+ * @TODO: Re-evaluate whether this is all truly legacy. The cib_force_diff
+ * portion is. However, F_CIB_GLOBAL_UPDATE may be set by a sync operation
+ * even in non-legacy mode, and manage_counters tells xml_create_patchset()
+ * whether to update version/epoch info.
+ */
if (pcmk__xe_attr_is_true(request, F_CIB_GLOBAL_UPDATE)) {
- /* legacy code */
- manage_counters = FALSE;
+ manage_counters = false;
cib__set_call_options(call_options, "call", cib_force_diff);
crm_trace("Global update detected");
- CRM_CHECK(call_type == 3 || call_type == 4, crm_err("Call type: %d", call_type);
- crm_log_xml_err(request, "bad op"));
+ CRM_LOG_ASSERT(pcmk__str_any_of(op,
+ PCMK__CIB_REQUEST_APPLY_PATCH,
+ PCMK__CIB_REQUEST_REPLACE,
+ NULL));
}
ping_modified_since = TRUE;
if (pcmk_is_set(call_options, cib_inhibit_bcast)) {
crm_trace("Skipping update: inhibit broadcast");
- manage_counters = FALSE;
- }
-
- if (!pcmk_is_set(call_options, cib_dryrun)
- && pcmk__str_eq(section, XML_CIB_TAG_STATUS, pcmk__str_casei)) {
- // Copying large CIBs accounts for a huge percentage of our CIB usage
- cib__set_call_options(call_options, "call", cib_zero_copy);
- } else {
- cib__clear_call_options(call_options, "call", cib_zero_copy);
- }
-
-#define XPATH_CONFIG "//" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION
-#define XPATH_NODES XPATH_CONFIG "/" XML_CIB_TAG_NODES
-#define XPATH_ALERTS XPATH_CONFIG "/" XML_CIB_TAG_ALERTS
-#define XPATH_STATUS "//" XML_TAG_CIB "/" XML_CIB_TAG_STATUS
-
- // Calculate the hash value of the section before the change
- if (pcmk__str_eq(PCMK__CIB_REQUEST_REPLACE, op, pcmk__str_none)) {
- current_nodes_digest = calculate_section_digest(XPATH_NODES,
- current_cib);
- current_alerts_digest = calculate_section_digest(XPATH_ALERTS,
- current_cib);
- current_status_digest = calculate_section_digest(XPATH_STATUS,
- current_cib);
- crm_trace("current-digest %s:%s:%s", current_nodes_digest,
- current_alerts_digest, current_status_digest);
+ manage_counters = false;
}
// result_cib must not be modified after cib_perform_op() returns
- rc = cib_perform_op(op, call_options, cib_op_func(call_type), FALSE,
- section, request, input, manage_counters,
- &config_changed, current_cib, &result_cib, cib_diff,
- &output);
+ rc = cib_perform_op(op, call_options, op_function, false, section,
+ request, input, manage_counters, &config_changed,
+ &the_cib, &result_cib, cib_diff, &output);
+ // @COMPAT: Legacy code
if (!manage_counters) {
int format = 1;
- /* Legacy code
- * If the diff is NULL at this point, it's because nothing changed
- */
+ // If the diff is NULL at this point, it's because nothing changed
if (*cib_diff != NULL) {
- crm_element_value_int(*cib_diff, "format", &format);
+ crm_element_value_int(*cib_diff, PCMK_XA_FORMAT, &format);
}
if (format == 1) {
@@ -1334,92 +1408,60 @@ cib_process_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff, gb
}
}
- /* Always write to disk for successful replace and upgrade ops. This also
+ /* Always write to disk for successful ops with the flag set. This also
* negates the need to detect ordering changes.
*/
if ((rc == pcmk_ok)
- && pcmk__str_any_of(op,
- PCMK__CIB_REQUEST_REPLACE,
- PCMK__CIB_REQUEST_UPGRADE,
- NULL)) {
- config_changed = TRUE;
- }
-
- if (rc == pcmk_ok && !pcmk_is_set(call_options, cib_dryrun)) {
- crm_trace("Activating %s->%s%s%s",
- crm_element_value(current_cib, XML_ATTR_NUMUPDATES),
- crm_element_value(result_cib, XML_ATTR_NUMUPDATES),
- (pcmk_is_set(call_options, cib_zero_copy)? " zero-copy" : ""),
- (config_changed? " changed" : ""));
- if (!pcmk_is_set(call_options, cib_zero_copy)) {
- rc = activateCibXml(result_cib, config_changed, op);
- crm_trace("Activated %s (%d)",
- crm_element_value(current_cib, XML_ATTR_NUMUPDATES), rc);
- }
+ && pcmk_is_set(operation->flags, cib__op_attr_writes_through)) {
- if ((rc == pcmk_ok) && contains_config_change(*cib_diff)) {
- cib_read_config(config_hash, result_cib);
- }
+ config_changed = true;
+ }
- if (pcmk__str_eq(PCMK__CIB_REQUEST_REPLACE, op, pcmk__str_none)) {
- char *result_nodes_digest = NULL;
- char *result_alerts_digest = NULL;
- char *result_status_digest = NULL;
-
- /* Calculate the hash value of the changed section. */
- result_nodes_digest = calculate_section_digest(XPATH_NODES,
- result_cib);
- result_alerts_digest = calculate_section_digest(XPATH_ALERTS,
- result_cib);
- result_status_digest = calculate_section_digest(XPATH_STATUS,
- result_cib);
- crm_trace("result-digest %s:%s:%s", result_nodes_digest,
- result_alerts_digest, result_status_digest);
-
- if (pcmk__str_eq(current_nodes_digest, result_nodes_digest,
- pcmk__str_none)) {
- change_section =
- pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,
- "CIB change section",
- "change_section", change_section,
- cib_change_section_nodes, "nodes");
- }
+ if ((rc == pcmk_ok)
+ && !pcmk_any_flags_set(call_options, cib_dryrun|cib_transaction)) {
- if (pcmk__str_eq(current_alerts_digest, result_alerts_digest,
- pcmk__str_none)) {
- change_section =
- pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,
- "CIB change section",
- "change_section", change_section,
- cib_change_section_alerts, "alerts");
+ if (result_cib != the_cib) {
+ if (pcmk_is_set(operation->flags, cib__op_attr_writes_through)) {
+ config_changed = true;
}
- if (pcmk__str_eq(current_status_digest, result_status_digest,
- pcmk__str_none)) {
- change_section =
- pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,
- "CIB change section",
- "change_section", change_section,
- cib_change_section_status, "status");
- }
+ crm_trace("Activating %s->%s%s",
+ crm_element_value(the_cib, XML_ATTR_NUMUPDATES),
+ crm_element_value(result_cib, XML_ATTR_NUMUPDATES),
+ (config_changed? " changed" : ""));
- if (change_section != cib_change_section_none) {
- send_r_notify = TRUE;
+ rc = activateCibXml(result_cib, config_changed, op);
+ if (rc != pcmk_ok) {
+ crm_err("Failed to activate new CIB: %s", pcmk_strerror(rc));
}
-
- free(result_nodes_digest);
- free(result_alerts_digest);
- free(result_status_digest);
+ }
+
+ if ((rc == pcmk_ok) && contains_config_change(*cib_diff)) {
+ cib_read_config(config_hash, result_cib);
+ }
- } else if (pcmk__str_eq(PCMK__CIB_REQUEST_ERASE, op, pcmk__str_none)) {
- send_r_notify = TRUE;
+ /* @COMPAT Nodes older than feature set 3.19.0 don't support
+ * transactions. In a mixed-version cluster with nodes <3.19.0, we must
+ * sync the updated CIB, so that the older nodes receive the changes.
+ * Any node that has already applied the transaction will ignore the
+ * synced CIB.
+ *
+ * To ensure the updated CIB is synced from only one node, we sync it
+ * from the originator.
+ */
+ if ((operation->type == cib__op_commit_transact)
+ && pcmk__str_eq(originator, OUR_NODENAME, pcmk__str_casei)
+ && compare_version(crm_element_value(the_cib, XML_ATTR_CRM_VERSION),
+ "3.19.0") < 0) {
+
+ sync_our_cib(request, TRUE);
}
mainloop_timer_stop(digest_timer);
mainloop_timer_start(digest_timer);
} else if (rc == -pcmk_err_schema_validation) {
- CRM_ASSERT(!pcmk_is_set(call_options, cib_zero_copy));
+ CRM_ASSERT(result_cib != the_cib);
if (output != NULL) {
crm_log_xml_info(output, "cib:output");
@@ -1432,61 +1474,31 @@ cib_process_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff, gb
crm_trace("Not activating %d %d %s", rc,
pcmk_is_set(call_options, cib_dryrun),
crm_element_value(result_cib, XML_ATTR_NUMUPDATES));
- if (!pcmk_is_set(call_options, cib_zero_copy)) {
+
+ if (result_cib != the_cib) {
free_xml(result_cib);
}
}
- if ((call_options & (cib_inhibit_notify|cib_dryrun)) == 0) {
+ if (!pcmk_any_flags_set(call_options,
+ cib_dryrun|cib_inhibit_notify|cib_transaction)) {
crm_trace("Sending notifications %d",
pcmk_is_set(call_options, cib_dryrun));
- cib_diff_notify(op, rc, call_id, client_id, client_name, origin, input,
- *cib_diff);
+ cib_diff_notify(op, rc, call_id, client_id, client_name, originator,
+ input, *cib_diff);
}
- if (send_r_notify) {
- cib_replace_notify(op, rc, call_id, client_id, client_name, origin,
- the_cib, *cib_diff, change_section);
- }
-
- pcmk__output_set_log_level(logger_out, LOG_TRACE);
- logger_out->message(logger_out, "xml-patchset", *cib_diff);
+ pcmk__log_xml_patchset(LOG_TRACE, *cib_diff);
done:
if (!pcmk_is_set(call_options, cib_discard_reply) || cib_legacy_mode()) {
- const char *caller = crm_element_value(request, F_CIB_CLIENTID);
-
- *reply = create_xml_node(NULL, "cib-reply");
- crm_xml_add(*reply, F_TYPE, T_CIB);
- crm_xml_add(*reply, F_CIB_OPERATION, op);
- crm_xml_add(*reply, F_CIB_CALLID, call_id);
- crm_xml_add(*reply, F_CIB_CLIENTID, caller);
- crm_xml_add_int(*reply, F_CIB_CALLOPTS, call_options);
- crm_xml_add_int(*reply, F_CIB_RC, rc);
-
- if (output != NULL) {
- crm_trace("Attaching reply output");
- add_message_xml(*reply, F_CIB_CALLDATA, output);
- }
-
- crm_log_xml_explicit(*reply, "cib:reply");
+ *reply = create_cib_reply(op, call_id, client_id, call_options, rc,
+ output);
}
- crm_trace("cleanup");
-
- if (cib_op_modifies(call_type) == FALSE && output != current_cib) {
+ if (output != the_cib) {
free_xml(output);
- output = NULL;
- }
-
- if (call_type >= 0) {
- cib_op_cleanup(call_type, call_options, &input, &output);
}
-
- free(current_nodes_digest);
- free(current_alerts_digest);
- free(current_status_digest);
-
crm_trace("done");
return rc;
}
@@ -1554,12 +1566,12 @@ initiate_exit(void)
xmlNode *leaving = NULL;
active = crm_active_peers();
- if (active < 2) {
+ if (active < 2) { // This is the last active node
terminate_cib(__func__, 0);
return;
}
- crm_info("Sending disconnect notification to %d peers...", active);
+ crm_info("Sending shutdown request to %d peers", active);
leaving = create_xml_node(NULL, "exit-notification");
crm_xml_add(leaving, F_TYPE, "cib");
@@ -1664,12 +1676,6 @@ terminate_cib(const char *caller, int fast)
uninitializeCib();
- if (logger_out != NULL) {
- logger_out->finish(logger_out, CRM_EX_OK, true, NULL);
- pcmk__output_free(logger_out);
- logger_out = NULL;
- }
-
if (fast > 0) {
/* Quit fast on error */
pcmk__stop_based_ipc(ipcs_ro, ipcs_rw, ipcs_shm);
diff --git a/daemons/based/based_common.c b/daemons/based/based_common.c
deleted file mode 100644
index 7e68cf0..0000000
--- a/daemons/based/based_common.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright 2008-2023 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 <crm_internal.h>
-
-#include <sys/param.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <stdlib.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <crm/crm.h>
-#include <crm/cib.h>
-#include <crm/msg_xml.h>
-#include <crm/common/ipc.h>
-#include <crm/cluster.h>
-
-#include <crm/common/xml.h>
-
-#include <pacemaker-based.h>
-
-gboolean stand_alone = FALSE;
-
-extern int cib_perform_command(xmlNode * request, xmlNode ** reply, xmlNode ** cib_diff,
- gboolean privileged);
-
-static xmlNode *
-cib_prepare_common(xmlNode * root, const char *section)
-{
- xmlNode *data = NULL;
-
- /* extract the CIB from the fragment */
- if (root == NULL) {
- return NULL;
-
- } else if (pcmk__strcase_any_of(crm_element_name(root), XML_TAG_FRAGMENT,
- F_CRM_DATA, F_CIB_CALLDATA, NULL)) {
- data = first_named_child(root, XML_TAG_CIB);
-
- } else {
- data = root;
- }
-
- /* grab the section specified for the command */
- if (section != NULL && data != NULL && pcmk__str_eq(crm_element_name(data), XML_TAG_CIB, pcmk__str_none)) {
- data = pcmk_find_cib_element(data, section);
- }
-
- /* crm_log_xml_trace(root, "cib:input"); */
- return data;
-}
-
-static int
-cib_prepare_none(xmlNode * request, xmlNode ** data, const char **section)
-{
- *data = NULL;
- *section = crm_element_value(request, F_CIB_SECTION);
- return pcmk_ok;
-}
-
-static int
-cib_prepare_data(xmlNode * request, xmlNode ** data, const char **section)
-{
- xmlNode *input_fragment = get_message_xml(request, F_CIB_CALLDATA);
-
- *section = crm_element_value(request, F_CIB_SECTION);
- *data = cib_prepare_common(input_fragment, *section);
- /* crm_log_xml_debug(*data, "data"); */
- return pcmk_ok;
-}
-
-static int
-cib_prepare_sync(xmlNode * request, xmlNode ** data, const char **section)
-{
- *data = NULL;
- *section = crm_element_value(request, F_CIB_SECTION);
- return pcmk_ok;
-}
-
-static int
-cib_prepare_diff(xmlNode * request, xmlNode ** data, const char **section)
-{
- xmlNode *input_fragment = NULL;
-
- *data = NULL;
- *section = NULL;
-
- if (pcmk__xe_attr_is_true(request, F_CIB_GLOBAL_UPDATE)) {
- input_fragment = get_message_xml(request, F_CIB_UPDATE_DIFF);
- } else {
- input_fragment = get_message_xml(request, F_CIB_CALLDATA);
- }
-
- CRM_CHECK(input_fragment != NULL, crm_log_xml_warn(request, "no input"));
- *data = cib_prepare_common(input_fragment, NULL);
- return pcmk_ok;
-}
-
-static int
-cib_cleanup_query(int options, xmlNode ** data, xmlNode ** output)
-{
- CRM_LOG_ASSERT(*data == NULL);
- if ((options & cib_no_children)
- || pcmk__str_eq(crm_element_name(*output), "xpath-query", pcmk__str_casei)) {
- free_xml(*output);
- }
- return pcmk_ok;
-}
-
-static int
-cib_cleanup_data(int options, xmlNode ** data, xmlNode ** output)
-{
- free_xml(*output);
- *data = NULL;
- return pcmk_ok;
-}
-
-static int
-cib_cleanup_output(int options, xmlNode ** data, xmlNode ** output)
-{
- free_xml(*output);
- return pcmk_ok;
-}
-
-static int
-cib_cleanup_none(int options, xmlNode ** data, xmlNode ** output)
-{
- CRM_LOG_ASSERT(*data == NULL);
- CRM_LOG_ASSERT(*output == NULL);
- return pcmk_ok;
-}
-
-static cib_operation_t cib_server_ops[] = {
- // Booleans are modifies_cib, needs_privileges
- {
- NULL, FALSE, FALSE,
- cib_prepare_none, cib_cleanup_none, cib_process_default
- },
- {
- PCMK__CIB_REQUEST_QUERY, FALSE, FALSE,
- cib_prepare_none, cib_cleanup_query, cib_process_query
- },
- {
- PCMK__CIB_REQUEST_MODIFY, TRUE, TRUE,
- cib_prepare_data, cib_cleanup_data, cib_process_modify
- },
- {
- PCMK__CIB_REQUEST_APPLY_PATCH, TRUE, TRUE,
- cib_prepare_diff, cib_cleanup_data, cib_server_process_diff
- },
- {
- PCMK__CIB_REQUEST_REPLACE, TRUE, TRUE,
- cib_prepare_data, cib_cleanup_data, cib_process_replace_svr
- },
- {
- PCMK__CIB_REQUEST_CREATE, TRUE, TRUE,
- cib_prepare_data, cib_cleanup_data, cib_process_create
- },
- {
- PCMK__CIB_REQUEST_DELETE, TRUE, TRUE,
- cib_prepare_data, cib_cleanup_data, cib_process_delete
- },
- {
- PCMK__CIB_REQUEST_SYNC_TO_ALL, FALSE, TRUE,
- cib_prepare_sync, cib_cleanup_none, cib_process_sync
- },
- {
- PCMK__CIB_REQUEST_BUMP, TRUE, TRUE,
- cib_prepare_none, cib_cleanup_output, cib_process_bump
- },
- {
- PCMK__CIB_REQUEST_ERASE, TRUE, TRUE,
- cib_prepare_none, cib_cleanup_output, cib_process_erase
- },
- {
- PCMK__CIB_REQUEST_NOOP, FALSE, FALSE,
- cib_prepare_none, cib_cleanup_none, cib_process_default
- },
- {
- PCMK__CIB_REQUEST_ABS_DELETE, TRUE, TRUE,
- cib_prepare_data, cib_cleanup_data, cib_process_delete_absolute
- },
- {
- PCMK__CIB_REQUEST_UPGRADE, TRUE, TRUE,
- cib_prepare_none, cib_cleanup_output, cib_process_upgrade_server
- },
- {
- PCMK__CIB_REQUEST_SECONDARY, FALSE, TRUE,
- cib_prepare_none, cib_cleanup_none, cib_process_readwrite
- },
- {
- PCMK__CIB_REQUEST_ALL_SECONDARY, FALSE, TRUE,
- cib_prepare_none, cib_cleanup_none, cib_process_readwrite
- },
- {
- PCMK__CIB_REQUEST_SYNC_TO_ONE, FALSE, TRUE,
- cib_prepare_sync, cib_cleanup_none, cib_process_sync_one
- },
- {
- PCMK__CIB_REQUEST_PRIMARY, TRUE, TRUE,
- cib_prepare_data, cib_cleanup_data, cib_process_readwrite
- },
- {
- PCMK__CIB_REQUEST_IS_PRIMARY, FALSE, TRUE,
- cib_prepare_none, cib_cleanup_none, cib_process_readwrite
- },
- {
- PCMK__CIB_REQUEST_SHUTDOWN, FALSE, TRUE,
- cib_prepare_sync, cib_cleanup_none, cib_process_shutdown_req
- },
- {
- CRM_OP_PING, FALSE, FALSE,
- cib_prepare_none, cib_cleanup_output, cib_process_ping
- },
-};
-
-int
-cib_get_operation_id(const char *op, int *operation)
-{
- static GHashTable *operation_hash = NULL;
-
- if (operation_hash == NULL) {
- int lpc = 0;
- int max_msg_types = PCMK__NELEM(cib_server_ops);
-
- operation_hash = pcmk__strkey_table(NULL, free);
- for (lpc = 1; lpc < max_msg_types; lpc++) {
- int *value = malloc(sizeof(int));
-
- if(value) {
- *value = lpc;
- g_hash_table_insert(operation_hash, (gpointer) cib_server_ops[lpc].operation, value);
- }
- }
- }
-
- if (op != NULL) {
- int *value = g_hash_table_lookup(operation_hash, op);
-
- if (value) {
- *operation = *value;
- return pcmk_ok;
- }
- }
- crm_err("Operation %s is not valid", op);
- *operation = -1;
- return -EINVAL;
-}
-
-xmlNode *
-cib_msg_copy(xmlNode * msg, gboolean with_data)
-{
- int lpc = 0;
- const char *field = NULL;
- const char *value = NULL;
- xmlNode *value_struct = NULL;
-
- static const char *field_list[] = {
- F_XML_TAGNAME,
- F_TYPE,
- F_CIB_CLIENTID,
- F_CIB_CALLOPTS,
- F_CIB_CALLID,
- F_CIB_OPERATION,
- F_CIB_ISREPLY,
- F_CIB_SECTION,
- F_CIB_HOST,
- F_CIB_RC,
- F_CIB_DELEGATED,
- F_CIB_OBJID,
- F_CIB_OBJTYPE,
- F_CIB_EXISTING,
- F_CIB_SEENCOUNT,
- F_CIB_TIMEOUT,
- F_CIB_GLOBAL_UPDATE,
- F_CIB_CLIENTNAME,
- F_CIB_USER,
- F_CIB_NOTIFY_TYPE,
- F_CIB_NOTIFY_ACTIVATE
- };
-
- static const char *data_list[] = {
- F_CIB_CALLDATA,
- F_CIB_UPDATE,
- F_CIB_UPDATE_RESULT
- };
-
- xmlNode *copy = create_xml_node(NULL, "copy");
-
- CRM_ASSERT(copy != NULL);
-
- for (lpc = 0; lpc < PCMK__NELEM(field_list); lpc++) {
- field = field_list[lpc];
- value = crm_element_value(msg, field);
- if (value != NULL) {
- crm_xml_add(copy, field, value);
- }
- }
- for (lpc = 0; with_data && lpc < PCMK__NELEM(data_list); lpc++) {
- field = data_list[lpc];
- value_struct = get_message_xml(msg, field);
- if (value_struct != NULL) {
- add_message_xml(copy, field, value_struct);
- }
- }
-
- return copy;
-}
-
-cib_op_t *
-cib_op_func(int call_type)
-{
- return &(cib_server_ops[call_type].fn);
-}
-
-gboolean
-cib_op_modifies(int call_type)
-{
- return cib_server_ops[call_type].modifies_cib;
-}
-
-int
-cib_op_can_run(int call_type, int call_options, bool privileged)
-{
- if (!privileged && cib_server_ops[call_type].needs_privileges) {
- return -EACCES;
- }
- return pcmk_ok;
-}
-
-int
-cib_op_prepare(int call_type, xmlNode * request, xmlNode ** input, const char **section)
-{
- crm_trace("Prepare %d", call_type);
- return cib_server_ops[call_type].prepare(request, input, section);
-}
-
-int
-cib_op_cleanup(int call_type, int options, xmlNode ** input, xmlNode ** output)
-{
- crm_trace("Cleanup %d", call_type);
- return cib_server_ops[call_type].cleanup(options, input, output);
-}
diff --git a/daemons/based/based_io.c b/daemons/based/based_io.c
index fc34f39..f252ac1 100644
--- a/daemons/based/based_io.c
+++ b/daemons/based/based_io.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2022 the Pacemaker project contributors
+ * Copyright 2004-2023 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -22,6 +22,9 @@
#include <sys/wait.h>
#include <sys/stat.h>
+#include <glib.h>
+#include <libxml/tree.h>
+
#include <crm/crm.h>
#include <crm/cib.h>
@@ -45,12 +48,15 @@ cib_rename(const char *old)
umask(S_IWGRP | S_IWOTH | S_IROTH);
new_fd = mkstemp(new);
- crm_err("Archiving unusable file %s as %s", old, new);
+
if ((new_fd < 0) || (rename(old, new) < 0)) {
- crm_perror(LOG_ERR, "Couldn't rename %s as %s", old, new);
- crm_err("Disabling disk writes and continuing");
+ crm_err("Couldn't archive unusable file %s (disabling disk writes and continuing)",
+ old);
cib_writes_enabled = FALSE;
+ } else {
+ crm_err("Archived unusable file %s as %s", old, new);
}
+
if (new_fd > 0) {
close(new_fd);
}
@@ -107,7 +113,7 @@ static int cib_archive_filter(const struct dirent * a)
if(stat(a_path, &s) != 0) {
rc = errno;
- crm_trace("%s - stat failed: %s (%d)", a->d_name, pcmk_strerror(rc), rc);
+ crm_trace("%s - stat failed: %s (%d)", a->d_name, pcmk_rc_str(rc), rc);
rc = 0;
} else if ((s.st_mode & S_IFREG) != S_IFREG) {
@@ -189,7 +195,7 @@ readCibXmlFile(const char *dir, const char *file, gboolean discard_status)
const char *name = NULL;
const char *value = NULL;
const char *validation = NULL;
- const char *use_valgrind = getenv("PCMK_valgrind_enabled");
+ const char *use_valgrind = pcmk__env_option(PCMK__ENV_VALGRIND_ENABLED);
xmlNode *root = NULL;
xmlNode *status = NULL;
@@ -214,7 +220,7 @@ readCibXmlFile(const char *dir, const char *file, gboolean discard_status)
crm_warn("Primary configuration corrupt or unusable, trying backups in %s", cib_root);
lpc = scandir(cib_root, &namelist, cib_archive_filter, cib_archive_sort);
if (lpc < 0) {
- crm_perror(LOG_NOTICE, "scandir(%s) failed", cib_root);
+ crm_err("scandir(%s) failed: %s", cib_root, pcmk_rc_str(errno));
}
}
@@ -418,7 +424,7 @@ write_cib_contents(gpointer p)
pid = fork();
if (pid < 0) {
- crm_perror(LOG_ERR, "Disabling disk writes after fork failure");
+ crm_err("Disabling disk writes after fork failure: %s", pcmk_rc_str(errno));
cib_writes_enabled = FALSE;
return FALSE;
}
diff --git a/daemons/based/based_messages.c b/daemons/based/based_messages.c
index d46456c..35d639a 100644
--- a/daemons/based/based_messages.c
+++ b/daemons/based/based_messages.c
@@ -19,6 +19,9 @@
#include <sys/param.h>
#include <sys/types.h>
+#include <glib.h>
+#include <libxml/tree.h>
+
#include <crm/crm.h>
#include <crm/cib/internal.h>
#include <crm/msg_xml.h>
@@ -61,25 +64,15 @@ cib_process_shutdown_req(const char *op, int options, const char *section, xmlNo
return pcmk_ok;
}
+// @COMPAT: Remove when PCMK__CIB_REQUEST_NOOP is removed
int
-cib_process_default(const char *op, int options, const char *section, xmlNode * req,
- xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
- xmlNode ** answer)
+cib_process_noop(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);
*answer = NULL;
-
- if (op == NULL) {
- result = -EINVAL;
- crm_err("No operation specified");
-
- } else if (strcmp(PCMK__CIB_REQUEST_NOOP, op) != 0) {
- result = -EPROTONOSUPPORT;
- crm_err("Action [%s] is not supported by the CIB manager", op);
- }
- return result;
+ return pcmk_ok;
}
int
@@ -158,10 +151,10 @@ cib_process_ping(const char *op, int options, const char *section, xmlNode * req
// Append additional detail so the receiver can log the differences
add_message_xml(*answer, F_CIB_CALLDATA, the_cib);
},
- {
+ if (the_cib != NULL) {
// Always include at least the version details
- const char *tag = TYPE(the_cib);
- xmlNode *shallow = create_xml_node(NULL, tag);
+ xmlNode *shallow = create_xml_node(NULL,
+ (const char *) the_cib->name);
copy_in_properties(shallow, the_cib);
add_message_xml(*answer, F_CIB_CALLDATA, shallow);
@@ -250,7 +243,7 @@ cib_process_upgrade_server(const char *op, int options, const char *section, xml
if (rc != pcmk_ok) {
// Notify originating peer so it can notify its local clients
- crm_node_t *origin = pcmk__search_cluster_node_cache(0, host);
+ crm_node_t *origin = pcmk__search_cluster_node_cache(0, host, NULL);
crm_info("Rejecting upgrade request from %s: %s "
CRM_XS " rc=%d peer=%s", host, pcmk_strerror(rc), rc,
@@ -341,8 +334,7 @@ cib_server_process_diff(const char *op, int options, const char *section, xmlNod
crm_warn("Requesting full CIB refresh because update failed: %s"
CRM_XS " rc=%d", pcmk_strerror(rc), rc);
- pcmk__output_set_log_level(logger_out, LOG_INFO);
- logger_out->message(logger_out, "xml-patchset", input);
+ pcmk__log_xml_patchset(LOG_INFO, input);
free_xml(*result_cib);
*result_cib = NULL;
send_sync_request(NULL);
@@ -356,15 +348,16 @@ cib_process_replace_svr(const char *op, int options, const char *section, xmlNod
xmlNode * input, xmlNode * existing_cib, xmlNode ** result_cib,
xmlNode ** answer)
{
- const char *tag = crm_element_name(input);
int rc =
cib_process_replace(op, options, section, req, input, existing_cib, result_cib, answer);
- if (rc == pcmk_ok && pcmk__str_eq(tag, XML_TAG_CIB, pcmk__str_casei)) {
+
+ if ((rc == pcmk_ok) && pcmk__xe_is(input, XML_TAG_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,
@@ -373,6 +366,49 @@ cib_process_delete_absolute(const char *op, int options, const char *section, xm
return -EINVAL;
}
+static xmlNode *
+cib_msg_copy(xmlNode *msg)
+{
+ static const char *field_list[] = {
+ F_XML_TAGNAME,
+ F_TYPE,
+ F_CIB_CLIENTID,
+ F_CIB_CALLOPTS,
+ F_CIB_CALLID,
+ F_CIB_OPERATION,
+ F_CIB_ISREPLY,
+ F_CIB_SECTION,
+ F_CIB_HOST,
+ F_CIB_RC,
+ F_CIB_DELEGATED,
+ F_CIB_OBJID,
+ F_CIB_OBJTYPE,
+ F_CIB_EXISTING,
+ F_CIB_SEENCOUNT,
+ F_CIB_TIMEOUT,
+ F_CIB_GLOBAL_UPDATE,
+ F_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)
{
@@ -384,22 +420,12 @@ sync_our_cib(xmlNode * request, gboolean all)
xmlNode *replace_request = NULL;
CRM_CHECK(the_cib != NULL, return -EINVAL);
-
- replace_request = cib_msg_copy(request, FALSE);
- CRM_CHECK(replace_request != NULL, return -EINVAL);
+ CRM_CHECK(all || (host != NULL), return -EINVAL);
crm_debug("Syncing CIB to %s", all ? "all peers" : host);
- if (all == FALSE && host == NULL) {
- crm_log_xml_err(request, "bad sync");
- }
- /* remove the "all == FALSE" condition
- *
- * sync_from was failing, the local client wasn't being notified
- * because it didn't know it was a reply
- * setting this does not prevent the other nodes from applying it
- * if all == TRUE
- */
+ replace_request = cib_msg_copy(request);
+
if (host != NULL) {
crm_xml_add(replace_request, F_CIB_ISREPLY, host);
}
@@ -425,3 +451,30 @@ sync_our_cib(xmlNode * request, gboolean all)
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, F_CIB_CLIENTID);
+ const char *origin = crm_element_value(req, F_ORIG);
+ 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);
+}
diff --git a/daemons/based/based_notify.c b/daemons/based/based_notify.c
index 5881f6d..00a4c54 100644
--- a/daemons/based/based_notify.c
+++ b/daemons/based/based_notify.c
@@ -21,6 +21,9 @@
#include <time.h>
+#include <glib.h>
+#include <libxml/tree.h>
+
#include <crm/crm.h>
#include <crm/cib/internal.h>
#include <crm/msg_xml.h>
@@ -30,7 +33,7 @@
#include <pacemaker-based.h>
struct cib_notification_s {
- xmlNode *msg;
+ const xmlNode *msg;
struct iovec *iov;
int32_t iov_size;
};
@@ -58,10 +61,6 @@ cib_notify_send_one(gpointer key, gpointer value, gpointer user_data)
do_send = TRUE;
- } else if (pcmk_is_set(client->flags, cib_notify_replace)
- && pcmk__str_eq(type, T_CIB_REPLACE_NOTIFY, pcmk__str_casei)) {
- do_send = TRUE;
-
} else if (pcmk_is_set(client->flags, cib_notify_confirm)
&& pcmk__str_eq(type, T_CIB_UPDATE_CONFIRM, pcmk__str_casei)) {
do_send = TRUE;
@@ -104,7 +103,7 @@ cib_notify_send_one(gpointer key, gpointer value, gpointer user_data)
}
static void
-cib_notify_send(xmlNode * xml)
+cib_notify_send(const xmlNode *xml)
{
struct iovec *iov;
struct cib_notification_s update;
@@ -198,15 +197,16 @@ cib_diff_notify(const char *op, int result, const char *call_id,
crm_xml_add(update_msg, F_SUBTYPE, T_CIB_DIFF_NOTIFY);
crm_xml_add(update_msg, F_CIB_OPERATION, op);
crm_xml_add(update_msg, F_CIB_CLIENTID, client_id);
+ crm_xml_add(update_msg, F_CIB_CLIENTNAME, client_name);
crm_xml_add(update_msg, F_CIB_CALLID, call_id);
crm_xml_add(update_msg, F_ORIG, origin);
crm_xml_add_int(update_msg, F_CIB_RC, result);
if (update != NULL) {
- type = crm_element_name(update);
+ type = (const char *) update->name;
crm_trace("Setting type to update->name: %s", type);
} else {
- type = crm_element_name(diff);
+ type = (const char *) diff->name;
crm_trace("Setting type to new_obj->name: %s", type);
}
crm_xml_add(update_msg, F_CIB_OBJID, ID(diff));
@@ -218,88 +218,7 @@ cib_diff_notify(const char *op, int result, const char *call_id,
}
add_message_xml(update_msg, F_CIB_UPDATE_RESULT, diff);
+ crm_log_xml_trace(update_msg, "diff-notify");
cib_notify_send(update_msg);
free_xml(update_msg);
}
-
-void
-cib_replace_notify(const char *op, int result, const char *call_id,
- const char *client_id, const char *client_name,
- const char *origin, xmlNode *update, xmlNode *diff,
- uint32_t change_section)
-{
- xmlNode *replace_msg = NULL;
-
- int add_updates = 0;
- int add_epoch = 0;
- int add_admin_epoch = 0;
-
- int del_updates = 0;
- int del_epoch = 0;
- int del_admin_epoch = 0;
-
- uint8_t log_level = LOG_INFO;
-
- if (diff == NULL) {
- return;
- }
-
- if (result != pcmk_ok) {
- log_level = LOG_WARNING;
- }
-
- cib_diff_version_details(diff, &add_admin_epoch, &add_epoch, &add_updates,
- &del_admin_epoch, &del_epoch, &del_updates);
-
- if (del_updates < 0) {
- crm_log_xml_debug(diff, "Bad replace diff");
- }
-
- if ((add_admin_epoch != del_admin_epoch)
- || (add_epoch != del_epoch)
- || (add_updates != del_updates)) {
-
- do_crm_log(log_level,
- "Replaced CIB generation %d.%d.%d with %d.%d.%d from client "
- "%s%s%s (%s) (%s)",
- del_admin_epoch, del_epoch, del_updates,
- add_admin_epoch, add_epoch, add_updates,
- client_name,
- ((call_id != NULL)? " call " : ""), pcmk__s(call_id, ""),
- pcmk__s(origin, "unspecified peer"), pcmk_strerror(result));
-
- } else if ((add_admin_epoch != 0)
- || (add_epoch != 0)
- || (add_updates != 0)) {
-
- do_crm_log(log_level,
- "Local-only replace of CIB generation %d.%d.%d from client "
- "%s%s%s (%s) (%s)",
- add_admin_epoch, add_epoch, add_updates,
- client_name,
- ((call_id != NULL)? " call " : ""), pcmk__s(call_id, ""),
- pcmk__s(origin, "unspecified peer"), pcmk_strerror(result));
- }
-
- replace_msg = create_xml_node(NULL, "notify-replace");
-
- crm_xml_add(replace_msg, F_TYPE, T_CIB_NOTIFY);
- crm_xml_add(replace_msg, F_SUBTYPE, T_CIB_REPLACE_NOTIFY);
- crm_xml_add(replace_msg, F_CIB_OPERATION, op);
- crm_xml_add(replace_msg, F_CIB_CLIENTID, client_id);
- crm_xml_add(replace_msg, F_CIB_CALLID, call_id);
- crm_xml_add(replace_msg, F_ORIG, origin);
- crm_xml_add_int(replace_msg, F_CIB_RC, result);
- crm_xml_add_ll(replace_msg, F_CIB_CHANGE_SECTION,
- (long long) change_section);
- attach_cib_generation(replace_msg, "cib-replace-generation", update);
-
- /* We can include update and diff if a replace callback needs them. Until
- * then, avoid the overhead.
- */
-
- crm_log_xml_trace(replace_msg, "CIB replaced");
-
- cib_notify_send(replace_msg);
- free_xml(replace_msg);
-}
diff --git a/daemons/based/based_operation.c b/daemons/based/based_operation.c
new file mode 100644
index 0000000..736d425
--- /dev/null
+++ b/daemons/based/based_operation.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008-2023 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 <crm_internal.h>
+
+#include <glib.h>
+
+#include <crm/crm.h>
+#include <crm/cib.h>
+#include <pacemaker-based.h>
+
+static const cib__op_fn_t cib_op_functions[] = {
+ [cib__op_abs_delete] = cib_process_delete_absolute,
+ [cib__op_apply_patch] = cib_server_process_diff,
+ [cib__op_bump] = cib_process_bump,
+ [cib__op_commit_transact] = cib_process_commit_transaction,
+ [cib__op_create] = cib_process_create,
+ [cib__op_delete] = cib_process_delete,
+ [cib__op_erase] = cib_process_erase,
+ [cib__op_is_primary] = cib_process_readwrite,
+ [cib__op_modify] = cib_process_modify,
+ [cib__op_noop] = cib_process_noop,
+ [cib__op_ping] = cib_process_ping,
+ [cib__op_primary] = cib_process_readwrite,
+ [cib__op_query] = cib_process_query,
+ [cib__op_replace] = cib_process_replace_svr,
+ [cib__op_secondary] = cib_process_readwrite,
+ [cib__op_shutdown] = cib_process_shutdown_req,
+ [cib__op_sync_all] = cib_process_sync,
+ [cib__op_sync_one] = cib_process_sync_one,
+ [cib__op_upgrade] = cib_process_upgrade_server,
+};
+
+/*!
+ * \internal
+ * \brief Get the function that performs a given server-side CIB operation
+ *
+ * \param[in] operation Operation whose function to look up
+ *
+ * \return Function that performs \p operation within \c pacemaker-based
+ */
+cib__op_fn_t
+based_get_op_function(const cib__operation_t *operation)
+{
+ enum cib__op_type type = operation->type;
+
+ CRM_ASSERT(type >= 0);
+
+ if (type >= PCMK__NELEM(cib_op_functions)) {
+ return NULL;
+ }
+ return cib_op_functions[type];
+}
diff --git a/daemons/based/based_remote.c b/daemons/based/based_remote.c
index 38136d2..4aa41fa 100644
--- a/daemons/based/based_remote.c
+++ b/daemons/based/based_remote.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2021 the Pacemaker project contributors
+ * Copyright 2004-2023 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
@@ -23,7 +23,9 @@
#include <stdlib.h>
#include <errno.h>
+
#include <glib.h>
+#include <libxml/tree.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
@@ -126,13 +128,13 @@ init_remote_listener(int port, gboolean encrypted)
/* create server socket */
ssock = malloc(sizeof(int));
if(ssock == NULL) {
- crm_perror(LOG_ERR, "Listener socket allocation failed");
+ crm_err("Listener socket allocation failed: %s", pcmk_rc_str(errno));
return -1;
}
*ssock = socket(AF_INET, SOCK_STREAM, 0);
if (*ssock == -1) {
- crm_perror(LOG_ERR, "Listener socket creation failed");
+ crm_err("Listener socket creation failed: %s", pcmk_rc_str(errno));
free(ssock);
return -1;
}
@@ -141,8 +143,8 @@ init_remote_listener(int port, gboolean encrypted)
optval = 1;
rc = setsockopt(*ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if (rc < 0) {
- crm_perror(LOG_WARNING,
- "Local address reuse not allowed on listener socket");
+ crm_err("Local address reuse not allowed on listener socket: %s",
+ pcmk_rc_str(errno));
}
/* bind server socket */
@@ -151,13 +153,13 @@ init_remote_listener(int port, gboolean encrypted)
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(port);
if (bind(*ssock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
- crm_perror(LOG_ERR, "Cannot bind to listener socket");
+ crm_err("Cannot bind to listener socket: %s", pcmk_rc_str(errno));
close(*ssock);
free(ssock);
return -2;
}
if (listen(*ssock, 10) == -1) {
- crm_perror(LOG_ERR, "Cannot listen on socket");
+ crm_err("Cannot listen on socket: %s", pcmk_rc_str(errno));
close(*ssock);
free(ssock);
return -3;
@@ -222,9 +224,9 @@ cib_remote_auth(xmlNode * login)
return FALSE;
}
- tmp = crm_element_name(login);
- if (!pcmk__str_eq(tmp, "cib_command", pcmk__str_casei)) {
- crm_err("Wrong tag: %s", tmp);
+ if (!pcmk__xe_is(login, T_CIB_COMMAND)) {
+ crm_err("Unrecognizable message from remote client");
+ crm_log_xml_info(login, "bad");
return FALSE;
}
@@ -296,7 +298,7 @@ cib_remote_listen(gpointer data)
memset(&addr, 0, sizeof(addr));
csock = accept(ssock, (struct sockaddr *)&addr, &laddr);
if (csock == -1) {
- crm_perror(LOG_ERR, "Could not accept socket connection");
+ crm_err("Could not accept socket connection: %s", pcmk_rc_str(errno));
return TRUE;
}
@@ -411,9 +413,8 @@ cib_handle_remote_msg(pcmk__client_t *client, xmlNode *command)
{
const char *value = NULL;
- value = crm_element_name(command);
- if (!pcmk__str_eq(value, "cib_command", pcmk__str_casei)) {
- crm_log_xml_trace(command, "Bad command: ");
+ if (!pcmk__xe_is(command, T_CIB_COMMAND)) {
+ crm_log_xml_trace(command, "bad");
return;
}
diff --git a/daemons/based/based_transaction.c b/daemons/based/based_transaction.c
new file mode 100644
index 0000000..89aea2e
--- /dev/null
+++ b/daemons/based/based_transaction.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2023 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 <crm_internal.h>
+
+#include <glib.h>
+#include <libxml/tree.h>
+
+#include "pacemaker-based.h"
+
+/*!
+ * \internal
+ * \brief Create a string describing the source of a commit-transaction request
+ *
+ * \param[in] client CIB client
+ * \param[in] origin Host where the commit request originated
+ *
+ * \return String describing the request source
+ *
+ * \note The caller is responsible for freeing the return value using \c free().
+ */
+char *
+based_transaction_source_str(const pcmk__client_t *client, const char *origin)
+{
+ char *source = NULL;
+
+ if (client != NULL) {
+ source = crm_strdup_printf("client %s (%s)%s%s",
+ pcmk__client_name(client),
+ pcmk__s(client->id, "unidentified"),
+ ((origin != NULL)? " on " : ""),
+ pcmk__s(origin, ""));
+
+ } else {
+ source = strdup((origin != NULL)? origin : "unknown source");
+ }
+
+ CRM_ASSERT(source != NULL);
+ return source;
+}
+
+/*!
+ * \internal
+ * \brief Process requests in a transaction
+ *
+ * Stop when a request fails or when all requests have been processed.
+ *
+ * \param[in,out] transaction Transaction to process
+ * \param[in] client CIB client
+ * \param[in] source String describing the commit request source
+ *
+ * \return Standard Pacemaker return code
+ */
+static int
+process_transaction_requests(xmlNodePtr transaction,
+ const pcmk__client_t *client, const char *source)
+{
+ for (xmlNodePtr request = first_named_child(transaction, T_CIB_COMMAND);
+ request != NULL; request = crm_next_same_xml(request)) {
+
+ const char *op = crm_element_value(request, F_CIB_OPERATION);
+ const char *host = crm_element_value(request, F_CIB_HOST);
+ const cib__operation_t *operation = NULL;
+ int rc = cib__get_operation(op, &operation);
+
+ if (rc == pcmk_rc_ok) {
+ if (!pcmk_is_set(operation->flags, cib__op_attr_transaction)
+ || (host != NULL)) {
+
+ rc = EOPNOTSUPP;
+ } else {
+ /* Commit-transaction is a privileged operation. If we reached
+ * this point, the request came from a privileged connection.
+ */
+ rc = cib_process_request(request, TRUE, client);
+ rc = pcmk_legacy2rc(rc);
+ }
+ }
+
+ if (rc != pcmk_rc_ok) {
+ crm_err("Aborting CIB transaction for %s due to failed %s request: "
+ "%s",
+ source, op, pcmk_rc_str(rc));
+ crm_log_xml_info(request, "Failed request");
+ return rc;
+ }
+
+ crm_trace("Applied %s request to transaction working CIB for %s",
+ op, source);
+ crm_log_xml_trace(request, "Successful request");
+ }
+
+ return pcmk_rc_ok;
+}
+
+/*!
+ * \internal
+ * \brief Commit a given CIB client's transaction to a working CIB copy
+ *
+ * \param[in] transaction Transaction to commit
+ * \param[in] client CIB client
+ * \param[in] origin Host where the commit request originated
+ * \param[in,out] result_cib Where to store result CIB
+ *
+ * \return Standard Pacemaker return code
+ *
+ * \note This function is expected to be called only by
+ * \p cib_process_commit_transaction().
+ * \note \p result_cib is expected to be a copy of the current CIB as created by
+ * \p cib_perform_op().
+ * \note The caller is responsible for activating and syncing \p result_cib on
+ * success, and for freeing it on failure.
+ */
+int
+based_commit_transaction(xmlNodePtr transaction, const pcmk__client_t *client,
+ const char *origin, xmlNodePtr *result_cib)
+{
+ xmlNodePtr saved_cib = the_cib;
+ int rc = pcmk_rc_ok;
+ char *source = NULL;
+
+ CRM_ASSERT(result_cib != NULL);
+
+ CRM_CHECK(pcmk__xe_is(transaction, T_CIB_TRANSACTION),
+ return pcmk_rc_no_transaction);
+
+ /* *result_cib should be a copy of the_cib (created by cib_perform_op()). If
+ * not, make a copy now. Change tracking isn't strictly required here
+ * because:
+ * * Each request in the transaction will have changes tracked and ACLs
+ * checked if appropriate.
+ * * cib_perform_op() will infer changes for the commit request at the end.
+ */
+ CRM_CHECK((*result_cib != NULL) && (*result_cib != the_cib),
+ *result_cib = copy_xml(the_cib));
+
+ source = based_transaction_source_str(client, origin);
+ crm_trace("Committing transaction for %s to working CIB", source);
+
+ // Apply all changes to a working copy of the CIB
+ the_cib = *result_cib;
+
+ rc = process_transaction_requests(transaction, client, origin);
+
+ crm_trace("Transaction commit %s for %s",
+ ((rc == pcmk_rc_ok)? "succeeded" : "failed"), source);
+
+ /* Some request types (for example, erase) may have freed the_cib (the
+ * working copy) and pointed it at a new XML object. In that case, it
+ * follows that *result_cib (the working copy) was freed.
+ *
+ * Point *result_cib at the updated working copy stored in the_cib.
+ */
+ *result_cib = the_cib;
+
+ // Point the_cib back to the unchanged original copy
+ the_cib = saved_cib;
+
+ free(source);
+ return rc;
+}
diff --git a/daemons/based/based_transaction.h b/daemons/based/based_transaction.h
new file mode 100644
index 0000000..9935c73
--- /dev/null
+++ b/daemons/based/based_transaction.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2023 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 BASED_TRANSACTION__H
+#define BASED_TRANSACTION__H
+
+#include <crm_internal.h>
+
+#include <libxml/tree.h>
+
+char *based_transaction_source_str(const pcmk__client_t *client,
+ const char *origin);
+
+int based_commit_transaction(xmlNodePtr transaction,
+ const pcmk__client_t *client,
+ const char *origin, xmlNodePtr *result_cib);
+
+#endif // BASED_TRANSACTION__H
diff --git a/daemons/based/pacemaker-based.c b/daemons/based/pacemaker-based.c
index 129997e..5dd7938 100644
--- a/daemons/based/pacemaker-based.c
+++ b/daemons/based/pacemaker-based.c
@@ -16,7 +16,8 @@
#include <bzlib.h>
#include <sys/types.h>
-#include <libxml/parser.h>
+#include <glib.h>
+#include <libxml/tree.h>
#include <crm/crm.h>
#include <crm/cib/internal.h>
@@ -42,6 +43,7 @@ gchar *cib_root = NULL;
static gboolean preserve_status = FALSE;
gboolean cib_writes_enabled = TRUE;
+gboolean stand_alone = FALSE;
int remote_fd = 0;
int remote_tls_fd = 0;
@@ -49,8 +51,6 @@ int remote_tls_fd = 0;
GHashTable *config_hash = NULL;
GHashTable *local_notify_queue = NULL;
-pcmk__output_t *logger_out = NULL;
-
static void cib_init(void);
void cib_shutdown(int nsig);
static bool startCib(const char *filename);
@@ -197,15 +197,6 @@ main(int argc, char **argv)
goto done;
}
- rc = pcmk__log_output_new(&logger_out);
- if (rc != pcmk_rc_ok) {
- exit_code = CRM_EX_ERROR;
- g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
- "Error creating output format log: %s", pcmk_rc_str(rc));
- goto done;
- }
- pcmk__output_set_log_level(logger_out, LOG_TRACE);
-
mainloop_add_signal(SIGTERM, cib_shutdown);
mainloop_add_signal(SIGPIPE, cib_enable_writes);
@@ -230,7 +221,7 @@ main(int argc, char **argv)
goto done;
}
- if (crm_ipc_connect(old_instance)) {
+ if (pcmk__connect_generic_ipc(old_instance) == pcmk_rc_ok) {
/* IPC end-point already up */
crm_ipc_close(old_instance);
crm_ipc_destroy(old_instance);
diff --git a/daemons/based/pacemaker-based.h b/daemons/based/pacemaker-based.h
index 05e49b3..33c7642 100644
--- a/daemons/based/pacemaker-based.h
+++ b/daemons/based/pacemaker-based.h
@@ -18,6 +18,9 @@
#include <errno.h>
#include <fcntl.h>
+#include <glib.h>
+#include <libxml/tree.h>
+
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/common/xml.h>
@@ -26,16 +29,19 @@
#include <crm/common/mainloop.h>
#include <crm/cib/internal.h>
+#include "based_transaction.h"
+
#ifdef HAVE_GNUTLS_GNUTLS_H
# include <gnutls/gnutls.h>
#endif
+#define OUR_NODENAME (stand_alone? "localhost" : crm_cluster->uname)
+
// CIB-specific client flags
enum cib_client_flags {
// Notifications
cib_notify_pre = (UINT64_C(1) << 0),
cib_notify_post = (UINT64_C(1) << 1),
- cib_notify_replace = (UINT64_C(1) << 2),
cib_notify_confirm = (UINT64_C(1) << 3),
cib_notify_diff = (UINT64_C(1) << 4),
@@ -43,16 +49,6 @@ enum cib_client_flags {
cib_is_daemon = (UINT64_C(1) << 12),
};
-typedef struct cib_operation_s {
- const char *operation;
- gboolean modifies_cib;
- gboolean needs_privileges;
- int (*prepare) (xmlNode *, xmlNode **, const char **);
- int (*cleanup) (int, xmlNode **, xmlNode **);
- int (*fn) (const char *, int, const char *, xmlNode *,
- xmlNode *, xmlNode *, xmlNode **, xmlNode **);
-} cib_operation_t;
-
extern bool based_is_primary;
extern GHashTable *config_hash;
extern xmlNode *the_cib;
@@ -67,7 +63,6 @@ extern gboolean stand_alone;
extern gboolean cib_shutdown_flag;
extern gchar *cib_root;
extern int cib_status;
-extern pcmk__output_t *logger_out;
extern struct qb_ipcs_service_handlers ipc_ro_callbacks;
extern struct qb_ipcs_service_handlers ipc_rw_callbacks;
@@ -79,6 +74,8 @@ void cib_peer_callback(xmlNode *msg, void *private_data);
void cib_common_callback_worker(uint32_t id, uint32_t flags,
xmlNode *op_request, pcmk__client_t *cib_client,
gboolean privileged);
+int cib_process_request(xmlNode *request, gboolean privileged,
+ const pcmk__client_t *cib_client);
void cib_shutdown(int nsig);
void terminate_cib(const char *caller, int fast);
gboolean cib_legacy_mode(void);
@@ -92,9 +89,9 @@ 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);
-int cib_process_default(const char *op, int options, const char *section,
- xmlNode *req, xmlNode *input, xmlNode *existing_cib,
- xmlNode **result_cib, xmlNode **answer);
+int cib_process_noop(const char *op, int options, const char *section,
+ xmlNode *req, xmlNode *input, xmlNode *existing_cib,
+ xmlNode **result_cib, xmlNode **answer);
int cib_process_ping(const char *op, int options, const char *section,
xmlNode *req, xmlNode *input, xmlNode *existing_cib,
xmlNode **result_cib, xmlNode **answer);
@@ -121,25 +118,17 @@ 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 cib_process_commit_transaction(const char *op, int options,
+ const char *section, xmlNode *req,
+ xmlNode *input, xmlNode *existing_cib,
+ xmlNode **result_cib, xmlNode **answer);
void send_sync_request(const char *host);
int sync_our_cib(xmlNode *request, gboolean all);
-xmlNode *cib_msg_copy(xmlNode *msg, gboolean with_data);
-int cib_get_operation_id(const char *op, int *operation);
-cib_op_t *cib_op_func(int call_type);
-gboolean cib_op_modifies(int call_type);
-int cib_op_prepare(int call_type, xmlNode *request, xmlNode **input,
- const char **section);
-int cib_op_cleanup(int call_type, int options, xmlNode **input,
- xmlNode **output);
-int cib_op_can_run(int call_type, int call_options, bool privileged);
+cib__op_fn_t based_get_op_function(const cib__operation_t *operation);
void cib_diff_notify(const char *op, int result, const char *call_id,
const char *client_id, const char *client_name,
const char *origin, xmlNode *update, xmlNode *diff);
-void cib_replace_notify(const char *op, int result, const char *call_id,
- const char *client_id, const char *client_name,
- const char *origin, xmlNode *update, xmlNode *diff,
- uint32_t change_section);
static inline const char *
cib_config_lookup(const char *opt)