root/daemons/fenced/pacemaker-fenced.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. st_ipc_accept
  2. st_ipc_dispatch
  3. st_ipc_closed
  4. st_ipc_destroy
  5. stonith_peer_callback
  6. stonith_peer_ais_callback
  7. stonith_peer_cs_destroy
  8. do_local_reply
  9. get_stonith_flag
  10. stonith_notify_client
  11. do_stonith_async_timeout_update
  12. do_stonith_notify
  13. do_stonith_notify_config
  14. do_stonith_notify_device
  15. do_stonith_notify_level
  16. topology_remove_helper
  17. remove_cib_device
  18. handle_topology_change
  19. remove_fencing_topology
  20. register_fencing_topology
  21. fencing_topology_init
  22. our_node_allowed_for
  23. watchdog_device_update
  24. cib_device_update
  25. cib_devices_update
  26. update_cib_stonith_devices_v2
  27. update_cib_stonith_devices_v1
  28. update_cib_stonith_devices
  29. node_has_attr
  30. update_fencing_topology
  31. update_cib_cache_cb
  32. init_cib_cache_cb
  33. stonith_shutdown
  34. cib_connection_destroy
  35. stonith_cleanup
  36. setup_cib
  37. st_peer_update_callback
  38. main

   1 /*
   2  * Copyright 2009-2021 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <sys/param.h>
  13 #include <stdio.h>
  14 #include <sys/types.h>
  15 #include <sys/stat.h>
  16 #include <unistd.h>
  17 #include <sys/utsname.h>
  18 
  19 #include <stdlib.h>
  20 #include <errno.h>
  21 #include <fcntl.h>
  22 #include <inttypes.h>  // PRIu32, PRIx32
  23 
  24 #include <crm/crm.h>
  25 #include <crm/msg_xml.h>
  26 #include <crm/common/ipc.h>
  27 #include <crm/common/ipc_internal.h>
  28 #include <crm/cluster/internal.h>
  29 
  30 #include <crm/stonith-ng.h>
  31 #include <crm/fencing/internal.h>
  32 #include <crm/common/xml.h>
  33 #include <crm/common/xml_internal.h>
  34 
  35 #include <crm/common/mainloop.h>
  36 
  37 #include <crm/cib/internal.h>
  38 #include <crm/pengine/status.h>
  39 #include <pacemaker-internal.h>
  40 
  41 #include <pacemaker-fenced.h>
  42 
  43 char *stonith_our_uname = NULL;
  44 long stonith_watchdog_timeout_ms = 0;
  45 
  46 static GMainLoop *mainloop = NULL;
  47 
  48 gboolean stand_alone = FALSE;
  49 static gboolean no_cib_connect = FALSE;
  50 static gboolean stonith_shutdown_flag = FALSE;
  51 
  52 static qb_ipcs_service_t *ipcs = NULL;
  53 static xmlNode *local_cib = NULL;
  54 static pe_working_set_t *fenced_data_set = NULL;
  55 
  56 static cib_t *cib_api = NULL;
  57 
  58 static pcmk__output_t *out = NULL;
  59 
  60 pcmk__supported_format_t formats[] = {
  61     PCMK__SUPPORTED_FORMAT_LOG,
  62     PCMK__SUPPORTED_FORMAT_NONE,
  63     PCMK__SUPPORTED_FORMAT_TEXT,
  64     { NULL, NULL, NULL }
  65 };
  66 
  67 static void stonith_shutdown(int nsig);
  68 static void stonith_cleanup(void);
  69 
  70 static int32_t
  71 st_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73     if (stonith_shutdown_flag) {
  74         crm_info("Ignoring new client [%d] during shutdown",
  75                  pcmk__client_pid(c));
  76         return -EPERM;
  77     }
  78 
  79     if (pcmk__new_client(c, uid, gid) == NULL) {
  80         return -EIO;
  81     }
  82     return 0;
  83 }
  84 
  85 /* Exit code means? */
  86 static int32_t
  87 st_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89     uint32_t id = 0;
  90     uint32_t flags = 0;
  91     int call_options = 0;
  92     xmlNode *request = NULL;
  93     pcmk__client_t *c = pcmk__find_client(qbc);
  94     const char *op = NULL;
  95 
  96     if (c == NULL) {
  97         crm_info("Invalid client: %p", qbc);
  98         return 0;
  99     }
 100 
 101     request = pcmk__client_data2xml(c, data, &id, &flags);
 102     if (request == NULL) {
 103         pcmk__ipc_send_ack(c, id, flags, "nack", CRM_EX_PROTOCOL);
 104         return 0;
 105     }
 106 
 107 
 108     op = crm_element_value(request, F_CRM_TASK);
 109     if(pcmk__str_eq(op, CRM_OP_RM_NODE_CACHE, pcmk__str_casei)) {
 110         crm_xml_add(request, F_TYPE, T_STONITH_NG);
 111         crm_xml_add(request, F_STONITH_OPERATION, op);
 112         crm_xml_add(request, F_STONITH_CLIENTID, c->id);
 113         crm_xml_add(request, F_STONITH_CLIENTNAME, pcmk__client_name(c));
 114         crm_xml_add(request, F_STONITH_CLIENTNODE, stonith_our_uname);
 115 
 116         send_cluster_message(NULL, crm_msg_stonith_ng, request, FALSE);
 117         free_xml(request);
 118         return 0;
 119     }
 120 
 121     if (c->name == NULL) {
 122         const char *value = crm_element_value(request, F_STONITH_CLIENTNAME);
 123 
 124         if (value == NULL) {
 125             value = "unknown";
 126         }
 127         c->name = crm_strdup_printf("%s.%u", value, c->pid);
 128     }
 129 
 130     crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
 131     crm_trace("Flags 0x%08" PRIx32 "/0x%08x for command %" PRIu32
 132               " from client %s", flags, call_options, id, pcmk__client_name(c));
 133 
 134     if (pcmk_is_set(call_options, st_opt_sync_call)) {
 135         CRM_ASSERT(flags & crm_ipc_client_response);
 136         CRM_LOG_ASSERT(c->request_id == 0);     /* This means the client has two synchronous events in-flight */
 137         c->request_id = id;     /* Reply only to the last one */
 138     }
 139 
 140     crm_xml_add(request, F_STONITH_CLIENTID, c->id);
 141     crm_xml_add(request, F_STONITH_CLIENTNAME, pcmk__client_name(c));
 142     crm_xml_add(request, F_STONITH_CLIENTNODE, stonith_our_uname);
 143 
 144     stonith_command(c, id, flags, request, NULL);
 145 
 146     free_xml(request);
 147     return 0;
 148 }
 149 
 150 /* Error code means? */
 151 static int32_t
 152 st_ipc_closed(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 153 {
 154     pcmk__client_t *client = pcmk__find_client(c);
 155 
 156     if (client == NULL) {
 157         return 0;
 158     }
 159 
 160     crm_trace("Connection %p closed", c);
 161     pcmk__free_client(client);
 162 
 163     /* 0 means: yes, go ahead and destroy the connection */
 164     return 0;
 165 }
 166 
 167 static void
 168 st_ipc_destroy(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 169 {
 170     crm_trace("Connection %p destroyed", c);
 171     st_ipc_closed(c);
 172 }
 173 
 174 static void
 175 stonith_peer_callback(xmlNode * msg, void *private_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 176 {
 177     const char *remote_peer = crm_element_value(msg, F_ORIG);
 178     const char *op = crm_element_value(msg, F_STONITH_OPERATION);
 179 
 180     if (pcmk__str_eq(op, "poke", pcmk__str_none)) {
 181         return;
 182     }
 183 
 184     crm_log_xml_trace(msg, "Peer[inbound]");
 185     stonith_command(NULL, 0, 0, msg, remote_peer);
 186 }
 187 
 188 #if SUPPORT_COROSYNC
 189 static void
 190 stonith_peer_ais_callback(cpg_handle_t handle,
     /* [previous][next][first][last][top][bottom][index][help] */
 191                           const struct cpg_name *groupName,
 192                           uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len)
 193 {
 194     uint32_t kind = 0;
 195     xmlNode *xml = NULL;
 196     const char *from = NULL;
 197     char *data = pcmk_message_common_cs(handle, nodeid, pid, msg, &kind, &from);
 198 
 199     if(data == NULL) {
 200         return;
 201     }
 202     if (kind == crm_class_cluster) {
 203         xml = string2xml(data);
 204         if (xml == NULL) {
 205             crm_err("Invalid XML: '%.120s'", data);
 206             free(data);
 207             return;
 208         }
 209         crm_xml_add(xml, F_ORIG, from);
 210         /* crm_xml_add_int(xml, F_SEQ, wrapper->id); */
 211         stonith_peer_callback(xml, NULL);
 212     }
 213 
 214     free_xml(xml);
 215     free(data);
 216     return;
 217 }
 218 
 219 static void
 220 stonith_peer_cs_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222     crm_crit("Lost connection to cluster layer, shutting down");
 223     stonith_shutdown(0);
 224 }
 225 #endif
 226 
 227 void
 228 do_local_reply(xmlNode * notify_src, const char *client_id, gboolean sync_reply, gboolean from_peer)
     /* [previous][next][first][last][top][bottom][index][help] */
 229 {
 230     /* send callback to originating child */
 231     pcmk__client_t *client_obj = NULL;
 232     int local_rc = pcmk_rc_ok;
 233 
 234     crm_trace("Sending response");
 235     client_obj = pcmk__find_client_by_id(client_id);
 236 
 237     crm_trace("Sending callback to request originator");
 238     if (client_obj == NULL) {
 239         local_rc = EPROTO;
 240         crm_trace("No client to sent the response to.  F_STONITH_CLIENTID not set.");
 241 
 242     } else {
 243         int rid = 0;
 244 
 245         if (sync_reply) {
 246             CRM_LOG_ASSERT(client_obj->request_id);
 247 
 248             rid = client_obj->request_id;
 249             client_obj->request_id = 0;
 250 
 251             crm_trace("Sending response %d to client %s%s",
 252                       rid, pcmk__client_name(client_obj),
 253                       (from_peer? " (originator of delegated request)" : ""));
 254 
 255         } else {
 256             crm_trace("Sending an event to client %s%s",
 257                       pcmk__client_name(client_obj),
 258                       (from_peer? " (originator of delegated request)" : ""));
 259         }
 260 
 261         local_rc = pcmk__ipc_send_xml(client_obj, rid, notify_src,
 262                                       (sync_reply? crm_ipc_flags_none
 263                                        : crm_ipc_server_event));
 264     }
 265 
 266     if ((local_rc != pcmk_rc_ok) && (client_obj != NULL)) {
 267         crm_warn("%s reply to client %s failed: %s",
 268                  (sync_reply? "Synchronous" : "Asynchronous"),
 269                  pcmk__client_name(client_obj), pcmk_rc_str(local_rc));
 270     }
 271 }
 272 
 273 uint64_t
 274 get_stonith_flag(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 275 {
 276     if (pcmk__str_eq(name, T_STONITH_NOTIFY_FENCE, pcmk__str_casei)) {
 277         return st_callback_notify_fence;
 278 
 279     } else if (pcmk__str_eq(name, STONITH_OP_DEVICE_ADD, pcmk__str_casei)) {
 280         return st_callback_device_add;
 281 
 282     } else if (pcmk__str_eq(name, STONITH_OP_DEVICE_DEL, pcmk__str_casei)) {
 283         return st_callback_device_del;
 284 
 285     } else if (pcmk__str_eq(name, T_STONITH_NOTIFY_HISTORY, pcmk__str_casei)) {
 286         return st_callback_notify_history;
 287 
 288     } else if (pcmk__str_eq(name, T_STONITH_NOTIFY_HISTORY_SYNCED, pcmk__str_casei)) {
 289         return st_callback_notify_history_synced;
 290 
 291     }
 292     return st_callback_unknown;
 293 }
 294 
 295 static void
 296 stonith_notify_client(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 297 {
 298 
 299     xmlNode *update_msg = user_data;
 300     pcmk__client_t *client = value;
 301     const char *type = NULL;
 302 
 303     CRM_CHECK(client != NULL, return);
 304     CRM_CHECK(update_msg != NULL, return);
 305 
 306     type = crm_element_value(update_msg, F_SUBTYPE);
 307     CRM_CHECK(type != NULL, crm_log_xml_err(update_msg, "notify"); return);
 308 
 309     if (client->ipcs == NULL) {
 310         crm_trace("Skipping client with NULL channel");
 311         return;
 312     }
 313 
 314     if (pcmk_is_set(client->flags, get_stonith_flag(type))) {
 315         int rc = pcmk__ipc_send_xml(client, 0, update_msg,
 316                                     crm_ipc_server_event|crm_ipc_server_error);
 317 
 318         if (rc != pcmk_rc_ok) {
 319             crm_warn("%s notification of client %s failed: %s "
 320                      CRM_XS " id=%.8s rc=%d", type, pcmk__client_name(client),
 321                      pcmk_rc_str(rc), client->id, rc);
 322         } else {
 323             crm_trace("Sent %s notification to client %s",
 324                       type, pcmk__client_name(client));
 325         }
 326     }
 327 }
 328 
 329 void
 330 do_stonith_async_timeout_update(const char *client_id, const char *call_id, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332     pcmk__client_t *client = NULL;
 333     xmlNode *notify_data = NULL;
 334 
 335     if (!timeout || !call_id || !client_id) {
 336         return;
 337     }
 338 
 339     client = pcmk__find_client_by_id(client_id);
 340     if (!client) {
 341         return;
 342     }
 343 
 344     notify_data = create_xml_node(NULL, T_STONITH_TIMEOUT_VALUE);
 345     crm_xml_add(notify_data, F_TYPE, T_STONITH_TIMEOUT_VALUE);
 346     crm_xml_add(notify_data, F_STONITH_CALLID, call_id);
 347     crm_xml_add_int(notify_data, F_STONITH_TIMEOUT, timeout);
 348 
 349     crm_trace("timeout update is %d for client %s and call id %s", timeout, client_id, call_id);
 350 
 351     if (client) {
 352         pcmk__ipc_send_xml(client, 0, notify_data, crm_ipc_server_event);
 353     }
 354 
 355     free_xml(notify_data);
 356 }
 357 
 358 void
 359 do_stonith_notify(int options, const char *type, int result, xmlNode * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 360 {
 361     /* TODO: Standardize the contents of data */
 362     xmlNode *update_msg = create_xml_node(NULL, "notify");
 363 
 364     CRM_CHECK(type != NULL,;);
 365 
 366     crm_xml_add(update_msg, F_TYPE, T_STONITH_NOTIFY);
 367     crm_xml_add(update_msg, F_SUBTYPE, type);
 368     crm_xml_add(update_msg, F_STONITH_OPERATION, type);
 369     crm_xml_add_int(update_msg, F_STONITH_RC, result);
 370 
 371     if (data != NULL) {
 372         add_message_xml(update_msg, F_STONITH_CALLDATA, data);
 373     }
 374 
 375     crm_trace("Notifying clients");
 376     pcmk__foreach_ipc_client(stonith_notify_client, update_msg);
 377     free_xml(update_msg);
 378     crm_trace("Notify complete");
 379 }
 380 
 381 static void
 382 do_stonith_notify_config(int options, const char *op, int rc,
     /* [previous][next][first][last][top][bottom][index][help] */
 383                          const char *desc, int active)
 384 {
 385     xmlNode *notify_data = create_xml_node(NULL, op);
 386 
 387     CRM_CHECK(notify_data != NULL, return);
 388 
 389     crm_xml_add(notify_data, F_STONITH_DEVICE, desc);
 390     crm_xml_add_int(notify_data, F_STONITH_ACTIVE, active);
 391 
 392     do_stonith_notify(options, op, rc, notify_data);
 393     free_xml(notify_data);
 394 }
 395 
 396 void
 397 do_stonith_notify_device(int options, const char *op, int rc, const char *desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 398 {
 399     do_stonith_notify_config(options, op, rc, desc, g_hash_table_size(device_list));
 400 }
 401 
 402 void
 403 do_stonith_notify_level(int options, const char *op, int rc, const char *desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 404 {
 405     do_stonith_notify_config(options, op, rc, desc, g_hash_table_size(topology));
 406 }
 407 
 408 static void
 409 topology_remove_helper(const char *node, int level)
     /* [previous][next][first][last][top][bottom][index][help] */
 410 {
 411     int rc;
 412     char *desc = NULL;
 413     xmlNode *data = create_xml_node(NULL, XML_TAG_FENCING_LEVEL);
 414 
 415     crm_xml_add(data, F_STONITH_ORIGIN, __func__);
 416     crm_xml_add_int(data, XML_ATTR_STONITH_INDEX, level);
 417     crm_xml_add(data, XML_ATTR_STONITH_TARGET, node);
 418 
 419     rc = stonith_level_remove(data, &desc);
 420     do_stonith_notify_level(0, STONITH_OP_LEVEL_DEL, rc, desc);
 421 
 422     free_xml(data);
 423     free(desc);
 424 }
 425 
 426 static void
 427 remove_cib_device(xmlXPathObjectPtr xpathObj)
     /* [previous][next][first][last][top][bottom][index][help] */
 428 {
 429     int max = numXpathResults(xpathObj), lpc = 0;
 430 
 431     for (lpc = 0; lpc < max; lpc++) {
 432         const char *rsc_id = NULL;
 433         const char *standard = NULL;
 434         xmlNode *match = getXpathResult(xpathObj, lpc);
 435 
 436         CRM_LOG_ASSERT(match != NULL);
 437         if(match != NULL) {
 438             standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
 439         }
 440 
 441         if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
 442             continue;
 443         }
 444 
 445         rsc_id = crm_element_value(match, XML_ATTR_ID);
 446 
 447         stonith_device_remove(rsc_id, TRUE);
 448     }
 449 }
 450 
 451 static void
 452 handle_topology_change(xmlNode *match, bool remove) 
     /* [previous][next][first][last][top][bottom][index][help] */
 453 {
 454     int rc;
 455     char *desc = NULL;
 456 
 457     CRM_CHECK(match != NULL, return);
 458     crm_trace("Updating %s", ID(match));
 459 
 460     if(remove) {
 461         int index = 0;
 462         char *key = stonith_level_key(match, -1);
 463 
 464         crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
 465         topology_remove_helper(key, index);
 466         free(key);
 467     }
 468 
 469     rc = stonith_level_register(match, &desc);
 470     do_stonith_notify_level(0, STONITH_OP_LEVEL_ADD, rc, desc);
 471 
 472     free(desc);
 473 }
 474 
 475 static void
 476 remove_fencing_topology(xmlXPathObjectPtr xpathObj)
     /* [previous][next][first][last][top][bottom][index][help] */
 477 {
 478     int max = numXpathResults(xpathObj), lpc = 0;
 479 
 480     for (lpc = 0; lpc < max; lpc++) {
 481         xmlNode *match = getXpathResult(xpathObj, lpc);
 482 
 483         CRM_LOG_ASSERT(match != NULL);
 484         if (match && crm_element_value(match, XML_DIFF_MARKER)) {
 485             /* Deletion */
 486             int index = 0;
 487             char *target = stonith_level_key(match, -1);
 488 
 489             crm_element_value_int(match, XML_ATTR_STONITH_INDEX, &index);
 490             if (target == NULL) {
 491                 crm_err("Invalid fencing target in element %s", ID(match));
 492 
 493             } else if (index <= 0) {
 494                 crm_err("Invalid level for %s in element %s", target, ID(match));
 495 
 496             } else {
 497                 topology_remove_helper(target, index);
 498             }
 499             /* } else { Deal with modifications during the 'addition' stage */
 500         }
 501     }
 502 }
 503 
 504 static void
 505 register_fencing_topology(xmlXPathObjectPtr xpathObj)
     /* [previous][next][first][last][top][bottom][index][help] */
 506 {
 507     int max = numXpathResults(xpathObj), lpc = 0;
 508 
 509     for (lpc = 0; lpc < max; lpc++) {
 510         xmlNode *match = getXpathResult(xpathObj, lpc);
 511 
 512         handle_topology_change(match, TRUE);
 513     }
 514 }
 515 
 516 /* Fencing
 517 <diff crm_feature_set="3.0.6">
 518   <diff-removed>
 519     <fencing-topology>
 520       <fencing-level id="f-p1.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="removed:top"/>
 521       <fencing-level id="f-p1.2" target="pcmk-1" index="2" devices="power" __crm_diff_marker__="removed:top"/>
 522       <fencing-level devices="disk,network" id="f-p2.1"/>
 523     </fencing-topology>
 524   </diff-removed>
 525   <diff-added>
 526     <fencing-topology>
 527       <fencing-level id="f-p.1" target="pcmk-1" index="1" devices="poison-pill" __crm_diff_marker__="added:top"/>
 528       <fencing-level id="f-p2.1" target="pcmk-2" index="1" devices="disk,something"/>
 529       <fencing-level id="f-p3.1" target="pcmk-2" index="2" devices="power" __crm_diff_marker__="added:top"/>
 530     </fencing-topology>
 531   </diff-added>
 532 </diff>
 533 */
 534 
 535 static void
 536 fencing_topology_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 537 {
 538     xmlXPathObjectPtr xpathObj = NULL;
 539     const char *xpath = "//" XML_TAG_FENCING_LEVEL;
 540 
 541     crm_trace("Full topology refresh");
 542     free_topology_list();
 543     init_topology_list();
 544 
 545     /* Grab everything */
 546     xpathObj = xpath_search(local_cib, xpath);
 547     register_fencing_topology(xpathObj);
 548 
 549     freeXpathObject(xpathObj);
 550 }
 551 
 552 #define rsc_name(x) x->clone_name?x->clone_name:x->id
 553 
 554 /*!
 555  * \internal
 556  * \brief Check whether our uname is in a resource's allowed node list
 557  *
 558  * \param[in] rsc  Resource to check
 559  *
 560  * \return Pointer to node object if found, NULL otherwise
 561  */
 562 static pe_node_t *
 563 our_node_allowed_for(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 564 {
 565     GHashTableIter iter;
 566     pe_node_t *node = NULL;
 567 
 568     if (rsc && stonith_our_uname) {
 569         g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 570         while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 571             if (node && strcmp(node->details->uname, stonith_our_uname) == 0) {
 572                 break;
 573             }
 574             node = NULL;
 575         }
 576     }
 577     return node;
 578 }
 579 
 580 static void
 581 watchdog_device_update(xmlNode *cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 582 {
 583     xmlNode *stonith_enabled_xml = NULL;
 584     const char *stonith_enabled_s = NULL;
 585     long timeout_ms = 0;
 586 
 587     stonith_enabled_xml = get_xpath_object("//nvpair[@name='stonith-enabled']",
 588                                            cib, LOG_NEVER);
 589     if (stonith_enabled_xml) {
 590         stonith_enabled_s = crm_element_value(stonith_enabled_xml, XML_NVPAIR_ATTR_VALUE);
 591     }
 592 
 593     if (stonith_enabled_s == NULL || crm_is_true(stonith_enabled_s)) {
 594         xmlNode *stonith_watchdog_xml = NULL;
 595         const char *value = NULL;
 596 
 597         stonith_watchdog_xml = get_xpath_object("//nvpair[@name='stonith-watchdog-timeout']",
 598                                                 cib, LOG_NEVER);
 599         if (stonith_watchdog_xml) {
 600             value = crm_element_value(stonith_watchdog_xml, XML_NVPAIR_ATTR_VALUE);
 601         }
 602         if (value) {
 603             timeout_ms = crm_get_msec(value);
 604         }
 605 
 606         if (timeout_ms < 0) {
 607             timeout_ms = pcmk__auto_watchdog_timeout();
 608         }
 609     }
 610 
 611     if (timeout_ms != stonith_watchdog_timeout_ms) {
 612         crm_notice("New watchdog timeout %lds (was %lds)", timeout_ms/1000, stonith_watchdog_timeout_ms/1000);
 613         stonith_watchdog_timeout_ms = timeout_ms;
 614 
 615         if (stonith_watchdog_timeout_ms > 0) {
 616             int rc;
 617             xmlNode *xml;
 618             stonith_key_value_t *params = NULL;
 619 
 620             params = stonith_key_value_add(params, PCMK_STONITH_HOST_LIST,
 621                                            stonith_our_uname);
 622 
 623             xml = create_device_registration_xml("watchdog", st_namespace_internal,
 624                                                  STONITH_WATCHDOG_AGENT, params,
 625                                                  NULL);
 626             stonith_key_value_freeall(params, 1, 1);
 627             rc = stonith_device_register(xml, NULL, FALSE);
 628             free_xml(xml);
 629             if (rc != pcmk_ok) {
 630                 crm_crit("Cannot register watchdog pseudo fence agent");
 631                 crm_exit(CRM_EX_FATAL);
 632             }
 633 
 634         } else {
 635             stonith_device_remove("watchdog", FALSE);
 636         }
 637     }
 638 }
 639 
 640 /*!
 641  * \internal
 642  * \brief If a resource or any of its children are STONITH devices, update their
 643  *        definitions given a cluster working set.
 644  *
 645  * \param[in] rsc       Resource to check
 646  * \param[in] data_set  Cluster working set with device information
 647  */
 648 static void cib_device_update(pe_resource_t *rsc, pe_working_set_t *data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 649 {
 650     pe_node_t *node = NULL;
 651     const char *value = NULL;
 652     const char *rclass = NULL;
 653     pe_node_t *parent = NULL;
 654 
 655     /* If this is a complex resource, check children rather than this resource itself. */
 656     if(rsc->children) {
 657         GList *gIter = NULL;
 658         for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
 659             cib_device_update(gIter->data, data_set);
 660             if(pe_rsc_is_clone(rsc)) {
 661                 crm_trace("Only processing one copy of the clone %s", rsc->id);
 662                 break;
 663             }
 664         }
 665         return;
 666     }
 667 
 668     /* We only care about STONITH resources. */
 669     rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
 670     if (!pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
 671         return;
 672     }
 673 
 674     /* If this STONITH resource is disabled, remove it. */
 675     if (pe__resource_is_disabled(rsc)) {
 676         crm_info("Device %s has been disabled", rsc->id);
 677         return;
 678     }
 679 
 680     /* Check whether our node is allowed for this resource (and its parent if in a group) */
 681     node = our_node_allowed_for(rsc);
 682     if (rsc->parent && (rsc->parent->variant == pe_group)) {
 683         parent = our_node_allowed_for(rsc->parent);
 684     }
 685 
 686     if(node == NULL) {
 687         /* Our node is disallowed, so remove the device */
 688         GHashTableIter iter;
 689 
 690         crm_info("Device %s has been disabled on %s: unknown", rsc->id, stonith_our_uname);
 691         g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 692         while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
 693             crm_trace("Available: %s = %d", node->details->uname, node->weight);
 694         }
 695 
 696         return;
 697 
 698     } else if(node->weight < 0 || (parent && parent->weight < 0)) {
 699         /* Our node (or its group) is disallowed by score, so remove the device */
 700         char *score = score2char((node->weight < 0) ? node->weight : parent->weight);
 701 
 702         crm_info("Device %s has been disabled on %s: score=%s", rsc->id, stonith_our_uname, score);
 703         free(score);
 704 
 705         return;
 706 
 707     } else {
 708         /* Our node is allowed, so update the device information */
 709         int rc;
 710         xmlNode *data;
 711         GHashTable *rsc_params = NULL;
 712         GHashTableIter gIter;
 713         stonith_key_value_t *params = NULL;
 714 
 715         const char *name = NULL;
 716         const char *agent = crm_element_value(rsc->xml, XML_EXPR_ATTR_TYPE);
 717         const char *rsc_provides = NULL;
 718 
 719         crm_debug("Device %s is allowed on %s: score=%d", rsc->id, stonith_our_uname, node->weight);
 720         rsc_params = pe_rsc_params(rsc, node, data_set);
 721         get_meta_attributes(rsc->meta, rsc, node, data_set);
 722 
 723         rsc_provides = g_hash_table_lookup(rsc->meta, PCMK_STONITH_PROVIDES);
 724 
 725         g_hash_table_iter_init(&gIter, rsc_params);
 726         while (g_hash_table_iter_next(&gIter, (gpointer *) & name, (gpointer *) & value)) {
 727             if (!name || !value) {
 728                 continue;
 729             }
 730             params = stonith_key_value_add(params, name, value);
 731             crm_trace(" %s=%s", name, value);
 732         }
 733 
 734         data = create_device_registration_xml(rsc_name(rsc), st_namespace_any,
 735                                               agent, params, rsc_provides);
 736         stonith_key_value_freeall(params, 1, 1);
 737         rc = stonith_device_register(data, NULL, TRUE);
 738         CRM_ASSERT(rc == pcmk_ok);
 739         free_xml(data);
 740     }
 741 }
 742 
 743 /*!
 744  * \internal
 745  * \brief Update all STONITH device definitions based on current CIB
 746  */
 747 static void
 748 cib_devices_update(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 749 {
 750     GList *gIter = NULL;
 751     GHashTableIter iter;
 752     stonith_device_t *device = NULL;
 753 
 754     crm_info("Updating devices to version %s.%s.%s",
 755              crm_element_value(local_cib, XML_ATTR_GENERATION_ADMIN),
 756              crm_element_value(local_cib, XML_ATTR_GENERATION),
 757              crm_element_value(local_cib, XML_ATTR_NUMUPDATES));
 758 
 759     CRM_ASSERT(fenced_data_set != NULL);
 760     fenced_data_set->input = local_cib;
 761     fenced_data_set->now = crm_time_new(NULL);
 762     fenced_data_set->localhost = stonith_our_uname;
 763     pe__set_working_set_flags(fenced_data_set, pe_flag_quick_location);
 764 
 765     cluster_status(fenced_data_set);
 766     pcmk__schedule_actions(fenced_data_set, NULL, NULL);
 767 
 768     g_hash_table_iter_init(&iter, device_list);
 769     while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
 770         if (device->cib_registered) {
 771             device->dirty = TRUE;
 772         }
 773     }
 774 
 775     for (gIter = fenced_data_set->resources; gIter != NULL; gIter = gIter->next) {
 776         cib_device_update(gIter->data, fenced_data_set);
 777     }
 778 
 779     g_hash_table_iter_init(&iter, device_list);
 780     while (g_hash_table_iter_next(&iter, NULL, (void **)&device)) {
 781         if (device->dirty) {
 782             g_hash_table_iter_remove(&iter);
 783         }
 784     }
 785 
 786     fenced_data_set->input = NULL; // Wasn't a copy, so don't let API free it
 787     pe_reset_working_set(fenced_data_set);
 788 }
 789 
 790 static void
 791 update_cib_stonith_devices_v2(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 792 {
 793     xmlNode *change = NULL;
 794     char *reason = NULL;
 795     bool needs_update = FALSE;
 796     xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
 797 
 798     for (change = pcmk__xml_first_child(patchset); change != NULL;
 799          change = pcmk__xml_next(change)) {
 800         const char *op = crm_element_value(change, XML_DIFF_OP);
 801         const char *xpath = crm_element_value(change, XML_DIFF_PATH);
 802         const char *shortpath = NULL;
 803 
 804         if ((op == NULL) ||
 805             (strcmp(op, "move") == 0) ||
 806             strstr(xpath, "/"XML_CIB_TAG_STATUS)) {
 807             continue;
 808         } else if (pcmk__str_eq(op, "delete", pcmk__str_casei) && strstr(xpath, "/"XML_CIB_TAG_RESOURCE)) {
 809             const char *rsc_id = NULL;
 810             char *search = NULL;
 811             char *mutable = NULL;
 812 
 813             if (strstr(xpath, XML_TAG_ATTR_SETS) ||
 814                 strstr(xpath, XML_TAG_META_SETS)) {
 815                 needs_update = TRUE;
 816                 reason = strdup("(meta) attribute deleted from resource");
 817                 break;
 818             } 
 819             mutable = strdup(xpath);
 820             rsc_id = strstr(mutable, "primitive[@id=\'");
 821             if (rsc_id != NULL) {
 822                 rsc_id += strlen("primitive[@id=\'");
 823                 search = strchr(rsc_id, '\'');
 824             }
 825             if (search != NULL) {
 826                 *search = 0;
 827                 stonith_device_remove(rsc_id, TRUE);
 828             } else {
 829                 crm_warn("Ignoring malformed CIB update (resource deletion)");
 830             }
 831             free(mutable);
 832 
 833         } else if (strstr(xpath, "/"XML_CIB_TAG_RESOURCES) ||
 834                    strstr(xpath, "/"XML_CIB_TAG_CONSTRAINTS) ||
 835                    strstr(xpath, "/"XML_CIB_TAG_RSCCONFIG)) {
 836             shortpath = strrchr(xpath, '/'); CRM_ASSERT(shortpath);
 837             reason = crm_strdup_printf("%s %s", op, shortpath+1);
 838             needs_update = TRUE;
 839             break;
 840         }
 841     }
 842 
 843     if(needs_update) {
 844         crm_info("Updating device list from CIB: %s", reason);
 845         cib_devices_update();
 846     } else {
 847         crm_trace("No updates for device list found in CIB");
 848     }
 849     free(reason);
 850 }
 851 
 852 
 853 static void
 854 update_cib_stonith_devices_v1(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 855 {
 856     const char *reason = "none";
 857     gboolean needs_update = FALSE;
 858     xmlXPathObjectPtr xpath_obj = NULL;
 859 
 860     /* process new constraints */
 861     xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_CONS_TAG_RSC_LOCATION);
 862     if (numXpathResults(xpath_obj) > 0) {
 863         int max = numXpathResults(xpath_obj), lpc = 0;
 864 
 865         /* Safest and simplest to always recompute */
 866         needs_update = TRUE;
 867         reason = "new location constraint";
 868 
 869         for (lpc = 0; lpc < max; lpc++) {
 870             xmlNode *match = getXpathResult(xpath_obj, lpc);
 871 
 872             crm_log_xml_trace(match, "new constraint");
 873         }
 874     }
 875     freeXpathObject(xpath_obj);
 876 
 877     /* process deletions */
 878     xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_CIB_TAG_RESOURCE);
 879     if (numXpathResults(xpath_obj) > 0) {
 880         remove_cib_device(xpath_obj);
 881     }
 882     freeXpathObject(xpath_obj);
 883 
 884     /* process additions */
 885     xpath_obj = xpath_search(msg, "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_RESOURCE);
 886     if (numXpathResults(xpath_obj) > 0) {
 887         int max = numXpathResults(xpath_obj), lpc = 0;
 888 
 889         for (lpc = 0; lpc < max; lpc++) {
 890             const char *rsc_id = NULL;
 891             const char *standard = NULL;
 892             xmlNode *match = getXpathResult(xpath_obj, lpc);
 893 
 894             rsc_id = crm_element_value(match, XML_ATTR_ID);
 895             standard = crm_element_value(match, XML_AGENT_ATTR_CLASS);
 896 
 897             if (!pcmk__str_eq(standard, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
 898                 continue;
 899             }
 900 
 901             crm_trace("Fencing resource %s was added or modified", rsc_id);
 902             reason = "new resource";
 903             needs_update = TRUE;
 904         }
 905     }
 906     freeXpathObject(xpath_obj);
 907 
 908     if(needs_update) {
 909         crm_info("Updating device list from CIB: %s", reason);
 910         cib_devices_update();
 911     }
 912 }
 913 
 914 static void
 915 update_cib_stonith_devices(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 916 {
 917     int format = 1;
 918     xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
 919 
 920     CRM_ASSERT(patchset);
 921     crm_element_value_int(patchset, "format", &format);
 922     switch(format) {
 923         case 1:
 924             update_cib_stonith_devices_v1(event, msg);
 925             break;
 926         case 2:
 927             update_cib_stonith_devices_v2(event, msg);
 928             break;
 929         default:
 930             crm_warn("Unknown patch format: %d", format);
 931     }
 932 }
 933 
 934 /* Needs to hold node name + attribute name + attribute value + 75 */
 935 #define XPATH_MAX 512
 936 
 937 /*!
 938  * \internal
 939  * \brief Check whether a node has a specific attribute name/value
 940  *
 941  * \param[in] node    Name of node to check
 942  * \param[in] name    Name of an attribute to look for
 943  * \param[in] value   The value the named attribute needs to be set to in order to be considered a match
 944  *
 945  * \return TRUE if the locally cached CIB has the specified node attribute
 946  */
 947 gboolean
 948 node_has_attr(const char *node, const char *name, const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 949 {
 950     char xpath[XPATH_MAX];
 951     xmlNode *match;
 952     int n;
 953 
 954     CRM_CHECK(local_cib != NULL, return FALSE);
 955 
 956     /* Search for the node's attributes in the CIB. While the schema allows
 957      * multiple sets of instance attributes, and allows instance attributes to
 958      * use id-ref to reference values elsewhere, that is intended for resources,
 959      * so we ignore that here.
 960      */
 961     n = snprintf(xpath, XPATH_MAX, "//" XML_CIB_TAG_NODES
 962                  "/" XML_CIB_TAG_NODE "[@uname='%s']/" XML_TAG_ATTR_SETS
 963                  "/" XML_CIB_TAG_NVPAIR "[@name='%s' and @value='%s']",
 964                  node, name, value);
 965     match = get_xpath_object(xpath, local_cib, LOG_NEVER);
 966 
 967     CRM_CHECK(n < XPATH_MAX, return FALSE);
 968     return (match != NULL);
 969 }
 970 
 971 static void
 972 update_fencing_topology(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 973 {
 974     int format = 1;
 975     const char *xpath;
 976     xmlXPathObjectPtr xpathObj = NULL;
 977     xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
 978 
 979     CRM_ASSERT(patchset);
 980     crm_element_value_int(patchset, "format", &format);
 981 
 982     if(format == 1) {
 983         /* Process deletions (only) */
 984         xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_REMOVED "//" XML_TAG_FENCING_LEVEL;
 985         xpathObj = xpath_search(msg, xpath);
 986 
 987         remove_fencing_topology(xpathObj);
 988         freeXpathObject(xpathObj);
 989 
 990         /* Process additions and changes */
 991         xpath = "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_TAG_FENCING_LEVEL;
 992         xpathObj = xpath_search(msg, xpath);
 993 
 994         register_fencing_topology(xpathObj);
 995         freeXpathObject(xpathObj);
 996 
 997     } else if(format == 2) {
 998         xmlNode *change = NULL;
 999         int add[] = { 0, 0, 0 };
1000         int del[] = { 0, 0, 0 };
1001 
1002         xml_patch_versions(patchset, add, del);
1003 
1004         for (change = pcmk__xml_first_child(patchset); change != NULL;
1005              change = pcmk__xml_next(change)) {
1006             const char *op = crm_element_value(change, XML_DIFF_OP);
1007             const char *xpath = crm_element_value(change, XML_DIFF_PATH);
1008 
1009             if(op == NULL) {
1010                 continue;
1011 
1012             } else if(strstr(xpath, "/" XML_TAG_FENCING_LEVEL) != NULL) {
1013                 /* Change to a specific entry */
1014 
1015                 crm_trace("Handling %s operation %d.%d.%d for %s", op, add[0], add[1], add[2], xpath);
1016                 if(strcmp(op, "move") == 0) {
1017                     continue;
1018 
1019                 } else if(strcmp(op, "create") == 0) {
1020                     handle_topology_change(change->children, FALSE);
1021 
1022                 } else if(strcmp(op, "modify") == 0) {
1023                     xmlNode *match = first_named_child(change, XML_DIFF_RESULT);
1024 
1025                     if(match) {
1026                         handle_topology_change(match->children, TRUE);
1027                     }
1028 
1029                 } else if(strcmp(op, "delete") == 0) {
1030                     /* Nuclear option, all we have is the path and an id... not enough to remove a specific entry */
1031                     crm_info("Re-initializing fencing topology after %s operation %d.%d.%d for %s",
1032                              op, add[0], add[1], add[2], xpath);
1033                     fencing_topology_init();
1034                     return;
1035                 }
1036 
1037             } else if (strstr(xpath, "/" XML_TAG_FENCING_TOPOLOGY) != NULL) {
1038                 /* Change to the topology in general */
1039                 crm_info("Re-initializing fencing topology after top-level %s operation  %d.%d.%d for %s",
1040                          op, add[0], add[1], add[2], xpath);
1041                 fencing_topology_init();
1042                 return;
1043 
1044             } else if (strstr(xpath, "/" XML_CIB_TAG_CONFIGURATION)) {
1045                 /* Changes to the whole config section, possibly including the topology as a whild */
1046                 if(first_named_child(change, XML_TAG_FENCING_TOPOLOGY) == NULL) {
1047                     crm_trace("Nothing for us in %s operation %d.%d.%d for %s.",
1048                               op, add[0], add[1], add[2], xpath);
1049 
1050                 } else if(strcmp(op, "delete") == 0 || strcmp(op, "create") == 0) {
1051                     crm_info("Re-initializing fencing topology after top-level %s operation %d.%d.%d for %s.",
1052                              op, add[0], add[1], add[2], xpath);
1053                     fencing_topology_init();
1054                     return;
1055                 }
1056 
1057             } else {
1058                 crm_trace("Nothing for us in %s operation %d.%d.%d for %s",
1059                           op, add[0], add[1], add[2], xpath);
1060             }
1061         }
1062 
1063     } else {
1064         crm_warn("Unknown patch format: %d", format);
1065     }
1066 }
1067 static bool have_cib_devices = FALSE;
1068 
1069 static void
1070 update_cib_cache_cb(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
1071 {
1072     int rc = pcmk_ok;
1073     xmlNode *stonith_enabled_xml = NULL;
1074     const char *stonith_enabled_s = NULL;
1075     static gboolean stonith_enabled_saved = TRUE;
1076 
1077     if(!have_cib_devices) {
1078         crm_trace("Skipping updates until we get a full dump");
1079         return;
1080 
1081     } else if(msg == NULL) {
1082         crm_trace("Missing %s update", event);
1083         return;
1084     }
1085 
1086     /* Maintain a local copy of the CIB so that we have full access
1087      * to device definitions, location constraints, and node attributes
1088      */
1089     if (local_cib != NULL) {
1090         int rc = pcmk_ok;
1091         xmlNode *patchset = NULL;
1092 
1093         crm_element_value_int(msg, F_CIB_RC, &rc);
1094         if (rc != pcmk_ok) {
1095             return;
1096         }
1097 
1098         patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
1099         xml_log_patchset(LOG_TRACE, "Config update", patchset);
1100         rc = xml_apply_patchset(local_cib, patchset, TRUE);
1101         switch (rc) {
1102             case pcmk_ok:
1103             case -pcmk_err_old_data:
1104                 break;
1105             case -pcmk_err_diff_resync:
1106             case -pcmk_err_diff_failed:
1107                 crm_notice("[%s] Patch aborted: %s (%d)", event, pcmk_strerror(rc), rc);
1108                 free_xml(local_cib);
1109                 local_cib = NULL;
1110                 break;
1111             default:
1112                 crm_warn("[%s] ABORTED: %s (%d)", event, pcmk_strerror(rc), rc);
1113                 free_xml(local_cib);
1114                 local_cib = NULL;
1115         }
1116     }
1117 
1118     if (local_cib == NULL) {
1119         crm_trace("Re-requesting full CIB");
1120         rc = cib_api->cmds->query(cib_api, NULL, &local_cib, cib_scope_local | cib_sync_call);
1121         if(rc != pcmk_ok) {
1122             crm_err("Couldn't retrieve the CIB: %s (%d)", pcmk_strerror(rc), rc);
1123             return;
1124         }
1125         CRM_ASSERT(local_cib != NULL);
1126         stonith_enabled_saved = FALSE; /* Trigger a full refresh below */
1127     }
1128 
1129     pcmk__refresh_node_caches_from_cib(local_cib);
1130 
1131     stonith_enabled_xml = get_xpath_object("//nvpair[@name='stonith-enabled']",
1132                                            local_cib, LOG_NEVER);
1133     if (stonith_enabled_xml) {
1134         stonith_enabled_s = crm_element_value(stonith_enabled_xml, XML_NVPAIR_ATTR_VALUE);
1135     }
1136 
1137     watchdog_device_update(local_cib);
1138 
1139     if (stonith_enabled_s && crm_is_true(stonith_enabled_s) == FALSE) {
1140         crm_trace("Ignoring CIB updates while fencing is disabled");
1141         stonith_enabled_saved = FALSE;
1142         return;
1143 
1144     } else if (stonith_enabled_saved == FALSE) {
1145         crm_info("Updating fencing device and topology lists "
1146                  "now that fencing is enabled");
1147         stonith_enabled_saved = TRUE;
1148         fencing_topology_init();
1149         cib_devices_update();
1150 
1151     } else {
1152         update_fencing_topology(event, msg);
1153         update_cib_stonith_devices(event, msg);
1154     }
1155 }
1156 
1157 static void
1158 init_cib_cache_cb(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
1159 {
1160     crm_info("Updating device list from CIB");
1161     have_cib_devices = TRUE;
1162     local_cib = copy_xml(output);
1163 
1164     pcmk__refresh_node_caches_from_cib(local_cib);
1165 
1166     fencing_topology_init();
1167     watchdog_device_update(local_cib);
1168     cib_devices_update();
1169 }
1170 
1171 static void
1172 stonith_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
1173 {
1174     crm_info("Terminating with %d clients", pcmk__ipc_client_count());
1175     stonith_shutdown_flag = TRUE;
1176     if (mainloop != NULL && g_main_loop_is_running(mainloop)) {
1177         g_main_loop_quit(mainloop);
1178     } else {
1179         stonith_cleanup();
1180         crm_exit(CRM_EX_OK);
1181     }
1182 }
1183 
1184 static void
1185 cib_connection_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
1186 {
1187     if (stonith_shutdown_flag) {
1188         crm_info("Connection to the CIB manager closed");
1189         return;
1190     } else {
1191         crm_crit("Lost connection to the CIB manager, shutting down");
1192     }
1193     if (cib_api) {
1194         cib_api->cmds->signoff(cib_api);
1195     }
1196     stonith_shutdown(0);
1197 }
1198 
1199 static void
1200 stonith_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1201 {
1202     if (cib_api) {
1203         cib_api->cmds->del_notify_callback(cib_api, T_CIB_DIFF_NOTIFY, update_cib_cache_cb);
1204         cib_api->cmds->signoff(cib_api);
1205     }
1206 
1207     if (ipcs) {
1208         qb_ipcs_destroy(ipcs);
1209     }
1210 
1211     crm_peer_destroy();
1212     pcmk__client_cleanup();
1213     free_stonith_remote_op_list();
1214     free_topology_list();
1215     free_device_list();
1216     free_metadata_cache();
1217 
1218     free(stonith_our_uname);
1219     stonith_our_uname = NULL;
1220 
1221     free_xml(local_cib);
1222     local_cib = NULL;
1223 }
1224 
1225 static pcmk__cli_option_t long_options[] = {
1226     // long option, argument type, storage, short option, description, flags
1227     {
1228         "stand-alone", no_argument, 0, 's',
1229         NULL, pcmk__option_default
1230     },
1231     {
1232         "stand-alone-w-cpg", no_argument, 0, 'c',
1233         NULL, pcmk__option_default
1234     },
1235     {
1236         "logfile", required_argument, 0, 'l',
1237         NULL, pcmk__option_default
1238     },
1239     {
1240         "verbose", no_argument, 0, 'V',
1241         NULL, pcmk__option_default
1242     },
1243     {
1244         "version", no_argument, 0, '$',
1245         NULL, pcmk__option_default
1246     },
1247     {
1248         "help", no_argument, 0, '?',
1249         NULL, pcmk__option_default
1250     },
1251     { 0, 0, 0, 0 }
1252 };
1253 
1254 static void
1255 setup_cib(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1256 {
1257     int rc, retries = 0;
1258 
1259     cib_api = cib_new();
1260     if (cib_api == NULL) {
1261         crm_err("No connection to the CIB manager");
1262         return;
1263     }
1264 
1265     do {
1266         sleep(retries);
1267         rc = cib_api->cmds->signon(cib_api, CRM_SYSTEM_STONITHD, cib_command);
1268     } while (rc == -ENOTCONN && ++retries < 5);
1269 
1270     if (rc != pcmk_ok) {
1271         crm_err("Could not connect to the CIB manager: %s (%d)", pcmk_strerror(rc), rc);
1272 
1273     } else if (pcmk_ok !=
1274                cib_api->cmds->add_notify_callback(cib_api, T_CIB_DIFF_NOTIFY, update_cib_cache_cb)) {
1275         crm_err("Could not set CIB notification callback");
1276 
1277     } else {
1278         rc = cib_api->cmds->query(cib_api, NULL, NULL, cib_scope_local);
1279         cib_api->cmds->register_callback(cib_api, rc, 120, FALSE, NULL, "init_cib_cache_cb",
1280                                          init_cib_cache_cb);
1281         cib_api->cmds->set_connection_dnotify(cib_api, cib_connection_destroy);
1282         crm_info("Watching for fencing topology changes");
1283     }
1284 }
1285 
1286 struct qb_ipcs_service_handlers ipc_callbacks = {
1287     .connection_accept = st_ipc_accept,
1288     .connection_created = NULL,
1289     .msg_process = st_ipc_dispatch,
1290     .connection_closed = st_ipc_closed,
1291     .connection_destroyed = st_ipc_destroy
1292 };
1293 
1294 /*!
1295  * \internal
1296  * \brief Callback for peer status changes
1297  *
1298  * \param[in] type  What changed
1299  * \param[in] node  What peer had the change
1300  * \param[in] data  Previous value of what changed
1301  */
1302 static void
1303 st_peer_update_callback(enum crm_status_type type, crm_node_t * node, const void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
1304 {
1305     if ((type != crm_status_processes)
1306         && !pcmk_is_set(node->flags, crm_remote_node)) {
1307         /*
1308          * This is a hack until we can send to a nodeid and/or we fix node name lookups
1309          * These messages are ignored in stonith_peer_callback()
1310          */
1311         xmlNode *query = create_xml_node(NULL, "stonith_command");
1312 
1313         crm_xml_add(query, F_XML_TAGNAME, "stonith_command");
1314         crm_xml_add(query, F_TYPE, T_STONITH_NG);
1315         crm_xml_add(query, F_STONITH_OPERATION, "poke");
1316 
1317         crm_debug("Broadcasting our uname because of node %u", node->id);
1318         send_cluster_message(NULL, crm_msg_stonith_ng, query, FALSE);
1319 
1320         free_xml(query);
1321     }
1322 }
1323 
1324 int
1325 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
1326 {
1327     int flag;
1328     int lpc = 0;
1329     int argerr = 0;
1330     int option_index = 0;
1331     crm_cluster_t *cluster = NULL;
1332     const char *actions[] = { "reboot", "off", "on", "list", "monitor", "status" };
1333     crm_ipc_t *old_instance = NULL;
1334     int rc = pcmk_rc_ok;
1335 
1336     crm_log_preinit(NULL, argc, argv);
1337     pcmk__set_cli_options(NULL, "[options]", long_options,
1338                           "daemon for executing fencing devices in a "
1339                           "Pacemaker cluster");
1340 
1341     while (1) {
1342         flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
1343         if (flag == -1) {
1344             break;
1345         }
1346 
1347         switch (flag) {
1348             case 'V':
1349                 crm_bump_log_level(argc, argv);
1350                 break;
1351             case 'l':
1352                 {
1353                     int rc = pcmk__add_logfile(optarg);
1354 
1355                     if (rc != pcmk_rc_ok) {
1356                         /* Logging has not yet been initialized, so stderr is
1357                          * the only way to get information out
1358                          */
1359                         fprintf(stderr, "Logging to %s is disabled: %s\n",
1360                                 optarg, pcmk_rc_str(rc));
1361                     }
1362                 }
1363                 break;
1364             case 's':
1365                 stand_alone = TRUE;
1366                 break;
1367             case 'c':
1368                 stand_alone = FALSE;
1369                 no_cib_connect = TRUE;
1370                 break;
1371             case '$':
1372             case '?':
1373                 pcmk__cli_help(flag, CRM_EX_OK);
1374                 break;
1375             default:
1376                 ++argerr;
1377                 break;
1378         }
1379     }
1380 
1381     if (argc - optind == 1 && pcmk__str_eq("metadata", argv[optind], pcmk__str_casei)) {
1382         printf("<?xml version=\"1.0\"?><!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n");
1383         printf("<resource-agent name=\"pacemaker-fenced\">\n");
1384         printf(" <version>1.0</version>\n");
1385         printf(" <longdesc lang=\"en\">Instance attributes available for all \"stonith\"-class resources"
1386                                        " and used by Pacemaker's fence daemon, formerly known as stonithd</longdesc>\n");
1387         printf(" <shortdesc lang=\"en\">Instance attributes available for all \"stonith\"-class resources</shortdesc>\n");
1388         printf(" <parameters>\n");
1389 
1390 #if 0
1391         // priority is not implemented yet
1392         printf("  <parameter name=\"priority\" unique=\"0\">\n");
1393         printf("    <shortdesc lang=\"en\">Devices that are not in a topology "
1394                "are tried in order of highest to lowest integer priority</shortdesc>\n");
1395         printf("    <content type=\"integer\" default=\"0\"/>\n");
1396         printf("  </parameter>\n");
1397 #endif
1398 
1399         printf("  <parameter name=\"%s\" unique=\"0\">\n",
1400                PCMK_STONITH_HOST_ARGUMENT);
1401         printf
1402             ("    <shortdesc lang=\"en\">Advanced use only: An alternate parameter to supply instead of 'port'</shortdesc>\n");
1403         printf
1404             ("    <longdesc lang=\"en\">Some devices do not support the standard 'port' parameter or may provide additional ones.\n"
1405              "Use this to specify an alternate, device-specific, parameter that should indicate the machine to be fenced.\n"
1406              "A value of 'none' can be used to tell the cluster not to supply any additional parameters.\n"
1407              "     </longdesc>\n");
1408         printf("    <content type=\"string\" default=\"port\"/>\n");
1409         printf("  </parameter>\n");
1410 
1411         printf("  <parameter name=\"%s\" unique=\"0\">\n",
1412                PCMK_STONITH_HOST_MAP);
1413         printf
1414             ("    <shortdesc lang=\"en\">A mapping of host names to ports numbers for devices that do not support host names.</shortdesc>\n");
1415         printf
1416             ("    <longdesc lang=\"en\">Eg. node1:1;node2:2,3 would tell the cluster to use port 1 for node1 and ports 2 and 3 for node2</longdesc>\n");
1417         printf("    <content type=\"string\" default=\"\"/>\n");
1418         printf("  </parameter>\n");
1419 
1420         printf("  <parameter name=\"%s\" unique=\"0\">\n",
1421                PCMK_STONITH_HOST_LIST);
1422         printf("    <shortdesc lang=\"en\">A list of machines controlled by "
1423                "this device (Optional unless %s=static-list).</shortdesc>\n",
1424                PCMK_STONITH_HOST_CHECK);
1425         printf("    <content type=\"string\" default=\"\"/>\n");
1426         printf("  </parameter>\n");
1427 
1428         printf("  <parameter name=\"%s\" unique=\"0\">\n",
1429                PCMK_STONITH_HOST_CHECK);
1430         printf
1431             ("    <shortdesc lang=\"en\">How to determine which machines are controlled by the device.</shortdesc>\n");
1432         printf("    <longdesc lang=\"en\">Allowed values: dynamic-list "
1433                "(query the device via the 'list' command), static-list "
1434                "(check the " PCMK_STONITH_HOST_LIST " attribute), status "
1435                "(query the device via the 'status' command), none (assume "
1436                "every device can fence every machine)</longdesc>\n");
1437         printf("    <content type=\"string\" default=\"dynamic-list\"/>\n");
1438         printf("  </parameter>\n");
1439 
1440         printf("  <parameter name=\"%s\" unique=\"0\">\n",
1441                PCMK_STONITH_DELAY_MAX);
1442         printf("    <shortdesc lang=\"en\">Enable a delay of no more than the "
1443                "time specified before executing fencing actions. Pacemaker "
1444                "derives the overall delay by taking the value of "
1445                PCMK_STONITH_DELAY_BASE " and adding a random delay value such "
1446                "that the sum is kept below this maximum.</shortdesc>\n");
1447         printf("    <longdesc lang=\"en\">This prevents double fencing when "
1448                "using slow devices such as sbd.\nUse this to enable a random "
1449                "delay for fencing actions.\nThe overall delay is derived from "
1450                "this random delay value adding a static delay so that the sum "
1451                "is kept below the maximum delay.</longdesc>\n");
1452         printf("    <content type=\"time\" default=\"0s\"/>\n");
1453         printf("  </parameter>\n");
1454 
1455         printf("  <parameter name=\"%s\" unique=\"0\">\n",
1456                PCMK_STONITH_DELAY_BASE);
1457         printf("    <shortdesc lang=\"en\">Enable a base delay for "
1458                "fencing actions and specify base delay value.</shortdesc>\n");
1459         printf("    <longdesc lang=\"en\">This prevents double fencing when "
1460                "different delays are configured on the nodes.\nUse this to "
1461                "enable a static delay for fencing actions.\nThe overall delay "
1462                "is derived from a random delay value adding this static delay "
1463                "so that the sum is kept below the maximum delay.</longdesc>\n");
1464         printf("    <content type=\"time\" default=\"0s\"/>\n");
1465         printf("  </parameter>\n");
1466 
1467         printf("  <parameter name=\"%s\" unique=\"0\">\n",
1468                PCMK_STONITH_ACTION_LIMIT);
1469         printf
1470             ("    <shortdesc lang=\"en\">The maximum number of actions can be performed in parallel on this device</shortdesc>\n");
1471         printf
1472             ("    <longdesc lang=\"en\">Cluster property concurrent-fencing=true needs to be configured first.\n"
1473              "Then use this to specify the maximum number of actions can be performed in parallel on this device. -1 is unlimited.</longdesc>\n");
1474         printf("    <content type=\"integer\" default=\"1\"/>\n");
1475         printf("  </parameter>\n");
1476 
1477 
1478         for (lpc = 0; lpc < PCMK__NELEM(actions); lpc++) {
1479             printf("  <parameter name=\"pcmk_%s_action\" unique=\"0\">\n", actions[lpc]);
1480             printf
1481                 ("    <shortdesc lang=\"en\">Advanced use only: An alternate command to run instead of '%s'</shortdesc>\n",
1482                  actions[lpc]);
1483             printf
1484                 ("    <longdesc lang=\"en\">Some devices do not support the standard commands or may provide additional ones.\n"
1485                  "Use this to specify an alternate, device-specific, command that implements the '%s' action.</longdesc>\n",
1486                  actions[lpc]);
1487             printf("    <content type=\"string\" default=\"%s\"/>\n", actions[lpc]);
1488             printf("  </parameter>\n");
1489 
1490             printf("  <parameter name=\"pcmk_%s_timeout\" unique=\"0\">\n", actions[lpc]);
1491             printf
1492                 ("    <shortdesc lang=\"en\">Advanced use only: Specify an alternate timeout to use for %s actions instead of stonith-timeout</shortdesc>\n",
1493                  actions[lpc]);
1494             printf
1495                 ("    <longdesc lang=\"en\">Some devices need much more/less time to complete than normal.\n"
1496                  "Use this to specify an alternate, device-specific, timeout for '%s' actions.</longdesc>\n",
1497                  actions[lpc]);
1498             printf("    <content type=\"time\" default=\"60s\"/>\n");
1499             printf("  </parameter>\n");
1500 
1501             printf("  <parameter name=\"pcmk_%s_retries\" unique=\"0\">\n", actions[lpc]);
1502             printf
1503                 ("    <shortdesc lang=\"en\">Advanced use only: The maximum number of times to retry the '%s' command within the timeout period</shortdesc>\n",
1504                  actions[lpc]);
1505             printf("    <longdesc lang=\"en\">Some devices do not support multiple connections."
1506                    " Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining."
1507                    " Use this option to alter the number of times Pacemaker retries '%s' actions before giving up."
1508                    "</longdesc>\n", actions[lpc]);
1509             printf("    <content type=\"integer\" default=\"2\"/>\n");
1510             printf("  </parameter>\n");
1511         }
1512 
1513         printf(" </parameters>\n");
1514         printf("</resource-agent>\n");
1515         return CRM_EX_OK;
1516     }
1517 
1518     if (optind != argc) {
1519         ++argerr;
1520     }
1521 
1522     if (argerr) {
1523         pcmk__cli_help('?', CRM_EX_USAGE);
1524     }
1525 
1526     crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
1527 
1528     crm_notice("Starting Pacemaker fencer");
1529 
1530     old_instance = crm_ipc_new("stonith-ng", 0);
1531     if (crm_ipc_connect(old_instance)) {
1532         /* IPC end-point already up */
1533         crm_ipc_close(old_instance);
1534         crm_ipc_destroy(old_instance);
1535         crm_err("pacemaker-fenced is already active, aborting startup");
1536         crm_exit(CRM_EX_OK);
1537     } else {
1538         /* not up or not authentic, we'll proceed either way */
1539         crm_ipc_destroy(old_instance);
1540         old_instance = NULL;
1541     }
1542 
1543     mainloop_add_signal(SIGTERM, stonith_shutdown);
1544 
1545     crm_peer_init();
1546 
1547     fenced_data_set = pe_new_working_set();
1548     CRM_ASSERT(fenced_data_set != NULL);
1549     pe__set_working_set_flags(fenced_data_set,
1550                               pe_flag_no_counts|pe_flag_no_compat);
1551     pe__set_working_set_flags(fenced_data_set, pe_flag_show_utilization);
1552 
1553     cluster = calloc(1, sizeof(crm_cluster_t));
1554     CRM_ASSERT(cluster != NULL);
1555 
1556     if (stand_alone == FALSE) {
1557 
1558         if (is_corosync_cluster()) {
1559 #if SUPPORT_COROSYNC
1560             cluster->destroy = stonith_peer_cs_destroy;
1561             cluster->cpg.cpg_deliver_fn = stonith_peer_ais_callback;
1562             cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership;
1563 #endif
1564         }
1565 
1566         crm_set_status_callback(&st_peer_update_callback);
1567 
1568         if (crm_cluster_connect(cluster) == FALSE) {
1569             crm_crit("Cannot sign in to the cluster... terminating");
1570             crm_exit(CRM_EX_FATAL);
1571         }
1572         stonith_our_uname = strdup(cluster->uname);
1573 
1574         if (no_cib_connect == FALSE) {
1575             setup_cib();
1576         }
1577 
1578     } else {
1579         stonith_our_uname = strdup("localhost");
1580     }
1581 
1582     init_device_list();
1583     init_topology_list();
1584 
1585     pcmk__serve_fenced_ipc(&ipcs, &ipc_callbacks);
1586 
1587     pcmk__register_formats(NULL, formats);
1588     rc = pcmk__output_new(&out, "log", NULL, argv);
1589     if ((rc != pcmk_rc_ok) || (out == NULL)) {
1590         crm_err("Can't log resource details due to internal error: %s\n",
1591                 pcmk_rc_str(rc));
1592         crm_exit(CRM_EX_FATAL);
1593     }
1594 
1595     pe__register_messages(out);
1596     pcmk__register_lib_messages(out);
1597 
1598     pcmk__output_set_log_level(out, LOG_TRACE);
1599     fenced_data_set->priv = out;
1600 
1601     /* Create the mainloop and run it... */
1602     mainloop = g_main_loop_new(NULL, FALSE);
1603     crm_notice("Pacemaker fencer successfully started and accepting connections");
1604     g_main_loop_run(mainloop);
1605 
1606     stonith_cleanup();
1607     free(cluster->uuid);
1608     free(cluster->uname);
1609     free(cluster);
1610     pe_free_working_set(fenced_data_set);
1611 
1612     pcmk__unregister_formats();
1613     out->finish(out, CRM_EX_OK, true, NULL);
1614     pcmk__output_free(out);
1615 
1616     crm_exit(CRM_EX_OK);
1617 }

/* [previous][next][first][last][top][bottom][index][help] */