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), return pcmk_rc_node_unknown);
 376 
 377     rsc_op = action->xml;
 378     task = crm_element_value(rsc_op, PCMK_XA_OPERATION);
 379     task_uuid = crm_element_value(action->xml, PCMK__XA_OPERATION_KEY);
 380     router_node = crm_element_value(rsc_op, PCMK__XA_ROUTER_NODE);
 381 
 382     if (!router_node) {
 383         router_node = on_node;
 384     }
 385 
 386     counter = pcmk__transition_key(controld_globals.transition_graph->id,
 387                                    action->id, get_target_rc(action),
 388                                    controld_globals.te_uuid);
 389     crm_xml_add(rsc_op, PCMK__XA_TRANSITION_KEY, counter);
 390 
 391     if (controld_is_local_node(router_node)) {
 392         is_local = TRUE;
 393     }
 394 
 395     value = crm_meta_value(action->params, PCMK__META_OP_NO_WAIT);
 396     if (crm_is_true(value)) {
 397         no_wait = TRUE;
 398     }
 399 
 400     cmd = pcmk__new_request(pcmk_ipc_controld, CRM_SYSTEM_TENGINE, router_node,
 401                             CRM_SYSTEM_LRMD, CRM_OP_INVOKE_LRM, rsc_op);
 402 
 403     if (is_local) {
 404         /* shortcut local resource commands */
 405         ha_msg_input_t data = {
 406             .msg = cmd,
 407             .xml = rsc_op,
 408         };
 409 
 410         fsa_data_t msg = {
 411             .id = 0,
 412             .data = &data,
 413             .data_type = fsa_dt_ha_msg,
 414             .fsa_input = I_NULL,
 415             .fsa_cause = C_FSA_INTERNAL,
 416             .actions = A_LRM_INVOKE,
 417             .origin = __func__,
 418         };
 419 
 420         do_lrm_invoke(A_LRM_INVOKE, C_FSA_INTERNAL, controld_globals.fsa_state,
 421                       I_NULL, &msg);
 422 
 423     } else {
 424         const pcmk__node_status_t *node =
 425             pcmk__get_node(0, router_node, NULL,
 426                            pcmk__node_search_cluster_member);
 427 
 428         crm_notice("Asking %s to execute %s on %s%s "
 429                    QB_XS " transition %s action %d",
 430                    router_node, task_uuid, on_node,
 431                    (no_wait? " without waiting" : ""), counter, action->id);
 432         rc = pcmk__cluster_send_message(node, pcmk_ipc_execd, cmd);
 433     }
 434 
 435     free(counter);
 436     pcmk__xml_free(cmd);
 437 
 438     pcmk__set_graph_action_flags(action, pcmk__graph_action_executed);
 439 
 440     if (rc == FALSE) {
 441         crm_err("Action %d failed: send", action->id);
 442         return ECOMM;
 443 
 444     } else if (no_wait) {
 445         /* Just mark confirmed. Don't bump the job count only to immediately
 446          * decrement it.
 447          */
 448         crm_info("Action %d confirmed - no wait", action->id);
 449         pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
 450         pcmk__update_graph(controld_globals.transition_graph, action);
 451         trigger_graph();
 452 
 453     } else if (pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
 454         crm_debug("Action %d: %s %s on %s(timeout %dms) was already confirmed.",
 455                   action->id, task, task_uuid, on_node, action->timeout);
 456     } else {
 457         if (action->timeout <= 0) {
 458             crm_err("Action %d: %s %s on %s had an invalid timeout (%dms).  Using %ums instead",
 459                     action->id, task, task_uuid, on_node, action->timeout, graph->network_delay);
 460             action->timeout = (int) graph->network_delay;
 461         }
 462         te_update_job_count(action, 1);
 463         te_start_action_timer(graph, action);
 464     }
 465 
 466     return pcmk_rc_ok;
 467 }
 468 
 469 struct te_peer_s
 470 {
 471         char *name;
 472         int jobs;
 473         int migrate_jobs;
 474 };
 475 
 476 static void te_peer_free(gpointer p)
     /* [previous][next][first][last][top][bottom][index][help] */
 477 {
 478     struct te_peer_s *peer = p;
 479 
 480     free(peer->name);
 481     free(peer);
 482 }
 483 
 484 void te_reset_job_counts(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 485 {
 486     GHashTableIter iter;
 487     struct te_peer_s *peer = NULL;
 488 
 489     if(te_targets == NULL) {
 490         te_targets = pcmk__strkey_table(NULL, te_peer_free);
 491     }
 492 
 493     g_hash_table_iter_init(&iter, te_targets);
 494     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & peer)) {
 495         peer->jobs = 0;
 496         peer->migrate_jobs = 0;
 497     }
 498 }
 499 
 500 static void
 501 te_update_job_count_on(const char *target, int offset, bool migrate)
     /* [previous][next][first][last][top][bottom][index][help] */
 502 {
 503     struct te_peer_s *r = NULL;
 504 
 505     if(target == NULL || te_targets == NULL) {
 506         return;
 507     }
 508 
 509     r = g_hash_table_lookup(te_targets, target);
 510     if(r == NULL) {
 511         r = pcmk__assert_alloc(1, sizeof(struct te_peer_s));
 512         r->name = pcmk__str_copy(target);
 513         g_hash_table_insert(te_targets, r->name, r);
 514     }
 515 
 516     r->jobs += offset;
 517     if(migrate) {
 518         r->migrate_jobs += offset;
 519     }
 520     crm_trace("jobs[%s] = %d", target, r->jobs);
 521 }
 522 
 523 static void
 524 te_update_job_count(pcmk__graph_action_t *action, int offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 525 {
 526     const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 527     const char *target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 528 
 529     if ((action->type != pcmk__rsc_graph_action) || (target == NULL)) {
 530         /* No limit on these */
 531         return;
 532     }
 533 
 534     /* if we have a router node, this means the action is performing
 535      * on a remote node. For now, we count all actions occurring on a
 536      * remote node against the job list on the cluster node hosting
 537      * the connection resources */
 538     target = crm_element_value(action->xml, PCMK__XA_ROUTER_NODE);
 539 
 540     if ((target == NULL)
 541         && pcmk__strcase_any_of(task, PCMK_ACTION_MIGRATE_TO,
 542                                 PCMK_ACTION_MIGRATE_FROM, NULL)) {
 543 
 544         const char *t1 = crm_meta_value(action->params,
 545                                         PCMK__META_MIGRATE_SOURCE);
 546         const char *t2 = crm_meta_value(action->params,
 547                                         PCMK__META_MIGRATE_TARGET);
 548 
 549         te_update_job_count_on(t1, offset, TRUE);
 550         te_update_job_count_on(t2, offset, TRUE);
 551         return;
 552     } else if (target == NULL) {
 553         target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 554     }
 555 
 556     te_update_job_count_on(target, offset, FALSE);
 557 }
 558 
 559 /*!
 560  * \internal
 561  * \brief Check whether a graph action is allowed to be executed on a node
 562  *
 563  * \param[in] graph   Transition graph being executed
 564  * \param[in] action  Graph action being executed
 565  * \param[in] target  Name of node where action should be executed
 566  *
 567  * \return true if action is allowed, otherwise false
 568  */
 569 static bool
 570 allowed_on_node(const pcmk__graph_t *graph, const pcmk__graph_action_t *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 571                 const char *target)
 572 {
 573     int limit = 0;
 574     struct te_peer_s *r = NULL;
 575     const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 576     const char *id = crm_element_value(action->xml, PCMK__XA_OPERATION_KEY);
 577 
 578     if(target == NULL) {
 579         /* No limit on these */
 580         return true;
 581 
 582     } else if(te_targets == NULL) {
 583         return false;
 584     }
 585 
 586     r = g_hash_table_lookup(te_targets, target);
 587     limit = throttle_get_job_limit(target);
 588 
 589     if(r == NULL) {
 590         r = pcmk__assert_alloc(1, sizeof(struct te_peer_s));
 591         r->name = pcmk__str_copy(target);
 592         g_hash_table_insert(te_targets, r->name, r);
 593     }
 594 
 595     if(limit <= r->jobs) {
 596         crm_trace("Peer %s is over their job limit of %d (%d): deferring %s",
 597                   target, limit, r->jobs, id);
 598         return false;
 599 
 600     } else if(graph->migration_limit > 0 && r->migrate_jobs >= graph->migration_limit) {
 601         if (pcmk__strcase_any_of(task, PCMK_ACTION_MIGRATE_TO,
 602                                  PCMK_ACTION_MIGRATE_FROM, NULL)) {
 603             crm_trace("Peer %s is over their migration job limit of %d (%d): deferring %s",
 604                       target, graph->migration_limit, r->migrate_jobs, id);
 605             return false;
 606         }
 607     }
 608 
 609     crm_trace("Peer %s has not hit their limit yet. current jobs = %d limit= %d limit", target, r->jobs, limit);
 610 
 611     return true;
 612 }
 613 
 614 /*!
 615  * \internal
 616  * \brief Check whether a graph action is allowed to be executed
 617  *
 618  * \param[in] graph   Transition graph being executed
 619  * \param[in] action  Graph action being executed
 620  *
 621  * \return true if action is allowed, otherwise false
 622  */
 623 static bool
 624 graph_action_allowed(pcmk__graph_t *graph, pcmk__graph_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 625 {
 626     const char *target = NULL;
 627     const char *task = crm_element_value(action->xml, PCMK_XA_OPERATION);
 628 
 629     if (action->type != pcmk__rsc_graph_action) {
 630         /* No limit on these */
 631         return true;
 632     }
 633 
 634     /* if we have a router node, this means the action is performing
 635      * on a remote node. For now, we count all actions occurring on a
 636      * remote node against the job list on the cluster node hosting
 637      * the connection resources */
 638     target = crm_element_value(action->xml, PCMK__XA_ROUTER_NODE);
 639 
 640     if ((target == NULL)
 641         && pcmk__strcase_any_of(task, PCMK_ACTION_MIGRATE_TO,
 642                                 PCMK_ACTION_MIGRATE_FROM, NULL)) {
 643         target = crm_meta_value(action->params, PCMK__META_MIGRATE_SOURCE);
 644         if (!allowed_on_node(graph, action, target)) {
 645             return false;
 646         }
 647 
 648         target = crm_meta_value(action->params, PCMK__META_MIGRATE_TARGET);
 649 
 650     } else if (target == NULL) {
 651         target = crm_element_value(action->xml, PCMK__META_ON_NODE);
 652     }
 653 
 654     return allowed_on_node(graph, action, target);
 655 }
 656 
 657 /*!
 658  * \brief Confirm a graph action (and optionally update graph)
 659  *
 660  * \param[in,out] action  Action to confirm
 661  * \param[in,out] graph   Update and trigger this graph (if non-NULL)
 662  */
 663 void
 664 te_action_confirmed(pcmk__graph_action_t *action, pcmk__graph_t *graph)
     /* [previous][next][first][last][top][bottom][index][help] */
 665 {
 666     if (!pcmk_is_set(action->flags, pcmk__graph_action_confirmed)) {
 667         if ((action->type == pcmk__rsc_graph_action)
 668             && (crm_element_value(action->xml, PCMK__META_ON_NODE) != NULL)) {
 669             te_update_job_count(action, -1);
 670         }
 671         pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
 672     }
 673     if (graph) {
 674         pcmk__update_graph(graph, action);
 675         trigger_graph();
 676     }
 677 }
 678 
 679 static pcmk__graph_functions_t te_graph_fns = {
 680     execute_pseudo_action,
 681     execute_rsc_action,
 682     execute_cluster_action,
 683     controld_execute_fence_action,
 684     graph_action_allowed,
 685 };
 686 
 687 /*
 688  * \internal
 689  * \brief Register the transitioner's graph functions with \p libpacemaker
 690  */
 691 void
 692 controld_register_graph_functions(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 693 {
 694     pcmk__set_graph_functions(&te_graph_fns);
 695 }
 696 
 697 void
 698 notify_crmd(pcmk__graph_t *graph)
     /* [previous][next][first][last][top][bottom][index][help] */
 699 {
 700     const char *type = "unknown";
 701     enum crmd_fsa_input event = I_NULL;
 702 
 703     crm_debug("Processing transition completion in state %s",
 704               fsa_state2string(controld_globals.fsa_state));
 705 
 706     CRM_CHECK(graph->complete, graph->complete = true);
 707 
 708     switch (graph->completion_action) {
 709         case pcmk__graph_wait:
 710             type = "stop";
 711             if (controld_globals.fsa_state == S_TRANSITION_ENGINE) {
 712                 event = I_TE_SUCCESS;
 713             }
 714             break;
 715         case pcmk__graph_done:
 716             type = "done";
 717             if (controld_globals.fsa_state == S_TRANSITION_ENGINE) {
 718                 event = I_TE_SUCCESS;
 719             }
 720             break;
 721 
 722         case pcmk__graph_restart:
 723             type = "restart";
 724             if (controld_globals.fsa_state == S_TRANSITION_ENGINE) {
 725                 if (controld_get_period_transition_timer() > 0) {
 726                     controld_stop_transition_timer();
 727                     controld_start_transition_timer();
 728                 } else {
 729                     event = I_PE_CALC;
 730                 }
 731 
 732             } else if (controld_globals.fsa_state == S_POLICY_ENGINE) {
 733                 controld_set_fsa_action_flags(A_PE_INVOKE);
 734                 controld_trigger_fsa();
 735             }
 736             break;
 737 
 738         case pcmk__graph_shutdown:
 739             type = "shutdown";
 740             if (pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 741                 event = I_STOP;
 742 
 743             } else {
 744                 crm_err("We didn't ask to be shut down, yet the scheduler is telling us to");
 745                 event = I_TERMINATE;
 746             }
 747     }
 748 
 749     crm_debug("Transition %d status: %s - %s", graph->id, type,
 750               pcmk__s(graph->abort_reason, "unspecified reason"));
 751 
 752     graph->abort_reason = NULL;
 753     graph->completion_action = pcmk__graph_done;
 754 
 755     if (event != I_NULL) {
 756         register_fsa_input(C_FSA_INTERNAL, event, NULL);
 757     } else {
 758         controld_trigger_fsa();
 759     }
 760 }

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