Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/lib/common/ipc_attrd.c b/lib/common/ipc_attrd.c
index 4a3808b873..62638f1120 100644
--- a/lib/common/ipc_attrd.c
+++ b/lib/common/ipc_attrd.c
@@ -1,481 +1,484 @@
/*
* Copyright 2011-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.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <crm/crm.h>
#include <crm/common/attrs_internal.h>
#include <crm/common/ipc.h>
#include <crm/common/ipc_attrd_internal.h>
#include <crm/common/xml.h>
#include "crmcommon_private.h"
static void
set_pairs_data(pcmk__attrd_api_reply_t *data, xmlNode *msg_data)
{
const char *name = NULL;
pcmk__attrd_query_pair_t *pair;
name = crm_element_value(msg_data, PCMK__XA_ATTR_NAME);
for (xmlNode *node = pcmk__xe_first_child(msg_data, PCMK_XE_NODE, NULL,
NULL);
node != NULL; node = pcmk__xe_next_same(node)) {
pair = pcmk__assert_alloc(1, sizeof(pcmk__attrd_query_pair_t));
pair->node = crm_element_value(node, PCMK__XA_ATTR_HOST);
pair->name = name;
pair->value = crm_element_value(node, PCMK__XA_ATTR_VALUE);
data->data.pairs = g_list_prepend(data->data.pairs, pair);
}
}
static bool
reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
{
const char *command = crm_element_value(request, PCMK_XA_TASK);
return pcmk__str_any_of(command,
PCMK__ATTRD_CMD_CLEAR_FAILURE,
PCMK__ATTRD_CMD_QUERY,
PCMK__ATTRD_CMD_REFRESH,
PCMK__ATTRD_CMD_UPDATE,
PCMK__ATTRD_CMD_UPDATE_BOTH,
PCMK__ATTRD_CMD_UPDATE_DELAY,
NULL);
}
static bool
dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
{
const char *value = NULL;
crm_exit_t status = CRM_EX_OK;
pcmk__attrd_api_reply_t reply_data = {
pcmk__attrd_reply_unknown
};
if (pcmk__xe_is(reply, PCMK__XE_ACK)) {
return false;
}
/* Do some basic validation of the reply */
value = crm_element_value(reply, PCMK__XA_T);
if (pcmk__str_empty(value)
|| !pcmk__str_eq(value, PCMK__VALUE_ATTRD, pcmk__str_none)) {
crm_info("Unrecognizable message from attribute manager: "
"message type '%s' not '" PCMK__VALUE_ATTRD "'",
pcmk__s(value, ""));
status = CRM_EX_PROTOCOL;
goto done;
}
value = crm_element_value(reply, PCMK__XA_SUBT);
/* Only the query command gets a reply for now. NULL counts as query for
* backward compatibility with attribute managers <2.1.3 that didn't set it.
*/
if (pcmk__str_eq(value, PCMK__ATTRD_CMD_QUERY, pcmk__str_null_matches)) {
if (!xmlHasProp(reply, (pcmkXmlStr) PCMK__XA_ATTR_NAME)) {
status = ENXIO; // Most likely, the attribute doesn't exist
goto done;
}
reply_data.reply_type = pcmk__attrd_reply_query;
set_pairs_data(&reply_data, reply);
} else {
crm_info("Unrecognizable message from attribute manager: "
"message subtype '%s' unknown", pcmk__s(value, ""));
status = CRM_EX_PROTOCOL;
goto done;
}
done:
pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
/* Free any reply data that was allocated */
if (reply_data.data.pairs) {
g_list_free_full(reply_data.data.pairs, free);
}
return false;
}
pcmk__ipc_methods_t *
pcmk__attrd_api_methods(void)
{
pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
if (cmds != NULL) {
cmds->new_data = NULL;
cmds->free_data = NULL;
cmds->post_connect = NULL;
cmds->reply_expected = reply_expected;
cmds->dispatch = dispatch;
}
return cmds;
}
/*!
* \internal
* \brief Create a generic attribute manager operation
*
* \param[in] user_name If not NULL, ACL user to set for operation
*
* \return XML of attribute manager operation
*/
static xmlNode *
create_attrd_op(const char *user_name)
{
xmlNode *attrd_op = pcmk__xe_create(NULL, __func__);
crm_xml_add(attrd_op, PCMK__XA_T, PCMK__VALUE_ATTRD);
crm_xml_add(attrd_op, PCMK__XA_SRC, pcmk__s(crm_system_name, "unknown"));
crm_xml_add(attrd_op, PCMK__XA_ATTR_USER, user_name);
return attrd_op;
}
static int
connect_and_send_attrd_request(pcmk_ipc_api_t *api, const xmlNode *request)
{
int rc = pcmk_rc_ok;
bool created_api = false;
+ enum pcmk_ipc_dispatch dispatch = pcmk_ipc_dispatch_sync;
if (api == NULL) {
rc = pcmk_new_ipc_api(&api, pcmk_ipc_attrd);
if (rc != pcmk_rc_ok) {
return rc;
}
created_api = true;
+ } else {
+ dispatch = api->dispatch_type;
}
- rc = pcmk__connect_ipc(api, pcmk_ipc_dispatch_sync, 5);
+ rc = pcmk__connect_ipc(api, dispatch, 5);
if (rc == pcmk_rc_ok) {
rc = pcmk__send_ipc_request(api, request);
}
if (created_api) {
pcmk_free_ipc_api(api);
}
return rc;
}
int
pcmk__attrd_api_clear_failures(pcmk_ipc_api_t *api, const char *node,
const char *resource, const char *operation,
const char *interval_spec, const char *user_name,
uint32_t options)
{
int rc = pcmk_rc_ok;
xmlNode *request = create_attrd_op(user_name);
const char *interval_desc = NULL;
const char *op_desc = NULL;
const char *target = pcmk__node_attr_target(node);
if (target != NULL) {
node = target;
}
if (operation) {
interval_desc = pcmk__s(interval_spec, "nonrecurring");
op_desc = operation;
} else {
interval_desc = "all";
op_desc = "operations";
}
crm_debug("Asking %s to clear failure of %s %s for %s on %s",
pcmk_ipc_name(api, true), interval_desc, op_desc,
pcmk__s(resource, "all resources"), pcmk__s(node, "all nodes"));
crm_xml_add(request, PCMK_XA_TASK, PCMK__ATTRD_CMD_CLEAR_FAILURE);
pcmk__xe_add_node(request, node, 0);
crm_xml_add(request, PCMK__XA_ATTR_RESOURCE, resource);
crm_xml_add(request, PCMK__XA_ATTR_CLEAR_OPERATION, operation);
crm_xml_add(request, PCMK__XA_ATTR_CLEAR_INTERVAL, interval_spec);
crm_xml_add_int(request, PCMK__XA_ATTR_IS_REMOTE,
pcmk_is_set(options, pcmk__node_attr_remote));
rc = connect_and_send_attrd_request(api, request);
pcmk__xml_free(request);
return rc;
}
int
pcmk__attrd_api_delete(pcmk_ipc_api_t *api, const char *node, const char *name,
uint32_t options)
{
const char *target = NULL;
if (name == NULL) {
return EINVAL;
}
target = pcmk__node_attr_target(node);
if (target != NULL) {
node = target;
}
/* Make sure the right update option is set. */
options &= ~pcmk__node_attr_delay;
options |= pcmk__node_attr_value;
return pcmk__attrd_api_update(api, node, name, NULL, NULL, NULL, NULL, options);
}
int
pcmk__attrd_api_purge(pcmk_ipc_api_t *api, const char *node, bool reap)
{
int rc = pcmk_rc_ok;
xmlNode *request = NULL;
const char *target = pcmk__node_attr_target(node);
if (target != NULL) {
node = target;
}
crm_debug("Asking %s to purge transient attributes%s for %s",
pcmk_ipc_name(api, true),
(reap? " and node cache entries" : ""),
pcmk__s(node, "local node"));
request = create_attrd_op(NULL);
crm_xml_add(request, PCMK_XA_TASK, PCMK__ATTRD_CMD_PEER_REMOVE);
pcmk__xe_set_bool_attr(request, PCMK__XA_REAP, reap);
pcmk__xe_add_node(request, node, 0);
rc = connect_and_send_attrd_request(api, request);
pcmk__xml_free(request);
return rc;
}
int
pcmk__attrd_api_query(pcmk_ipc_api_t *api, const char *node, const char *name,
uint32_t options)
{
int rc = pcmk_rc_ok;
xmlNode *request = NULL;
const char *target = NULL;
if (name == NULL) {
return EINVAL;
}
if (pcmk_is_set(options, pcmk__node_attr_query_all)) {
node = NULL;
} else {
target = pcmk__node_attr_target(node);
if (target != NULL) {
node = target;
}
}
crm_debug("Querying %s for value of '%s'%s%s",
pcmk_ipc_name(api, true), name,
((node == NULL)? "" : " on "), pcmk__s(node, ""));
request = create_attrd_op(NULL);
crm_xml_add(request, PCMK__XA_ATTR_NAME, name);
crm_xml_add(request, PCMK_XA_TASK, PCMK__ATTRD_CMD_QUERY);
pcmk__xe_add_node(request, node, 0);
rc = connect_and_send_attrd_request(api, request);
pcmk__xml_free(request);
return rc;
}
int
pcmk__attrd_api_refresh(pcmk_ipc_api_t *api, const char *node)
{
int rc = pcmk_rc_ok;
xmlNode *request = NULL;
const char *target = pcmk__node_attr_target(node);
if (target != NULL) {
node = target;
}
crm_debug("Asking %s to write all transient attributes for %s to CIB",
pcmk_ipc_name(api, true), pcmk__s(node, "local node"));
request = create_attrd_op(NULL);
crm_xml_add(request, PCMK_XA_TASK, PCMK__ATTRD_CMD_REFRESH);
pcmk__xe_add_node(request, node, 0);
rc = connect_and_send_attrd_request(api, request);
pcmk__xml_free(request);
return rc;
}
static void
add_op_attr(xmlNode *op, uint32_t options)
{
if (pcmk_all_flags_set(options, pcmk__node_attr_value | pcmk__node_attr_delay)) {
crm_xml_add(op, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE_BOTH);
} else if (pcmk_is_set(options, pcmk__node_attr_value)) {
crm_xml_add(op, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE);
} else if (pcmk_is_set(options, pcmk__node_attr_delay)) {
crm_xml_add(op, PCMK_XA_TASK, PCMK__ATTRD_CMD_UPDATE_DELAY);
}
}
static void
populate_update_op(xmlNode *op, const char *node, const char *name, const char *value,
const char *dampen, const char *set, uint32_t options)
{
if (pcmk_is_set(options, pcmk__node_attr_pattern)) {
crm_xml_add(op, PCMK__XA_ATTR_REGEX, name);
} else {
crm_xml_add(op, PCMK__XA_ATTR_NAME, name);
}
if (pcmk_is_set(options, pcmk__node_attr_utilization)) {
crm_xml_add(op, PCMK__XA_ATTR_SET_TYPE, PCMK_XE_UTILIZATION);
} else {
crm_xml_add(op, PCMK__XA_ATTR_SET_TYPE, PCMK_XE_INSTANCE_ATTRIBUTES);
}
add_op_attr(op, options);
crm_xml_add(op, PCMK__XA_ATTR_VALUE, value);
crm_xml_add(op, PCMK__XA_ATTR_DAMPENING, dampen);
pcmk__xe_add_node(op, node, 0);
crm_xml_add(op, PCMK__XA_ATTR_SET, set);
crm_xml_add_int(op, PCMK__XA_ATTR_IS_REMOTE,
pcmk_is_set(options, pcmk__node_attr_remote));
crm_xml_add_int(op, PCMK__XA_ATTR_IS_PRIVATE,
pcmk_is_set(options, pcmk__node_attr_private));
if (pcmk_is_set(options, pcmk__node_attr_sync_local)) {
crm_xml_add(op, PCMK__XA_ATTR_SYNC_POINT, PCMK__VALUE_LOCAL);
} else if (pcmk_is_set(options, pcmk__node_attr_sync_cluster)) {
crm_xml_add(op, PCMK__XA_ATTR_SYNC_POINT, PCMK__VALUE_CLUSTER);
}
}
int
pcmk__attrd_api_update(pcmk_ipc_api_t *api, const char *node, const char *name,
const char *value, const char *dampen, const char *set,
const char *user_name, uint32_t options)
{
int rc = pcmk_rc_ok;
xmlNode *request = NULL;
const char *target = NULL;
if (name == NULL) {
return EINVAL;
}
target = pcmk__node_attr_target(node);
if (target != NULL) {
node = target;
}
crm_debug("Asking %s to update '%s' to '%s' for %s",
pcmk_ipc_name(api, true), name, pcmk__s(value, "(null)"),
pcmk__s(node, "local node"));
request = create_attrd_op(user_name);
populate_update_op(request, node, name, value, dampen, set, options);
rc = connect_and_send_attrd_request(api, request);
pcmk__xml_free(request);
return rc;
}
int
pcmk__attrd_api_update_list(pcmk_ipc_api_t *api, GList *attrs, const char *dampen,
const char *set, const char *user_name,
uint32_t options)
{
int rc = pcmk_rc_ok;
xmlNode *request = NULL;
if (attrs == NULL) {
return EINVAL;
}
/* There are two different ways of handling a list of attributes:
*
* (1) For messages originating from some command line tool, we have to send
* them one at a time. In this loop, we just call pcmk__attrd_api_update
* for each, letting it deal with creating the API object if it doesn't
* already exist.
*
* The reason we can't use a single message in this case is that we can't
* trust that the server supports it. Remote nodes could be involved
* here, and there's no guarantee that a newer client running on a remote
* node is talking to (or proxied through) a cluster node with a newer
* attrd. We also can't just try sending a single message and then falling
* back on multiple. There's no handshake with the attrd server to
* determine its version. And then we would need to do that fallback in the
* dispatch function for this to work for all connection types (mainloop in
* particular), and at that point we won't know what the original message
* was in order to break it apart and resend as individual messages.
*
* (2) For messages between daemons, we can be assured that the local attrd
* will support the new message and that it can send to the other attrds
* as one request or split up according to the minimum supported version.
*/
for (GList *iter = attrs; iter != NULL; iter = iter->next) {
pcmk__attrd_query_pair_t *pair = (pcmk__attrd_query_pair_t *) iter->data;
if (pcmk__is_daemon) {
const char *target = NULL;
xmlNode *child = NULL;
/* First time through this loop - create the basic request. */
if (request == NULL) {
request = create_attrd_op(user_name);
add_op_attr(request, options);
}
/* Add a child node for this operation. We add the task to the top
* level XML node so attrd_ipc_dispatch doesn't need changes. And
* then we also add the task to each child node in populate_update_op
* so attrd_client_update knows what form of update is taking place.
*/
child = pcmk__xe_create(request, PCMK_XE_OP);
target = pcmk__node_attr_target(pair->node);
if (target != NULL) {
pair->node = target;
}
populate_update_op(child, pair->node, pair->name, pair->value, dampen,
set, options);
} else {
rc = pcmk__attrd_api_update(api, pair->node, pair->name, pair->value,
dampen, set, user_name, options);
}
}
/* If we were doing multiple attributes at once, we still need to send the
* request. Do that now, creating and destroying the API object if needed.
*/
if (pcmk__is_daemon) {
rc = connect_and_send_attrd_request(api, request);
pcmk__xml_free(request);
}
return rc;
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 4:07 AM (8 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018209
Default Alt Text
(15 KB)

Event Timeline