root/daemons/controld/controld_execd_state.c

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

DEFINITIONS

This source file includes following definitions.
  1. free_rsc_info
  2. free_deletion_op
  3. free_recurring_op
  4. fail_pending_op
  5. lrm_state_is_local
  6. lrm_state_create
  7. remote_proxy_remove_by_node
  8. find_connected_proxy_by_node
  9. remote_proxy_disconnect_by_node
  10. internal_lrm_state_destroy
  11. lrm_state_reset_tables
  12. lrm_state_init_local
  13. lrm_state_destroy_all
  14. controld_get_executor_state
  15. lrm_state_get_list
  16. lrm_state_disconnect_only
  17. lrm_state_disconnect
  18. lrm_state_is_connected
  19. lrm_state_poke_connection
  20. controld_connect_local_executor
  21. crmd_remote_proxy_new
  22. crmd_is_proxy_session
  23. crmd_proxy_send
  24. crmd_proxy_dispatch
  25. remote_config_check
  26. crmd_remote_proxy_cb
  27. controld_connect_remote_executor
  28. lrm_state_get_metadata
  29. lrm_state_cancel
  30. lrm_state_get_rsc_info
  31. controld_execute_resource_agent
  32. lrm_state_register_rsc
  33. lrm_state_unregister_rsc

   1 /*
   2  * Copyright 2012-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 <errno.h>
  13 
  14 #include <crm/crm.h>
  15 #include <crm/common/iso8601.h>
  16 #include <crm/common/xml.h>
  17 #include <crm/lrmd_internal.h>
  18 
  19 #include <pacemaker-internal.h>
  20 #include <pacemaker-controld.h>
  21 
  22 static GHashTable *lrm_state_table = NULL;
  23 extern GHashTable *proxy_table;
  24 int lrmd_internal_proxy_send(lrmd_t * lrmd, xmlNode *msg);
  25 void lrmd_internal_set_proxy_callback(lrmd_t * lrmd, void *userdata, void (*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg));
  26 
  27 static void
  28 free_rsc_info(gpointer value)
     /* [previous][next][first][last][top][bottom][index][help] */
  29 {
  30     lrmd_rsc_info_t *rsc_info = value;
  31 
  32     lrmd_free_rsc_info(rsc_info);
  33 }
  34 
  35 static void
  36 free_deletion_op(gpointer value)
     /* [previous][next][first][last][top][bottom][index][help] */
  37 {
  38     struct pending_deletion_op_s *op = value;
  39 
  40     free(op->rsc);
  41     delete_ha_msg_input(op->input);
  42     free(op);
  43 }
  44 
  45 static void
  46 free_recurring_op(gpointer value)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48     active_op_t *op = value;
  49 
  50     free(op->user_data);
  51     free(op->rsc_id);
  52     free(op->op_type);
  53     free(op->op_key);
  54     if (op->params) {
  55         g_hash_table_destroy(op->params);
  56     }
  57     free(op);
  58 }
  59 
  60 static gboolean
  61 fail_pending_op(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63     lrmd_event_data_t event = { 0, };
  64     lrm_state_t *lrm_state = user_data;
  65     active_op_t *op = value;
  66 
  67     crm_trace("Pre-emptively failing " PCMK__OP_FMT " on %s (call=%s, %s)",
  68               op->rsc_id, op->op_type, op->interval_ms,
  69               lrm_state->node_name, (char*)key, op->user_data);
  70 
  71     event.type = lrmd_event_exec_complete;
  72     event.rsc_id = op->rsc_id;
  73     event.op_type = op->op_type;
  74     event.user_data = op->user_data;
  75     event.timeout = 0;
  76     event.interval_ms = op->interval_ms;
  77     lrmd__set_result(&event, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_NOT_CONNECTED,
  78                      "Action was pending when executor connection was dropped");
  79     event.t_run = op->start_time;
  80     event.t_rcchange = op->start_time;
  81 
  82     event.call_id = op->call_id;
  83     event.remote_nodename = lrm_state->node_name;
  84     event.params = op->params;
  85 
  86     process_lrm_event(lrm_state, &event, op, NULL);
  87     lrmd__reset_result(&event);
  88     return TRUE;
  89 }
  90 
  91 gboolean
  92 lrm_state_is_local(lrm_state_t *lrm_state)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94     return (lrm_state != NULL) && controld_is_local_node(lrm_state->node_name);
  95 }
  96 
  97 /*!
  98  * \internal
  99  * \brief Create executor state entry for a node and add it to the state table
 100  *
 101  * \param[in]  node_name  Node to create entry for
 102  *
 103  * \return Newly allocated executor state object initialized for \p node_name
 104  */
 105 static lrm_state_t *
 106 lrm_state_create(const char *node_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 107 {
 108     lrm_state_t *state = NULL;
 109 
 110     if (!node_name) {
 111         crm_err("No node name given for lrm state object");
 112         return NULL;
 113     }
 114 
 115     state = pcmk__assert_alloc(1, sizeof(lrm_state_t));
 116 
 117     state->node_name = pcmk__str_copy(node_name);
 118     state->rsc_info_cache = pcmk__strkey_table(NULL, free_rsc_info);
 119     state->deletion_ops = pcmk__strkey_table(free, free_deletion_op);
 120     state->active_ops = pcmk__strkey_table(free, free_recurring_op);
 121     state->resource_history = pcmk__strkey_table(NULL, history_free);
 122     state->metadata_cache = metadata_cache_new();
 123 
 124     g_hash_table_insert(lrm_state_table, (char *)state->node_name, state);
 125     return state;
 126 }
 127 
 128 static gboolean
 129 remote_proxy_remove_by_node(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131     remote_proxy_t *proxy = value;
 132     const char *node_name = user_data;
 133 
 134     if (pcmk__str_eq(node_name, proxy->node_name, pcmk__str_casei)) {
 135         return TRUE;
 136     }
 137 
 138     return FALSE;
 139 }
 140 
 141 static remote_proxy_t *
 142 find_connected_proxy_by_node(const char * node_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144     GHashTableIter gIter;
 145     remote_proxy_t *proxy = NULL;
 146 
 147     CRM_CHECK(proxy_table != NULL, return NULL);
 148 
 149     g_hash_table_iter_init(&gIter, proxy_table);
 150 
 151     while (g_hash_table_iter_next(&gIter, NULL, (gpointer *) &proxy)) {
 152         if (proxy->source
 153             && pcmk__str_eq(node_name, proxy->node_name, pcmk__str_casei)) {
 154             return proxy;
 155         }
 156     }
 157 
 158     return NULL;
 159 }
 160 
 161 static void
 162 remote_proxy_disconnect_by_node(const char * node_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164     remote_proxy_t *proxy = NULL;
 165 
 166     CRM_CHECK(proxy_table != NULL, return);
 167 
 168     while ((proxy = find_connected_proxy_by_node(node_name)) != NULL) {
 169         /* mainloop_del_ipc_client() eventually calls remote_proxy_disconnected()
 170          * , which removes the entry from proxy_table.
 171          * Do not do this in a g_hash_table_iter_next() loop. */
 172         if (proxy->source) {
 173             mainloop_del_ipc_client(proxy->source);
 174         }
 175     }
 176 
 177     return;
 178 }
 179 
 180 static void
 181 internal_lrm_state_destroy(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 182 {
 183     lrm_state_t *lrm_state = data;
 184 
 185     if (!lrm_state) {
 186         return;
 187     }
 188 
 189     /* Rather than directly remove the recorded proxy entries from proxy_table,
 190      * make sure any connected proxies get disconnected. So that
 191      * remote_proxy_disconnected() will be called and as well remove the
 192      * entries from proxy_table.
 193      */
 194     remote_proxy_disconnect_by_node(lrm_state->node_name);
 195 
 196     crm_trace("Destroying proxy table %s with %u members",
 197               lrm_state->node_name, g_hash_table_size(proxy_table));
 198     // Just in case there's still any leftovers in proxy_table
 199     g_hash_table_foreach_remove(proxy_table, remote_proxy_remove_by_node, (char *) lrm_state->node_name);
 200     remote_ra_cleanup(lrm_state);
 201     lrmd_api_delete(lrm_state->conn);
 202 
 203     if (lrm_state->rsc_info_cache) {
 204         crm_trace("Destroying rsc info cache with %u members",
 205                   g_hash_table_size(lrm_state->rsc_info_cache));
 206         g_hash_table_destroy(lrm_state->rsc_info_cache);
 207     }
 208     if (lrm_state->resource_history) {
 209         crm_trace("Destroying history op cache with %u members",
 210                   g_hash_table_size(lrm_state->resource_history));
 211         g_hash_table_destroy(lrm_state->resource_history);
 212     }
 213     if (lrm_state->deletion_ops) {
 214         crm_trace("Destroying deletion op cache with %u members",
 215                   g_hash_table_size(lrm_state->deletion_ops));
 216         g_hash_table_destroy(lrm_state->deletion_ops);
 217     }
 218     if (lrm_state->active_ops != NULL) {
 219         crm_trace("Destroying pending op cache with %u members",
 220                   g_hash_table_size(lrm_state->active_ops));
 221         g_hash_table_destroy(lrm_state->active_ops);
 222     }
 223     metadata_cache_free(lrm_state->metadata_cache);
 224 
 225     free((char *)lrm_state->node_name);
 226     free(lrm_state);
 227 }
 228 
 229 void
 230 lrm_state_reset_tables(lrm_state_t * lrm_state, gboolean reset_metadata)
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232     if (lrm_state->resource_history) {
 233         crm_trace("Resetting resource history cache with %u members",
 234                   g_hash_table_size(lrm_state->resource_history));
 235         g_hash_table_remove_all(lrm_state->resource_history);
 236     }
 237     if (lrm_state->deletion_ops) {
 238         crm_trace("Resetting deletion operations cache with %u members",
 239                   g_hash_table_size(lrm_state->deletion_ops));
 240         g_hash_table_remove_all(lrm_state->deletion_ops);
 241     }
 242     if (lrm_state->active_ops != NULL) {
 243         crm_trace("Resetting active operations cache with %u members",
 244                   g_hash_table_size(lrm_state->active_ops));
 245         g_hash_table_remove_all(lrm_state->active_ops);
 246     }
 247     if (lrm_state->rsc_info_cache) {
 248         crm_trace("Resetting resource information cache with %u members",
 249                   g_hash_table_size(lrm_state->rsc_info_cache));
 250         g_hash_table_remove_all(lrm_state->rsc_info_cache);
 251     }
 252     if (reset_metadata) {
 253         metadata_cache_reset(lrm_state->metadata_cache);
 254     }
 255 }
 256 
 257 gboolean
 258 lrm_state_init_local(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 259 {
 260     if (lrm_state_table) {
 261         return TRUE;
 262     }
 263 
 264     lrm_state_table = pcmk__strikey_table(NULL, internal_lrm_state_destroy);
 265     if (!lrm_state_table) {
 266         return FALSE;
 267     }
 268 
 269     proxy_table = pcmk__strikey_table(NULL, remote_proxy_free);
 270     if (!proxy_table) {
 271         g_hash_table_destroy(lrm_state_table);
 272         lrm_state_table = NULL;
 273         return FALSE;
 274     }
 275 
 276     return TRUE;
 277 }
 278 
 279 void
 280 lrm_state_destroy_all(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282     if (lrm_state_table) {
 283         crm_trace("Destroying state table with %u members",
 284                   g_hash_table_size(lrm_state_table));
 285         g_hash_table_destroy(lrm_state_table); lrm_state_table = NULL;
 286     }
 287     if(proxy_table) {
 288         crm_trace("Destroying proxy table with %u members",
 289                   g_hash_table_size(proxy_table));
 290         g_hash_table_destroy(proxy_table); proxy_table = NULL;
 291     }
 292 }
 293 
 294 /*!
 295  * \internal
 296  * \brief Get executor state object
 297  *
 298  * \param[in] node_name  Get executor state for this node (local node if NULL)
 299  * \param[in] create     If true, create executor state if it doesn't exist
 300  *
 301  * \return Executor state object for \p node_name
 302  */
 303 lrm_state_t *
 304 controld_get_executor_state(const char *node_name, bool create)
     /* [previous][next][first][last][top][bottom][index][help] */
 305 {
 306     lrm_state_t *state = NULL;
 307 
 308     if ((node_name == NULL) && (controld_globals.cluster != NULL)) {
 309         node_name = controld_globals.cluster->priv->node_name;
 310     }
 311     if ((node_name == NULL) || (lrm_state_table == NULL)) {
 312         return NULL;
 313     }
 314 
 315     state = g_hash_table_lookup(lrm_state_table, node_name);
 316     if ((state == NULL) && create) {
 317         state = lrm_state_create(node_name);
 318     }
 319     return state;
 320 }
 321 
 322 /* @TODO the lone caller just needs to iterate over the values, so replace this
 323  * with a g_hash_table_foreach() wrapper instead
 324  */
 325 GList *
 326 lrm_state_get_list(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 327 {
 328     if (lrm_state_table == NULL) {
 329         return NULL;
 330     }
 331     return g_hash_table_get_values(lrm_state_table);
 332 }
 333 
 334 void
 335 lrm_state_disconnect_only(lrm_state_t * lrm_state)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337     int removed = 0;
 338 
 339     if (!lrm_state->conn) {
 340         return;
 341     }
 342     crm_trace("Disconnecting %s", lrm_state->node_name);
 343 
 344     remote_proxy_disconnect_by_node(lrm_state->node_name);
 345 
 346     ((lrmd_t *) lrm_state->conn)->cmds->disconnect(lrm_state->conn);
 347 
 348     if (!pcmk_is_set(controld_globals.fsa_input_register, R_SHUTDOWN)) {
 349         removed = g_hash_table_foreach_remove(lrm_state->active_ops,
 350                                               fail_pending_op, lrm_state);
 351         crm_trace("Synthesized %d operation failures for %s", removed, lrm_state->node_name);
 352     }
 353 }
 354 
 355 void
 356 lrm_state_disconnect(lrm_state_t * lrm_state)
     /* [previous][next][first][last][top][bottom][index][help] */
 357 {
 358     if (!lrm_state->conn) {
 359         return;
 360     }
 361 
 362     lrm_state_disconnect_only(lrm_state);
 363 
 364     lrmd_api_delete(lrm_state->conn);
 365     lrm_state->conn = NULL;
 366 }
 367 
 368 int
 369 lrm_state_is_connected(lrm_state_t * lrm_state)
     /* [previous][next][first][last][top][bottom][index][help] */
 370 {
 371     if (!lrm_state->conn) {
 372         return FALSE;
 373     }
 374     return ((lrmd_t *) lrm_state->conn)->cmds->is_connected(lrm_state->conn);
 375 }
 376 
 377 int
 378 lrm_state_poke_connection(lrm_state_t * lrm_state)
     /* [previous][next][first][last][top][bottom][index][help] */
 379 {
 380 
 381     if (!lrm_state->conn) {
 382         return -ENOTCONN;
 383     }
 384     return ((lrmd_t *) lrm_state->conn)->cmds->poke_connection(lrm_state->conn);
 385 }
 386 
 387 // \return Standard Pacemaker return code
 388 int
 389 controld_connect_local_executor(lrm_state_t *lrm_state)
     /* [previous][next][first][last][top][bottom][index][help] */
 390 {
 391     int rc = pcmk_rc_ok;
 392 
 393     if (lrm_state->conn == NULL) {
 394         lrmd_t *api = NULL;
 395 
 396         rc = lrmd__new(&api, NULL, NULL, 0);
 397         if (rc != pcmk_rc_ok) {
 398             return rc;
 399         }
 400         api->cmds->set_callback(api, lrm_op_callback);
 401         lrm_state->conn = api;
 402     }
 403 
 404     rc = ((lrmd_t *) lrm_state->conn)->cmds->connect(lrm_state->conn,
 405                                                      CRM_SYSTEM_CRMD, NULL);
 406     rc = pcmk_legacy2rc(rc);
 407 
 408     if (rc == pcmk_rc_ok) {
 409         lrm_state->num_lrm_register_fails = 0;
 410     } else {
 411         lrm_state->num_lrm_register_fails++;
 412     }
 413     return rc;
 414 }
 415 
 416 static remote_proxy_t *
 417 crmd_remote_proxy_new(lrmd_t *lrmd, const char *node_name, const char *session_id, const char *channel)
     /* [previous][next][first][last][top][bottom][index][help] */
 418 {
 419     struct ipc_client_callbacks proxy_callbacks = {
 420         .dispatch = remote_proxy_dispatch,
 421         .destroy = remote_proxy_disconnected
 422     };
 423     remote_proxy_t *proxy = remote_proxy_new(lrmd, &proxy_callbacks, node_name,
 424                                              session_id, channel);
 425     return proxy;
 426 }
 427 
 428 gboolean
 429 crmd_is_proxy_session(const char *session)
     /* [previous][next][first][last][top][bottom][index][help] */
 430 {
 431     return g_hash_table_lookup(proxy_table, session) ? TRUE : FALSE;
 432 }
 433 
 434 void
 435 crmd_proxy_send(const char *session, xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437     remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
 438     lrm_state_t *lrm_state = NULL;
 439 
 440     if (!proxy) {
 441         return;
 442     }
 443     crm_log_xml_trace(msg, "to-proxy");
 444     lrm_state = controld_get_executor_state(proxy->node_name, false);
 445     if (lrm_state) {
 446         crm_trace("Sending event to %.8s on %s", proxy->session_id, proxy->node_name);
 447         remote_proxy_relay_event(proxy, msg);
 448     }
 449 }
 450 
 451 static void
 452 crmd_proxy_dispatch(const char *session, xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 453 {
 454     crm_trace("Processing proxied IPC message from session %s", session);
 455     crm_log_xml_trace(msg, "controller[inbound]");
 456     crm_xml_add(msg, PCMK__XA_CRM_SYS_FROM, session);
 457     if (controld_authorize_ipc_message(msg, NULL, session)) {
 458         route_message(C_IPC_MESSAGE, msg);
 459     }
 460     controld_trigger_fsa();
 461 }
 462 
 463 static void
 464 remote_config_check(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 465 {
 466     if (rc != pcmk_ok) {
 467         crm_err("Query resulted in an error: %s", pcmk_strerror(rc));
 468 
 469         if (rc == -EACCES || rc == -pcmk_err_schema_validation) {
 470             crm_err("The cluster is mis-configured - shutting down and staying down");
 471         }
 472 
 473     } else {
 474         lrmd_t * lrmd = (lrmd_t *)user_data;
 475         crm_time_t *now = crm_time_new(NULL);
 476         GHashTable *config_hash = pcmk__strkey_table(free, free);
 477         pcmk_rule_input_t rule_input = {
 478             .now = now,
 479         };
 480 
 481         crm_debug("Call %d : Parsing CIB options", call_id);
 482         pcmk_unpack_nvpair_blocks(output, PCMK_XE_CLUSTER_PROPERTY_SET,
 483                                   PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS, &rule_input,
 484                                   config_hash, NULL);
 485 
 486         /* Now send it to the remote peer */
 487         lrmd__validate_remote_settings(lrmd, config_hash);
 488 
 489         g_hash_table_destroy(config_hash);
 490         crm_time_free(now);
 491     }
 492 }
 493 
 494 static void
 495 crmd_remote_proxy_cb(lrmd_t *lrmd, void *userdata, xmlNode *msg)
     /* [previous][next][first][last][top][bottom][index][help] */
 496 {
 497     lrm_state_t *lrm_state = userdata;
 498     const char *session = crm_element_value(msg, PCMK__XA_LRMD_IPC_SESSION);
 499     remote_proxy_t *proxy = g_hash_table_lookup(proxy_table, session);
 500 
 501     const char *op = crm_element_value(msg, PCMK__XA_LRMD_IPC_OP);
 502     if (pcmk__str_eq(op, LRMD_IPC_OP_NEW, pcmk__str_casei)) {
 503         const char *channel = crm_element_value(msg, PCMK__XA_LRMD_IPC_SERVER);
 504 
 505         proxy = crmd_remote_proxy_new(lrmd, lrm_state->node_name, session, channel);
 506         if (!remote_ra_controlling_guest(lrm_state)) {
 507             if (proxy != NULL) {
 508                 cib_t *cib_conn = controld_globals.cib_conn;
 509 
 510                 /* Look up PCMK_OPT_STONITH_WATCHDOG_TIMEOUT and send to the
 511                  * remote peer for validation
 512                  */
 513                 int rc = cib_conn->cmds->query(cib_conn, PCMK_XE_CRM_CONFIG,
 514                                                NULL, cib_none);
 515                 cib_conn->cmds->register_callback_full(cib_conn, rc, 10, FALSE,
 516                                                        lrmd,
 517                                                        "remote_config_check",
 518                                                        remote_config_check,
 519                                                        NULL);
 520             }
 521         } else {
 522             crm_debug("Skipping remote_config_check for guest-nodes");
 523         }
 524 
 525     } else if (pcmk__str_eq(op, LRMD_IPC_OP_SHUTDOWN_REQ, pcmk__str_casei)) {
 526         char *now_s = NULL;
 527 
 528         crm_notice("%s requested shutdown of its remote connection",
 529                    lrm_state->node_name);
 530 
 531         if (!remote_ra_is_in_maintenance(lrm_state)) {
 532             now_s = pcmk__ttoa(time(NULL));
 533             update_attrd(lrm_state->node_name, PCMK__NODE_ATTR_SHUTDOWN, now_s,
 534                          NULL, TRUE);
 535             free(now_s);
 536 
 537             remote_proxy_ack_shutdown(lrmd);
 538 
 539             crm_warn("Reconnection attempts to %s may result in failures that must be cleared",
 540                     lrm_state->node_name);
 541         } else {
 542             remote_proxy_nack_shutdown(lrmd);
 543 
 544             crm_notice("Remote resource for %s is not managed so no ordered shutdown happening",
 545                     lrm_state->node_name);
 546         }
 547         return;
 548 
 549     } else if (pcmk__str_eq(op, LRMD_IPC_OP_REQUEST, pcmk__str_casei) && proxy && proxy->is_local) {
 550         /* This is for the controller, which we are, so don't try
 551          * to send to ourselves over IPC -- do it directly.
 552          */
 553         uint32_t flags = 0U;
 554         int rc = pcmk_rc_ok;
 555         xmlNode *wrapper = pcmk__xe_first_child(msg, PCMK__XE_LRMD_IPC_MSG,
 556                                                 NULL, NULL);
 557         xmlNode *request = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
 558 
 559         CRM_CHECK(request != NULL, return);
 560         CRM_CHECK(lrm_state->node_name, return);
 561         crm_xml_add(request, PCMK_XE_ACL_ROLE, "pacemaker-remote");
 562         pcmk__update_acl_user(request, PCMK__XA_LRMD_IPC_USER,
 563                               lrm_state->node_name);
 564 
 565         /* Pacemaker Remote nodes don't know their own names (as known to the
 566          * cluster). When getting a node info request with no name or ID, add
 567          * the name, so we don't return info for ourselves instead of the
 568          * Pacemaker Remote node.
 569          */
 570         if (pcmk__str_eq(crm_element_value(request, PCMK__XA_CRM_TASK),
 571                          CRM_OP_NODE_INFO, pcmk__str_none)) {
 572             int node_id = 0;
 573 
 574             crm_element_value_int(request, PCMK_XA_ID, &node_id);
 575             if ((node_id <= 0)
 576                 && (crm_element_value(request, PCMK_XA_UNAME) == NULL)) {
 577                 crm_xml_add(request, PCMK_XA_UNAME, lrm_state->node_name);
 578             }
 579         }
 580 
 581         crmd_proxy_dispatch(session, request);
 582 
 583         rc = pcmk__xe_get_flags(msg, PCMK__XA_LRMD_IPC_MSG_FLAGS, &flags, 0U);
 584         if (rc != pcmk_rc_ok) {
 585             crm_warn("Couldn't parse controller flags from remote request: %s",
 586                      pcmk_rc_str(rc));
 587         }
 588         if (pcmk_is_set(flags, crm_ipc_client_response)) {
 589             int msg_id = 0;
 590             xmlNode *op_reply = pcmk__xe_create(NULL, PCMK__XE_ACK);
 591 
 592             crm_xml_add(op_reply, PCMK_XA_FUNCTION, __func__);
 593             crm_xml_add_int(op_reply, PCMK__XA_LINE, __LINE__);
 594 
 595             crm_element_value_int(msg, PCMK__XA_LRMD_IPC_MSG_ID, &msg_id);
 596             remote_proxy_relay_response(proxy, op_reply, msg_id);
 597 
 598             pcmk__xml_free(op_reply);
 599         }
 600 
 601     } else {
 602         remote_proxy_cb(lrmd, lrm_state->node_name, msg);
 603     }
 604 }
 605 
 606 
 607 // \return Standard Pacemaker return code
 608 int
 609 controld_connect_remote_executor(lrm_state_t *lrm_state, const char *server,
     /* [previous][next][first][last][top][bottom][index][help] */
 610                                  int port, int timeout_ms)
 611 {
 612     int rc = pcmk_rc_ok;
 613 
 614     if (lrm_state->conn == NULL) {
 615         lrmd_t *api = NULL;
 616 
 617         rc = lrmd__new(&api, lrm_state->node_name, server, port);
 618         if (rc != pcmk_rc_ok) {
 619             crm_warn("Pacemaker Remote connection to %s:%s failed: %s "
 620                      QB_XS " rc=%d", server, port, pcmk_rc_str(rc), rc);
 621 
 622             return rc;
 623         }
 624         lrm_state->conn = api;
 625         api->cmds->set_callback(api, remote_lrm_op_callback);
 626         lrmd_internal_set_proxy_callback(api, lrm_state, crmd_remote_proxy_cb);
 627     }
 628 
 629     crm_trace("Initiating remote connection to %s:%d with timeout %dms",
 630               server, port, timeout_ms);
 631     rc = ((lrmd_t *) lrm_state->conn)->cmds->connect_async(lrm_state->conn,
 632                                                            lrm_state->node_name,
 633                                                            timeout_ms);
 634     if (rc == pcmk_ok) {
 635         lrm_state->num_lrm_register_fails = 0;
 636     } else {
 637         lrm_state->num_lrm_register_fails++; // Ignored for remote connections
 638     }
 639     return pcmk_legacy2rc(rc);
 640 }
 641 
 642 int
 643 lrm_state_get_metadata(lrm_state_t * lrm_state,
     /* [previous][next][first][last][top][bottom][index][help] */
 644                        const char *class,
 645                        const char *provider,
 646                        const char *agent, char **output, enum lrmd_call_options options)
 647 {
 648     lrmd_key_value_t *params = NULL;
 649 
 650     if (!lrm_state->conn) {
 651         return -ENOTCONN;
 652     }
 653 
 654     /* Add the node name to the environment, as is done with normal resource
 655      * action calls. Meta-data calls shouldn't need it, but some agents are
 656      * written with an ocf_local_nodename call at the beginning regardless of
 657      * action. Without the environment variable, the agent would try to contact
 658      * the controller to get the node name -- but the controller would be
 659      * blocking on the synchronous meta-data call.
 660      *
 661      * At this point, we have to assume that agents are unlikely to make other
 662      * calls that require the controller, such as crm_node --quorum or
 663      * --cluster-id.
 664      *
 665      * @TODO Make meta-data calls asynchronous. (This will be part of a larger
 666      * project to make meta-data calls via the executor rather than directly.)
 667      */
 668     params = lrmd_key_value_add(params, CRM_META "_" PCMK__META_ON_NODE,
 669                                 lrm_state->node_name);
 670 
 671     return ((lrmd_t *) lrm_state->conn)->cmds->get_metadata_params(lrm_state->conn,
 672             class, provider, agent, output, options, params);
 673 }
 674 
 675 int
 676 lrm_state_cancel(lrm_state_t *lrm_state, const char *rsc_id, const char *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 677                  guint interval_ms)
 678 {
 679     if (!lrm_state->conn) {
 680         return -ENOTCONN;
 681     }
 682 
 683     /* Figure out a way to make this async?
 684      * NOTICE: Currently it's synced and directly acknowledged in do_lrm_invoke(). */
 685     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
 686         return remote_ra_cancel(lrm_state, rsc_id, action, interval_ms);
 687     }
 688     return ((lrmd_t *) lrm_state->conn)->cmds->cancel(lrm_state->conn, rsc_id,
 689                                                       action, interval_ms);
 690 }
 691 
 692 lrmd_rsc_info_t *
 693 lrm_state_get_rsc_info(lrm_state_t * lrm_state, const char *rsc_id, enum lrmd_call_options options)
     /* [previous][next][first][last][top][bottom][index][help] */
 694 {
 695     lrmd_rsc_info_t *rsc = NULL;
 696 
 697     if (!lrm_state->conn) {
 698         return NULL;
 699     }
 700     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
 701         return remote_ra_get_rsc_info(lrm_state, rsc_id);
 702     }
 703 
 704     rsc = g_hash_table_lookup(lrm_state->rsc_info_cache, rsc_id);
 705     if (rsc == NULL) {
 706         /* only contact the lrmd if we don't already have a cached rsc info */
 707         rsc = ((lrmd_t *) lrm_state->conn)->cmds->get_rsc_info(lrm_state->conn, rsc_id, options);
 708         if (rsc == NULL) {
 709                     return NULL;
 710         }
 711         /* cache the result */
 712         g_hash_table_insert(lrm_state->rsc_info_cache, rsc->id, rsc);
 713     }
 714 
 715     return lrmd_copy_rsc_info(rsc);
 716 
 717 }
 718 
 719 /*!
 720  * \internal
 721  * \brief Initiate a resource agent action
 722  *
 723  * \param[in,out] lrm_state       Executor state object
 724  * \param[in]     rsc_id          ID of resource for action
 725  * \param[in]     action          Action to execute
 726  * \param[in]     userdata        String to copy and pass to execution callback
 727  * \param[in]     interval_ms     Action interval (in milliseconds)
 728  * \param[in]     timeout_ms      Action timeout (in milliseconds)
 729  * \param[in]     start_delay_ms  Delay (in ms) before initiating action
 730  * \param[in]     parameters      Hash table of resource parameters
 731  * \param[out]    call_id         Where to store call ID on success
 732  *
 733  * \return Standard Pacemaker return code
 734  */
 735 int
 736 controld_execute_resource_agent(lrm_state_t *lrm_state, const char *rsc_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 737                                 const char *action, const char *userdata,
 738                                 guint interval_ms, int timeout_ms,
 739                                 int start_delay_ms, GHashTable *parameters,
 740                                 int *call_id)
 741 {
 742     int rc = pcmk_rc_ok;
 743     lrmd_key_value_t *params = NULL;
 744 
 745     if (lrm_state->conn == NULL) {
 746         return ENOTCONN;
 747     }
 748 
 749     // Convert parameters from hash table to list
 750     if (parameters != NULL) {
 751         const char *key = NULL;
 752         const char *value = NULL;
 753         GHashTableIter iter;
 754 
 755         g_hash_table_iter_init(&iter, parameters);
 756         while (g_hash_table_iter_next(&iter, (gpointer *) &key,
 757                                       (gpointer *) &value)) {
 758             params = lrmd_key_value_add(params, key, value);
 759         }
 760     }
 761 
 762     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
 763         rc = controld_execute_remote_agent(lrm_state, rsc_id, action,
 764                                            userdata, interval_ms, timeout_ms,
 765                                            start_delay_ms, params, call_id);
 766 
 767     } else {
 768         rc = ((lrmd_t *) lrm_state->conn)->cmds->exec(lrm_state->conn, rsc_id,
 769                                                       action, userdata,
 770                                                       interval_ms, timeout_ms,
 771                                                       start_delay_ms,
 772                                                       lrmd_opt_notify_changes_only,
 773                                                       params);
 774         if (rc < 0) {
 775             rc = pcmk_legacy2rc(rc);
 776         } else {
 777             *call_id = rc;
 778             rc = pcmk_rc_ok;
 779         }
 780     }
 781     return rc;
 782 }
 783 
 784 int
 785 lrm_state_register_rsc(lrm_state_t * lrm_state,
     /* [previous][next][first][last][top][bottom][index][help] */
 786                        const char *rsc_id,
 787                        const char *class,
 788                        const char *provider, const char *agent, enum lrmd_call_options options)
 789 {
 790     lrmd_t *conn = (lrmd_t *) lrm_state->conn;
 791 
 792     if (conn == NULL) {
 793         return -ENOTCONN;
 794     }
 795 
 796     if (is_remote_lrmd_ra(agent, provider, NULL)) {
 797         return controld_get_executor_state(rsc_id, true)? pcmk_ok : -EINVAL;
 798     }
 799 
 800     /* @TODO Implement an asynchronous version of this (currently a blocking
 801      * call to the lrmd).
 802      */
 803     return conn->cmds->register_rsc(lrm_state->conn, rsc_id, class, provider,
 804                                     agent, options);
 805 }
 806 
 807 int
 808 lrm_state_unregister_rsc(lrm_state_t * lrm_state,
     /* [previous][next][first][last][top][bottom][index][help] */
 809                          const char *rsc_id, enum lrmd_call_options options)
 810 {
 811     if (!lrm_state->conn) {
 812         return -ENOTCONN;
 813     }
 814 
 815     if (is_remote_lrmd_ra(NULL, NULL, rsc_id)) {
 816         g_hash_table_remove(lrm_state_table, rsc_id);
 817         return pcmk_ok;
 818     }
 819 
 820     g_hash_table_remove(lrm_state->rsc_info_cache, rsc_id);
 821 
 822     /* @TODO Optimize this ... this function is a blocking round trip from
 823      * client to daemon. The controld_execd_state.c code path that uses this
 824      * function should always treat it as an async operation. The executor API
 825      * should make an async version available.
 826      */
 827     return ((lrmd_t *) lrm_state->conn)->cmds->unregister_rsc(lrm_state->conn, rsc_id, options);
 828 }

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