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. cib_device_update
  24. cib_devices_update
  25. update_cib_stonith_devices_v2
  26. update_cib_stonith_devices_v1
  27. update_cib_stonith_devices
  28. node_has_attr
  29. update_fencing_topology
  30. update_cib_cache_cb
  31. init_cib_cache_cb
  32. stonith_shutdown
  33. cib_connection_destroy
  34. stonith_cleanup
  35. setup_cib
  36. st_peer_update_callback
  37. main

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

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