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. internal_lrm_state_destroy
  10. lrm_state_reset_tables
  11. lrm_state_init_local
  12. lrm_state_destroy_all
  13. lrm_state_find
  14. lrm_state_find_or_create
  15. lrm_state_get_list
  16. find_connected_proxy_by_node
  17. remote_proxy_disconnect_by_node
  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
  36. crmd_unpack_alerts
  37. crmd_alert_node_event
  38. crmd_alert_fencing_op
  39. crmd_alert_resource_op

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

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