root/daemons/schedulerd/schedulerd_messages.c

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

DEFINITIONS

This source file includes following definitions.
  1. init_working_set
  2. handle_pecalc_request
  3. handle_unknown_request
  4. handle_hello_request
  5. schedulerd_register_handlers
  6. pe_ipc_accept
  7. pe_ipc_dispatch
  8. pe_ipc_closed
  9. pe_ipc_destroy

   1 /*
   2  * Copyright 2004-2024 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 <crm/crm.h>
  13 #include <crm/common/xml.h>
  14 #include <pacemaker-internal.h>
  15 
  16 #include <stdbool.h>
  17 #include <sys/stat.h>
  18 #include <sys/types.h>
  19 #include <unistd.h>
  20 
  21 #include "pacemaker-schedulerd.h"
  22 
  23 static GHashTable *schedulerd_handlers = NULL;
  24 
  25 static pcmk_scheduler_t *
  26 init_working_set(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28     pcmk_scheduler_t *scheduler = pe_new_working_set();
  29 
  30     pcmk__mem_assert(scheduler);
  31 
  32     crm_config_error = FALSE;
  33     crm_config_warning = FALSE;
  34 
  35     was_processing_error = FALSE;
  36     was_processing_warning = FALSE;
  37 
  38     scheduler->priv = logger_out;
  39     return scheduler;
  40 }
  41 
  42 static xmlNode *
  43 handle_pecalc_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
  44 {
  45     static struct series_s {
  46         const char *name;
  47         const char *param;
  48 
  49         /* Maximum number of inputs of this kind to save to disk.
  50          * If -1, save all; if 0, save none.
  51          */
  52         int wrap;
  53     } series[] = {
  54         { "pe-error", PCMK_OPT_PE_ERROR_SERIES_MAX, -1 },
  55         { "pe-warn",  PCMK_OPT_PE_WARN_SERIES_MAX, 5000 },
  56         { "pe-input", PCMK_OPT_PE_INPUT_SERIES_MAX, 4000 },
  57     };
  58 
  59     xmlNode *msg = request->xml;
  60     xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_CRM_XML, NULL, NULL);
  61     xmlNode *xml_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
  62 
  63     static char *last_digest = NULL;
  64     static char *filename = NULL;
  65 
  66     unsigned int seq;
  67     int series_id = 0;
  68     int series_wrap = 0;
  69     char *digest = NULL;
  70     const char *value = NULL;
  71     time_t execution_date = time(NULL);
  72     xmlNode *converted = NULL;
  73     xmlNode *reply = NULL;
  74     bool is_repoke = false;
  75     bool process = true;
  76     pcmk_scheduler_t *scheduler = init_working_set();
  77 
  78     pcmk__ipc_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags,
  79                        PCMK__XE_ACK, NULL, CRM_EX_INDETERMINATE);
  80 
  81     digest = calculate_xml_versioned_digest(xml_data, FALSE, FALSE,
  82                                             CRM_FEATURE_SET);
  83     converted = pcmk__xml_copy(NULL, xml_data);
  84     if (pcmk__update_configured_schema(&converted, true) != pcmk_rc_ok) {
  85         scheduler->graph = pcmk__xe_create(NULL, PCMK__XE_TRANSITION_GRAPH);
  86         crm_xml_add_int(scheduler->graph, "transition_id", 0);
  87         crm_xml_add_int(scheduler->graph, PCMK_OPT_CLUSTER_DELAY, 0);
  88         process = false;
  89         free(digest);
  90 
  91     } else if (pcmk__str_eq(digest, last_digest, pcmk__str_casei)) {
  92         is_repoke = true;
  93         free(digest);
  94 
  95     } else {
  96         free(last_digest);
  97         last_digest = digest;
  98     }
  99 
 100     if (process) {
 101         pcmk__schedule_actions(converted,
 102                                pcmk_sched_no_counts
 103                                |pcmk_sched_no_compat
 104                                |pcmk_sched_show_utilization, scheduler);
 105     }
 106 
 107     // Get appropriate index into series[] array
 108     if (was_processing_error || crm_config_error) {
 109         series_id = 0;
 110     } else if (was_processing_warning || crm_config_warning) {
 111         series_id = 1;
 112     } else {
 113         series_id = 2;
 114     }
 115 
 116     value = pcmk__cluster_option(scheduler->config_hash,
 117                                  series[series_id].param);
 118     if ((value == NULL)
 119         || (pcmk__scan_min_int(value, &series_wrap, -1) != pcmk_rc_ok)) {
 120         series_wrap = series[series_id].wrap;
 121     }
 122 
 123     if (pcmk__read_series_sequence(PE_STATE_DIR, series[series_id].name,
 124                                    &seq) != pcmk_rc_ok) {
 125         // @TODO maybe handle errors better ...
 126         seq = 0;
 127     }
 128     crm_trace("Series %s: wrap=%d, seq=%u, pref=%s",
 129               series[series_id].name, series_wrap, seq, value);
 130 
 131     scheduler->input = NULL;
 132     reply = create_reply(msg, scheduler->graph);
 133 
 134     if (reply == NULL) {
 135         pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
 136                             "Failed building ping reply for client %s",
 137                             pcmk__client_name(request->ipc_client));
 138         goto done;
 139     }
 140 
 141     if (series_wrap == 0) { // Don't save any inputs of this kind
 142         free(filename);
 143         filename = NULL;
 144 
 145     } else if (!is_repoke) { // Input changed, save to disk
 146         free(filename);
 147         filename = pcmk__series_filename(PE_STATE_DIR,
 148                                          series[series_id].name, seq, true);
 149     }
 150 
 151     crm_xml_add(reply, PCMK__XA_CRM_TGRAPH_IN, filename);
 152     crm_xml_add_int(reply, PCMK__XA_GRAPH_ERRORS, was_processing_error);
 153     crm_xml_add_int(reply, PCMK__XA_GRAPH_WARNINGS, was_processing_warning);
 154     crm_xml_add_int(reply, PCMK__XA_CONFIG_ERRORS, crm_config_error);
 155     crm_xml_add_int(reply, PCMK__XA_CONFIG_WARNINGS, crm_config_warning);
 156 
 157     pcmk__log_transition_summary(filename);
 158 
 159     if (series_wrap == 0) {
 160         crm_debug("Not saving input to disk (disabled by configuration)");
 161 
 162     } else if (is_repoke) {
 163         crm_info("Input has not changed since last time, not saving to disk");
 164 
 165     } else {
 166         unlink(filename);
 167         crm_xml_add_ll(xml_data, PCMK_XA_EXECUTION_DATE,
 168                        (long long) execution_date);
 169         pcmk__xml_write_file(xml_data, filename, true, NULL);
 170         pcmk__write_series_sequence(PE_STATE_DIR, series[series_id].name,
 171                                     ++seq, series_wrap);
 172     }
 173 
 174     pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
 175 
 176 done:
 177     free_xml(converted);
 178     pe_free_working_set(scheduler);
 179 
 180     return reply;
 181 }
 182 
 183 static xmlNode *
 184 handle_unknown_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186     pcmk__ipc_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags,
 187                        PCMK__XE_ACK, NULL, CRM_EX_INVALID_PARAM);
 188 
 189     pcmk__format_result(&request->result, CRM_EX_PROTOCOL, PCMK_EXEC_INVALID,
 190                         "Unknown IPC request type '%s' (bug?)",
 191                         pcmk__client_name(request->ipc_client));
 192     return NULL;
 193 }
 194 
 195 static xmlNode *
 196 handle_hello_request(pcmk__request_t *request)
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198     pcmk__ipc_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags,
 199                        PCMK__XE_ACK, NULL, CRM_EX_INDETERMINATE);
 200 
 201     crm_trace("Received IPC hello from %s", pcmk__client_name(request->ipc_client));
 202 
 203     pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
 204     return NULL;
 205 }
 206 
 207 static void
 208 schedulerd_register_handlers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210     pcmk__server_command_t handlers[] = {
 211         { CRM_OP_HELLO, handle_hello_request },
 212         { CRM_OP_PECALC, handle_pecalc_request },
 213         { NULL, handle_unknown_request },
 214     };
 215 
 216     schedulerd_handlers = pcmk__register_handlers(handlers);
 217 }
 218 
 219 static int32_t
 220 pe_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222     crm_trace("Connection %p", c);
 223     if (pcmk__new_client(c, uid, gid) == NULL) {
 224         return -ENOMEM;
 225     }
 226     return 0;
 227 }
 228 
 229 static int32_t
 230 pe_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232     uint32_t id = 0;
 233     uint32_t flags = 0;
 234     xmlNode *msg = NULL;
 235     pcmk__client_t *c = pcmk__find_client(qbc);
 236     const char *sys_to = NULL;
 237 
 238     CRM_CHECK(c != NULL, return 0);
 239 
 240     if (schedulerd_handlers == NULL) {
 241         schedulerd_register_handlers();
 242     }
 243 
 244     msg = pcmk__client_data2xml(c, data, &id, &flags);
 245     if (msg == NULL) {
 246         pcmk__ipc_send_ack(c, id, flags, PCMK__XE_ACK, NULL, CRM_EX_PROTOCOL);
 247         return 0;
 248     }
 249 
 250     sys_to = crm_element_value(msg, PCMK__XA_CRM_SYS_TO);
 251 
 252     if (pcmk__str_eq(crm_element_value(msg, PCMK__XA_SUBT),
 253                      PCMK__VALUE_RESPONSE, pcmk__str_none)) {
 254         pcmk__ipc_send_ack(c, id, flags, PCMK__XE_ACK, NULL,
 255                            CRM_EX_INDETERMINATE);
 256         crm_info("Ignoring IPC reply from %s", pcmk__client_name(c));
 257 
 258     } else if (!pcmk__str_eq(sys_to, CRM_SYSTEM_PENGINE, pcmk__str_none)) {
 259         pcmk__ipc_send_ack(c, id, flags, PCMK__XE_ACK, NULL,
 260                            CRM_EX_INDETERMINATE);
 261         crm_info("Ignoring invalid IPC message: to '%s' not "
 262                  CRM_SYSTEM_PENGINE, pcmk__s(sys_to, ""));
 263 
 264     } else {
 265         char *log_msg = NULL;
 266         const char *reason = NULL;
 267         xmlNode *reply = NULL;
 268 
 269         pcmk__request_t request = {
 270             .ipc_client     = c,
 271             .ipc_id         = id,
 272             .ipc_flags      = flags,
 273             .peer           = NULL,
 274             .xml            = msg,
 275             .call_options   = 0,
 276             .result         = PCMK__UNKNOWN_RESULT,
 277         };
 278 
 279         request.op = crm_element_value_copy(request.xml, PCMK__XA_CRM_TASK);
 280         CRM_CHECK(request.op != NULL, return 0);
 281 
 282         reply = pcmk__process_request(&request, schedulerd_handlers);
 283 
 284         if (reply != NULL) {
 285             pcmk__ipc_send_xml(c, id, reply, crm_ipc_server_event);
 286             free_xml(reply);
 287         }
 288 
 289         reason = request.result.exit_reason;
 290 
 291         log_msg = crm_strdup_printf("Processed %s request from %s %s: %s%s%s%s",
 292                                     request.op, pcmk__request_origin_type(&request),
 293                                     pcmk__request_origin(&request),
 294                                     pcmk_exec_status_str(request.result.execution_status),
 295                                     (reason == NULL)? "" : " (",
 296                                     (reason == NULL)? "" : reason,
 297                                     (reason == NULL)? "" : ")");
 298 
 299         if (!pcmk__result_ok(&request.result)) {
 300             crm_warn("%s", log_msg);
 301         } else {
 302             crm_debug("%s", log_msg);
 303         }
 304 
 305         free(log_msg);
 306         pcmk__reset_request(&request);
 307     }
 308 
 309     free_xml(msg);
 310     return 0;
 311 }
 312 
 313 /* Error code means? */
 314 static int32_t
 315 pe_ipc_closed(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317     pcmk__client_t *client = pcmk__find_client(c);
 318 
 319     if (client == NULL) {
 320         return 0;
 321     }
 322     crm_trace("Connection %p", c);
 323     pcmk__free_client(client);
 324     return 0;
 325 }
 326 
 327 static void
 328 pe_ipc_destroy(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 329 {
 330     crm_trace("Connection %p", c);
 331     pe_ipc_closed(c);
 332 }
 333 
 334 struct qb_ipcs_service_handlers ipc_callbacks = {
 335     .connection_accept = pe_ipc_accept,
 336     .connection_created = NULL,
 337     .msg_process = pe_ipc_dispatch,
 338     .connection_closed = pe_ipc_closed,
 339     .connection_destroyed = pe_ipc_destroy
 340 };

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