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. lrm_state_destroy
  8. remote_proxy_remove_by_node
  9. find_connected_proxy_by_node
  10. remote_proxy_disconnect_by_node
  11. internal_lrm_state_destroy
  12. lrm_state_reset_tables
  13. lrm_state_init_local
  14. lrm_state_destroy_all
  15. lrm_state_find
  16. lrm_state_find_or_create
  17. lrm_state_get_list
  18. lrm_state_disconnect_only
  19. lrm_state_disconnect
  20. lrm_state_is_connected
  21. lrm_state_poke_connection
  22. controld_connect_local_executor
  23. crmd_remote_proxy_new
  24. crmd_is_proxy_session
  25. crmd_proxy_send
  26. crmd_proxy_dispatch
  27. remote_config_check
  28. crmd_remote_proxy_cb
  29. controld_connect_remote_executor
  30. lrm_state_get_metadata
  31. lrm_state_cancel
  32. lrm_state_get_rsc_info
  33. controld_execute_resource_agent
  34. lrm_state_register_rsc
  35. lrm_state_unregister_rsc

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

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