root/fencing/main.c

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

DEFINITIONS

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

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

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