Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4624227
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/tools/attrd_updater.c b/tools/attrd_updater.c
index d186886f07..3fa6ef2eaf 100644
--- a/tools/attrd_updater.c
+++ b/tools/attrd_updater.c
@@ -1,466 +1,467 @@
/*
* Copyright 2004-2020 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 <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <libgen.h>
#include <sys/param.h>
#include <sys/types.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/attrd_internal.h>
static pcmk__cli_option_t long_options[] = {
// long option, argument type, storage, short option, description, flags
{
"help", no_argument, NULL, '?',
"\tThis text", pcmk__option_default
},
{
"version", no_argument, NULL, '$',
"\tVersion information", pcmk__option_default
},
{
"verbose", no_argument, NULL, 'V',
"\tIncrease debug output\n", pcmk__option_default
},
{
"name", required_argument, NULL, 'n',
"The attribute's name", pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '-',
"\nCommands:", pcmk__option_default
},
{
"update", required_argument, NULL, 'U',
"Update attribute's value in pacemaker-attrd. If this causes the value "
"to change, it will also be updated in the cluster configuration.",
pcmk__option_default
},
{
"update-both", required_argument, NULL, 'B',
"Update attribute's value and time to wait (dampening) in "
"pacemaker-attrd. If this causes the value or dampening to change, "
"the attribute will also be written to the cluster configuration, "
"so be aware that repeatedly changing the dampening reduces its "
"effectiveness.",
pcmk__option_default
},
{
"update-delay", no_argument, NULL, 'Y',
"Update attribute's dampening in pacemaker-attrd (requires "
"-d/--delay). If this causes the dampening to change, the "
"attribute will also be written to the cluster configuration, so "
"be aware that repeatedly changing the dampening reduces its "
"effectiveness.",
pcmk__option_default
},
{
"query", no_argument, NULL, 'Q',
"\tQuery the attribute's value from pacemaker-attrd",
pcmk__option_default
},
{
"delete", no_argument, NULL, 'D',
"\tDelete attribute from pacemaker-attrd. If a value was previously "
"set, it will also be removed from the cluster configuration",
pcmk__option_default
},
{
"refresh", no_argument, NULL, 'R',
"\t(Advanced) Force the pacemaker-attrd daemon to resend all current "
"values to the CIB",
pcmk__option_default
},
{
"-spacer-", no_argument, NULL, '-',
"\nAdditional options:", pcmk__option_default
},
{
"delay", required_argument, NULL, 'd',
"The time to wait (dampening) in seconds for further changes "
"before writing",
pcmk__option_default
},
{
"set", required_argument, NULL, 's',
"(Advanced) The attribute set in which to place the value",
pcmk__option_default
},
{
"node", required_argument, NULL, 'N',
"Set the attribute for the named node (instead of the local one)",
pcmk__option_default
},
{
"all", no_argument, NULL, 'A',
"Show values of the attribute for all nodes (query only)",
pcmk__option_default
},
// @TODO Implement --lifetime
{
"lifetime", required_argument, NULL, 'l',
"(Not yet implemented) Lifetime of the node attribute (silently "
"ignored by cluster)",
pcmk__option_default
},
{
"private", no_argument, NULL, 'p',
"\tIf this creates a new attribute, never write the attribute to CIB",
pcmk__option_default
},
/* Legacy options */
{
"quiet", no_argument, NULL, 'q',
NULL, pcmk__option_hidden
},
{
"update", required_argument, NULL, 'v',
NULL, pcmk__option_hidden
},
{
"section", required_argument, NULL, 'S',
NULL, pcmk__option_hidden
},
{ 0, 0, 0, 0 }
};
static int do_query(const char *attr_name, const char *attr_node, gboolean query_all);
static int do_update(char command, const char *attr_node, const char *attr_name,
const char *attr_value, const char *attr_section,
const char *attr_set, const char *attr_dampen, int attr_options);
// Free memory at exit to make analyzers happy
#define cleanup_memory() \
free(attr_dampen); \
free(attr_name); \
free(attr_node); \
free(attr_section); \
free(attr_set);
#define set_option(option_var) \
if (option_var) { \
free(option_var); \
} \
option_var = strdup(optarg);
int
main(int argc, char **argv)
{
int index = 0;
int argerr = 0;
int attr_options = pcmk__node_attr_none;
int flag;
crm_exit_t exit_code = CRM_EX_OK;
char *attr_node = NULL;
char *attr_name = NULL;
char *attr_set = NULL;
char *attr_section = NULL;
char *attr_dampen = NULL;
const char *attr_value = NULL;
char command = 'Q';
gboolean query_all = FALSE;
crm_log_cli_init("attrd_updater");
pcmk__set_cli_options(NULL, "-n <attribute> <command> [options]",
long_options,
"query and update Pacemaker node attributes");
if (argc < 2) {
pcmk__cli_help('?', CRM_EX_USAGE);
}
while (1) {
flag = pcmk__next_cli_option(argc, argv, &index, NULL);
if (flag == -1)
break;
switch (flag) {
case 'V':
crm_bump_log_level(argc, argv);
break;
case '?':
case '$':
cleanup_memory();
pcmk__cli_help(flag, CRM_EX_OK);
break;
case 'n':
set_option(attr_name);
break;
case 's':
set_option(attr_set);
break;
case 'd':
set_option(attr_dampen);
break;
case 'l':
case 'S':
set_option(attr_section);
break;
case 'N':
set_option(attr_node);
break;
case 'A':
query_all = TRUE;
break;
case 'p':
set_bit(attr_options, pcmk__node_attr_private);
break;
case 'q':
break;
case 'Y':
command = flag;
crm_log_args(argc, argv); /* Too much? */
break;
case 'Q':
case 'B':
case 'R':
case 'D':
case 'U':
case 'v':
command = flag;
attr_value = optarg;
crm_log_args(argc, argv); /* Too much? */
break;
default:
++argerr;
break;
}
}
if (optind > argc) {
++argerr;
}
if (command != 'R' && attr_name == NULL) {
++argerr;
}
if (argerr) {
cleanup_memory();
pcmk__cli_help('?', CRM_EX_USAGE);
}
if (command == 'Q') {
exit_code = crm_errno2exit(do_query(attr_name, attr_node, query_all));
} else {
/* @TODO We don't know whether the specified node is a Pacemaker Remote
* node or not, so we can't set pcmk__node_attr_remote when appropriate.
* However, it's not a big problem, because pacemaker-attrd will learn
* and remember a node's "remoteness".
*/
exit_code = pcmk_rc2exitc(do_update(command,
pcmk__node_attr_target(attr_node),
attr_name, attr_value,
attr_section, attr_set,
attr_dampen, attr_options));
}
cleanup_memory();
crm_exit(exit_code);
}
/*!
* \internal
* \brief Submit a query request to pacemaker-attrd and wait for reply
*
* \param[in] name Name of attribute to query
* \param[in] host Query applies to this host only (or all hosts if NULL)
* \param[out] reply On success, will be set to new XML tree with reply
*
* \return pcmk_ok on success, -errno on error
* \note On success, caller is responsible for freeing result via free_xml(*reply)
*/
static int
send_attrd_query(const char *name, const char *host, xmlNode **reply)
{
int rc;
crm_ipc_t *ipc;
xmlNode *query;
/* Build the query XML */
query = create_xml_node(NULL, __FUNCTION__);
if (query == NULL) {
return -ENOMEM;
}
crm_xml_add(query, F_TYPE, T_ATTRD);
crm_xml_add(query, F_ORIG, crm_system_name);
crm_xml_add(query, PCMK__XA_ATTR_NODE_NAME, host);
crm_xml_add(query, PCMK__XA_TASK, PCMK__ATTRD_CMD_QUERY);
crm_xml_add(query, PCMK__XA_ATTR_NAME, name);
/* Connect to pacemaker-attrd, send query XML and get reply */
crm_debug("Sending query for value of %s on %s", name, (host? host : "all nodes"));
ipc = crm_ipc_new(T_ATTRD, 0);
if (crm_ipc_connect(ipc) == FALSE) {
crm_perror(LOG_ERR, "Connection to cluster attribute manager failed");
rc = -ENOTCONN;
} else {
rc = crm_ipc_send(ipc, query, crm_ipc_flags_none|crm_ipc_client_response, 0, reply);
if (rc > 0) {
rc = pcmk_ok;
}
crm_ipc_close(ipc);
}
+ crm_ipc_destroy(ipc);
free_xml(query);
return(rc);
}
/*!
* \brief Validate pacemaker-attrd's XML reply to an query
*
* param[in] reply Root of reply XML tree to validate
* param[in] attr_name Name of attribute that was queried
*
* \return pcmk_ok on success,
* -errno on error (-ENXIO = requested attribute does not exist)
*/
static int
validate_attrd_reply(xmlNode *reply, const char *attr_name)
{
const char *reply_attr;
if (reply == NULL) {
fprintf(stderr, "Could not query value of %s: reply did not contain valid XML\n",
attr_name);
return -pcmk_err_schema_validation;
}
crm_log_xml_trace(reply, "Reply");
reply_attr = crm_element_value(reply, PCMK__XA_ATTR_NAME);
if (reply_attr == NULL) {
fprintf(stderr, "Could not query value of %s: attribute does not exist\n",
attr_name);
return -ENXIO;
}
if (safe_str_neq(crm_element_value(reply, F_TYPE), T_ATTRD)
|| (crm_element_value(reply, PCMK__XA_ATTR_VERSION) == NULL)
|| strcmp(reply_attr, attr_name)) {
fprintf(stderr,
"Could not query value of %s: reply did not contain expected identification\n",
attr_name);
return -pcmk_err_schema_validation;
}
return pcmk_ok;
}
/*!
* \brief Print the attribute values in a pacemaker-attrd XML query reply
*
* \param[in] reply Root of XML tree with query reply
* \param[in] attr_name Name of attribute that was queried
*
* \return TRUE if any values were printed
*/
static gboolean
print_attrd_values(xmlNode *reply, const char *attr_name)
{
xmlNode *child;
const char *reply_host, *reply_value;
gboolean have_values = FALSE;
/* Iterate through reply's XML tags (a node tag for each host-value pair) */
for (child = __xml_first_child(reply); child != NULL; child = __xml_next(child)) {
if (safe_str_neq((const char*)child->name, XML_CIB_TAG_NODE)) {
crm_warn("Ignoring unexpected %s tag in query reply", child->name);
} else {
reply_host = crm_element_value(child, PCMK__XA_ATTR_NODE_NAME);
reply_value = crm_element_value(child, PCMK__XA_ATTR_VALUE);
if (reply_host == NULL) {
crm_warn("Ignoring %s tag without %s attribute in query reply",
XML_CIB_TAG_NODE, PCMK__XA_ATTR_NODE_NAME);
} else {
printf("name=\"%s\" host=\"%s\" value=\"%s\"\n",
attr_name, reply_host, (reply_value? reply_value : ""));
have_values = TRUE;
}
}
}
return have_values;
}
/*!
* \brief Submit a query to pacemaker-attrd and print reply
*
* \param[in] attr_name Name of attribute to be affected by request
* \param[in] attr_node Name of host to query for (or NULL for localhost)
* \param[in] query_all If TRUE, ignore attr_node and query all nodes instead
*
* \return pcmk_ok on success, -errno on error
*/
static int
do_query(const char *attr_name, const char *attr_node, gboolean query_all)
{
xmlNode *reply = NULL;
int rc;
/* Decide which node(s) to query */
if (query_all == TRUE) {
attr_node = NULL;
} else {
attr_node = pcmk__node_attr_target(attr_node);
}
/* Build and send pacemaker-attrd request, and get XML reply */
rc = send_attrd_query(attr_name, attr_node, &reply);
if (rc != pcmk_ok) {
fprintf(stderr, "Could not query value of %s: %s (%d)\n", attr_name, pcmk_strerror(rc), rc);
return rc;
}
/* Validate the XML reply */
rc = validate_attrd_reply(reply, attr_name);
if (rc != pcmk_ok) {
if (reply != NULL) {
free_xml(reply);
}
return rc;
}
/* Print the values from the reply */
if (print_attrd_values(reply, attr_name) == FALSE) {
fprintf(stderr,
"Could not query value of %s: reply had attribute name but no host values\n",
attr_name);
free_xml(reply);
return -pcmk_err_schema_validation;
}
return pcmk_ok;
}
static int
do_update(char command, const char *attr_node, const char *attr_name,
const char *attr_value, const char *attr_section,
const char *attr_set, const char *attr_dampen, int attr_options)
{
int rc = pcmk__node_attr_request(NULL, command, attr_node, attr_name,
attr_value, attr_section, attr_set,
attr_dampen, NULL, attr_options);
if (rc != pcmk_rc_ok) {
fprintf(stderr, "Could not update %s=%s: %s (%d)\n",
attr_name, attr_value, pcmk_rc_str(rc), rc);
}
return rc;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Jul 8, 6:07 PM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2002477
Default Alt Text
(14 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment