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 = g_timeout_add(action->timeout + graph->network_delay,
  30                                   action_timer_callback, (void *) action);
  31     CRM_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         crm_node_t *node = NULL;
  52 
  53         g_hash_table_iter_init(&iter, crm_peer_cache);
  54         while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
  55             xmlNode *cmd = NULL;
  56 
  57             if (pcmk__str_eq(controld_globals.our_nodename, node->uname,
  58                              pcmk__str_casei)) {
  59                 continue;
  60             }
  61 
  62             cmd = create_request(task, pseudo->xml, node->uname,
  63                                  CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL);
  64             pcmk__cluster_send_message(node, crm_msg_crmd, cmd);
  65             free_xml(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 crm_node_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.our_nodename;
 134             }
 135         }
 136     }
 137 
 138     if (pcmk__str_eq(router_node, controld_globals.our_nodename,
 139                      pcmk__str_casei)) {
 140         is_local = TRUE;
 141     }
 142 
 143     value = crm_meta_value(action->params, PCMK__META_OP_NO_WAIT);
 144     if (crm_is_true(value)) {
 145         no_wait = TRUE;
 146     }
 147 
 148     crm_info("Handling controller request '%s' (%s on %s)%s%s",
 149              id, task, on_node, (is_local? " locally" : ""),
 150              (no_wait? " without waiting" : ""));
 151 
 152     if (is_local
 153         && pcmk__str_eq(task, PCMK_ACTION_DO_SHUTDOWN, pcmk__str_none)) {
 154         /* defer until everything else completes */
 155         crm_info("Controller request '%s' is a local shutdown", id);
 156         graph->completion_action = pcmk__graph_shutdown;
 157         graph->abort_reason = "local shutdown";
 158         te_action_confirmed(action, graph);
 159         return pcmk_rc_ok;
 160 
 161     } else if (pcmk__str_eq(task, PCMK_ACTION_DO_SHUTDOWN, pcmk__str_none)) {
 162         crm_node_t *peer = 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 = create_request(task, action->xml, router_node, CRM_SYSTEM_CRMD, CRM_SYSTEM_TENGINE, NULL);
 169 
 170     counter = pcmk__transition_key(controld_globals.transition_graph->id,
 171                                    action->id, get_target_rc(action),
 172                                    controld_globals.te_uuid);
 173     crm_xml_add(cmd, PCMK__XA_TRANSITION_KEY, counter);
 174 
 175     node = pcmk__get_node(0, router_node, NULL,
 176                           pcmk__node_search_cluster_member);
 177     rc = pcmk__cluster_send_message(node, crm_msg_crmd, cmd);
 178     free(counter);
 179     free_xml(cmd);
 180 
 181     if (rc == FALSE) {
 182         crm_err("Action %d failed: send", action->id);
 183         return ECOMM;
 184 
 185     } else if (no_wait) {
 186         te_action_confirmed(action, graph);
 187 
 188     } else {
 189         if (action->timeout <= 0) {
 190             crm_err("Action %d: %s on %s had an invalid timeout (%dms).  Using %ums instead",
 191                     action->id, task, on_node, action->timeout, graph->network_delay);
 192             action->timeout = (int) graph->network_delay;
 193         }
 194         te_start_action_timer(graph, action);
 195     }
 196 
 197     return pcmk_rc_ok;
 198 }
 199 
 200 /*!
 201  * \internal
 202  * \brief Synthesize an executor event for a resource action timeout
 203  *
 204  * \param[in] action     Resource action that timed out
 205  * \param[in] target_rc  Expected result of action that timed out
 206  *
 207  * Synthesize an executor event for a resource action timeout. (If the executor
 208  * gets a timeout while waiting for a resource action to complete, that will be
 209  * reported via the usual callback. This timeout means we didn't hear from the
 210  * executor itself or the controller that relayed the action to the executor.)
 211  *
 212  * \return Newly created executor event for result of \p action
 213  * \note The caller is responsible for freeing the return value using
 214  *       lrmd_free_event().
 215  */
 216 static lrmd_event_data_t *
 217 synthesize_timeout_event(const pcmk__graph_action_t *action, int target_rc)
     /* [previous][next][first][last][top][bottom][index][help] */
 218 {
 219     lrmd_event_data_t *op = NULL;
 220     const char *target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 221     const char *reason = NULL;
 222     char *dynamic_reason = NULL;
 223 
 224     if (pcmk__str_eq(target, pcmk__cluster_local_node_name(),
 225                      pcmk__str_casei)) {
 226         reason = "Local executor did not return result in time";
 227     } else {
 228         const char *router_node = NULL;
 229 
 230         router_node = crm_element_value(action->xml, PCMK__XA_ROUTER_NODE);
 231         if (router_node == NULL) {
 232             router_node = target;
 233         }
 234         dynamic_reason = crm_strdup_printf("Controller on %s did not return "
 235                                            "result in time", router_node);
 236         reason = dynamic_reason;
 237     }
 238 
 239     op = pcmk__event_from_graph_action(NULL, action, PCMK_EXEC_TIMEOUT,
 240                                        PCMK_OCF_UNKNOWN_ERROR, reason);
 241     op->call_id = -1;
 242     op->user_data = pcmk__transition_key(controld_globals.transition_graph->id,
 243                                          action->id, target_rc,
 244                                          controld_globals.te_uuid);
 245     free(dynamic_reason);
 246     return op;
 247 }
 248 
 249 static void
 250 controld_record_action_event(pcmk__graph_action_t *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 251                              lrmd_event_data_t *op)
 252 {
 253     cib_t *cib_conn = controld_globals.cib_conn;
 254 
 255     xmlNode *state = NULL;
 256     xmlNode *rsc = NULL;
 257     xmlNode *action_rsc = NULL;
 258 
 259     int rc = pcmk_ok;
 260 
 261     const char *rsc_id = NULL;
 262     const char *target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 263     const char *task_uuid = crm_element_value(action->xml,
 264                                               PCMK__XA_OPERATION_KEY);
 265     const char *target_uuid = crm_element_value(action->xml,
 266                                                 PCMK__META_ON_NODE_UUID);
 267 
 268     int target_rc = get_target_rc(action);
 269 
 270     action_rsc = pcmk__xe_first_child(action->xml, PCMK_XE_PRIMITIVE, NULL,
 271                                       NULL);
 272     if (action_rsc == NULL) {
 273         return;
 274     }
 275 
 276     rsc_id = pcmk__xe_id(action_rsc);
 277     CRM_CHECK(rsc_id != NULL,
 278               crm_log_xml_err(action->xml, "Bad:action"); return);
 279 
 280 /*
 281   update the CIB
 282 
 283 <node_state id="hadev">
 284       <lrm>
 285         <lrm_resources>
 286           <lrm_resource id="rsc2" last_op="start" op_code="0" target="hadev"/>
 287 */
 288 
 289     state = pcmk__xe_create(NULL, PCMK__XE_NODE_STATE);
 290 
 291     crm_xml_add(state, PCMK_XA_ID, target_uuid);
 292     crm_xml_add(state, PCMK_XA_UNAME, target);
 293 
 294     rsc = pcmk__xe_create(state, PCMK__XE_LRM);
 295     crm_xml_add(rsc, PCMK_XA_ID, target_uuid);
 296 
 297     rsc = pcmk__xe_create(rsc, PCMK__XE_LRM_RESOURCES);
 298     rsc = pcmk__xe_create(rsc, PCMK__XE_LRM_RESOURCE);
 299     crm_xml_add(rsc, PCMK_XA_ID, rsc_id);
 300 
 301 
 302     crm_copy_xml_element(action_rsc, rsc, PCMK_XA_TYPE);
 303     crm_copy_xml_element(action_rsc, rsc, PCMK_XA_CLASS);
 304     crm_copy_xml_element(action_rsc, rsc, PCMK_XA_PROVIDER);
 305 
 306     pcmk__create_history_xml(rsc, op, CRM_FEATURE_SET, target_rc, target,
 307                              __func__);
 308 
 309     rc = cib_conn->cmds->modify(cib_conn, PCMK_XE_STATUS, state,
 310                                 cib_scope_local);
 311     fsa_register_cib_callback(rc, NULL, cib_action_updated);
 312     free_xml(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     CRM_ASSERT(action != NULL);
 371     CRM_ASSERT(action->xml != NULL);
 372 
 373     pcmk__clear_graph_action_flags(action, pcmk__graph_action_executed);
 374     on_node = crm_element_value(action->xml, PCMK__META_ON_NODE);
 375 
 376     CRM_CHECK(!pcmk__str_empty(on_node),
 377               crm_err("Corrupted command(id=%s) %s: no node",
 378                       pcmk__xe_id(action->xml), pcmk__s(task, "without task"));
 379               return pcmk_rc_node_unknown);
 380 
 381     rsc_op = action->xml;
 382     task = crm_element_value(rsc_op, PCMK_XA_OPERATION);
 383     task_uuid = crm_element_value(action->xml, PCMK__XA_OPERATION_KEY);
 384     router_node = crm_element_value(rsc_op, PCMK__XA_ROUTER_NODE);
 385 
 386     if (!router_node) {
 387         router_node = on_node;
 388     }
 389 
 390     counter = pcmk__transition_key(controld_globals.transition_graph->id,
 391                                    action->id, get_target_rc(action),
 392                                    controld_globals.te_uuid);
 393     crm_xml_add(rsc_op, PCMK__XA_TRANSITION_KEY, counter);
 394 
 395     if (pcmk__str_eq(router_node, controld_globals.our_nodename,
 396                      pcmk__str_casei)) {
 397         is_local = TRUE;
 398     }
 399 
 400     value = crm_meta_value(action->params, PCMK__META_OP_NO_WAIT);
 401     if (crm_is_true(value)) {
 402         no_wait = TRUE;
 403     }
 404 
 405     crm_notice("Initiating %s operation %s%s on %s%s "CRM_XS" action %d",
 406                task, task_uuid, (is_local? " locally" : ""), on_node,
 407                (no_wait? " without waiting" : ""), action->id);
 408 
 409     cmd = create_request(CRM_OP_INVOKE_LRM, rsc_op, router_node,
 410                          CRM_SYSTEM_LRMD, CRM_SYSTEM_TENGINE, NULL);
 411 
 412     if (is_local) {
 413         /* shortcut local resource commands */
 414         ha_msg_input_t data = {
 415             .msg = cmd,
 416             .xml = rsc_op,
 417         };
 418 
 419         fsa_data_t msg = {
 420             .id = 0,
 421             .data = &data,
 422             .data_type = fsa_dt_ha_msg,
 423             .fsa_input = I_NULL,
 424             .fsa_cause = C_FSA_INTERNAL,
 425             .actions = A_LRM_INVOKE,
 426             .origin = __func__,
 427         };
 428 
 429         do_lrm_invoke(A_LRM_INVOKE, C_FSA_INTERNAL, controld_globals.fsa_state,
 430                       I_NULL, &msg);
 431 
 432     } else {
 433         const crm_node_t *node =
 434             pcmk__get_node(0, router_node, NULL,
 435                            pcmk__node_search_cluster_member);
 436 
 437         rc = pcmk__cluster_send_message(node, crm_msg_lrmd, cmd);
 438     }
 439 
 440     free(counter);
 441     free_xml(cmd);
 442 
 443     pcmk__set_graph_action_flags(action, pcmk__graph_action_executed);
 444 
 445     if (rc == FALSE) {
 446         crm_err("Action %d failed: send", action->id);
 447         return ECOMM;
 448 
 449     } else if (no_wait) {
 450         /* Just mark confirmed. Don't bump the job count only to immediately
 451          * decrement it.
 452          */
 453         crm_info("Action %d confirmed - no wait", action->id);
 454         pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
 455         pcmk__update_graph(controld_globals.transition_graph, action);
 456         trigger_graph();
 457 
 458     } else if (pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
 459         crm_debug("Action %d: %s %s on %s(timeout %dms) was already confirmed.",
 460                   action->id, task, task_uuid, on_node, action->timeout);
 461     } else {
 462         if (action->timeout <= 0) {
 463             crm_err("Action %d: %s %s on %s had an invalid timeout (%dms).  Using %ums instead",
 464                     action->id, task, task_uuid, on_node, action->timeout, graph->network_delay);
 465             action->timeout = (int) graph->network_delay;
 466         }
 467         te_update_job_count(action, 1);
 468         te_start_action_timer(graph, action);
 469     }
 470 
 471     return pcmk_rc_ok;
 472 }
 473 
 474 struct te_peer_s
 475 {
 476         char *name;
 477         int jobs;
 478         int migrate_jobs;
 479 };
 480 
 481 static void te_peer_free(gpointer p)
     /* [previous][next][first][last][top][bottom][index][help] */
 482 {
 483     struct te_peer_s *peer = p;
 484 
 485     free(peer->name);
 486     free(peer);
 487 }
 488 
 489 void te_reset_job_counts(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 490 {
 491     GHashTableIter iter;
 492     struct te_peer_s *peer = NULL;
 493 
 494     if(te_targets == NULL) {
 495         te_targets = pcmk__strkey_table(NULL, te_peer_free);
 496     }
 497 
 498     g_hash_table_iter_init(&iter, te_targets);
 499     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & peer)) {
 500         peer->jobs = 0;
 501         peer->migrate_jobs = 0;
 502     }
 503 }
 504 
 505 static void
 506 te_update_job_count_on(const char *target, int offset, bool migrate)
     /* [previous][next][first][last][top][bottom][index][help] */
 507 {
 508     struct te_peer_s *r = NULL;
 509 
 510     if(target == NULL || te_targets == NULL) {
 511         return;
 512     }
 513 
 514     r = g_hash_table_lookup(te_targets, target);
 515     if(r == NULL) {
 516         r = pcmk__assert_alloc(1, sizeof(struct te_peer_s));
 517         r->name = pcmk__str_copy(target);
 518         g_hash_table_insert(te_targets, r->name, r);
 519     }
 520 
 521     r->jobs += offset;
 522     if(migrate) {
 523         r->migrate_jobs += offset;
 524     }
 525     crm_trace("jobs[%s] = %d", target, r->jobs);
 526 }
 527 
 528 static void
 529 te_update_job_count(pcmk__graph_action_t *action, int offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 530 {
 531     const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 532     const char *target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 533 
 534     if ((action->type != pcmk__rsc_graph_action) || (target == NULL)) {
 535         /* No limit on these */
 536         return;
 537     }
 538 
 539     /* if we have a router node, this means the action is performing
 540      * on a remote node. For now, we count all actions occurring on a
 541      * remote node against the job list on the cluster node hosting
 542      * the connection resources */
 543     target = crm_element_value(action->xml, PCMK__XA_ROUTER_NODE);
 544 
 545     if ((target == NULL)
 546         && pcmk__strcase_any_of(task, PCMK_ACTION_MIGRATE_TO,
 547                                 PCMK_ACTION_MIGRATE_FROM, NULL)) {
 548 
 549         const char *t1 = crm_meta_value(action->params,
 550                                         PCMK__META_MIGRATE_SOURCE);
 551         const char *t2 = crm_meta_value(action->params,
 552                                         PCMK__META_MIGRATE_TARGET);
 553 
 554         te_update_job_count_on(t1, offset, TRUE);
 555         te_update_job_count_on(t2, offset, TRUE);
 556         return;
 557     } else if (target == NULL) {
 558         target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 559     }
 560 
 561     te_update_job_count_on(target, offset, FALSE);
 562 }
 563 
 564 /*!
 565  * \internal
 566  * \brief Check whether a graph action is allowed to be executed on a node
 567  *
 568  * \param[in] graph   Transition graph being executed
 569  * \param[in] action  Graph action being executed
 570  * \param[in] target  Name of node where action should be executed
 571  *
 572  * \return true if action is allowed, otherwise false
 573  */
 574 static bool
 575 allowed_on_node(const pcmk__graph_t *graph, const pcmk__graph_action_t *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 576                 const char *target)
 577 {
 578     int limit = 0;
 579     struct te_peer_s *r = NULL;
 580     const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 581     const char *id = crm_element_value(action->xml, PCMK__XA_OPERATION_KEY);
 582 
 583     if(target == NULL) {
 584         /* No limit on these */
 585         return true;
 586 
 587     } else if(te_targets == NULL) {
 588         return false;
 589     }
 590 
 591     r = g_hash_table_lookup(te_targets, target);
 592     limit = throttle_get_job_limit(target);
 593 
 594     if(r == NULL) {
 595         r = pcmk__assert_alloc(1, sizeof(struct te_peer_s));
 596         r->name = pcmk__str_copy(target);
 597         g_hash_table_insert(te_targets, r->name, r);
 598     }
 599 
 600     if(limit <= r->jobs) {
 601         crm_trace("Peer %s is over their job limit of %d (%d): deferring %s",
 602                   target, limit, r->jobs, id);
 603         return false;
 604 
 605     } else if(graph->migration_limit > 0 && r->migrate_jobs >= graph->migration_limit) {
 606         if (pcmk__strcase_any_of(task, PCMK_ACTION_MIGRATE_TO,
 607                                  PCMK_ACTION_MIGRATE_FROM, NULL)) {
 608             crm_trace("Peer %s is over their migration job limit of %d (%d): deferring %s",
 609                       target, graph->migration_limit, r->migrate_jobs, id);
 610             return false;
 611         }
 612     }
 613 
 614     crm_trace("Peer %s has not hit their limit yet. current jobs = %d limit= %d limit", target, r->jobs, limit);
 615 
 616     return true;
 617 }
 618 
 619 /*!
 620  * \internal
 621  * \brief Check whether a graph action is allowed to be executed
 622  *
 623  * \param[in] graph   Transition graph being executed
 624  * \param[in] action  Graph action being executed
 625  *
 626  * \return true if action is allowed, otherwise false
 627  */
 628 static bool
 629 graph_action_allowed(pcmk__graph_t *graph, pcmk__graph_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 630 {
 631     const char *target = NULL;
 632     const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 633 
 634     if (action->type != pcmk__rsc_graph_action) {
 635         /* No limit on these */
 636         return true;
 637     }
 638 
 639     /* if we have a router node, this means the action is performing
 640      * on a remote node. For now, we count all actions occurring on a
 641      * remote node against the job list on the cluster node hosting
 642      * the connection resources */
 643     target = crm_element_value(action->xml, PCMK__XA_ROUTER_NODE);
 644 
 645     if ((target == NULL)
 646         && pcmk__strcase_any_of(task, PCMK_ACTION_MIGRATE_TO,
 647                                 PCMK_ACTION_MIGRATE_FROM, NULL)) {
 648         target = crm_meta_value(action->params, PCMK__META_MIGRATE_SOURCE);
 649         if (!allowed_on_node(graph, action, target)) {
 650             return false;
 651         }
 652 
 653         target = crm_meta_value(action->params, PCMK__META_MIGRATE_TARGET);
 654 
 655     } else if (target == NULL) {
 656         target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 657     }
 658 
 659     return allowed_on_node(graph, action, target);
 660 }
 661 
 662 /*!
 663  * \brief Confirm a graph action (and optionally update graph)
 664  *
 665  * \param[in,out] action  Action to confirm
 666  * \param[in,out] graph   Update and trigger this graph (if non-NULL)
 667  */
 668 void
 669 te_action_confirmed(pcmk__graph_action_t *action, pcmk__graph_t *graph)
     /* [previous][next][first][last][top][bottom][index][help] */
 670 {
 671     if (!pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
 672         if ((action->type == pcmk__rsc_graph_action)
 673             && (crm_element_value(action->xml, PCMK__META_ON_NODE) != NULL)) {
 674             te_update_job_count(action, -1);
 675         }
 676         pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
 677     }
 678     if (graph) {
 679         pcmk__update_graph(graph, action);
 680         trigger_graph();
 681     }
 682 }
 683 
 684 static pcmk__graph_functions_t te_graph_fns = {
 685     execute_pseudo_action,
 686     execute_rsc_action,
 687     execute_cluster_action,
 688     controld_execute_fence_action,
 689     graph_action_allowed,
 690 };
 691 
 692 /*
 693  * \internal
 694  * \brief Register the transitioner's graph functions with \p libpacemaker
 695  */
 696 void
 697 controld_register_graph_functions(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 698 {
 699     pcmk__set_graph_functions(&te_graph_fns);
 700 }
 701 
 702 void
 703 notify_crmd(pcmk__graph_t *graph)
     /* [previous][next][first][last][top][bottom][index][help] */
 704 {
 705     const char *type = "unknown";
 706     enum crmd_fsa_input event = I_NULL;
 707 
 708     crm_debug("Processing transition completion in state %s",
 709               fsa_state2string(controld_globals.fsa_state));
 710 
 711     CRM_CHECK(graph->complete, graph->complete = true);
 712 
 713     switch (graph->completion_action) {
 714         case pcmk__graph_wait:
 715             type = "stop";
 716             if (controld_globals.fsa_state == S_TRANSITION_ENGINE) {
 717                 event = I_TE_SUCCESS;
 718             }
 719             break;
 720         case pcmk__graph_done:
 721             type = "done";
 722             if (controld_globals.fsa_state == S_TRANSITION_ENGINE) {
 723                 event = I_TE_SUCCESS;
 724             }
 725             break;
 726 
 727         case pcmk__graph_restart:
 728             type = "restart";
 729             if (controld_globals.fsa_state == S_TRANSITION_ENGINE) {
 730                 if (controld_get_period_transition_timer() > 0) {
 731                     controld_stop_transition_timer();
 732                     controld_start_transition_timer();
 733                 } else {
 734                     event = I_PE_CALC;
 735                 }
 736 
 737             } else if (controld_globals.fsa_state == S_POLICY_ENGINE) {
 738                 controld_set_fsa_action_flags(A_PE_INVOKE);
 739                 controld_trigger_fsa();
 740             }
 741             break;
 742 
 743         case pcmk__graph_shutdown:
 744             type = "shutdown";
 745             if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 746                 event = I_STOP;
 747 
 748             } else {
 749                 crm_err("We didn't ask to be shut down, yet the scheduler is telling us to");
 750                 event = I_TERMINATE;
 751             }
 752     }
 753 
 754     crm_debug("Transition %d status: %s - %s", graph->id, type,
 755               pcmk__s(graph->abort_reason, "unspecified reason"));
 756 
 757     graph->abort_reason = NULL;
 758     graph->completion_action = pcmk__graph_done;
 759 
 760     if (event != I_NULL) {
 761         register_fsa_input(C_FSA_INTERNAL, event, NULL);
 762     } else {
 763         controld_trigger_fsa();
 764     }
 765 }

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