root/daemons/controld/controld_te_actions.c

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

DEFINITIONS

This source file includes following definitions.
  1. te_start_action_timer
  2. execute_pseudo_action
  3. get_target_rc
  4. execute_cluster_action
  5. synthesize_timeout_event
  6. controld_record_action_event
  7. controld_record_action_timeout
  8. execute_rsc_action
  9. te_peer_free
  10. te_reset_job_counts
  11. te_update_job_count_on
  12. te_update_job_count
  13. allowed_on_node
  14. graph_action_allowed
  15. te_action_confirmed
  16. controld_register_graph_functions
  17. notify_crmd

   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 <sys/param.h>
  13 #include <crm/crm.h>
  14 #include <crm/cib.h>
  15 #include <crm/lrmd.h>               // lrmd_event_data_t, lrmd_free_event()
  16 #include <crm/common/xml.h>
  17 #include <crm/cluster.h>
  18 
  19 #include <pacemaker-internal.h>
  20 #include <pacemaker-controld.h>
  21 
  22 static GHashTable *te_targets = NULL;
  23 void send_rsc_command(pcmk__graph_action_t *action);
  24 static void te_update_job_count(pcmk__graph_action_t *action, int offset);
  25 
  26 static void
  27 te_start_action_timer(const pcmk__graph_t *graph, pcmk__graph_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
  28 {
  29     action->timer = pcmk__create_timer(action->timeout + graph->network_delay,
  30                                        action_timer_callback, action);
  31     pcmk__assert(action->timer != 0);
  32 }
  33 
  34 /*!
  35  * \internal
  36  * \brief Execute a graph pseudo-action
  37  *
  38  * \param[in,out] graph   Transition graph being executed
  39  * \param[in,out] pseudo  Pseudo-action to execute
  40  *
  41  * \return Standard Pacemaker return code
  42  */
  43 static int
  44 execute_pseudo_action(pcmk__graph_t *graph, pcmk__graph_action_t *pseudo)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46     const char *task = crm_element_value(pseudo->xml, PCMK_XA_OPERATION);
  47 
  48     /* send to peers as well? */
  49     if (pcmk__str_eq(task, PCMK_ACTION_MAINTENANCE_NODES, pcmk__str_casei)) {
  50         GHashTableIter iter;
  51         pcmk__node_status_t *node = NULL;
  52 
  53         g_hash_table_iter_init(&iter, pcmk__peer_cache);
  54         while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
  55             xmlNode *cmd = NULL;
  56 
  57             if (controld_is_local_node(node->name)) {
  58                 continue;
  59             }
  60 
  61             cmd = pcmk__new_request(pcmk_ipc_controld, CRM_SYSTEM_TENGINE,
  62                                     node->name, CRM_SYSTEM_CRMD, task,
  63                                     pseudo->xml);
  64             pcmk__cluster_send_message(node, pcmk_ipc_controld, cmd);
  65             pcmk__xml_free(cmd);
  66         }
  67 
  68         remote_ra_process_maintenance_nodes(pseudo->xml);
  69     } else {
  70         /* Check action for Pacemaker Remote node side effects */
  71         remote_ra_process_pseudo(pseudo->xml);
  72     }
  73 
  74     crm_debug("Pseudo-action %d (%s) fired and confirmed", pseudo->id,
  75               crm_element_value(pseudo->xml, PCMK__XA_OPERATION_KEY));
  76     te_action_confirmed(pseudo, graph);
  77     return pcmk_rc_ok;
  78 }
  79 
  80 static int
  81 get_target_rc(pcmk__graph_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83     int exit_status;
  84 
  85     pcmk__scan_min_int(crm_meta_value(action->params, PCMK__META_OP_TARGET_RC),
  86                        &exit_status, 0);
  87     return exit_status;
  88 }
  89 
  90 /*!
  91  * \internal
  92  * \brief Execute a cluster action from a transition graph
  93  *
  94  * \param[in,out] graph   Transition graph being executed
  95  * \param[in,out] action  Cluster action to execute
  96  *
  97  * \return Standard Pacemaker return code
  98  */
  99 static int
 100 execute_cluster_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102     char *counter = NULL;
 103     xmlNode *cmd = NULL;
 104     gboolean is_local = FALSE;
 105 
 106     const char *id = NULL;
 107     const char *task = NULL;
 108     const char *value = NULL;
 109     const char *on_node = NULL;
 110     const char *router_node = NULL;
 111 
 112     gboolean rc = TRUE;
 113     gboolean no_wait = FALSE;
 114 
 115     const pcmk__node_status_t *node = NULL;
 116 
 117     id = pcmk__xe_id(action->xml);
 118     CRM_CHECK(!pcmk__str_empty(id), return EPROTO);
 119 
 120     task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 121     CRM_CHECK(!pcmk__str_empty(task), return EPROTO);
 122 
 123     on_node = crm_element_value(action->xml, PCMK__META_ON_NODE);
 124     CRM_CHECK(!pcmk__str_empty(on_node), return pcmk_rc_node_unknown);
 125 
 126     router_node = crm_element_value(action->xml, PCMK__XA_ROUTER_NODE);
 127     if (router_node == NULL) {
 128         router_node = on_node;
 129         if (pcmk__str_eq(task, PCMK_ACTION_LRM_DELETE, pcmk__str_none)) {
 130             const char *mode = crm_element_value(action->xml, PCMK__XA_MODE);
 131 
 132             if (pcmk__str_eq(mode, PCMK__VALUE_CIB, pcmk__str_none)) {
 133                 router_node = controld_globals.cluster->priv->node_name;
 134             }
 135         }
 136     }
 137 
 138     if (controld_is_local_node(router_node)) {
 139         is_local = TRUE;
 140     }
 141 
 142     value = crm_meta_value(action->params, PCMK__META_OP_NO_WAIT);
 143     if (crm_is_true(value)) {
 144         no_wait = TRUE;
 145     }
 146 
 147     crm_info("Handling controller request '%s' (%s on %s)%s%s",
 148              id, task, on_node, (is_local? " locally" : ""),
 149              (no_wait? " without waiting" : ""));
 150 
 151     if (is_local
 152         && pcmk__str_eq(task, PCMK_ACTION_DO_SHUTDOWN, pcmk__str_none)) {
 153         /* defer until everything else completes */
 154         crm_info("Controller request '%s' is a local shutdown", id);
 155         graph->completion_action = pcmk__graph_shutdown;
 156         graph->abort_reason = "local shutdown";
 157         te_action_confirmed(action, graph);
 158         return pcmk_rc_ok;
 159 
 160     } else if (pcmk__str_eq(task, PCMK_ACTION_DO_SHUTDOWN, pcmk__str_none)) {
 161         pcmk__node_status_t *peer =
 162             pcmk__get_node(0, router_node, NULL,
 163                            pcmk__node_search_cluster_member);
 164 
 165         pcmk__update_peer_expected(__func__, peer, CRMD_JOINSTATE_DOWN);
 166     }
 167 
 168     cmd = pcmk__new_request(pcmk_ipc_controld, CRM_SYSTEM_TENGINE, router_node,
 169                             CRM_SYSTEM_CRMD, task, action->xml);
 170 
 171     counter = pcmk__transition_key(controld_globals.transition_graph->id,
 172                                    action->id, get_target_rc(action),
 173                                    controld_globals.te_uuid);
 174     crm_xml_add(cmd, PCMK__XA_TRANSITION_KEY, counter);
 175 
 176     node = pcmk__get_node(0, router_node, NULL,
 177                           pcmk__node_search_cluster_member);
 178     rc = pcmk__cluster_send_message(node, pcmk_ipc_controld, cmd);
 179     free(counter);
 180     pcmk__xml_free(cmd);
 181 
 182     if (rc == FALSE) {
 183         crm_err("Action %d failed: send", action->id);
 184         return ECOMM;
 185 
 186     } else if (no_wait) {
 187         te_action_confirmed(action, graph);
 188 
 189     } else {
 190         if (action->timeout <= 0) {
 191             crm_err("Action %d: %s on %s had an invalid timeout (%dms).  Using %ums instead",
 192                     action->id, task, on_node, action->timeout, graph->network_delay);
 193             action->timeout = (int) graph->network_delay;
 194         }
 195         te_start_action_timer(graph, action);
 196     }
 197 
 198     return pcmk_rc_ok;
 199 }
 200 
 201 /*!
 202  * \internal
 203  * \brief Synthesize an executor event for a resource action timeout
 204  *
 205  * \param[in] action     Resource action that timed out
 206  * \param[in] target_rc  Expected result of action that timed out
 207  *
 208  * Synthesize an executor event for a resource action timeout. (If the executor
 209  * gets a timeout while waiting for a resource action to complete, that will be
 210  * reported via the usual callback. This timeout means we didn't hear from the
 211  * executor itself or the controller that relayed the action to the executor.)
 212  *
 213  * \return Newly created executor event for result of \p action
 214  * \note The caller is responsible for freeing the return value using
 215  *       lrmd_free_event().
 216  */
 217 static lrmd_event_data_t *
 218 synthesize_timeout_event(const pcmk__graph_action_t *action, int target_rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220     lrmd_event_data_t *op = NULL;
 221     const char *target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 222     const char *reason = NULL;
 223     char *dynamic_reason = NULL;
 224 
 225     if (pcmk__str_eq(target, pcmk__cluster_local_node_name(),
 226                      pcmk__str_casei)) {
 227         reason = "Local executor did not return result in time";
 228     } else {
 229         const char *router_node = NULL;
 230 
 231         router_node = crm_element_value(action->xml, PCMK__XA_ROUTER_NODE);
 232         if (router_node == NULL) {
 233             router_node = target;
 234         }
 235         dynamic_reason = crm_strdup_printf("Controller on %s did not return "
 236                                            "result in time", router_node);
 237         reason = dynamic_reason;
 238     }
 239 
 240     op = pcmk__event_from_graph_action(NULL, action, PCMK_EXEC_TIMEOUT,
 241                                        PCMK_OCF_UNKNOWN_ERROR, reason);
 242     op->call_id = -1;
 243     op->user_data = pcmk__transition_key(controld_globals.transition_graph->id,
 244                                          action->id, target_rc,
 245                                          controld_globals.te_uuid);
 246     free(dynamic_reason);
 247     return op;
 248 }
 249 
 250 static void
 251 controld_record_action_event(pcmk__graph_action_t *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 252                              lrmd_event_data_t *op)
 253 {
 254     cib_t *cib_conn = controld_globals.cib_conn;
 255 
 256     xmlNode *state = NULL;
 257     xmlNode *rsc = NULL;
 258     xmlNode *action_rsc = NULL;
 259 
 260     int rc = pcmk_ok;
 261 
 262     const char *rsc_id = NULL;
 263     const char *target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 264     const char *task_uuid = crm_element_value(action->xml,
 265                                               PCMK__XA_OPERATION_KEY);
 266     const char *target_uuid = crm_element_value(action->xml,
 267                                                 PCMK__META_ON_NODE_UUID);
 268 
 269     int target_rc = get_target_rc(action);
 270 
 271     action_rsc = pcmk__xe_first_child(action->xml, PCMK_XE_PRIMITIVE, NULL,
 272                                       NULL);
 273     if (action_rsc == NULL) {
 274         return;
 275     }
 276 
 277     rsc_id = pcmk__xe_id(action_rsc);
 278     CRM_CHECK(rsc_id != NULL,
 279               crm_log_xml_err(action->xml, "Bad:action"); return);
 280 
 281 /*
 282   update the CIB
 283 
 284 <node_state id="hadev">
 285       <lrm>
 286         <lrm_resources>
 287           <lrm_resource id="rsc2" last_op="start" op_code="0" target="hadev"/>
 288 */
 289 
 290     state = pcmk__xe_create(NULL, PCMK__XE_NODE_STATE);
 291 
 292     crm_xml_add(state, PCMK_XA_ID, target_uuid);
 293     crm_xml_add(state, PCMK_XA_UNAME, target);
 294 
 295     rsc = pcmk__xe_create(state, PCMK__XE_LRM);
 296     crm_xml_add(rsc, PCMK_XA_ID, target_uuid);
 297 
 298     rsc = pcmk__xe_create(rsc, PCMK__XE_LRM_RESOURCES);
 299     rsc = pcmk__xe_create(rsc, PCMK__XE_LRM_RESOURCE);
 300     crm_xml_add(rsc, PCMK_XA_ID, rsc_id);
 301 
 302 
 303     crm_copy_xml_element(action_rsc, rsc, PCMK_XA_TYPE);
 304     crm_copy_xml_element(action_rsc, rsc, PCMK_XA_CLASS);
 305     crm_copy_xml_element(action_rsc, rsc, PCMK_XA_PROVIDER);
 306 
 307     pcmk__create_history_xml(rsc, op, CRM_FEATURE_SET, target_rc, target,
 308                              __func__);
 309 
 310     rc = cib_conn->cmds->modify(cib_conn, PCMK_XE_STATUS, state, cib_none);
 311     fsa_register_cib_callback(rc, NULL, cib_action_updated);
 312     pcmk__xml_free(state);
 313 
 314     crm_trace("Sent CIB update (call ID %d) for synthesized event of action %d (%s on %s)",
 315               rc, action->id, task_uuid, target);
 316     pcmk__set_graph_action_flags(action, pcmk__graph_action_sent_update);
 317 }
 318 
 319 void
 320 controld_record_action_timeout(pcmk__graph_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 321 {
 322     lrmd_event_data_t *op = NULL;
 323 
 324     const char *target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 325     const char *task_uuid = crm_element_value(action->xml,
 326                                               PCMK__XA_OPERATION_KEY);
 327 
 328     int target_rc = get_target_rc(action);
 329 
 330     crm_warn("%s %d: %s on %s timed out",
 331              action->xml->name, action->id, task_uuid, target);
 332 
 333     op = synthesize_timeout_event(action, target_rc);
 334     controld_record_action_event(action, op);
 335     lrmd_free_event(op);
 336 }
 337 
 338 /*!
 339  * \internal
 340  * \brief Execute a resource action from a transition graph
 341  *
 342  * \param[in,out] graph   Transition graph being executed
 343  * \param[in,out] action  Resource action to execute
 344  *
 345  * \return Standard Pacemaker return code
 346  */
 347 static int
 348 execute_rsc_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 349 {
 350     /* never overwrite stop actions in the CIB with
 351      *   anything other than completed results
 352      *
 353      * Writing pending stops makes it look like the
 354      *   resource is running again
 355      */
 356     xmlNode *cmd = NULL;
 357     xmlNode *rsc_op = NULL;
 358 
 359     gboolean rc = TRUE;
 360     gboolean no_wait = FALSE;
 361     gboolean is_local = FALSE;
 362 
 363     char *counter = NULL;
 364     const char *task = NULL;
 365     const char *value = NULL;
 366     const char *on_node = NULL;
 367     const char *router_node = NULL;
 368     const char *task_uuid = NULL;
 369 
 370     pcmk__assert((action != NULL) && (action->xml != NULL));
 371 
 372     pcmk__clear_graph_action_flags(action, pcmk__graph_action_executed);
 373     on_node = crm_element_value(action->xml, PCMK__META_ON_NODE);
 374 
 375     CRM_CHECK(!pcmk__str_empty(on_node),
 376               crm_err("Corrupted command(id=%s) %s: no node",
 377                       pcmk__xe_id(action->xml), pcmk__s(task, "without task"));
 378               return pcmk_rc_node_unknown);
 379 
 380     rsc_op = action->xml;
 381     task = crm_element_value(rsc_op, PCMK_XA_OPERATION);
 382     task_uuid = crm_element_value(action->xml, PCMK__XA_OPERATION_KEY);
 383     router_node = crm_element_value(rsc_op, PCMK__XA_ROUTER_NODE);
 384 
 385     if (!router_node) {
 386         router_node = on_node;
 387     }
 388 
 389     counter = pcmk__transition_key(controld_globals.transition_graph->id,
 390                                    action->id, get_target_rc(action),
 391                                    controld_globals.te_uuid);
 392     crm_xml_add(rsc_op, PCMK__XA_TRANSITION_KEY, counter);
 393 
 394     if (controld_is_local_node(router_node)) {
 395         is_local = TRUE;
 396     }
 397 
 398     value = crm_meta_value(action->params, PCMK__META_OP_NO_WAIT);
 399     if (crm_is_true(value)) {
 400         no_wait = TRUE;
 401     }
 402 
 403     crm_notice("Initiating %s operation %s%s on %s%s " QB_XS " action %d",
 404                task, task_uuid, (is_local? " locally" : ""), on_node,
 405                (no_wait? " without waiting" : ""), action->id);
 406 
 407     cmd = pcmk__new_request(pcmk_ipc_controld, CRM_SYSTEM_TENGINE, router_node,
 408                             CRM_SYSTEM_LRMD, CRM_OP_INVOKE_LRM, rsc_op);
 409 
 410     if (is_local) {
 411         /* shortcut local resource commands */
 412         ha_msg_input_t data = {
 413             .msg = cmd,
 414             .xml = rsc_op,
 415         };
 416 
 417         fsa_data_t msg = {
 418             .id = 0,
 419             .data = &data,
 420             .data_type = fsa_dt_ha_msg,
 421             .fsa_input = I_NULL,
 422             .fsa_cause = C_FSA_INTERNAL,
 423             .actions = A_LRM_INVOKE,
 424             .origin = __func__,
 425         };
 426 
 427         do_lrm_invoke(A_LRM_INVOKE, C_FSA_INTERNAL, controld_globals.fsa_state,
 428                       I_NULL, &msg);
 429 
 430     } else {
 431         const pcmk__node_status_t *node =
 432             pcmk__get_node(0, router_node, NULL,
 433                            pcmk__node_search_cluster_member);
 434 
 435         rc = pcmk__cluster_send_message(node, pcmk_ipc_execd, cmd);
 436     }
 437 
 438     free(counter);
 439     pcmk__xml_free(cmd);
 440 
 441     pcmk__set_graph_action_flags(action, pcmk__graph_action_executed);
 442 
 443     if (rc == FALSE) {
 444         crm_err("Action %d failed: send", action->id);
 445         return ECOMM;
 446 
 447     } else if (no_wait) {
 448         /* Just mark confirmed. Don't bump the job count only to immediately
 449          * decrement it.
 450          */
 451         crm_info("Action %d confirmed - no wait", action->id);
 452         pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
 453         pcmk__update_graph(controld_globals.transition_graph, action);
 454         trigger_graph();
 455 
 456     } else if (pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
 457         crm_debug("Action %d: %s %s on %s(timeout %dms) was already confirmed.",
 458                   action->id, task, task_uuid, on_node, action->timeout);
 459     } else {
 460         if (action->timeout <= 0) {
 461             crm_err("Action %d: %s %s on %s had an invalid timeout (%dms).  Using %ums instead",
 462                     action->id, task, task_uuid, on_node, action->timeout, graph->network_delay);
 463             action->timeout = (int) graph->network_delay;
 464         }
 465         te_update_job_count(action, 1);
 466         te_start_action_timer(graph, action);
 467     }
 468 
 469     return pcmk_rc_ok;
 470 }
 471 
 472 struct te_peer_s
 473 {
 474         char *name;
 475         int jobs;
 476         int migrate_jobs;
 477 };
 478 
 479 static void te_peer_free(gpointer p)
     /* [previous][next][first][last][top][bottom][index][help] */
 480 {
 481     struct te_peer_s *peer = p;
 482 
 483     free(peer->name);
 484     free(peer);
 485 }
 486 
 487 void te_reset_job_counts(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 488 {
 489     GHashTableIter iter;
 490     struct te_peer_s *peer = NULL;
 491 
 492     if(te_targets == NULL) {
 493         te_targets = pcmk__strkey_table(NULL, te_peer_free);
 494     }
 495 
 496     g_hash_table_iter_init(&iter, te_targets);
 497     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & peer)) {
 498         peer->jobs = 0;
 499         peer->migrate_jobs = 0;
 500     }
 501 }
 502 
 503 static void
 504 te_update_job_count_on(const char *target, int offset, bool migrate)
     /* [previous][next][first][last][top][bottom][index][help] */
 505 {
 506     struct te_peer_s *r = NULL;
 507 
 508     if(target == NULL || te_targets == NULL) {
 509         return;
 510     }
 511 
 512     r = g_hash_table_lookup(te_targets, target);
 513     if(r == NULL) {
 514         r = pcmk__assert_alloc(1, sizeof(struct te_peer_s));
 515         r->name = pcmk__str_copy(target);
 516         g_hash_table_insert(te_targets, r->name, r);
 517     }
 518 
 519     r->jobs += offset;
 520     if(migrate) {
 521         r->migrate_jobs += offset;
 522     }
 523     crm_trace("jobs[%s] = %d", target, r->jobs);
 524 }
 525 
 526 static void
 527 te_update_job_count(pcmk__graph_action_t *action, int offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 528 {
 529     const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 530     const char *target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 531 
 532     if ((action->type != pcmk__rsc_graph_action) || (target == NULL)) {
 533         /* No limit on these */
 534         return;
 535     }
 536 
 537     /* if we have a router node, this means the action is performing
 538      * on a remote node. For now, we count all actions occurring on a
 539      * remote node against the job list on the cluster node hosting
 540      * the connection resources */
 541     target = crm_element_value(action->xml, PCMK__XA_ROUTER_NODE);
 542 
 543     if ((target == NULL)
 544         && pcmk__strcase_any_of(task, PCMK_ACTION_MIGRATE_TO,
 545                                 PCMK_ACTION_MIGRATE_FROM, NULL)) {
 546 
 547         const char *t1 = crm_meta_value(action->params,
 548                                         PCMK__META_MIGRATE_SOURCE);
 549         const char *t2 = crm_meta_value(action->params,
 550                                         PCMK__META_MIGRATE_TARGET);
 551 
 552         te_update_job_count_on(t1, offset, TRUE);
 553         te_update_job_count_on(t2, offset, TRUE);
 554         return;
 555     } else if (target == NULL) {
 556         target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 557     }
 558 
 559     te_update_job_count_on(target, offset, FALSE);
 560 }
 561 
 562 /*!
 563  * \internal
 564  * \brief Check whether a graph action is allowed to be executed on a node
 565  *
 566  * \param[in] graph   Transition graph being executed
 567  * \param[in] action  Graph action being executed
 568  * \param[in] target  Name of node where action should be executed
 569  *
 570  * \return true if action is allowed, otherwise false
 571  */
 572 static bool
 573 allowed_on_node(const pcmk__graph_t *graph, const pcmk__graph_action_t *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 574                 const char *target)
 575 {
 576     int limit = 0;
 577     struct te_peer_s *r = NULL;
 578     const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 579     const char *id = crm_element_value(action->xml, PCMK__XA_OPERATION_KEY);
 580 
 581     if(target == NULL) {
 582         /* No limit on these */
 583         return true;
 584 
 585     } else if(te_targets == NULL) {
 586         return false;
 587     }
 588 
 589     r = g_hash_table_lookup(te_targets, target);
 590     limit = throttle_get_job_limit(target);
 591 
 592     if(r == NULL) {
 593         r = pcmk__assert_alloc(1, sizeof(struct te_peer_s));
 594         r->name = pcmk__str_copy(target);
 595         g_hash_table_insert(te_targets, r->name, r);
 596     }
 597 
 598     if(limit <= r->jobs) {
 599         crm_trace("Peer %s is over their job limit of %d (%d): deferring %s",
 600                   target, limit, r->jobs, id);
 601         return false;
 602 
 603     } else if(graph->migration_limit > 0 && r->migrate_jobs >= graph->migration_limit) {
 604         if (pcmk__strcase_any_of(task, PCMK_ACTION_MIGRATE_TO,
 605                                  PCMK_ACTION_MIGRATE_FROM, NULL)) {
 606             crm_trace("Peer %s is over their migration job limit of %d (%d): deferring %s",
 607                       target, graph->migration_limit, r->migrate_jobs, id);
 608             return false;
 609         }
 610     }
 611 
 612     crm_trace("Peer %s has not hit their limit yet. current jobs = %d limit= %d limit", target, r->jobs, limit);
 613 
 614     return true;
 615 }
 616 
 617 /*!
 618  * \internal
 619  * \brief Check whether a graph action is allowed to be executed
 620  *
 621  * \param[in] graph   Transition graph being executed
 622  * \param[in] action  Graph action being executed
 623  *
 624  * \return true if action is allowed, otherwise false
 625  */
 626 static bool
 627 graph_action_allowed(pcmk__graph_t *graph, pcmk__graph_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 628 {
 629     const char *target = NULL;
 630     const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 631 
 632     if (action->type != pcmk__rsc_graph_action) {
 633         /* No limit on these */
 634         return true;
 635     }
 636 
 637     /* if we have a router node, this means the action is performing
 638      * on a remote node. For now, we count all actions occurring on a
 639      * remote node against the job list on the cluster node hosting
 640      * the connection resources */
 641     target = crm_element_value(action->xml, PCMK__XA_ROUTER_NODE);
 642 
 643     if ((target == NULL)
 644         && pcmk__strcase_any_of(task, PCMK_ACTION_MIGRATE_TO,
 645                                 PCMK_ACTION_MIGRATE_FROM, NULL)) {
 646         target = crm_meta_value(action->params, PCMK__META_MIGRATE_SOURCE);
 647         if (!allowed_on_node(graph, action, target)) {
 648             return false;
 649         }
 650 
 651         target = crm_meta_value(action->params, PCMK__META_MIGRATE_TARGET);
 652 
 653     } else if (target == NULL) {
 654         target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 655     }
 656 
 657     return allowed_on_node(graph, action, target);
 658 }
 659 
 660 /*!
 661  * \brief Confirm a graph action (and optionally update graph)
 662  *
 663  * \param[in,out] action  Action to confirm
 664  * \param[in,out] graph   Update and trigger this graph (if non-NULL)
 665  */
 666 void
 667 te_action_confirmed(pcmk__graph_action_t *action, pcmk__graph_t *graph)
     /* [previous][next][first][last][top][bottom][index][help] */
 668 {
 669     if (!pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
 670         if ((action->type == pcmk__rsc_graph_action)
 671             && (crm_element_value(action->xml, PCMK__META_ON_NODE) != NULL)) {
 672             te_update_job_count(action, -1);
 673         }
 674         pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
 675     }
 676     if (graph) {
 677         pcmk__update_graph(graph, action);
 678         trigger_graph();
 679     }
 680 }
 681 
 682 static pcmk__graph_functions_t te_graph_fns = {
 683     execute_pseudo_action,
 684     execute_rsc_action,
 685     execute_cluster_action,
 686     controld_execute_fence_action,
 687     graph_action_allowed,
 688 };
 689 
 690 /*
 691  * \internal
 692  * \brief Register the transitioner's graph functions with \p libpacemaker
 693  */
 694 void
 695 controld_register_graph_functions(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 696 {
 697     pcmk__set_graph_functions(&te_graph_fns);
 698 }
 699 
 700 void
 701 notify_crmd(pcmk__graph_t *graph)
     /* [previous][next][first][last][top][bottom][index][help] */
 702 {
 703     const char *type = "unknown";
 704     enum crmd_fsa_input event = I_NULL;
 705 
 706     crm_debug("Processing transition completion in state %s",
 707               fsa_state2string(controld_globals.fsa_state));
 708 
 709     CRM_CHECK(graph->complete, graph->complete = true);
 710 
 711     switch (graph->completion_action) {
 712         case pcmk__graph_wait:
 713             type = "stop";
 714             if (controld_globals.fsa_state == S_TRANSITION_ENGINE) {
 715                 event = I_TE_SUCCESS;
 716             }
 717             break;
 718         case pcmk__graph_done:
 719             type = "done";
 720             if (controld_globals.fsa_state == S_TRANSITION_ENGINE) {
 721                 event = I_TE_SUCCESS;
 722             }
 723             break;
 724 
 725         case pcmk__graph_restart:
 726             type = "restart";
 727             if (controld_globals.fsa_state == S_TRANSITION_ENGINE) {
 728                 if (controld_get_period_transition_timer() > 0) {
 729                     controld_stop_transition_timer();
 730                     controld_start_transition_timer();
 731                 } else {
 732                     event = I_PE_CALC;
 733                 }
 734 
 735             } else if (controld_globals.fsa_state == S_POLICY_ENGINE) {
 736                 controld_set_fsa_action_flags(A_PE_INVOKE);
 737                 controld_trigger_fsa();
 738             }
 739             break;
 740 
 741         case pcmk__graph_shutdown:
 742             type = "shutdown";
 743             if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 744                 event = I_STOP;
 745 
 746             } else {
 747                 crm_err("We didn't ask to be shut down, yet the scheduler is telling us to");
 748                 event = I_TERMINATE;
 749             }
 750     }
 751 
 752     crm_debug("Transition %d status: %s - %s", graph->id, type,
 753               pcmk__s(graph->abort_reason, "unspecified reason"));
 754 
 755     graph->abort_reason = NULL;
 756     graph->completion_action = pcmk__graph_done;
 757 
 758     if (event != I_NULL) {
 759         register_fsa_input(C_FSA_INTERNAL, event, NULL);
 760     } else {
 761         controld_trigger_fsa();
 762     }
 763 }

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