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

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