root/daemons/schedulerd/pacemaker-schedulerd.c

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

DEFINITIONS

This source file includes following definitions.
  1. process_pe_message
  2. pe_ipc_accept
  3. pe_ipc_dispatch
  4. pe_ipc_closed
  5. pe_ipc_destroy
  6. main
  7. pengine_shutdown

   1 /*
   2  * Copyright 2004-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 <crm/crm.h>
  13 #include <stdio.h>
  14 #include <stdbool.h>
  15 #include <sys/stat.h>
  16 #include <sys/types.h>
  17 #include <unistd.h>
  18 
  19 #include <stdlib.h>
  20 #include <errno.h>
  21 #include <fcntl.h>
  22 
  23 #include <libxml/parser.h>
  24 
  25 #include <crm/common/ipc_internal.h>
  26 #include <crm/common/mainloop.h>
  27 #include <crm/pengine/internal.h>
  28 #include <pacemaker-internal.h>
  29 #include <crm/msg_xml.h>
  30 
  31 #define OPTARGS "hVc"
  32 
  33 static GMainLoop *mainloop = NULL;
  34 static qb_ipcs_service_t *ipcs = NULL;
  35 static pe_working_set_t *sched_data_set = NULL;
  36 
  37 #define get_series()    was_processing_error?1:was_processing_warning?2:3
  38 
  39 typedef struct series_s {
  40     const char *name;
  41     const char *param;
  42     int wrap;
  43 } series_t;
  44 
  45 series_t series[] = {
  46     {"pe-unknown", "_do_not_match_anything_", -1},
  47     {"pe-error", "pe-error-series-max", -1},
  48     {"pe-warn", "pe-warn-series-max", 200},
  49     {"pe-input", "pe-input-series-max", 400},
  50 };
  51 
  52 void pengine_shutdown(int nsig);
  53 
  54 static gboolean
  55 process_pe_message(xmlNode *msg, xmlNode *xml_data, pcmk__client_t *sender)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57     static char *last_digest = NULL;
  58     static char *filename = NULL;
  59 
  60     const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
  61     const char *op = crm_element_value(msg, F_CRM_TASK);
  62     const char *ref = crm_element_value(msg, F_CRM_REFERENCE);
  63 
  64     crm_trace("Processing %s op (ref=%s)...", op, ref);
  65 
  66     if (op == NULL) {
  67         /* error */
  68 
  69     } else if (strcasecmp(op, CRM_OP_HELLO) == 0) {
  70         /* ignore */
  71 
  72     } else if (pcmk__str_eq(crm_element_value(msg, F_CRM_MSG_TYPE), XML_ATTR_RESPONSE, pcmk__str_casei)) {
  73         /* ignore */
  74 
  75     } else if (sys_to == NULL || strcasecmp(sys_to, CRM_SYSTEM_PENGINE) != 0) {
  76         crm_trace("Bad sys-to %s", crm_str(sys_to));
  77         return FALSE;
  78 
  79     } else if (strcasecmp(op, CRM_OP_PECALC) == 0) {
  80         unsigned int seq;
  81         int series_id = 0;
  82         int series_wrap = 0;
  83         char *digest = NULL;
  84         const char *value = NULL;
  85         time_t execution_date = time(NULL);
  86         xmlNode *converted = NULL;
  87         xmlNode *reply = NULL;
  88         gboolean is_repoke = FALSE;
  89         gboolean process = TRUE;
  90 
  91         pcmk__config_error = false;
  92         pcmk__config_warning = false;
  93 
  94         was_processing_error = FALSE;
  95         was_processing_warning = FALSE;
  96 
  97         if (sched_data_set == NULL) {
  98             sched_data_set = pe_new_working_set();
  99             CRM_ASSERT(sched_data_set != NULL);
 100             pe__set_working_set_flags(sched_data_set,
 101                                       pe_flag_no_counts|pe_flag_no_compat);
 102         }
 103 
 104         digest = calculate_xml_versioned_digest(xml_data, FALSE, FALSE, CRM_FEATURE_SET);
 105         converted = copy_xml(xml_data);
 106         if (cli_config_update(&converted, NULL, TRUE) == FALSE) {
 107             sched_data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH);
 108             crm_xml_add_int(sched_data_set->graph, "transition_id", 0);
 109             crm_xml_add_int(sched_data_set->graph, "cluster-delay", 0);
 110             process = FALSE;
 111             free(digest);
 112 
 113         } else if (pcmk__str_eq(digest, last_digest, pcmk__str_casei)) {
 114             crm_info("Input has not changed since last time, not saving to disk");
 115             is_repoke = TRUE;
 116             free(digest);
 117 
 118         } else {
 119             free(last_digest);
 120             last_digest = digest;
 121         }
 122 
 123         if (process) {
 124             pcmk__schedule_actions(sched_data_set, converted, NULL);
 125         }
 126 
 127         series_id = get_series();
 128         series_wrap = series[series_id].wrap;
 129         value = pe_pref(sched_data_set->config_hash, series[series_id].param);
 130 
 131         if (value != NULL) {
 132             series_wrap = (int) crm_parse_ll(value, NULL);
 133             if (errno != 0) {
 134                 series_wrap = series[series_id].wrap;
 135             }
 136 
 137         } else {
 138             pcmk__config_warn("No value specified for cluster preference: %s",
 139                               series[series_id].param);
 140         }
 141 
 142         if (pcmk__read_series_sequence(PE_STATE_DIR, series[series_id].name,
 143                                        &seq) != pcmk_rc_ok) {
 144             // @TODO maybe handle errors better ...
 145             seq = 0;
 146         }
 147         crm_trace("Series %s: wrap=%d, seq=%u, pref=%s",
 148                   series[series_id].name, series_wrap, seq, value);
 149 
 150         sched_data_set->input = NULL;
 151         reply = create_reply(msg, sched_data_set->graph);
 152         CRM_ASSERT(reply != NULL);
 153 
 154         if (is_repoke == FALSE) {
 155             free(filename);
 156             filename = pcmk__series_filename(PE_STATE_DIR,
 157                                              series[series_id].name, seq, true);
 158         }
 159 
 160         crm_xml_add(reply, F_CRM_TGRAPH_INPUT, filename);
 161         crm_xml_add_int(reply, "graph-errors", was_processing_error);
 162         crm_xml_add_int(reply, "graph-warnings", was_processing_warning);
 163         crm_xml_add_int(reply, "config-errors", pcmk__config_error);
 164         crm_xml_add_int(reply, "config-warnings", pcmk__config_warning);
 165 
 166         if (pcmk__ipc_send_xml(sender, 0, reply,
 167                                crm_ipc_server_event) != pcmk_rc_ok) {
 168             int graph_file_fd = 0;
 169             char *graph_file = NULL;
 170             umask(S_IWGRP | S_IWOTH | S_IROTH);
 171 
 172             graph_file = crm_strdup_printf("%s/pengine.graph.XXXXXX",
 173                                            PE_STATE_DIR);
 174             graph_file_fd = mkstemp(graph_file);
 175 
 176             crm_err("Couldn't send transition graph to peer, writing to %s instead",
 177                     graph_file);
 178 
 179             crm_xml_add(reply, F_CRM_TGRAPH, graph_file);
 180             write_xml_fd(sched_data_set->graph, graph_file, graph_file_fd, FALSE);
 181 
 182             free(graph_file);
 183             free_xml(first_named_child(reply, F_CRM_DATA));
 184             CRM_ASSERT(pcmk__ipc_send_xml(sender, 0, reply,
 185                                           crm_ipc_server_event) == pcmk_rc_ok);
 186         }
 187 
 188         free_xml(reply);
 189         pe_reset_working_set(sched_data_set);
 190         pcmk__log_transition_summary(filename);
 191 
 192         if (is_repoke == FALSE && series_wrap != 0) {
 193             unlink(filename);
 194             crm_xml_add_ll(xml_data, "execution-date", (long long) execution_date);
 195             write_xml_file(xml_data, filename, TRUE);
 196             pcmk__write_series_sequence(PE_STATE_DIR, series[series_id].name,
 197                                         ++seq, series_wrap);
 198         } else {
 199             crm_trace("Not writing out %s: %d & %d", filename, is_repoke, series_wrap);
 200         }
 201 
 202         free_xml(converted);
 203     }
 204 
 205     return TRUE;
 206 }
 207 
 208 static int32_t
 209 pe_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
     /* [previous][next][first][last][top][bottom][index][help] */
 210 {
 211     crm_trace("Connection %p", c);
 212     if (pcmk__new_client(c, uid, gid) == NULL) {
 213         return -EIO;
 214     }
 215     return 0;
 216 }
 217 
 218 gboolean process_pe_message(xmlNode *msg, xmlNode *xml_data,
 219                             pcmk__client_t *sender);
 220 
 221 static int32_t
 222 pe_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224     uint32_t id = 0;
 225     uint32_t flags = 0;
 226     pcmk__client_t *c = pcmk__find_client(qbc);
 227     xmlNode *msg = pcmk__client_data2xml(c, data, &id, &flags);
 228 
 229     pcmk__ipc_send_ack(c, id, flags, "ack", CRM_EX_INDETERMINATE);
 230     if (msg != NULL) {
 231         xmlNode *data_xml = get_message_xml(msg, F_CRM_DATA);
 232 
 233         process_pe_message(msg, data_xml, c);
 234         free_xml(msg);
 235     }
 236     return 0;
 237 }
 238 
 239 /* Error code means? */
 240 static int32_t
 241 pe_ipc_closed(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 242 {
 243     pcmk__client_t *client = pcmk__find_client(c);
 244 
 245     if (client == NULL) {
 246         return 0;
 247     }
 248     crm_trace("Connection %p", c);
 249     pcmk__free_client(client);
 250     return 0;
 251 }
 252 
 253 static void
 254 pe_ipc_destroy(qb_ipcs_connection_t * c)
     /* [previous][next][first][last][top][bottom][index][help] */
 255 {
 256     crm_trace("Connection %p", c);
 257     pe_ipc_closed(c);
 258 }
 259 
 260 struct qb_ipcs_service_handlers ipc_callbacks = {
 261     .connection_accept = pe_ipc_accept,
 262     .connection_created = NULL,
 263     .msg_process = pe_ipc_dispatch,
 264     .connection_closed = pe_ipc_closed,
 265     .connection_destroyed = pe_ipc_destroy
 266 };
 267 
 268 static pcmk__cli_option_t long_options[] = {
 269     // long option, argument type, storage, short option, description, flags
 270     {
 271         "help", no_argument, NULL, '?',
 272         "\tThis text", pcmk__option_default
 273     },
 274     {
 275         "verbose", no_argument, NULL, 'V',
 276         "\tIncrease debug output", pcmk__option_default
 277     },
 278     { 0, 0, 0, 0 }
 279 };
 280 
 281 int
 282 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 283 {
 284     int flag;
 285     int index = 0;
 286     int argerr = 0;
 287 
 288     crm_log_preinit(NULL, argc, argv);
 289     pcmk__set_cli_options(NULL, "[options]", long_options,
 290                           "daemon for calculating a Pacemaker cluster's "
 291                           "response to events");
 292 
 293     mainloop_add_signal(SIGTERM, pengine_shutdown);
 294 
 295     while (1) {
 296         flag = pcmk__next_cli_option(argc, argv, &index, NULL);
 297         if (flag == -1)
 298             break;
 299 
 300         switch (flag) {
 301             case 'V':
 302                 crm_bump_log_level(argc, argv);
 303                 break;
 304             case 'h':          /* Help message */
 305                 pcmk__cli_help('?', CRM_EX_OK);
 306                 break;
 307             default:
 308                 ++argerr;
 309                 break;
 310         }
 311     }
 312 
 313     if (argc - optind == 1 && pcmk__str_eq("metadata", argv[optind], pcmk__str_casei)) {
 314         pe_metadata();
 315         return CRM_EX_OK;
 316     }
 317 
 318     if (optind > argc) {
 319         ++argerr;
 320     }
 321 
 322     if (argerr) {
 323         pcmk__cli_help('?', CRM_EX_USAGE);
 324     }
 325 
 326     crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE);
 327     crm_notice("Starting Pacemaker scheduler");
 328 
 329     if (pcmk__daemon_can_write(PE_STATE_DIR, NULL) == FALSE) {
 330         crm_err("Terminating due to bad permissions on " PE_STATE_DIR);
 331         fprintf(stderr,
 332                 "ERROR: Bad permissions on " PE_STATE_DIR " (see logs for details)\n");
 333         fflush(stderr);
 334         return CRM_EX_FATAL;
 335     }
 336 
 337     ipcs = mainloop_add_ipc_server(CRM_SYSTEM_PENGINE, QB_IPC_SHM, &ipc_callbacks);
 338     if (ipcs == NULL) {
 339         crm_err("Failed to create IPC server: shutting down and inhibiting respawn");
 340         crm_exit(CRM_EX_FATAL);
 341     }
 342 
 343     /* Create the mainloop and run it... */
 344     mainloop = g_main_loop_new(NULL, FALSE);
 345     crm_notice("Pacemaker scheduler successfully started and accepting connections");
 346     g_main_loop_run(mainloop);
 347 
 348     pe_free_working_set(sched_data_set);
 349     pcmk__unregister_formats();
 350     crm_info("Exiting %s", crm_system_name);
 351     crm_exit(CRM_EX_OK);
 352 }
 353 
 354 void
 355 pengine_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357     mainloop_del_ipc_server(ipcs);
 358     pe_free_working_set(sched_data_set);
 359     crm_exit(CRM_EX_OK);
 360 }

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