Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/daemons/attrd/pacemaker-attrd.c b/daemons/attrd/pacemaker-attrd.c
index 15c6a8075e..141ed8277f 100644
--- a/daemons/attrd/pacemaker-attrd.c
+++ b/daemons/attrd/pacemaker-attrd.c
@@ -1,441 +1,441 @@
/*
* Copyright 2013-2019 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 <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <crm/crm.h>
#include <crm/cib/internal.h>
#include <crm/msg_xml.h>
#include <crm/pengine/rules.h>
#include <crm/common/iso8601.h>
#include <crm/common/ipc.h>
#include <crm/common/ipcs.h>
#include <crm/common/xml.h>
#include <crm/cluster/internal.h>
-#include <crm/attrd.h>
+#include <crm/common/attrd_internal.h>
#include "pacemaker-attrd.h"
lrmd_t *the_lrmd = NULL;
crm_cluster_t *attrd_cluster = NULL;
crm_trigger_t *attrd_config_read = NULL;
static crm_exit_t attrd_exit_status = CRM_EX_OK;
static void
attrd_cpg_dispatch(cpg_handle_t handle,
const struct cpg_name *groupName,
uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
{
uint32_t kind = 0;
xmlNode *xml = NULL;
const char *from = NULL;
char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
if(data == NULL) {
return;
}
if (kind == crm_class_cluster) {
xml = string2xml(data);
}
if (xml == NULL) {
crm_err("Bad message of class %d received from %s[%u]: '%.120s'", kind, from, nodeid, data);
} else {
crm_node_t *peer = crm_get_peer(nodeid, from);
attrd_peer_message(peer, xml);
}
free_xml(xml);
free(data);
}
static void
attrd_cpg_destroy(gpointer unused)
{
if (attrd_shutting_down()) {
crm_info("Corosync disconnection complete");
} else {
crm_crit("Lost connection to cluster layer, shutting down");
attrd_exit_status = CRM_EX_DISCONNECT;
attrd_shutdown(0);
}
}
static void
attrd_cib_replaced_cb(const char *event, xmlNode * msg)
{
if (attrd_shutting_down()) {
return;
}
if (attrd_election_won()) {
crm_notice("Updating all attributes after %s event", event);
write_attributes(TRUE, FALSE);
}
// Check for changes in alerts
mainloop_set_trigger(attrd_config_read);
}
static void
attrd_cib_destroy_cb(gpointer user_data)
{
cib_t *conn = user_data;
conn->cmds->signoff(conn); /* Ensure IPC is cleaned up */
if (attrd_shutting_down()) {
crm_info("Connection disconnection complete");
} else {
/* eventually this should trigger a reconnect, not a shutdown */
crm_crit("Lost connection to the CIB manager, shutting down");
attrd_exit_status = CRM_EX_DISCONNECT;
attrd_shutdown(0);
}
return;
}
static void
attrd_erase_cb(xmlNode *msg, int call_id, int rc, xmlNode *output,
void *user_data)
{
do_crm_log_unlikely((rc? LOG_NOTICE : LOG_DEBUG),
"Cleared transient attributes: %s "
CRM_XS " xpath=%s rc=%d",
pcmk_strerror(rc), (char *) user_data, rc);
}
#define XPATH_TRANSIENT "//node_state[@uname='%s']/" XML_TAG_TRANSIENT_NODEATTRS
/*!
* \internal
* \brief Wipe all transient attributes for this node from the CIB
*
* Clear any previous transient node attributes from the CIB. This is
* normally done by the DC's controller when this node leaves the cluster, but
* this handles the case where the node restarted so quickly that the
* cluster layer didn't notice.
*
* \todo If pacemaker-attrd respawns after crashing (see PCMK_respawned),
* ideally we'd skip this and sync our attributes from the writer.
* However, currently we reject any values for us that the writer has, in
* attrd_peer_update().
*/
static void
attrd_erase_attrs()
{
int call_id;
char *xpath = crm_strdup_printf(XPATH_TRANSIENT, attrd_cluster->uname);
crm_info("Clearing transient attributes from CIB " CRM_XS " xpath=%s",
xpath);
call_id = the_cib->cmds->remove(the_cib, xpath, NULL,
cib_quorum_override | cib_xpath);
the_cib->cmds->register_callback_full(the_cib, call_id, 120, FALSE, xpath,
"attrd_erase_cb", attrd_erase_cb,
free);
}
static int
attrd_cib_connect(int max_retry)
{
static int attempts = 0;
int rc = -ENOTCONN;
the_cib = cib_new();
if (the_cib == NULL) {
return -ENOTCONN;
}
do {
if(attempts > 0) {
sleep(attempts);
}
attempts++;
crm_debug("Connection attempt %d to the CIB manager", attempts);
rc = the_cib->cmds->signon(the_cib, T_ATTRD, cib_command);
} while(rc != pcmk_ok && attempts < max_retry);
if (rc != pcmk_ok) {
crm_err("Connection to the CIB manager failed: %s " CRM_XS " rc=%d",
pcmk_strerror(rc), rc);
goto cleanup;
}
crm_debug("Connected to the CIB manager after %d attempts", attempts);
rc = the_cib->cmds->set_connection_dnotify(the_cib, attrd_cib_destroy_cb);
if (rc != pcmk_ok) {
crm_err("Could not set disconnection callback");
goto cleanup;
}
rc = the_cib->cmds->add_notify_callback(the_cib, T_CIB_REPLACE_NOTIFY, attrd_cib_replaced_cb);
if(rc != pcmk_ok) {
crm_err("Could not set CIB notification callback");
goto cleanup;
}
rc = the_cib->cmds->add_notify_callback(the_cib, T_CIB_DIFF_NOTIFY, attrd_cib_updated_cb);
if (rc != pcmk_ok) {
crm_err("Could not set CIB notification callback (update)");
goto cleanup;
}
return pcmk_ok;
cleanup:
the_cib->cmds->signoff(the_cib);
cib_delete(the_cib);
the_cib = NULL;
return -ENOTCONN;
}
/*!
* \internal
* \brief Prepare the CIB after cluster is connected
*/
static void
attrd_cib_init()
{
// We have no attribute values in memory, wipe the CIB to match
attrd_erase_attrs();
// Set a trigger for reading the CIB (for the alerts section)
attrd_config_read = mainloop_add_trigger(G_PRIORITY_HIGH, attrd_read_options, NULL);
// Always read the CIB at start-up
mainloop_set_trigger(attrd_config_read);
}
static qb_ipcs_service_t *ipcs = NULL;
static int32_t
attrd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
{
uint32_t id = 0;
uint32_t flags = 0;
crm_client_t *client = crm_client_get(c);
xmlNode *xml = crm_ipcs_recv(client, data, size, &id, &flags);
const char *op;
if (xml == NULL) {
crm_debug("No msg from %d (%p)", crm_ipcs_client_pid(c), c);
return 0;
}
#if ENABLE_ACL
CRM_ASSERT(client->user != NULL);
crm_acl_get_set_user(xml, F_ATTRD_USER, client->user);
#endif
crm_trace("Processing msg from %d (%p)", crm_ipcs_client_pid(c), c);
crm_log_xml_trace(xml, __FUNCTION__);
op = crm_element_value(xml, F_ATTRD_TASK);
if (client->name == NULL) {
const char *value = crm_element_value(xml, F_ORIG);
client->name = crm_strdup_printf("%s.%d", value?value:"unknown", client->pid);
}
if (safe_str_eq(op, ATTRD_OP_PEER_REMOVE)) {
attrd_send_ack(client, id, flags);
attrd_client_peer_remove(client->name, xml);
} else if (safe_str_eq(op, ATTRD_OP_CLEAR_FAILURE)) {
attrd_send_ack(client, id, flags);
attrd_client_clear_failure(xml);
} else if (safe_str_eq(op, ATTRD_OP_UPDATE)) {
attrd_send_ack(client, id, flags);
attrd_client_update(xml);
} else if (safe_str_eq(op, ATTRD_OP_UPDATE_BOTH)) {
attrd_send_ack(client, id, flags);
attrd_client_update(xml);
} else if (safe_str_eq(op, ATTRD_OP_UPDATE_DELAY)) {
attrd_send_ack(client, id, flags);
attrd_client_update(xml);
} else if (safe_str_eq(op, ATTRD_OP_REFRESH)) {
attrd_send_ack(client, id, flags);
attrd_client_refresh();
} else if (safe_str_eq(op, ATTRD_OP_QUERY)) {
/* queries will get reply, so no ack is necessary */
attrd_client_query(client, id, flags, xml);
} else {
crm_info("Ignoring request from client %s with unknown operation %s",
client->name, op);
}
free_xml(xml);
return 0;
}
void
attrd_ipc_fini()
{
if (ipcs != NULL) {
crm_client_disconnect_all(ipcs);
qb_ipcs_destroy(ipcs);
ipcs = NULL;
}
}
static int
attrd_cluster_connect()
{
attrd_cluster = calloc(1, sizeof(crm_cluster_t));
attrd_cluster->destroy = attrd_cpg_destroy;
attrd_cluster->cpg.cpg_deliver_fn = attrd_cpg_dispatch;
attrd_cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership;
crm_set_status_callback(&attrd_peer_change_cb);
if (crm_cluster_connect(attrd_cluster) == FALSE) {
crm_err("Cluster connection failed");
return -ENOTCONN;
}
return pcmk_ok;
}
/* *INDENT-OFF* */
static struct crm_option long_options[] = {
/* Top-level Options */
{"help", 0, 0, '?', "\tThis text"},
{"verbose", 0, 0, 'V', "\tIncrease debug output"},
{0, 0, 0, 0}
};
/* *INDENT-ON* */
int
main(int argc, char **argv)
{
int flag = 0;
int index = 0;
int argerr = 0;
crm_ipc_t *old_instance = NULL;
attrd_init_mainloop();
crm_log_preinit(NULL, argc, argv);
crm_set_options(NULL, "[options]", long_options,
"Daemon for aggregating and atomically storing node attribute updates into the CIB");
mainloop_add_signal(SIGTERM, attrd_shutdown);
while (1) {
flag = crm_get_option(argc, argv, &index);
if (flag == -1)
break;
switch (flag) {
case 'V':
crm_bump_log_level(argc, argv);
break;
case 'h': /* Help message */
crm_help(flag, CRM_EX_OK);
break;
default:
++argerr;
break;
}
}
if (optind > argc) {
++argerr;
}
if (argerr) {
crm_help('?', CRM_EX_USAGE);
}
crm_log_init(T_ATTRD, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
crm_notice("Starting Pacemaker node attribute manager");
old_instance = crm_ipc_new(T_ATTRD, 0);
if (crm_ipc_connect(old_instance)) {
/* IPC end-point already up */
crm_ipc_close(old_instance);
crm_ipc_destroy(old_instance);
crm_err("pacemaker-attrd is already active, aborting startup");
crm_exit(CRM_EX_OK);
} else {
/* not up or not authentic, we'll proceed either way */
crm_ipc_destroy(old_instance);
old_instance = NULL;
}
attributes = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, free_attribute);
/* Connect to the CIB before connecting to the cluster or listening for IPC.
* This allows us to assume the CIB is connected whenever we process a
* cluster or IPC message (which also avoids start-up race conditions).
*/
if (attrd_cib_connect(10) != pcmk_ok) {
attrd_exit_status = CRM_EX_FATAL;
goto done;
}
crm_info("CIB connection active");
if (attrd_cluster_connect() != pcmk_ok) {
attrd_exit_status = CRM_EX_FATAL;
goto done;
}
crm_info("Cluster connection active");
// Initialization that requires the cluster to be connected
attrd_election_init();
attrd_cib_init();
/* Set a private attribute for ourselves with the protocol version we
* support. This lets all nodes determine the minimum supported version
* across all nodes. It also ensures that the writer learns our node name,
* so it can send our attributes to the CIB.
*/
attrd_broadcast_protocol();
attrd_init_ipc(&ipcs, attrd_ipc_dispatch);
crm_notice("Pacemaker node attribute manager successfully started and accepting connections");
attrd_run_mainloop();
done:
crm_info("Shutting down attribute manager");
attrd_election_fini();
attrd_ipc_fini();
attrd_lrmd_disconnect();
attrd_cib_disconnect();
g_hash_table_destroy(attributes);
crm_exit(attrd_exit_status);
}
diff --git a/daemons/controld/controld_attrd.c b/daemons/controld/controld_attrd.c
index 8ae6992c22..cea914af36 100644
--- a/daemons/controld/controld_attrd.c
+++ b/daemons/controld/controld_attrd.c
@@ -1,184 +1,184 @@
/*
* Copyright 2006-2019 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 <crm/crm.h>
-#include <crm/attrd.h>
+#include <crm/common/attrd_internal.h>
#include <crm/msg_xml.h>
#include <pacemaker-controld.h>
static crm_ipc_t *attrd_ipc = NULL;
void
controld_close_attrd_ipc()
{
if (attrd_ipc) {
crm_trace("Closing connection to pacemaker-attrd");
crm_ipc_close(attrd_ipc);
crm_ipc_destroy(attrd_ipc);
attrd_ipc = NULL;
}
}
static void
log_attrd_error(const char *host, const char *name, const char *value,
gboolean is_remote, char command, int rc)
{
const char *node_type = (is_remote? "Pacemaker Remote" : "cluster");
gboolean shutting_down = is_set(fsa_input_register, R_SHUTDOWN);
const char *when = (shutting_down? " at shutdown" : "");
switch (command) {
case 0:
crm_err("Could not clear failure attributes for %s on %s node %s%s: %s "
CRM_XS " rc=%d", (name? name : "all resources"), node_type,
host, when, pcmk_strerror(rc), rc);
break;
case 'C':
crm_err("Could not purge %s node %s in attribute manager%s: %s "
CRM_XS " rc=%d",
node_type, host, when, pcmk_strerror(rc), rc);
break;
case 'U':
/* We weren't able to update an attribute after several retries,
* so something is horribly wrong with the attribute manager or the
* underlying system.
*/
do_crm_log(AM_I_DC? LOG_CRIT : LOG_ERR,
"Could not update attribute %s=%s for %s node %s%s: %s "
CRM_XS " rc=%d", name, value, node_type, host, when,
pcmk_strerror(rc), rc);
if (AM_I_DC) {
/* We are unable to provide accurate information to the
* scheduler, so allow another node to take over DC.
* @TODO Should we do this unconditionally on any failure?
*/
crmd_exit(CRM_EX_FATAL);
} else if (shutting_down) {
// Fast-track shutdown since unable to request via attribute
register_fsa_input(C_FSA_INTERNAL, I_FAIL, NULL);
}
break;
}
}
static void
update_attrd_helper(const char *host, const char *name, const char *value,
const char *interval_spec, const char *user_name,
gboolean is_remote_node, char command)
{
int rc;
int attrd_opts = attrd_opt_none;
if (is_remote_node) {
attrd_opts |= attrd_opt_remote;
}
if (attrd_ipc == NULL) {
attrd_ipc = crm_ipc_new(T_ATTRD, 0);
}
for (int attempt = 1; attempt <= 4; ++attempt) {
rc = pcmk_ok;
// If we're not already connected, try to connect
if (crm_ipc_connected(attrd_ipc) == FALSE) {
if (attempt == 1) {
// Start with a clean slate
crm_ipc_close(attrd_ipc);
}
if (crm_ipc_connect(attrd_ipc) == FALSE) {
rc = errno;
}
crm_debug("Attribute manager connection attempt %d of 4: %s (%d)",
attempt, pcmk_strerror(rc), rc);
}
if (rc == pcmk_ok) {
rc = command?
attrd_update_delegate(attrd_ipc, command, host, name, value,
XML_CIB_TAG_STATUS, NULL, NULL,
user_name, attrd_opts)
/* No command means clear fail count (name/value is really
* resource/operation)
*/
: attrd_clear_delegate(attrd_ipc, host, name, value,
interval_spec, user_name, attrd_opts);
crm_debug("Attribute manager request attempt %d of 4: %s (%d)",
attempt, pcmk_strerror(rc), rc);
}
if (rc == pcmk_ok) {
// Success, we're done
break;
} else if ((rc != EAGAIN) && (rc != EALREADY)) {
/* EAGAIN or EALREADY indicates a temporary block, so just try
* again. Otherwise, close the connection for a clean slate.
*/
crm_ipc_close(attrd_ipc);
}
/* @TODO If the attribute manager remains unavailable the entire time,
* this function takes more than 6 seconds. Maybe set a timer for
* retries, to let the main loop do other work.
*/
if (attempt < 4) {
sleep(attempt);
}
}
if (rc != pcmk_ok) {
log_attrd_error(host, name, value, is_remote_node, command, rc);
}
}
void
update_attrd(const char *host, const char *name, const char *value,
const char *user_name, gboolean is_remote_node)
{
update_attrd_helper(host, name, value, NULL, user_name, is_remote_node,
'U');
}
void
update_attrd_remote_node_removed(const char *host, const char *user_name)
{
crm_trace("Asking attribute manager to purge Pacemaker Remote node %s",
host);
update_attrd_helper(host, NULL, NULL, NULL, user_name, TRUE, 'C');
}
void
update_attrd_clear_failures(const char *host, const char *rsc, const char *op,
const char *interval_spec, gboolean is_remote_node)
{
const char *op_desc = NULL;
const char *interval_desc = NULL;
const char *node_type = is_remote_node? "Pacemaker Remote" : "cluster";
if (op) {
interval_desc = interval_spec? interval_spec : "nonrecurring";
op_desc = op;
} else {
interval_desc = "all";
op_desc = "operations";
}
crm_info("Asking pacemaker-attrd to clear failure of %s %s for %s on %s node %s",
interval_desc, op_desc, rsc, node_type, host);
update_attrd_helper(host, rsc, op, interval_spec, NULL, is_remote_node, 0);
}
diff --git a/include/crm/Makefile.am b/include/crm/Makefile.am
index 566e9feafc..8f11a56557 100644
--- a/include/crm/Makefile.am
+++ b/include/crm/Makefile.am
@@ -1,19 +1,19 @@
#
# Copyright 2004-2019 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.
#
MAINTAINERCLEANFILES = Makefile.in
headerdir=$(pkgincludedir)/crm
-header_HEADERS = attrd.h cib.h cluster.h compatibility.h crm.h \
+header_HEADERS = cib.h cluster.h compatibility.h crm.h \
lrmd.h msg_xml.h services.h stonith-ng.h
noinst_HEADERS = lrmd_internal.h
SUBDIRS = common pengine cib fencing cluster
diff --git a/include/crm/common/Makefile.am b/include/crm/common/Makefile.am
index 7c1c090129..4e77e50c34 100644
--- a/include/crm/common/Makefile.am
+++ b/include/crm/common/Makefile.am
@@ -1,18 +1,19 @@
#
# Copyright 2004-2019 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.
#
MAINTAINERCLEANFILES = Makefile.in
headerdir=$(pkgincludedir)/crm/common
header_HEADERS = xml.h ipc.h util.h iso8601.h mainloop.h logging.h results.h \
nvpair.h
noinst_HEADERS = cib_secrets.h ipcs.h internal.h alerts_internal.h \
iso8601_internal.h remote_internal.h xml_internal.h \
- ipc_internal.h output.h cmdline_internal.h curses_internal.h
+ ipc_internal.h output.h cmdline_internal.h curses_internal.h \
+ attrd_internal.h
diff --git a/include/crm/attrd.h b/include/crm/common/attrd_internal.h
similarity index 53%
rename from include/crm/attrd.h
rename to include/crm/common/attrd_internal.h
index 5ec1948670..6d9169ac81 100644
--- a/include/crm/attrd.h
+++ b/include/crm/common/attrd_internal.h
@@ -1,47 +1,37 @@
-/*
- * Copyright 2004-2018 the Pacemaker project contributors
+/*
+ * Copyright 2004-2019 the Pacemaker project contributors
*
* The version control history for this file may have further details.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * This source code is licensed under the GNU Lesser General Public License
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
+
#ifndef CRM_ATTRD__H
# define CRM_ATTRD__H
#ifdef __cplusplus
extern "C" {
#endif
# include <crm/common/ipc.h>
/* attribute options for clients to use with these functions */
#define attrd_opt_none 0x000
#define attrd_opt_remote 0x001
#define attrd_opt_private 0x002
const char *attrd_get_target(const char *name);
int attrd_update_delegate(crm_ipc_t * ipc, char command, const char *host,
const char *name, const char *value, const char *section,
const char *set, const char *dampen, const char *user_name, int options);
int attrd_clear_delegate(crm_ipc_t *ipc, const char *host, const char *resource,
const char *operation, const char *interval_spec,
const char *user_name, int options);
#ifdef __cplusplus
}
#endif
#endif
diff --git a/lib/common/attrd_client.c b/lib/common/attrd_client.c
index 7a3b2503de..750236a00f 100644
--- a/lib/common/attrd_client.c
+++ b/lib/common/attrd_client.c
@@ -1,306 +1,312 @@
/*
- * Copyright 2011-2018 Andrew Beekhof <andrew@beekhof.net>
+ * Copyright 2011-2019 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 _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <crm_internal.h>
#include <stdio.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
-#include <crm/attrd.h>
+#include <crm/common/attrd_internal.h>
/*!
* \internal
* \brief Create a generic pacemaker-attrd operation
*
* \param[in] user_name If not NULL, ACL user to set for operation
*
* \return XML of pacemaker-attrd operation
*/
static xmlNode *
create_attrd_op(const char *user_name)
{
xmlNode *attrd_op = create_xml_node(NULL, __FUNCTION__);
crm_xml_add(attrd_op, F_TYPE, T_ATTRD);
crm_xml_add(attrd_op, F_ORIG, (crm_system_name? crm_system_name: "unknown"));
#if ENABLE_ACL
crm_xml_add(attrd_op, F_ATTRD_USER, user_name);
#endif
return attrd_op;
}
/*!
* \internal
* \brief Send an operation to pacemaker-attrd via IPC
*
* \param[in] ipc Connection to pacemaker-attrd (or NULL to use a local connection)
* \param[in] attrd_op XML of pacemaker-attrd operation to send
*
* \return pcmk_ok on success, -errno otherwise
*/
static int
send_attrd_op(crm_ipc_t *ipc, xmlNode *attrd_op)
{
int rc = -ENOTCONN;
int max = 5;
static gboolean connected = TRUE;
static crm_ipc_t *local_ipc = NULL;
static enum crm_ipc_flags flags = crm_ipc_flags_none;
if (ipc == NULL && local_ipc == NULL) {
local_ipc = crm_ipc_new(T_ATTRD, 0);
flags |= crm_ipc_client_response;
connected = FALSE;
}
if (ipc == NULL) {
ipc = local_ipc;
}
while (max > 0) {
if (connected == FALSE) {
crm_info("Connecting to cluster... %d retries remaining", max);
connected = crm_ipc_connect(ipc);
}
if (connected) {
rc = crm_ipc_send(ipc, attrd_op, flags, 0, NULL);
} else {
crm_perror(LOG_INFO, "Connection to cluster attribute manager failed");
}
if (ipc != local_ipc) {
break;
} else if (rc > 0) {
break;
} else if (rc == -EAGAIN || rc == -EALREADY) {
sleep(5 - max);
max--;
} else {
crm_ipc_close(ipc);
connected = FALSE;
sleep(5 - max);
max--;
}
}
if (rc > 0) {
rc = pcmk_ok;
}
return rc;
}
/*!
+ * \internal
* \brief Send a request to pacemaker-attrd
*
* \param[in] ipc Connection to pacemaker-attrd (or NULL to use a local connection)
* \param[in] command A character indicating the type of pacemaker-attrd request:
* U or v: update attribute (or refresh if name is NULL)
* u: update attributes matching regular expression in name
* D: delete attribute (value must be NULL)
* R: refresh
* B: update both attribute and its dampening
* Y: update attribute dampening only
* Q: query attribute
* C: remove peer specified by host
* \param[in] host Affect only this host (or NULL for all hosts)
* \param[in] name Name of attribute to affect
* \param[in] value Attribute value to set
* \param[in] section Status or nodes
* \param[in] set ID of attribute set to use (or NULL to choose first)
* \param[in] dampen Attribute dampening to use with B/Y, and U/v if creating
* \param[in] user_name ACL user to pass to pacemaker-attrd
* \param[in] options Bitmask that may include:
* attrd_opt_remote: host is a Pacemaker Remote node
* attrd_opt_private: attribute is private (not kept in CIB)
*
* \return pcmk_ok if request was successfully submitted to pacemaker-attrd, else -errno
*/
int
attrd_update_delegate(crm_ipc_t *ipc, char command, const char *host,
const char *name, const char *value, const char *section,
const char *set, const char *dampen,
const char *user_name, int options)
{
int rc = pcmk_ok;
const char *task = NULL;
const char *name_as = NULL;
const char *display_host = (host ? host : "localhost");
const char *display_command = NULL; /* for commands without name/value */
xmlNode *update = create_attrd_op(user_name);
/* remap common aliases */
if (safe_str_eq(section, "reboot")) {
section = XML_CIB_TAG_STATUS;
} else if (safe_str_eq(section, "forever")) {
section = XML_CIB_TAG_NODES;
}
if (name == NULL && command == 'U') {
command = 'R';
}
switch (command) {
case 'u':
task = ATTRD_OP_UPDATE;
name_as = F_ATTRD_REGEX;
break;
case 'D':
case 'U':
case 'v':
task = ATTRD_OP_UPDATE;
name_as = F_ATTRD_ATTRIBUTE;
break;
case 'R':
task = ATTRD_OP_REFRESH;
display_command = "refresh";
break;
case 'B':
task = ATTRD_OP_UPDATE_BOTH;
name_as = F_ATTRD_ATTRIBUTE;
break;
case 'Y':
task = ATTRD_OP_UPDATE_DELAY;
name_as = F_ATTRD_ATTRIBUTE;
break;
case 'Q':
task = ATTRD_OP_QUERY;
name_as = F_ATTRD_ATTRIBUTE;
break;
case 'C':
task = ATTRD_OP_PEER_REMOVE;
display_command = "purge";
break;
}
if (name_as != NULL) {
if (name == NULL) {
rc = -EINVAL;
goto done;
}
crm_xml_add(update, name_as, name);
}
crm_xml_add(update, F_ATTRD_TASK, task);
crm_xml_add(update, F_ATTRD_VALUE, value);
crm_xml_add(update, F_ATTRD_DAMPEN, dampen);
crm_xml_add(update, F_ATTRD_SECTION, section);
crm_xml_add(update, F_ATTRD_HOST, host);
crm_xml_add(update, F_ATTRD_SET, set);
crm_xml_add_int(update, F_ATTRD_IS_REMOTE, is_set(options, attrd_opt_remote));
crm_xml_add_int(update, F_ATTRD_IS_PRIVATE, is_set(options, attrd_opt_private));
rc = send_attrd_op(ipc, update);
done:
free_xml(update);
if (display_command) {
crm_debug("Asked pacemaker-attrd to %s %s: %s (%d)",
display_command, display_host, pcmk_strerror(rc), rc);
} else {
crm_debug("Asked pacemaker-attrd to update %s=%s for %s: %s (%d)",
name, value, display_host, pcmk_strerror(rc), rc);
}
return rc;
}
/*!
+ * \internal
* \brief Send a request to pacemaker-attrd to clear resource failure
*
* \param[in] ipc Connection to pacemaker-attrd (NULL to use local connection)
* \param[in] host Affect only this host (or NULL for all hosts)
* \param[in] resource Name of resource to clear (or NULL for all)
* \param[in] operation Name of operation to clear (or NULL for all)
* \param[in] interval_spec If operation is not NULL, its interval
* \param[in] user_name ACL user to pass to pacemaker-attrd
* \param[in] options attrd_opt_remote if host is a Pacemaker Remote node
*
* \return pcmk_ok if request was successfully submitted to pacemaker-attrd, else -errno
*/
int
attrd_clear_delegate(crm_ipc_t *ipc, const char *host, const char *resource,
const char *operation, const char *interval_spec,
const char *user_name, int options)
{
int rc = pcmk_ok;
xmlNode *clear_op = create_attrd_op(user_name);
const char *interval_desc = NULL;
const char *op_desc = NULL;
crm_xml_add(clear_op, F_ATTRD_TASK, ATTRD_OP_CLEAR_FAILURE);
crm_xml_add(clear_op, F_ATTRD_HOST, host);
crm_xml_add(clear_op, F_ATTRD_RESOURCE, resource);
crm_xml_add(clear_op, F_ATTRD_OPERATION, operation);
crm_xml_add(clear_op, F_ATTRD_INTERVAL, interval_spec);
crm_xml_add_int(clear_op, F_ATTRD_IS_REMOTE, is_set(options, attrd_opt_remote));
rc = send_attrd_op(ipc, clear_op);
free_xml(clear_op);
if (operation) {
interval_desc = interval_spec? interval_spec : "nonrecurring";
op_desc = operation;
} else {
interval_desc = "all";
op_desc = "operations";
}
crm_debug("Asked pacemaker-attrd to clear failure of %s %s for %s on %s: %s (%d)",
interval_desc, op_desc, (resource? resource : "all resources"),
(host? host : "all nodes"), pcmk_strerror(rc), rc);
return rc;
}
#define LRM_TARGET_ENV "OCF_RESKEY_" CRM_META "_" XML_LRM_ATTR_TARGET
+/*!
+ * \internal
+ */
const char *
attrd_get_target(const char *name)
{
if(safe_str_eq(name, "auto") || safe_str_eq(name, "localhost")) {
name = NULL;
}
if(name != NULL) {
return name;
} else {
char *target_var = crm_meta_name(XML_RSC_ATTR_TARGET);
char *phys_var = crm_meta_name(PCMK_ENV_PHYSICAL_HOST);
const char *target = getenv(target_var);
const char *host_physical = getenv(phys_var);
// It is important to use the name by which the scheduler knows us
if (host_physical && safe_str_eq(target, "host")) {
name = host_physical;
} else {
const char *host_pcmk = getenv(LRM_TARGET_ENV);
if (host_pcmk) {
name = host_pcmk;
}
}
free(target_var);
free(phys_var);
}
// TODO? Call get_local_node_name() if name == NULL
// (currently would require linkage against libcrmcluster)
return name;
}
diff --git a/tools/attrd_updater.c b/tools/attrd_updater.c
index 3dfec5c93b..9ffcb00126 100644
--- a/tools/attrd_updater.c
+++ b/tools/attrd_updater.c
@@ -1,378 +1,378 @@
/*
* Copyright 2004-2019 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/attrd.h>
+#include <crm/common/attrd_internal.h>
/* *INDENT-OFF* */
static struct crm_option long_options[] = {
/* Top-level Options */
{"help", 0, 0, '?', "\tThis text"},
{"version", 0, 0, '$', "\tVersion information" },
{"verbose", 0, 0, 'V', "\tIncrease debug output\n"},
{"name", 1, 0, 'n', "The attribute's name"},
{"-spacer-",1, 0, '-', "\nCommands:"},
{"update", 1, 0, 'U', "Update the attribute's value in pacemaker-attrd. If this causes the value to change, it will also be updated in the cluster configuration"},
{"update-both", 1, 0, 'B', "Update the 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."},
{"update-delay", 0, 0, 'Y', "Update the 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."},
{"query", 0, 0, 'Q', "\tQuery the attribute's value from pacemaker-attrd"},
{"delete", 0, 0, 'D', "\tDelete the attribute in pacemaker-attrd. If a value was previously set, it will also be removed from the cluster configuration"},
{"refresh", 0, 0, 'R', "\t(Advanced) Force the pacemaker-attrd daemon to resend all current values to the CIB\n"},
{"-spacer-",1, 0, '-', "\nAdditional options:"},
{"delay", 1, 0, 'd', "The time to wait (dampening) in seconds for further changes before writing"},
{"set", 1, 0, 's', "(Advanced) The attribute set in which to place the value"},
{"node", 1, 0, 'N', "Set the attribute for the named node (instead of the local one)"},
{"all", 0, 0, 'A', "Show values of the attribute for all nodes (query only)"},
/* lifetime could be implemented if there is sufficient user demand */
{"lifetime",1, 0, 'l', "(Deprecated) Lifetime of the node attribute (silently ignored by cluster)"},
{"private", 0, 0, 'p', "\tIf this creates a new attribute, never write the attribute to the CIB"},
/* Legacy options */
{"quiet", 0, 0, 'q', NULL, pcmk_option_hidden},
{"update", 1, 0, 'v', NULL, pcmk_option_hidden},
{"section", 1, 0, 'S', NULL, pcmk_option_hidden},
{0, 0, 0, 0}
};
/* *INDENT-ON* */
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 = attrd_opt_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");
crm_set_options(NULL, "command -n attribute [options]", long_options,
"Tool for updating cluster node attributes");
if (argc < 2) {
crm_help('?', CRM_EX_USAGE);
}
while (1) {
flag = crm_get_option(argc, argv, &index);
if (flag == -1)
break;
switch (flag) {
case 'V':
crm_bump_log_level(argc, argv);
break;
case '?':
case '$':
cleanup_memory();
crm_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, attrd_opt_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();
crm_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 attrd_opt_remote when appropriate.
* However, it's not a big problem, because pacemaker-attrd will learn
* and remember a node's "remoteness".
*/
exit_code = crm_errno2exit(do_update(command,
attrd_get_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, F_ATTRD_HOST, host);
crm_xml_add(query, F_ATTRD_TASK, ATTRD_OP_QUERY);
crm_xml_add(query, F_ATTRD_ATTRIBUTE, 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);
}
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, F_ATTRD_ATTRIBUTE);
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, F_ATTRD_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, F_ATTRD_HOST);
reply_value = crm_element_value(child, F_ATTRD_VALUE);
if (reply_host == NULL) {
crm_warn("Ignoring %s tag without %s attribute in query reply",
XML_CIB_TAG_NODE, F_ATTRD_HOST);
} 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 = attrd_get_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 = attrd_update_delegate(NULL, command, attr_node, attr_name,
attr_value, attr_section, attr_set,
attr_dampen, NULL, attr_options);
if (rc != pcmk_ok) {
fprintf(stderr, "Could not update %s=%s: %s (%d)\n", attr_name, attr_value, pcmk_strerror(rc), rc);
}
return rc;
}
diff --git a/tools/crm_attribute.c b/tools/crm_attribute.c
index 9892c06688..5503786741 100644
--- a/tools/crm_attribute.c
+++ b/tools/crm_attribute.c
@@ -1,350 +1,350 @@
/*
* Copyright 2004-2019 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 <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <time.h>
#include <sys/param.h>
#include <sys/types.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/ipc.h>
#include <crm/common/util.h>
#include <crm/cluster.h>
#include <crm/cib.h>
-#include <crm/attrd.h>
+#include <crm/common/attrd_internal.h>
#include <sys/utsname.h>
gboolean BE_QUIET = FALSE;
char command = 'G';
const char *dest_uname = NULL;
char *dest_node = NULL;
char *set_name = NULL;
char *attr_id = NULL;
char *attr_name = NULL;
char *attr_pattern = NULL;
const char *type = NULL;
const char *rsc_id = NULL;
const char *attr_value = NULL;
const char *attr_default = NULL;
const char *set_type = NULL;
/* *INDENT-OFF* */
static struct crm_option long_options[] = {
/* Top-level Options */
{"help", 0, 0, '?', "\tThis text"},
{"version", 0, 0, '$', "\tVersion information" },
{"verbose", 0, 0, 'V', "\tIncrease debug output"},
{"quiet", 0, 0, 'q', "\tPrint only the value on stdout\n"},
{"name", 1, 0, 'n', "Name of the attribute/option to operate on"},
{"pattern", 1, 0, 'P', "Pattern matching names of attributes (only with -v/-D and -l reboot)"},
{"-spacer-", 0, 0, '-', "\nCommands:"},
{"query", 0, 0, 'G', "\tQuery the current value of the attribute/option"},
{"update", 1, 0, 'v', "Update the value of the attribute/option"},
{"delete", 0, 0, 'D', "\tDelete the attribute/option"},
{"-spacer-", 0, 0, '-', "\nAdditional Options:"},
{"node", 1, 0, 'N', "Set an attribute for the named node (instead of a cluster option). See also: -l"},
{"type", 1, 0, 't', "Which part of the configuration to update/delete/query the option in"},
{"-spacer-", 0, 0, '-', "\t\t\tValid values: crm_config, rsc_defaults, op_defaults, tickets"},
{"lifetime", 1, 0, 'l', "Lifetime of the node attribute"},
{"-spacer-", 0, 0, '-', "\t\t\tValid values: reboot, forever"},
{"utilization", 0, 0, 'z', "Set an utilization attribute for the node."},
{"set-name", 1, 0, 's', "(Advanced) The attribute set in which to place the value"},
{"id", 1, 0, 'i', "\t(Advanced) The ID used to identify the attribute"},
{"default", 1, 0, 'd', "(Advanced) The default value to display if none is found in the configuration"},
{"inhibit-policy-engine", 0, 0, '!', NULL, 1},
/* legacy */
{"quiet", 0, 0, 'Q', NULL, 1},
{"node-uname", 1, 0, 'U', NULL, 1},
{"get-value", 0, 0, 'G', NULL, 1},
{"delete-attr", 0, 0, 'D', NULL, 1},
{"attr-value", 1, 0, 'v', NULL, 1},
{"attr-name", 1, 0, 'n', NULL, 1},
{"attr-id", 1, 0, 'i', NULL, 1},
{"-spacer-", 1, 0, '-', "\nExamples:", pcmk_option_paragraph},
{"-spacer-", 1, 0, '-', "Add a new node attribute called 'location' with the value of 'office' for host 'myhost':", pcmk_option_paragraph},
{"-spacer-", 1, 0, '-', " crm_attribute --node myhost --name location --update office", pcmk_option_example},
{"-spacer-", 1, 0, '-', "Query the value of the 'location' node attribute for host 'myhost':", pcmk_option_paragraph},
{"-spacer-", 1, 0, '-', " crm_attribute --node myhost --name location --query", pcmk_option_example},
{"-spacer-", 1, 0, '-', "Change the value of the 'location' node attribute for host 'myhost':", pcmk_option_paragraph},
{"-spacer-", 1, 0, '-', " crm_attribute --node myhost --name location --update backoffice", pcmk_option_example},
{"-spacer-", 1, 0, '-', "Delete the 'location' node attribute for host 'myhost':", pcmk_option_paragraph},
{"-spacer-", 1, 0, '-', " crm_attribute --node myhost --name location --delete", pcmk_option_example},
{"-spacer-", 1, 0, '-', "Query the value of the cluster-delay cluster option:", pcmk_option_paragraph},
{"-spacer-", 1, 0, '-', " crm_attribute --type crm_config --name cluster-delay --query", pcmk_option_example},
{"-spacer-", 1, 0, '-', "Query the value of the cluster-delay cluster option. Only print the value:", pcmk_option_paragraph},
{"-spacer-", 1, 0, '-', " crm_attribute --type crm_config --name cluster-delay --query --quiet", pcmk_option_example},
{0, 0, 0, 0}
};
/* *INDENT-ON* */
int
main(int argc, char **argv)
{
cib_t *the_cib = NULL;
int rc = pcmk_ok;
int cib_opts = cib_sync_call;
int argerr = 0;
int flag;
int option_index = 0;
int is_remote_node = 0;
bool try_attrd = true;
crm_log_cli_init("crm_attribute");
crm_set_options(NULL, "<command> -n <attribute> [options]", long_options,
"Manage node's attributes and cluster options."
"\n\nAllows node attributes and cluster options to be queried, modified and deleted.\n");
if (argc < 2) {
crm_help('?', CRM_EX_USAGE);
}
while (1) {
flag = crm_get_option(argc, argv, &option_index);
if (flag == -1)
break;
switch (flag) {
case 'V':
crm_bump_log_level(argc, argv);
break;
case '$':
case '?':
crm_help(flag, CRM_EX_OK);
break;
case 'G':
command = flag;
attr_value = optarg;
break;
case 'D':
case 'v':
command = flag;
attr_value = optarg;
crm_log_args(argc, argv);
break;
case 'q':
case 'Q':
BE_QUIET = TRUE;
break;
case 'U':
case 'N':
dest_uname = strdup(optarg);
break;
case 's':
set_name = strdup(optarg);
break;
case 'l':
case 't':
type = optarg;
break;
case 'z':
type = XML_CIB_TAG_NODES;
set_type = XML_TAG_UTILIZATION;
break;
case 'n':
attr_name = strdup(optarg);
break;
case 'P':
attr_pattern = strdup(optarg);
break;
case 'i':
attr_id = strdup(optarg);
break;
case 'r':
rsc_id = optarg;
break;
case 'd':
attr_default = optarg;
break;
case '!':
crm_warn("Inhibiting notifications for this update");
cib_opts |= cib_inhibit_notify;
break;
default:
printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag);
++argerr;
break;
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
if (optind > argc) {
++argerr;
}
if (argerr) {
crm_help('?', CRM_EX_USAGE);
}
the_cib = cib_new();
rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
if (rc != pcmk_ok) {
fprintf(stderr, "Error connecting to the CIB manager: %s\n",
pcmk_strerror(rc));
crm_exit(crm_errno2exit(rc));
}
if (type == NULL && dest_uname != NULL) {
type = "forever";
}
if (safe_str_eq(type, "reboot")) {
type = XML_CIB_TAG_STATUS;
} else if (safe_str_eq(type, "forever")) {
type = XML_CIB_TAG_NODES;
}
if (type == NULL && dest_uname == NULL) {
/* we're updating cluster options - don't populate dest_node */
type = XML_CIB_TAG_CRMCONFIG;
} else if (safe_str_eq(type, XML_CIB_TAG_CRMCONFIG)) {
} else if (safe_str_neq(type, XML_CIB_TAG_TICKETS)) {
/* If we are being called from a resource agent via the cluster,
* the correct local node name will be passed as an environment
* variable. Otherwise, we have to ask the cluster.
*/
dest_uname = attrd_get_target(dest_uname);
if (dest_uname == NULL) {
dest_uname = get_local_node_name();
}
rc = query_node_uuid(the_cib, dest_uname, &dest_node, &is_remote_node);
if (pcmk_ok != rc) {
fprintf(stderr, "Could not map name=%s to a UUID\n", dest_uname);
the_cib->cmds->signoff(the_cib);
cib_delete(the_cib);
crm_exit(crm_errno2exit(rc));
}
}
if ((command == 'D') && (attr_name == NULL) && (attr_pattern == NULL)) {
fprintf(stderr, "Error: must specify attribute name or pattern to delete\n");
crm_exit(CRM_EX_USAGE);
}
if (attr_pattern) {
if (((command != 'v') && (command != 'D'))
|| safe_str_neq(type, XML_CIB_TAG_STATUS)) {
fprintf(stderr, "Error: pattern can only be used with till-reboot update or delete\n");
crm_exit(CRM_EX_USAGE);
}
command = 'u';
free(attr_name);
attr_name = attr_pattern;
}
// Only go through attribute manager for transient attributes
try_attrd = safe_str_eq(type, XML_CIB_TAG_STATUS);
// Don't try to contact attribute manager if we're using a file as CIB
if (getenv("CIB_file") || getenv("CIB_shadow")) {
try_attrd = FALSE;
}
if (((command == 'v') || (command == 'D') || (command == 'u')) && try_attrd
&& pcmk_ok == attrd_update_delegate(NULL, command, dest_uname, attr_name,
attr_value, type, set_name, NULL, NULL,
is_remote_node?attrd_opt_remote:attrd_opt_none)) {
crm_info("Update %s=%s sent via pacemaker-attrd",
attr_name, ((command == 'D')? "<none>" : attr_value));
} else if (command == 'D') {
rc = delete_attr_delegate(the_cib, cib_opts, type, dest_node, set_type, set_name,
attr_id, attr_name, attr_value, TRUE, NULL);
if (rc == -ENXIO) {
/* Nothing to delete...
* which means it's not there...
* which is what the admin wanted
*/
rc = pcmk_ok;
}
} else if (command == 'v') {
CRM_LOG_ASSERT(type != NULL);
CRM_LOG_ASSERT(attr_name != NULL);
CRM_LOG_ASSERT(attr_value != NULL);
rc = update_attr_delegate(the_cib, cib_opts, type, dest_node, set_type, set_name,
attr_id, attr_name, attr_value, TRUE, NULL, is_remote_node ? "remote" : NULL);
} else { /* query */
char *read_value = NULL;
rc = read_attr_delegate(the_cib, type, dest_node, set_type, set_name,
attr_id, attr_name, &read_value, TRUE, NULL);
if (rc == -ENXIO && attr_default) {
read_value = strdup(attr_default);
rc = pcmk_ok;
}
crm_info("Read %s=%s %s%s",
attr_name, crm_str(read_value), set_name ? "in " : "", set_name ? set_name : "");
if (rc == -ENOTUNIQ) {
// Multiple matches (already displayed) are not error for queries
rc = pcmk_ok;
} else if (BE_QUIET == FALSE) {
fprintf(stdout, "%s%s %s%s %s%s value=%s\n",
type ? "scope=" : "", type ? type : "",
attr_id ? "id=" : "", attr_id ? attr_id : "",
attr_name ? "name=" : "", attr_name ? attr_name : "",
read_value ? read_value : "(null)");
} else if (read_value != NULL) {
fprintf(stdout, "%s\n", read_value);
}
free(read_value);
}
if (rc == -ENOTUNIQ) {
printf("Please choose from one of the matches above and supply the 'id' with --attr-id\n");
} else if (rc != pcmk_ok) {
fprintf(stderr, "Error performing operation: %s\n", pcmk_strerror(rc));
}
the_cib->cmds->signoff(the_cib);
cib_delete(the_cib);
crm_exit(crm_errno2exit(rc));
}
diff --git a/tools/crm_node.c b/tools/crm_node.c
index ff806d8010..0214afde34 100644
--- a/tools/crm_node.c
+++ b/tools/crm_node.c
@@ -1,664 +1,664 @@
/*
* Copyright 2004-2019 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 <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <crm/crm.h>
#include <crm/common/cmdline_internal.h>
#include <crm/common/mainloop.h>
#include <crm/msg_xml.h>
#include <crm/cib.h>
-#include <crm/attrd.h>
+#include <crm/common/attrd_internal.h>
#define SUMMARY "crm_node - Tool for displaying low-level node information"
struct {
gboolean corosync;
gboolean dangerous_cmd;
gboolean force_flag;
char command;
int nodeid;
char *target_uname;
} options = {
.command = '\0',
.force_flag = FALSE
};
gboolean command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
gboolean name_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
gboolean remove_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error);
static char *pid_s = NULL;
static GMainLoop *mainloop = NULL;
static crm_exit_t exit_code = CRM_EX_OK;
#define INDENT " "
static GOptionEntry command_entries[] = {
{ "cluster-id", 'i', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Display this node's cluster id",
NULL },
{ "list", 'l', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Display all known members (past and present) of this cluster",
NULL },
{ "name", 'n', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Display the name used by the cluster for this node",
NULL },
{ "partition", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Display the members of this partition",
NULL },
{ "quorum", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
"Display a 1 if our partition has quorum, 0 if not",
NULL },
{ "name-for-id", 'N', 0, G_OPTION_ARG_CALLBACK, name_cb,
"Display the name used by the cluster for the node with the specified ID",
"ID" },
{ "remove", 'R', 0, G_OPTION_ARG_CALLBACK, remove_cb,
"(Advanced) Remove the (stopped) node with the specified name from Pacemaker's\n"
INDENT "configuration and caches (the node must already have been removed from\n"
INDENT "the underlying cluster stack configuration",
"NAME" },
{ NULL }
};
static GOptionEntry addl_entries[] = {
{ "force", 'f', 0, G_OPTION_ARG_NONE, &options.force_flag,
NULL,
NULL },
#if SUPPORT_COROSYNC
/* Unused and deprecated */
{ "corosync", 'C', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &options.corosync,
NULL,
NULL },
#endif
// @TODO add timeout option for when IPC replies are needed
{ NULL }
};
gboolean
command_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
if (safe_str_eq("-i", option_name) || safe_str_eq("--cluster-id", option_name)) {
options.command = 'i';
} else if (safe_str_eq("-l", option_name) || safe_str_eq("--list", option_name)) {
options.command = 'l';
} else if (safe_str_eq("-n", option_name) || safe_str_eq("--name", option_name)) {
options.command = 'n';
} else if (safe_str_eq("-p", option_name) || safe_str_eq("--partition", option_name)) {
options.command = 'p';
} else if (safe_str_eq("-q", option_name) || safe_str_eq("--quorum", option_name)) {
options.command = 'q';
} else {
g_set_error(error, G_OPTION_ERROR, CRM_EX_INVALID_PARAM, "Unknown param passed to command_cb: %s\n", option_name);
return FALSE;
}
return TRUE;
}
gboolean
name_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
options.command = 'N';
options.nodeid = crm_parse_int(optarg, NULL);
return TRUE;
}
gboolean
remove_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
if (optarg == NULL) {
crm_err("-R option requires an argument");
g_set_error(error, G_OPTION_ERROR, CRM_EX_INVALID_PARAM, "-R option requires an argument");
return FALSE;
}
options.command = 'R';
options.dangerous_cmd = TRUE;
options.target_uname = strdup(optarg);
return TRUE;
}
/*!
* \internal
* \brief Exit crm_node
* Clean up memory, and either quit mainloop (if running) or exit
*
* \param[in] value Exit status
*/
static void
crm_node_exit(crm_exit_t value)
{
if (pid_s) {
free(pid_s);
pid_s = NULL;
}
exit_code = value;
if (mainloop && g_main_loop_is_running(mainloop)) {
g_main_loop_quit(mainloop);
} else {
crm_exit(exit_code);
}
}
static void
exit_disconnect(gpointer user_data)
{
fprintf(stderr, "error: Lost connection to cluster\n");
crm_node_exit(CRM_EX_DISCONNECT);
}
typedef int (*ipc_dispatch_fn) (const char *buffer, ssize_t length,
gpointer userdata);
static crm_ipc_t *
new_mainloop_for_ipc(const char *system, ipc_dispatch_fn dispatch)
{
mainloop_io_t *source = NULL;
crm_ipc_t *ipc = NULL;
struct ipc_client_callbacks ipc_callbacks = {
.dispatch = dispatch,
.destroy = exit_disconnect
};
mainloop = g_main_loop_new(NULL, FALSE);
source = mainloop_add_ipc_client(system, G_PRIORITY_DEFAULT, 0,
NULL, &ipc_callbacks);
ipc = mainloop_get_ipc_client(source);
if (ipc == NULL) {
fprintf(stderr,
"error: Could not connect to cluster (is it running?)\n");
crm_node_exit(CRM_EX_DISCONNECT);
}
return ipc;
}
static void
run_mainloop_and_exit()
{
g_main_loop_run(mainloop);
g_main_loop_unref(mainloop);
mainloop = NULL;
crm_node_exit(exit_code);
}
static int
send_controller_hello(crm_ipc_t *controller)
{
xmlNode *hello = NULL;
int rc;
pid_s = crm_getpid_s();
hello = create_hello_message(pid_s, crm_system_name, "1", "0");
rc = crm_ipc_send(controller, hello, 0, 0, NULL);
free_xml(hello);
return (rc < 0)? rc : 0;
}
static int
send_node_info_request(crm_ipc_t *controller, uint32_t nodeid)
{
xmlNode *ping = NULL;
int rc;
ping = create_request(CRM_OP_NODE_INFO, NULL, NULL, CRM_SYSTEM_CRMD,
crm_system_name, pid_s);
if (nodeid > 0) {
crm_xml_add_int(ping, XML_ATTR_ID, nodeid);
}
rc = crm_ipc_send(controller, ping, 0, 0, NULL);
free_xml(ping);
return (rc < 0)? rc : 0;
}
static int
dispatch_controller(const char *buffer, ssize_t length, gpointer userdata)
{
xmlNode *message = string2xml(buffer);
xmlNode *data = NULL;
const char *value = NULL;
if (message == NULL) {
fprintf(stderr, "error: Could not understand reply from controller\n");
crm_node_exit(CRM_EX_PROTOCOL);
return 0;
}
crm_log_xml_trace(message, "controller reply");
exit_code = CRM_EX_PROTOCOL;
// Validate reply
value = crm_element_value(message, F_CRM_MSG_TYPE);
if (safe_str_neq(value, XML_ATTR_RESPONSE)) {
fprintf(stderr, "error: Message from controller was not a reply\n");
goto done;
}
value = crm_element_value(message, XML_ATTR_REFERENCE);
if (value == NULL) {
fprintf(stderr, "error: Controller reply did not specify original message\n");
goto done;
}
data = get_message_xml(message, F_CRM_DATA);
if (data == NULL) {
fprintf(stderr, "error: Controller reply did not contain any data\n");
goto done;
}
switch (options.command) {
case 'i':
value = crm_element_value(data, XML_ATTR_ID);
if (value == NULL) {
fprintf(stderr, "error: Controller reply did not contain node ID\n");
} else {
printf("%s\n", value);
exit_code = CRM_EX_OK;
}
break;
case 'n':
case 'N':
value = crm_element_value(data, XML_ATTR_UNAME);
if (value == NULL) {
fprintf(stderr, "Node is not known to cluster\n");
exit_code = CRM_EX_NOHOST;
} else {
printf("%s\n", value);
exit_code = CRM_EX_OK;
}
break;
case 'q':
value = crm_element_value(data, XML_ATTR_HAVE_QUORUM);
if (value == NULL) {
fprintf(stderr, "error: Controller reply did not contain quorum status\n");
} else {
bool quorum = crm_is_true(value);
printf("%d\n", quorum);
exit_code = quorum? CRM_EX_OK : CRM_EX_QUORUM;
}
break;
default:
fprintf(stderr, "internal error: Controller reply not expected\n");
exit_code = CRM_EX_SOFTWARE;
break;
}
done:
free_xml(message);
crm_node_exit(exit_code);
return 0;
}
static void
run_controller_mainloop(uint32_t nodeid)
{
crm_ipc_t *controller = NULL;
int rc;
controller = new_mainloop_for_ipc(CRM_SYSTEM_CRMD, dispatch_controller);
rc = send_controller_hello(controller);
if (rc < 0) {
fprintf(stderr, "error: Could not register with controller: %s\n",
pcmk_strerror(rc));
crm_node_exit(crm_errno2exit(rc));
}
rc = send_node_info_request(controller, nodeid);
if (rc < 0) {
fprintf(stderr, "error: Could not ping controller: %s\n",
pcmk_strerror(rc));
crm_node_exit(crm_errno2exit(rc));
}
// Run main loop to get controller reply via dispatch_controller()
run_mainloop_and_exit();
}
static void
print_node_name()
{
// Check environment first (i.e. when called by resource agent)
const char *name = getenv("OCF_RESKEY_" CRM_META "_" XML_LRM_ATTR_TARGET);
if (name != NULL) {
printf("%s\n", name);
crm_node_exit(CRM_EX_OK);
} else {
// Otherwise ask the controller
run_controller_mainloop(0);
}
}
static int
cib_remove_node(long id, const char *name)
{
int rc;
cib_t *cib = NULL;
xmlNode *node = NULL;
xmlNode *node_state = NULL;
crm_trace("Removing %s from the CIB", name);
if(name == NULL && id == 0) {
return -ENOTUNIQ;
}
node = create_xml_node(NULL, XML_CIB_TAG_NODE);
node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
crm_xml_add(node, XML_ATTR_UNAME, name);
crm_xml_add(node_state, XML_ATTR_UNAME, name);
if (id > 0) {
crm_xml_set_id(node, "%ld", id);
crm_xml_add(node_state, XML_ATTR_ID, ID(node));
}
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
rc = cib->cmds->remove(cib, XML_CIB_TAG_NODES, node, cib_sync_call);
if (rc != pcmk_ok) {
printf("Could not remove %s[%ld] from " XML_CIB_TAG_NODES ": %s",
name, id, pcmk_strerror(rc));
}
rc = cib->cmds->remove(cib, XML_CIB_TAG_STATUS, node_state, cib_sync_call);
if (rc != pcmk_ok) {
printf("Could not remove %s[%ld] from " XML_CIB_TAG_STATUS ": %s",
name, id, pcmk_strerror(rc));
}
cib->cmds->signoff(cib);
cib_delete(cib);
return rc;
}
static int
tools_remove_node_cache(const char *node_name, long nodeid, const char *target)
{
int rc = -1;
crm_ipc_t *conn = crm_ipc_new(target, 0);
xmlNode *cmd = NULL;
if (!conn) {
return -ENOTCONN;
}
if (!crm_ipc_connect(conn)) {
crm_perror(LOG_ERR, "Connection to %s failed", target);
crm_ipc_destroy(conn);
return -ENOTCONN;
}
if(safe_str_eq(target, CRM_SYSTEM_CRMD)) {
// The controller requires a hello message before sending a request
rc = send_controller_hello(conn);
if (rc < 0) {
fprintf(stderr, "error: Could not register with controller: %s\n",
pcmk_strerror(rc));
return rc;
}
}
crm_trace("Removing %s[%ld] from the %s membership cache",
node_name, nodeid, target);
if(safe_str_eq(target, T_ATTRD)) {
cmd = create_xml_node(NULL, __FUNCTION__);
crm_xml_add(cmd, F_TYPE, T_ATTRD);
crm_xml_add(cmd, F_ORIG, crm_system_name);
crm_xml_add(cmd, F_ATTRD_TASK, ATTRD_OP_PEER_REMOVE);
crm_xml_add(cmd, F_ATTRD_HOST, node_name);
if (nodeid > 0) {
crm_xml_add_int(cmd, F_ATTRD_HOST_ID, (int) nodeid);
}
} else {
cmd = create_request(CRM_OP_RM_NODE_CACHE,
NULL, NULL, target, crm_system_name, pid_s);
if (nodeid > 0) {
crm_xml_set_id(cmd, "%ld", nodeid);
}
crm_xml_add(cmd, XML_ATTR_UNAME, node_name);
}
rc = crm_ipc_send(conn, cmd, 0, 0, NULL);
crm_debug("%s peer cache cleanup for %s (%ld): %d",
target, node_name, nodeid, rc);
if (rc > 0) {
rc = cib_remove_node(nodeid, node_name);
}
if (conn) {
crm_ipc_close(conn);
crm_ipc_destroy(conn);
}
free_xml(cmd);
return rc > 0 ? 0 : rc;
}
static void
remove_node(const char *target_uname)
{
int d = 0;
long nodeid = 0;
const char *node_name = NULL;
char *endptr = NULL;
const char *daemons[] = {
CRM_SYSTEM_CRMD,
"stonith-ng",
T_ATTRD,
CRM_SYSTEM_MCP,
};
// Check whether node was specified by name or numeric ID
errno = 0;
nodeid = strtol(target_uname, &endptr, 10);
if ((errno != 0) || (endptr == target_uname) || (*endptr != '\0')
|| (nodeid <= 0)) {
// It's not a positive integer, so assume it's a node name
nodeid = 0;
node_name = target_uname;
}
for (d = 0; d < DIMOF(daemons); d++) {
if (tools_remove_node_cache(node_name, nodeid, daemons[d])) {
crm_err("Failed to connect to %s to remove node '%s'",
daemons[d], target_uname);
crm_node_exit(CRM_EX_ERROR);
return;
}
}
crm_node_exit(CRM_EX_OK);
}
static gint
compare_node_xml(gconstpointer a, gconstpointer b)
{
const char *a_name = crm_element_value((xmlNode*) a, "uname");
const char *b_name = crm_element_value((xmlNode*) b, "uname");
return strcmp((a_name? a_name : ""), (b_name? b_name : ""));
}
static int
node_mcp_dispatch(const char *buffer, ssize_t length, gpointer userdata)
{
GList *nodes = NULL;
xmlNode *node = NULL;
xmlNode *msg = string2xml(buffer);
const char *uname;
const char *state;
if (msg == NULL) {
fprintf(stderr, "error: Could not understand pacemakerd response\n");
crm_node_exit(CRM_EX_PROTOCOL);
return 0;
}
crm_log_xml_trace(msg, "message");
for (node = __xml_first_child(msg); node != NULL; node = __xml_next(node)) {
nodes = g_list_insert_sorted(nodes, node, compare_node_xml);
}
for (GList *iter = nodes; iter; iter = iter->next) {
node = (xmlNode*) iter->data;
uname = crm_element_value(node, "uname");
state = crm_element_value(node, "state");
if (options.command == 'l') {
int id = 0;
crm_element_value_int(node, "id", &id);
printf("%d %s %s\n", id, (uname? uname : ""), (state? state : ""));
// This is CRM_NODE_MEMBER but we don't want to include cluster header
} else if ((options.command == 'p') && safe_str_eq(state, "member")) {
printf("%s ", (uname? uname : ""));
}
}
if (options.command == 'p') {
fprintf(stdout, "\n");
}
free_xml(msg);
crm_node_exit(CRM_EX_OK);
return 0;
}
static void
run_pacemakerd_mainloop()
{
crm_ipc_t *ipc = NULL;
xmlNode *poke = NULL;
ipc = new_mainloop_for_ipc(CRM_SYSTEM_MCP, node_mcp_dispatch);
// Sending anything will get us a list of nodes
poke = create_xml_node(NULL, "poke");
crm_ipc_send(ipc, poke, 0, 0, NULL);
free_xml(poke);
// Handle reply via node_mcp_dispatch()
run_mainloop_and_exit();
}
static GOptionContext *
build_arg_context(pcmk__common_args_t *args, GOptionGroup *group) {
GOptionContext *context = NULL;
GOptionEntry extra_prog_entries[] = {
{ "quiet", 'Q', 0, G_OPTION_ARG_NONE, &(args->quiet),
"Be less descriptive in output.",
NULL },
{ NULL }
};
context = pcmk__build_arg_context(args, NULL, &group);
/* Add the -q option, which cannot be part of the globally supported options
* because some tools use that flag for something else.
*/
pcmk__add_main_args(context, extra_prog_entries);
pcmk__add_arg_group(context, "commands", "Commands:",
"Show command help", command_entries);
pcmk__add_arg_group(context, "additional", "Additional Options:",
"Show additional options", addl_entries);
return context;
}
int
main(int argc, char **argv)
{
pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
GError *error = NULL;
GOptionContext *context = NULL;
GOptionGroup *output_group = NULL;
gchar **processed_args = NULL;
context = build_arg_context(args, output_group);
crm_log_cli_init("crm_node");
processed_args = pcmk__cmdline_preproc(argc, argv, "NR");
if (!g_option_context_parse_strv(context, &processed_args, &error)) {
fprintf(stderr, "%s: %s\n", g_get_prgname(), error->message);
exit_code = CRM_EX_USAGE;
goto done;
}
for (int i = 0; i < args->verbosity; i++) {
crm_bump_log_level(argc, argv);
}
if (args->version) {
/* FIXME: When crm_node is converted to use formatted output, this can go. */
crm_help('v', CRM_EX_USAGE);
}
if (optind > argc || options.command == 0) {
fprintf(stderr, "%s", g_option_context_get_help(context, TRUE, NULL));
exit_code = CRM_EX_USAGE;
goto done;
}
if (options.dangerous_cmd && options.force_flag == FALSE) {
fprintf(stderr, "The supplied command is considered dangerous."
" To prevent accidental destruction of the cluster,"
" the --force flag is required in order to proceed.\n");
exit_code = CRM_EX_USAGE;
goto done;
}
switch (options.command) {
case 'n':
print_node_name();
break;
case 'R':
remove_node(options.target_uname);
break;
case 'i':
case 'q':
case 'N':
run_controller_mainloop(options.nodeid);
break;
case 'l':
case 'p':
run_pacemakerd_mainloop();
break;
default:
break;
}
done:
g_strfreev(processed_args);
pcmk__free_arg_context(context);
crm_node_exit(exit_code);
return exit_code;
}
diff --git a/tools/crm_resource.h b/tools/crm_resource.h
index 48236b6695..84b094b1b6 100644
--- a/tools/crm_resource.h
+++ b/tools/crm_resource.h
@@ -1,103 +1,103 @@
/*
* Copyright 2004-2019 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 <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/services.h>
#include <crm/common/xml.h>
#include <crm/common/mainloop.h>
#include <crm/cib.h>
-#include <crm/attrd.h>
+#include <crm/common/attrd_internal.h>
#include <crm/pengine/rules.h>
#include <crm/pengine/status.h>
#include <crm/pengine/internal.h>
#include <pacemaker-internal.h>
extern bool print_pending;
extern bool scope_master;
extern bool do_force;
extern bool BE_QUIET;
extern int resource_verbose;
extern int cib_options;
extern int crmd_replies_needed;
extern char *move_lifetime;
extern const char *attr_set_type;
/* ban */
int cli_resource_prefer(const char *rsc_id, const char *host, cib_t * cib_conn);
int cli_resource_ban(const char *rsc_id, const char *host, GListPtr allnodes, cib_t * cib_conn);
int cli_resource_clear(const char *rsc_id, const char *host, GListPtr allnodes, cib_t * cib_conn,
bool clear_ban_constraints);
int cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, const char *rsc, const char *node, bool scope_master);
/* print */
void cli_resource_print_cts(resource_t * rsc);
void cli_resource_print_raw(resource_t * rsc);
void cli_resource_print_cts_constraints(pe_working_set_t * data_set);
void cli_resource_print_location(resource_t * rsc, const char *prefix);
void cli_resource_print_colocation(resource_t * rsc, bool dependents, bool recursive, int offset);
int cli_resource_print(resource_t *rsc, pe_working_set_t *data_set,
bool expanded);
int cli_resource_print_list(pe_working_set_t * data_set, bool raw);
int cli_resource_print_attribute(resource_t *rsc, const char *attr,
pe_working_set_t *data_set);
int cli_resource_print_property(resource_t *rsc, const char *attr,
pe_working_set_t *data_set);
int cli_resource_print_operations(const char *rsc_id, const char *host_uname, bool active, pe_working_set_t * data_set);
/* runtime */
void cli_resource_check(cib_t * cib, resource_t *rsc);
int cli_resource_fail(crm_ipc_t * crmd_channel, const char *host_uname, const char *rsc_id, pe_working_set_t * data_set);
int cli_resource_search(resource_t *rsc, const char *requested_name,
pe_working_set_t *data_set);
int cli_resource_delete(crm_ipc_t *crmd_channel, const char *host_uname,
resource_t *rsc, const char *operation,
const char *interval_spec, bool just_failures,
pe_working_set_t *data_set);
int cli_cleanup_all(crm_ipc_t *crmd_channel, const char *node_name,
const char *operation, const char *interval_spec,
pe_working_set_t *data_set);
int cli_resource_restart(pe_resource_t *rsc, const char *host, int timeout_ms,
cib_t *cib);
int cli_resource_move(resource_t *rsc, const char *rsc_id,
const char *host_name, cib_t *cib,
pe_working_set_t *data_set);
int cli_resource_execute_from_params(const char *rsc_name, const char *rsc_class,
const char *rsc_prov, const char *rsc_type,
const char *rsc_action, GHashTable *params,
GHashTable *override_hash, int timeout_ms);
int cli_resource_execute(resource_t *rsc, const char *requested_name,
const char *rsc_action, GHashTable *override_hash,
int timeout_ms, cib_t *cib,
pe_working_set_t *data_set);
int cli_resource_update_attribute(resource_t *rsc, const char *requested_name,
const char *attr_set, const char *attr_id,
const char *attr_name, const char *attr_value,
bool recursive, cib_t *cib,
pe_working_set_t *data_set);
int cli_resource_delete_attribute(resource_t *rsc, const char *requested_name,
const char *attr_set, const char *attr_id,
const char *attr_name, cib_t *cib,
pe_working_set_t *data_set);
GList* subtract_lists(GList *from, GList *items, GCompareFunc cmp);
int update_working_set_xml(pe_working_set_t *data_set, xmlNode **xml);
int wait_till_stable(int timeout_ms, cib_t * cib);
void cli_resource_why(cib_t *cib_conn, GListPtr resources, resource_t *rsc,
node_t *node);
diff --git a/tools/notifyServicelogEvent.c b/tools/notifyServicelogEvent.c
index ed4967cad9..620a7997c8 100644
--- a/tools/notifyServicelogEvent.c
+++ b/tools/notifyServicelogEvent.c
@@ -1,192 +1,192 @@
/*
* Original copyright 2009 International Business Machines, IBM, Mark Hamzy
- * Later changes copyright 2009-2018 the Pacemaker project contributors
+ * Later changes copyright 2009-2019 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.
*/
/* gcc -o notifyServicelogEvent `pkg-config --cflags servicelog-1` `pkg-config --libs servicelog-1` notifyServicelogEvent.c
*/
#include <crm_internal.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <servicelog.h>
#include <syslog.h>
#include <unistd.h>
#include <config.h>
#include <inttypes.h> /* U64T ~ PRIu64, U64TS ~ SCNu64 */
#include <crm/common/xml.h>
#include <crm/common/util.h>
-#include <crm/attrd.h>
+#include <crm/common/attrd_internal.h>
typedef enum { STATUS_GREEN = 1, STATUS_YELLOW, STATUS_RED } STATUS;
const char *status2char(STATUS status);
STATUS event2status(struct sl_event *event);
const char *
status2char(STATUS status)
{
switch (status) {
default:
case STATUS_GREEN:
return "green";
case STATUS_YELLOW:
return "yellow";
case STATUS_RED:
return "red";
}
}
STATUS
event2status(struct sl_event * event)
{
STATUS status = STATUS_GREEN;
crm_debug("Severity = %d, Disposition = %d", event->severity, event->disposition);
/* @TBD */
if (event->severity == SL_SEV_WARNING) {
status = STATUS_YELLOW;
}
if (event->disposition == SL_DISP_UNRECOVERABLE) {
status = STATUS_RED;
}
return status;
}
static struct crm_option long_options[] = {
/* Top-level Options */
{"help", 0, 0, '?', "\tThis text"},
{"version", 0, 0, '$', "\tVersion information"},
{"-spacer-", 0, 0, '-', "\nUsage: notifyServicelogEvent event_id"},
{"-spacer-", 0, 0, '-',
"\nWhere event_id is unique unsigned event identifier which is then passed into servicelog"},
{0, 0, 0, 0}
};
int
main(int argc, char *argv[])
{
int argerr = 0;
int flag;
int index = 0;
int rc = 0;
servicelog *slog = NULL;
struct sl_event *event = NULL;
uint64_t event_id = 0;
crm_log_cli_init("notifyServicelogEvent");
crm_set_options(NULL, "event_id ", long_options,
"Gets called upon events written to servicelog database");
if (argc < 2) {
argerr++;
}
while (1) {
flag = crm_get_option(argc, argv, &index);
if (flag == -1)
break;
switch (flag) {
case '?':
case '$':
crm_help(flag, CRM_EX_OK);
break;
default:
++argerr;
break;
}
}
if (argc - optind != 1) {
++argerr;
}
if (argerr) {
crm_help('?', CRM_EX_USAGE);
}
openlog("notifyServicelogEvent", LOG_NDELAY, LOG_USER);
if (sscanf(argv[optind], "%" U64TS, &event_id) != 1) {
crm_err("Error: could not read event_id from args!");
rc = 1;
goto cleanup;
}
if (event_id == 0) {
crm_err("Error: event_id is 0!");
rc = 1;
goto cleanup;
}
rc = servicelog_open(&slog, 0); /* flags is one of SL_FLAG_xxx */
if (!slog) {
crm_err("Error: servicelog_open failed, rc = %d", rc);
rc = 1;
goto cleanup;
}
if (slog) {
rc = servicelog_event_get(slog, event_id, &event);
}
if (rc == 0) {
STATUS status = STATUS_GREEN;
const char *health_component = "#health-ipmi";
const char *health_status = NULL;
crm_debug("Event id = %" U64T ", Log timestamp = %s, Event timestamp = %s",
event_id, ctime(&(event->time_logged)), ctime(&(event->time_event)));
status = event2status(event);
health_status = status2char(status);
if (health_status) {
gboolean rc;
/* @TODO pass attrd_opt_remote when appropriate */
rc = (attrd_update_delegate(NULL, 'v', NULL, health_component,
health_status, NULL, NULL, NULL, NULL,
attrd_opt_none) > 0);
crm_debug("Updating attribute ('%s', '%s') = %d",
health_component, health_status, rc);
} else {
crm_err("Error: status2char failed, status = %d", status);
rc = 1;
}
} else {
crm_err("Error: servicelog_event_get failed, rc = %d", rc);
}
cleanup:
if (event) {
servicelog_event_free(event);
}
if (slog) {
servicelog_close(slog);
}
closelog();
return rc;
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 4:01 AM (8 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018206
Default Alt Text
(88 KB)

Event Timeline