root/crmd/pengine.c

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

DEFINITIONS

This source file includes following definitions.
  1. save_cib_contents
  2. pe_ipc_destroy
  3. pe_ipc_dispatch
  4. do_pe_control
  5. do_pe_invoke
  6. force_local_option
  7. do_pe_invoke_callback

   1 /* 
   2  * Copyright (C) 2004 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 <unistd.h>  /* pid_t, sleep, ssize_t */
  22 
  23 #include <crm/cib.h>
  24 #include <crm/cluster.h>
  25 #include <crm/common/xml.h>
  26 #include <crm/crm.h>
  27 #include <crm/msg_xml.h>
  28 
  29 #include <crmd.h>
  30 #include <crmd_fsa.h>
  31 #include <crmd_messages.h>  /* register_fsa_error_adv */
  32 
  33 
  34 struct crm_subsystem_s *pe_subsystem = NULL;
  35 void do_pe_invoke_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data);
  36 
  37 static void
  38 save_cib_contents(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40     char *id = user_data;
  41 
  42     register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
  43     CRM_CHECK(id != NULL, return);
  44 
  45     if (rc == pcmk_ok) {
  46         int len = 15;
  47         char *filename = NULL;
  48 
  49         len += strlen(id);
  50         len += strlen(PE_STATE_DIR);
  51 
  52         filename = calloc(1, len);
  53         CRM_CHECK(filename != NULL, return);
  54 
  55         sprintf(filename, PE_STATE_DIR "/pe-core-%s.bz2", id);
  56         if (write_xml_file(output, filename, TRUE) < 0) {
  57             crm_err("Could not save Cluster Information Base to %s after Policy Engine crash",
  58                     filename);
  59         } else {
  60             crm_notice("Saved Cluster Information Base to %s after Policy Engine crash",
  61                        filename);
  62         }
  63 
  64         free(filename);
  65     }
  66 }
  67 
  68 static void
  69 pe_ipc_destroy(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71     if (is_set(fsa_input_register, pe_subsystem->flag_required)) {
  72         int rc = pcmk_ok;
  73         char *uuid_str = crm_generate_uuid();
  74 
  75         crm_crit("Connection to the Policy Engine failed "
  76                  CRM_XS " pid=%d uuid=%s", pe_subsystem->pid, uuid_str);
  77 
  78         /*
  79          * The PE died...
  80          *
  81          * Save the current CIB so that we have a chance of
  82          * figuring out what killed it.
  83          *
  84          * Delay raising the I_ERROR until the query below completes or
  85          * 5s is up, whichever comes first.
  86          *
  87          */
  88         rc = fsa_cib_conn->cmds->query(fsa_cib_conn, NULL, NULL, cib_scope_local);
  89         fsa_register_cib_callback(rc, FALSE, uuid_str, save_cib_contents);
  90 
  91     } else {
  92         if (is_heartbeat_cluster()) {
  93             stop_subsystem(pe_subsystem, FALSE);
  94         }
  95         crm_info("Connection to the Policy Engine released");
  96     }
  97 
  98     clear_bit(fsa_input_register, pe_subsystem->flag_connected);
  99     pe_subsystem->pid = -1;
 100     pe_subsystem->source = NULL;
 101     pe_subsystem->client = NULL;
 102 
 103     mainloop_set_trigger(fsa_source);
 104     return;
 105 }
 106 
 107 static int
 108 pe_ipc_dispatch(const char *buffer, ssize_t length, gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110     xmlNode *msg = string2xml(buffer);
 111 
 112     if (msg) {
 113         route_message(C_IPC_MESSAGE, msg);
 114     }
 115 
 116     free_xml(msg);
 117     return 0;
 118 }
 119 
 120 /*       A_PE_START, A_PE_STOP, A_TE_RESTART    */
 121 void
 122 do_pe_control(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 123               enum crmd_fsa_cause cause,
 124               enum crmd_fsa_state cur_state,
 125               enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 126 {
 127     struct crm_subsystem_s *this_subsys = pe_subsystem;
 128 
 129     long long stop_actions = A_PE_STOP;
 130     long long start_actions = A_PE_START;
 131 
 132     static struct ipc_client_callbacks pe_callbacks = {
 133         .dispatch = pe_ipc_dispatch,
 134         .destroy = pe_ipc_destroy
 135     };
 136 
 137     if (action & stop_actions) {
 138         clear_bit(fsa_input_register, pe_subsystem->flag_required);
 139 
 140         mainloop_del_ipc_client(pe_subsystem->source);
 141         pe_subsystem->source = NULL;
 142 
 143         clear_bit(fsa_input_register, pe_subsystem->flag_connected);
 144     }
 145 
 146     if ((action & start_actions) && (is_set(fsa_input_register, R_PE_CONNECTED) == FALSE)) {
 147         if (cur_state != S_STOPPING) {
 148             set_bit(fsa_input_register, pe_subsystem->flag_required);
 149 
 150             pe_subsystem->source =
 151                 mainloop_add_ipc_client(CRM_SYSTEM_PENGINE, G_PRIORITY_DEFAULT,
 152                                         5 * 1024 * 1024 /* 5MB */ , NULL, &pe_callbacks);
 153 
 154             if (pe_subsystem->source == NULL) {
 155                 crm_warn("Setup of client connection failed, not adding channel to mainloop");
 156                 register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
 157                 return;
 158             }
 159 
 160             /* if (is_openais_cluster()) { */
 161             /*     pe_subsystem->pid = pe_subsystem->ipc->farside_pid; */
 162             /* } */
 163 
 164             set_bit(fsa_input_register, pe_subsystem->flag_connected);
 165 
 166         } else {
 167             crm_info("Ignoring request to start %s while shutting down", this_subsys->name);
 168         }
 169     }
 170 }
 171 
 172 int fsa_pe_query = 0;
 173 char *fsa_pe_ref = NULL;
 174 
 175 /*       A_PE_INVOKE    */
 176 void
 177 do_pe_invoke(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
 178              enum crmd_fsa_cause cause,
 179              enum crmd_fsa_state cur_state,
 180              enum crmd_fsa_input current_input, fsa_data_t * msg_data)
 181 {
 182     if (AM_I_DC == FALSE) {
 183         crm_err("Not invoking Policy Engine because not DC: %s",
 184                 fsa_action2string(action));
 185         return;
 186     }
 187 
 188     if (is_set(fsa_input_register, R_PE_CONNECTED) == FALSE) {
 189         if (is_set(fsa_input_register, R_SHUTDOWN)) {
 190             crm_err("Cannot shut down gracefully without the Policy Engine");
 191             register_fsa_input_before(C_FSA_INTERNAL, I_TERMINATE, NULL);
 192 
 193         } else {
 194             crm_info("Waiting for the Policy Engine to connect");
 195             crmd_fsa_stall(FALSE);
 196             register_fsa_action(A_PE_START);
 197         }
 198         return;
 199     }
 200 
 201     if (cur_state != S_POLICY_ENGINE) {
 202         crm_notice("Not invoking Policy Engine because in state %s",
 203                    fsa_state2string(cur_state));
 204         return;
 205     }
 206     if (is_set(fsa_input_register, R_HAVE_CIB) == FALSE) {
 207         crm_err("Attempted to invoke Policy Engine without consistent Cluster Information Base!");
 208 
 209         /* start the join from scratch */
 210         register_fsa_input_before(C_FSA_INTERNAL, I_ELECTION, NULL);
 211         return;
 212     }
 213 
 214     fsa_pe_query = fsa_cib_conn->cmds->query(fsa_cib_conn, NULL, NULL, cib_scope_local);
 215 
 216     crm_debug("Query %d: Requesting the current CIB: %s", fsa_pe_query,
 217               fsa_state2string(fsa_state));
 218 
 219     /* Make sure any queued calculations are discarded */
 220     free(fsa_pe_ref);
 221     fsa_pe_ref = NULL;
 222 
 223     fsa_register_cib_callback(fsa_pe_query, FALSE, NULL, do_pe_invoke_callback);
 224 }
 225 
 226 static void
 227 force_local_option(xmlNode *xml, const char *attr_name, const char *attr_value)
     /* [previous][next][first][last][top][bottom][index][help] */
 228 {
 229     int max = 0;
 230     int lpc = 0;
 231     int xpath_max = 1024;
 232     char *xpath_string = NULL;
 233     xmlXPathObjectPtr xpathObj = NULL;
 234 
 235     xpath_string = calloc(1, xpath_max);
 236     lpc = snprintf(xpath_string, xpath_max, "%.128s//%s//nvpair[@name='%.128s']",
 237                        get_object_path(XML_CIB_TAG_CRMCONFIG), XML_CIB_TAG_PROPSET, attr_name);
 238     CRM_LOG_ASSERT(lpc > 0);
 239 
 240     xpathObj = xpath_search(xml, xpath_string);
 241     max = numXpathResults(xpathObj);
 242     free(xpath_string);
 243 
 244     for (lpc = 0; lpc < max; lpc++) {
 245         xmlNode *match = getXpathResult(xpathObj, lpc);
 246         crm_trace("Forcing %s/%s = %s", ID(match), attr_name, attr_value);
 247         crm_xml_add(match, XML_NVPAIR_ATTR_VALUE, attr_value);
 248     }
 249 
 250     if(max == 0) {
 251         xmlNode *configuration = NULL;
 252         xmlNode *crm_config = NULL;
 253         xmlNode *cluster_property_set = NULL;
 254 
 255         crm_trace("Creating %s-%s for %s=%s",
 256                   CIB_OPTIONS_FIRST, attr_name, attr_name, attr_value);
 257 
 258         configuration = find_entity(xml, XML_CIB_TAG_CONFIGURATION, NULL);
 259         if (configuration == NULL) {
 260             configuration = create_xml_node(xml, XML_CIB_TAG_CONFIGURATION);
 261         }
 262 
 263         crm_config = find_entity(configuration, XML_CIB_TAG_CRMCONFIG, NULL);
 264         if (crm_config == NULL) {
 265             crm_config = create_xml_node(configuration, XML_CIB_TAG_CRMCONFIG);
 266         }
 267 
 268         cluster_property_set = find_entity(crm_config, XML_CIB_TAG_PROPSET, NULL);
 269         if (cluster_property_set == NULL) {
 270             cluster_property_set = create_xml_node(crm_config, XML_CIB_TAG_PROPSET);
 271             crm_xml_add(cluster_property_set, XML_ATTR_ID, CIB_OPTIONS_FIRST);
 272         }
 273 
 274         xml = create_xml_node(cluster_property_set, XML_CIB_TAG_NVPAIR);
 275 
 276         crm_xml_set_id(xml, "%s-%s", CIB_OPTIONS_FIRST, attr_name);
 277         crm_xml_add(xml, XML_NVPAIR_ATTR_NAME, attr_name);
 278         crm_xml_add(xml, XML_NVPAIR_ATTR_VALUE, attr_value);
 279     }
 280     freeXpathObject(xpathObj);
 281 }
 282 
 283 void
 284 do_pe_invoke_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286     int sent;
 287     xmlNode *cmd = NULL;
 288     pid_t watchdog = pcmk_locate_sbd();
 289 
 290     if (rc != pcmk_ok) {
 291         crm_err("Could not retrieve the Cluster Information Base: %s "
 292                 CRM_XS " call=%d", pcmk_strerror(rc), call_id);
 293         register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
 294         return;
 295 
 296     } else if (call_id != fsa_pe_query) {
 297         crm_trace("Skipping superseded CIB query: %d (current=%d)", call_id, fsa_pe_query);
 298         return;
 299 
 300     } else if (AM_I_DC == FALSE || is_set(fsa_input_register, R_PE_CONNECTED) == FALSE) {
 301         crm_debug("No need to invoke the PE anymore");
 302         return;
 303 
 304     } else if (fsa_state != S_POLICY_ENGINE) {
 305         crm_debug("Discarding PE request in state: %s", fsa_state2string(fsa_state));
 306         return;
 307 
 308     /* this callback counts as 1 */
 309     } else if (num_cib_op_callbacks() > 1) {
 310         crm_debug("Re-asking for the CIB: %d other peer updates still pending",
 311                   (num_cib_op_callbacks() - 1));
 312         sleep(1);
 313         register_fsa_action(A_PE_INVOKE);
 314         return;
 315 
 316     } else if (fsa_state != S_POLICY_ENGINE) {
 317         crm_err("Invoking PE in state: %s", fsa_state2string(fsa_state));
 318         return;
 319     }
 320 
 321     CRM_LOG_ASSERT(output != NULL);
 322 
 323     /* refresh our remote-node cache when the pengine is invoked */
 324     crm_remote_peer_cache_refresh(output);
 325 
 326     crm_xml_add(output, XML_ATTR_DC_UUID, fsa_our_uuid);
 327     crm_xml_add_int(output, XML_ATTR_HAVE_QUORUM, fsa_has_quorum);
 328 
 329     force_local_option(output, XML_ATTR_HAVE_WATCHDOG, watchdog?"true":"false");
 330 
 331     if (ever_had_quorum && crm_have_quorum == FALSE) {
 332         crm_xml_add_int(output, XML_ATTR_QUORUM_PANIC, 1);
 333     }
 334 
 335     cmd = create_request(CRM_OP_PECALC, output, NULL, CRM_SYSTEM_PENGINE, CRM_SYSTEM_DC, NULL);
 336 
 337     free(fsa_pe_ref);
 338     fsa_pe_ref = crm_element_value_copy(cmd, XML_ATTR_REFERENCE);
 339 
 340     sent = crm_ipc_send(mainloop_get_ipc_client(pe_subsystem->source), cmd, 0, 0, NULL);
 341     if (sent <= 0) {
 342         crm_err("Could not contact the pengine: %d", sent);
 343         register_fsa_error_adv(C_FSA_INTERNAL, I_ERROR, NULL, NULL, __FUNCTION__);
 344     }
 345 
 346     crm_debug("Invoking the PE: query=%d, ref=%s, seq=%llu, quorate=%d",
 347               fsa_pe_query, fsa_pe_ref, crm_peer_seq, fsa_has_quorum);
 348     free_xml(cmd);
 349 }

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