41#include <gnutls/gnutls.h>
42#include <sys/socket.h>
43#include <netinet/in.h>
44#include <netinet/ip.h>
48#define MAX_TLS_RECV_WAIT 10000
52static int lrmd_api_disconnect(
lrmd_t * lrmd);
53static int lrmd_api_is_connected(
lrmd_t * lrmd);
57static void lrmd_internal_proxy_dispatch(
lrmd_t *lrmd, xmlNode *msg);
61#define TLS_HANDSHAKE_TIMEOUT 5
63static void lrmd_tls_disconnect(
lrmd_t * lrmd);
64static int global_remote_msg_id = 0;
65static void lrmd_tls_connection_destroy(gpointer userdata);
66static int add_tls_to_mainloop(
lrmd_t *lrmd,
bool do_api_handshake);
68typedef struct lrmd_private_s {
79 char *remote_nodename;
92 int expected_late_replies;
93 GList *pending_notify;
100 void (*proxy_callback)(
lrmd_t *lrmd,
void *userdata, xmlNode *msg);
101 void *proxy_callback_userdata;
105static int process_lrmd_handshake_reply(xmlNode *reply,
lrmd_private_t *native);
106static void report_async_connection_result(
lrmd_t * lrmd,
int rc);
109lrmd_list_add(
lrmd_list_t * head,
const char *value)
114 p->
val = strdup(value);
117 while (end && end->
next) {
136 char *val = (
char *)head->
val;
151 p->
key = strdup(key);
152 p->
value = strdup(value);
155 while (end && end->
next) {
202 event->interval_ms = interval_ms;
213 copy->
type =
event->type;
223 copy->
call_id =
event->call_id;
224 copy->
timeout =
event->timeout;
228 copy->
rc =
event->rc;
230 copy->
t_run =
event->t_run;
252 free((
void *) event->
rsc_id);
257 if (event->
params != NULL) {
258 g_hash_table_destroy(event->
params);
264lrmd_dispatch_internal(gpointer
data, gpointer user_data)
275 if (proxy_session != NULL) {
277 lrmd_internal_proxy_dispatch(lrmd, msg);
279 }
else if (!native->callback) {
281 crm_trace(
"notify event received but client has not set callback");
318 event.t_rcchange = epoch;
322 event.exec_time = QB_MAX(0, exec_time);
326 event.queue_time = QB_MAX(0, queue_time);
348 native->callback(&event);
351 g_hash_table_destroy(event.params);
358lrmd_ipc_dispatch(
const char *buffer, ssize_t length, gpointer userdata)
363 if (native->callback != NULL) {
366 lrmd_dispatch_internal(msg, lrmd);
373lrmd_free_xml(gpointer userdata)
379remote_executor_connected(
lrmd_t * lrmd)
387handle_remote_msg(xmlNode *xml,
lrmd_t *lrmd)
390 const char *msg_type = NULL;
394 lrmd_dispatch_internal(xml, lrmd);
398 if (native->expected_late_replies > 0) {
399 native->expected_late_replies--;
405 int rc = process_lrmd_handshake_reply(xml, native);
412 crm_err(
"Got outdated Pacemaker Remote reply %d", reply_id);
427process_pending_notifies(gpointer userdata)
432 if (native->pending_notify == NULL) {
433 return G_SOURCE_CONTINUE;
436 crm_trace(
"Processing pending notifies");
437 g_list_foreach(native->pending_notify, lrmd_dispatch_internal, lrmd);
438 g_list_free_full(native->pending_notify, lrmd_free_xml);
439 native->pending_notify = NULL;
440 return G_SOURCE_CONTINUE;
453lrmd_tls_dispatch(gpointer userdata)
460 if (!remote_executor_connected(lrmd)) {
461 crm_trace(
"TLS dispatch triggered after disconnect");
473 crm_info(
"Lost %s executor connection while reading data",
474 (native->remote_nodename? native->remote_nodename :
"local"));
475 lrmd_tls_disconnect(lrmd);
488 handle_remote_msg(xml, lrmd);
499 switch (native->type) {
504 if (native->pending_notify) {
519 crm_err(
"Unsupported executor connection type (bug?): %d",
521 return -EPROTONOSUPPORT;
534 switch (private->type) {
540 lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
546 lrmd_tls_dispatch(lrmd);
549 crm_err(
"Unsupported executor connection type (bug?): %d",
553 if (lrmd_api_is_connected(lrmd) == FALSE) {
562lrmd_create_op(
const char *token,
const char *op, xmlNode *
data,
int timeout,
565 xmlNode *op_msg = NULL;
581 crm_trace(
"Created executor %s command with call options %.8lx (%d)",
582 op, (
long)options, options);
587lrmd_ipc_connection_destroy(gpointer userdata)
592 switch (native->type) {
594 crm_info(
"Disconnected from local executor");
597 crm_info(
"Disconnected from remote executor on %s",
598 native->remote_nodename);
601 crm_err(
"Unsupported executor connection type %d (bug?)",
607 native->source = NULL;
609 if (native->callback) {
612 event.remote_nodename = native->remote_nodename;
613 native->callback(&event);
618lrmd_tls_connection_destroy(gpointer userdata)
623 crm_info(
"TLS connection destroyed");
626 gnutls_bye(native->remote->
tls_session, GNUTLS_SHUT_RDWR);
634 if (native->sock >= 0) {
637 if (native->process_notify) {
639 native->process_notify = NULL;
641 if (native->pending_notify) {
642 g_list_free_full(native->pending_notify, lrmd_free_xml);
643 native->pending_notify = NULL;
645 if (native->handshake_trigger != NULL) {
647 native->handshake_trigger = NULL;
650 free(native->remote->
buffer);
652 native->remote->
buffer = NULL;
657 if (native->callback) {
661 native->callback(&event);
669 const char *msg_type)
678read_remote_reply(
lrmd_t *lrmd,
int total_timeout,
int expected_reply_id,
682 time_t start = time(NULL);
683 const char *msg_type = NULL;
685 int remaining_timeout = 0;
694 for (*reply = NULL; *reply == NULL; ) {
697 if (*reply == NULL) {
699 if (remaining_timeout) {
700 remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
702 remaining_timeout = total_timeout;
704 if (remaining_timeout <= 0) {
714 if (*reply == NULL) {
723 crm_err(
"Empty msg type received while waiting for reply");
729 native->pending_notify = g_list_append(native->pending_notify, *reply);
730 if (native->process_notify) {
737 crm_err(
"Expected a reply, got %s", msg_type);
740 }
else if (reply_id != expected_reply_id) {
741 if (native->expected_late_replies > 0) {
742 native->expected_late_replies--;
744 crm_err(
"Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
751 if (native->remote->
buffer && native->process_notify) {
760send_remote_message(
lrmd_t *lrmd, xmlNode *msg)
765 global_remote_msg_id++;
766 if (global_remote_msg_id <= 0) {
767 global_remote_msg_id = 1;
773 crm_err(
"Disconnecting because TLS message could not be sent to "
775 lrmd_tls_disconnect(lrmd);
781lrmd_tls_send_recv(
lrmd_t * lrmd, xmlNode * msg,
int timeout, xmlNode ** reply)
786 if (!remote_executor_connected(lrmd)) {
790 rc = send_remote_message(lrmd, msg);
795 rc = read_remote_reply(lrmd,
timeout, global_remote_msg_id, &xml);
797 crm_err(
"Disconnecting remote after request %d reply not received: %s "
798 QB_XS
" rc=%d timeout=%dms",
800 lrmd_tls_disconnect(lrmd);
813lrmd_send_xml(
lrmd_t * lrmd, xmlNode * msg,
int timeout, xmlNode ** reply)
818 switch (native->type) {
823 rc = lrmd_tls_send_recv(lrmd, msg,
timeout, reply);
826 crm_err(
"Unsupported executor connection type (bug?): %d",
828 rc = -EPROTONOSUPPORT;
835lrmd_send_xml_no_reply(
lrmd_t * lrmd, xmlNode * msg)
840 switch (native->type) {
845 rc = send_remote_message(lrmd, msg);
850 native->expected_late_replies++;
855 crm_err(
"Unsupported executor connection type (bug?): %d",
857 rc = -EPROTONOSUPPORT;
864lrmd_api_is_connected(
lrmd_t * lrmd)
868 switch (native->type) {
872 return remote_executor_connected(lrmd);
874 crm_err(
"Unsupported executor connection type (bug?): %d",
899lrmd_send_command(
lrmd_t *lrmd,
const char *op, xmlNode *
data,
900 xmlNode **output_data,
int timeout,
905 xmlNode *op_msg = NULL;
906 xmlNode *op_reply = NULL;
908 if (!lrmd_api_is_connected(lrmd)) {
913 crm_err(
"No operation specified");
918 crm_trace(
"Sending %s op to executor", op);
920 op_msg = lrmd_create_op(native->token, op,
data,
timeout, options);
922 if (op_msg == NULL) {
927 rc = lrmd_send_xml(lrmd, op_msg,
timeout, &op_reply);
929 rc = lrmd_send_xml_no_reply(lrmd, op_msg);
934 crm_perror(LOG_ERR,
"Couldn't perform %s operation (timeout=%d): %d", op,
timeout, rc);
937 }
else if (op_reply == NULL) {
952 *output_data = op_reply;
957 if (lrmd_api_is_connected(lrmd) == FALSE) {
958 crm_err(
"Executor disconnected");
967lrmd_api_poke_connection(
lrmd_t * lrmd)
1005lrmd_handshake_hello_msg(
const char *
name,
bool is_proxy)
1023process_lrmd_handshake_reply(xmlNode *reply,
lrmd_private_t *native)
1030 long long uptime = -1;
1040 native->remote->
uptime = uptime;
1043 native->remote->
start_state = strdup(start_state);
1047 crm_err(
"Executor protocol version mismatch between client (%s) and server (%s)",
1051 crm_err(
"Invalid registration message: %s", msg_type);
1054 }
else if (tmp_ticket == NULL) {
1055 crm_err(
"No registration token provided");
1059 crm_trace(
"Obtained registration token: %s", tmp_ticket);
1060 native->token = strdup(tmp_ticket);
1069lrmd_handshake(
lrmd_t * lrmd,
const char *
name)
1073 xmlNode *reply = NULL;
1074 xmlNode *hello = lrmd_handshake_hello_msg(
name, native->proxy_callback != NULL);
1076 rc = lrmd_send_xml(lrmd, hello, -1, &reply);
1079 crm_perror(LOG_DEBUG,
"Couldn't complete registration with the executor API: %d", rc);
1081 }
else if (reply == NULL) {
1082 crm_err(
"Did not receive registration reply");
1085 rc = process_lrmd_handshake_reply(reply, native);
1092 lrmd_api_disconnect(lrmd);
1099lrmd_handshake_async(
lrmd_t * lrmd,
const char *
name)
1103 xmlNode *hello = lrmd_handshake_hello_msg(
name, native->proxy_callback != NULL);
1105 rc = send_remote_message(lrmd, hello);
1108 native->expected_late_replies++;
1110 lrmd_api_disconnect(lrmd);
1118lrmd_ipc_connect(
lrmd_t * lrmd,
int *fd)
1124 .dispatch = lrmd_ipc_dispatch,
1125 .destroy = lrmd_ipc_connection_destroy
1128 crm_info(
"Connecting to executor");
1133 if (native->ipc != NULL) {
1148 if (native->ipc == NULL) {
1149 crm_debug(
"Could not connect to the executor API");
1157copy_gnutls_datum(gnutls_datum_t *dest, gnutls_datum_t *source)
1159 pcmk__assert((dest != NULL) && (source != NULL) && (source->data != NULL));
1161 dest->data = gnutls_malloc(source->size);
1164 memcpy(dest->data, source->data, source->size);
1165 dest->size = source->size;
1169clear_gnutls_datum(gnutls_datum_t *datum)
1171 gnutls_free(datum->data);
1176#define KEY_READ_LEN 256
1180read_gnutls_key(
const char *location, gnutls_datum_t *key)
1182 FILE *stream = NULL;
1185 if ((location == NULL) || (key == NULL)) {
1189 stream = fopen(location,
"r");
1190 if (stream == NULL) {
1194 key->data = gnutls_malloc(buf_len);
1196 while (!feof(stream)) {
1197 int next = fgetc(stream);
1200 if (!feof(stream)) {
1201 crm_warn(
"Pacemaker Remote key read was partially successful "
1202 "(copy in memory may be corrupted)");
1206 if (key->size == buf_len) {
1208 key->data = gnutls_realloc(key->data, buf_len);
1211 key->data[key->size++] = (
unsigned char) next;
1215 if (key->size == 0) {
1216 clear_gnutls_datum(key);
1226 const char *location;
1231key_is_cached(
struct key_cache_s *key_cache)
1233 return key_cache->updated != 0;
1237key_cache_expired(
struct key_cache_s *key_cache)
1239 return (time(NULL) - key_cache->updated) >= 60;
1243clear_key_cache(
struct key_cache_s *key_cache)
1245 clear_gnutls_datum(&(key_cache->key));
1246 if ((key_cache->updated != 0) || (key_cache->location != NULL)) {
1247 key_cache->updated = 0;
1248 key_cache->location = NULL;
1249 crm_debug(
"Cleared Pacemaker Remote key cache");
1254get_cached_key(
struct key_cache_s *key_cache, gnutls_datum_t *key)
1256 copy_gnutls_datum(key, &(key_cache->key));
1257 crm_debug(
"Using cached Pacemaker Remote key from %s",
1258 pcmk__s(key_cache->location,
"unknown location"));
1262cache_key(
struct key_cache_s *key_cache, gnutls_datum_t *key,
1263 const char *location)
1265 key_cache->updated = time(NULL);
1266 key_cache->location = location;
1267 copy_gnutls_datum(&(key_cache->key), key);
1268 crm_debug(
"Using (and cacheing) Pacemaker Remote key from %s",
1269 pcmk__s(location,
"unknown location"));
1283get_remote_key(
const char *location, gnutls_datum_t *key)
1285 static struct key_cache_s key_cache = { 0, };
1288 if ((location == NULL) || (key == NULL)) {
1292 if (key_is_cached(&key_cache)) {
1293 if (key_cache_expired(&key_cache)) {
1294 clear_key_cache(&key_cache);
1296 get_cached_key(&key_cache, key);
1301 rc = read_gnutls_key(location, key);
1305 cache_key(&key_cache, key, location);
1326 static const char *env_location = NULL;
1327 static bool need_env =
true;
1337 if (env_location != NULL) {
1338 rc = get_remote_key(env_location, key);
1343 crm_warn(
"Could not read Pacemaker Remote key from %s: %s",
1354 crm_warn(
"Could not read Pacemaker Remote key from default location %s: %s",
1360report_async_connection_result(
lrmd_t * lrmd,
int rc)
1364 if (native->callback) {
1367 event.remote_nodename = native->remote_nodename;
1368 event.connection_rc = rc;
1369 native->callback(&event);
1374tls_handshake_failed(
lrmd_t *lrmd,
int tls_rc,
int rc)
1378 crm_warn(
"Disconnecting after TLS handshake with "
1379 "Pacemaker Remote server %s:%d failed: %s",
1380 native->server, native->port,
1381 (rc == EPROTO)? gnutls_strerror(tls_rc) :
pcmk_rc_str(rc));
1386 lrmd_tls_connection_destroy(lrmd);
1390tls_handshake_succeeded(
lrmd_t *lrmd)
1402 crm_info(
"TLS connection to Pacemaker Remote server %s:%d succeeded",
1403 native->server, native->port);
1404 rc = add_tls_to_mainloop(lrmd,
true);
1423tls_client_handshake(
lrmd_t *lrmd)
1426 int tls_rc = GNUTLS_E_SUCCESS;
1431 tls_handshake_failed(lrmd, tls_rc, rc);
1447add_tls_to_mainloop(
lrmd_t *lrmd,
bool do_api_handshake)
1453 native->server, native->port);
1456 .dispatch = lrmd_tls_dispatch,
1457 .destroy = lrmd_tls_connection_destroy,
1461 process_pending_notifies, lrmd);
1471 if (do_api_handshake) {
1472 rc = lrmd_handshake_async(lrmd,
name);
1478struct handshake_data_s {
1485try_handshake_cb(gpointer user_data)
1487 struct handshake_data_s *hs = user_data;
1493 int tls_rc = GNUTLS_E_SUCCESS;
1495 if (time(NULL) >= hs->start_time + hs->timeout_sec) {
1498 tls_handshake_failed(lrmd, GNUTLS_E_TIMEDOUT, rc);
1506 tls_handshake_succeeded(lrmd);
1509 }
else if (rc == EAGAIN) {
1514 tls_handshake_failed(lrmd, tls_rc, rc);
1521lrmd_tcp_connect_cb(
void *userdata,
int rc,
int sock)
1525 int tls_rc = GNUTLS_E_SUCCESS;
1528 native->async_timer = 0;
1531 lrmd_tls_connection_destroy(lrmd);
1532 crm_info(
"Could not connect to Pacemaker Remote at %s:%d: %s "
1534 native->server, native->port,
pcmk_rc_str(rc), rc);
1541 native->sock = sock;
1543 if (native->tls == NULL) {
1544 rc =
pcmk__init_tls(&native->tls,
false, use_cert ? GNUTLS_CRD_CERTIFICATE : GNUTLS_CRD_PSK);
1546 if ((rc !=
pcmk_rc_ok) || (native->tls == NULL)) {
1547 lrmd_tls_connection_destroy(lrmd);
1554 gnutls_datum_t psk_key = { NULL, 0 };
1558 crm_info(
"Could not connect to Pacemaker Remote at %s:%d: %s "
1560 native->server, native->port,
pcmk_rc_str(rc), rc);
1561 lrmd_tls_connection_destroy(lrmd);
1567 gnutls_free(psk_key.data);
1572 lrmd_tls_connection_destroy(lrmd);
1573 report_async_connection_result(lrmd, -EPROTO);
1583 struct handshake_data_s *hs = NULL;
1585 if (native->handshake_trigger != NULL) {
1591 hs->start_time = time(NULL);
1598 tls_handshake_succeeded(lrmd);
1601 tls_handshake_failed(lrmd, tls_rc, rc);
1614 &(native->sock), lrmd, lrmd_tcp_connect_cb);
1616 crm_warn(
"Pacemaker Remote connection to %s:%d failed: %s "
1618 native->server, native->port,
pcmk_rc_str(rc), rc);
1621 native->async_timer = timer_id;
1626lrmd_tls_connect(
lrmd_t * lrmd,
int *fd)
1634 &(native->sock), NULL, NULL);
1636 crm_warn(
"Pacemaker Remote connection to %s:%d failed: %s "
1638 native->server, native->port,
pcmk_rc_str(rc), rc);
1639 lrmd_tls_connection_destroy(lrmd);
1643 if (native->tls == NULL) {
1644 rc =
pcmk__init_tls(&native->tls,
false, use_cert ? GNUTLS_CRD_CERTIFICATE : GNUTLS_CRD_PSK);
1647 lrmd_tls_connection_destroy(lrmd);
1653 gnutls_datum_t psk_key = { NULL, 0 };
1657 lrmd_tls_connection_destroy(lrmd);
1662 gnutls_free(psk_key.data);
1667 lrmd_tls_connection_destroy(lrmd);
1671 if (tls_client_handshake(lrmd) !=
pcmk_rc_ok) {
1675 crm_info(
"Client TLS connection established with Pacemaker Remote server %s:%d", native->server,
1681 rc = add_tls_to_mainloop(lrmd,
false);
1687lrmd_api_connect(
lrmd_t * lrmd,
const char *
name,
int *fd)
1692 switch (native->type) {
1694 rc = lrmd_ipc_connect(lrmd, fd);
1697 rc = lrmd_tls_connect(lrmd, fd);
1701 crm_err(
"Unsupported executor connection type (bug?): %d",
1703 rc = -EPROTONOSUPPORT;
1707 rc = lrmd_handshake(lrmd,
name);
1720 CRM_CHECK(native && native->callback,
return -EINVAL);
1722 switch (native->type) {
1726 rc = lrmd_api_connect(lrmd,
name, NULL);
1728 report_async_connection_result(lrmd, rc);
1732 rc = lrmd_tls_connect_async(lrmd,
timeout);
1736 crm_err(
"Unsupported executor connection type (bug?): %d",
1738 rc = -EPROTONOSUPPORT;
1745lrmd_ipc_disconnect(
lrmd_t * lrmd)
1749 if (native->source != NULL) {
1752 native->source = NULL;
1755 }
else if (native->ipc) {
1766lrmd_tls_disconnect(
lrmd_t * lrmd)
1771 gnutls_bye(native->remote->
tls_session, GNUTLS_SHUT_RDWR);
1776 if (native->async_timer) {
1777 g_source_remove(native->async_timer);
1778 native->async_timer = 0;
1781 if (native->source != NULL) {
1784 native->source = NULL;
1786 }
else if (native->sock >= 0) {
1787 close(native->sock);
1791 if (native->pending_notify) {
1792 g_list_free_full(native->pending_notify, lrmd_free_xml);
1793 native->pending_notify = NULL;
1798lrmd_api_disconnect(
lrmd_t * lrmd)
1803 switch (native->type) {
1805 crm_debug(
"Disconnecting from local executor");
1806 lrmd_ipc_disconnect(lrmd);
1809 crm_debug(
"Disconnecting from remote executor on %s",
1810 native->remote_nodename);
1811 lrmd_tls_disconnect(lrmd);
1814 crm_err(
"Unsupported executor connection type (bug?): %d",
1816 rc = -EPROTONOSUPPORT;
1819 free(native->token);
1820 native->token = NULL;
1822 free(native->peer_version);
1823 native->peer_version = NULL;
1828lrmd_api_register_rsc(
lrmd_t * lrmd,
1834 xmlNode *
data = NULL;
1836 if (!
class || !
type || !rsc_id) {
1840 && (provider == NULL)) {
1873 const char *provider,
const char *
type)
1898 free(rsc_info->
type);
1909 xmlNode *output = NULL;
1910 const char *
class = NULL;
1911 const char *provider = NULL;
1912 const char *
type = NULL;
1927 if (!
class || !
type) {
1954lrmd_api_get_recurring_ops(
lrmd_t *lrmd,
const char *rsc_id,
int timeout_ms,
1957 xmlNode *
data = NULL;
1958 xmlNode *output_xml = NULL;
1961 if (output == NULL) {
1973 timeout_ms, options,
true);
1979 if ((rc !=
pcmk_ok) || (output_xml == NULL)) {
1985 (rsc_xml != NULL) && (rc ==
pcmk_ok);
1989 if (rsc_id == NULL) {
1990 crm_err(
"Could not parse recurring operation information from executor");
2001 if (op_info == NULL) {
2005 op_info->
rsc_id = strdup(rsc_id);
2012 *output = g_list_prepend(*output, op_info);
2025 native->callback = callback;
2033 native->proxy_callback = callback;
2034 native->proxy_callback_userdata = userdata;
2038lrmd_internal_proxy_dispatch(
lrmd_t *lrmd, xmlNode *msg)
2042 if (native->proxy_callback) {
2044 native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
2057 return lrmd_send_xml_no_reply(lrmd, msg);
2061stonith_get_metadata(
const char *
type,
char **output)
2066 if (stonith_api == NULL) {
2067 crm_err(
"Could not get fence agent meta-data: API memory allocation failed");
2073 if ((rc ==
pcmk_ok) && (*output == NULL)) {
2076 stonith_api->
cmds->
free(stonith_api);
2081lrmd_api_get_metadata(
lrmd_t *lrmd,
const char *standard,
const char *provider,
2082 const char *
type,
char **output,
2086 output, options, NULL);
2090lrmd_api_get_metadata_params(
lrmd_t *lrmd,
const char *standard,
2091 const char *provider,
const char *
type,
2096 GHashTable *params_table = NULL;
2098 if (!standard || !
type) {
2107 return stonith_get_metadata(
type, output);
2129 crm_err(
"Failed to retrieve meta-data for %s:%s:%s",
2130 standard, provider,
type);
2135 if (!
action->stdout_data) {
2136 crm_err(
"Failed to receive meta-data for %s:%s:%s",
2137 standard, provider,
type);
2142 *output = strdup(
action->stdout_data);
2149lrmd_api_exec(
lrmd_t *lrmd,
const char *rsc_id,
const char *
action,
2150 const char *userdata, guint interval_ms,
2168 for (tmp = params; tmp; tmp = tmp->
next) {
2181lrmd_api_exec_alert(
lrmd_t *lrmd,
const char *alert_id,
const char *alert_path,
2194 for (tmp = params; tmp; tmp = tmp->
next) {
2207lrmd_api_cancel(
lrmd_t *lrmd,
const char *rsc_id,
const char *
action,
2230 if (stonith_api == NULL) {
2231 crm_err(
"Could not list fence agents: API memory allocation failed");
2235 &stonith_resources, 0);
2236 stonith_api->
cmds->
free(stonith_api);
2238 for (dIter = stonith_resources; dIter; dIter = dIter->
next) {
2241 *resources = lrmd_list_add(*resources, dIter->
value);
2251 const char *provider)
2254 int stonith_count = 0;
2260 GList *gIter = NULL;
2263 for (gIter = agents; gIter != NULL; gIter = gIter->next) {
2264 *resources = lrmd_list_add(*resources, (
const char *)gIter->data);
2267 g_list_free_full(agents, free);
2274 if (stonith_count) {
2276 stonith_count = list_stonith_agents(resources);
2277 if (stonith_count > 0) {
2278 rc += stonith_count;
2282 crm_notice(
"No agents found for class %s",
class);
2283 rc = -EPROTONOSUPPORT;
2289does_provider_have_agent(
const char *agent,
const char *provider,
const char *
class)
2292 GList *agents = NULL;
2293 GList *gIter2 = NULL;
2296 for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
2301 g_list_free_full(agents, free);
2306lrmd_api_list_ocf_providers(
lrmd_t * lrmd,
const char *agent,
lrmd_list_t ** providers)
2309 char *provider = NULL;
2310 GList *ocf_providers = NULL;
2311 GList *gIter = NULL;
2315 for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
2316 provider = gIter->data;
2317 if (!agent || does_provider_have_agent(agent, provider,
2319 *providers = lrmd_list_add(*providers, (
const char *)gIter->data);
2324 g_list_free_full(ocf_providers, free);
2332 GList *standards = NULL;
2333 GList *gIter = NULL;
2337 for (gIter = standards; gIter != NULL; gIter = gIter->next) {
2338 *supported = lrmd_list_add(*supported, (
const char *)gIter->data);
2342 if (list_stonith_agents(NULL) > 0) {
2347 g_list_free_full(standards, free);
2382 *api = calloc(1,
sizeof(
lrmd_t));
2393 (*api)->lrmd_private = pvt;
2400 if ((pvt->remote == NULL) || ((*api)->cmds == NULL)) {
2407 (*api)->cmds->connect = lrmd_api_connect;
2408 (*api)->cmds->connect_async = lrmd_api_connect_async;
2409 (*api)->cmds->is_connected = lrmd_api_is_connected;
2410 (*api)->cmds->poke_connection = lrmd_api_poke_connection;
2411 (*api)->cmds->disconnect = lrmd_api_disconnect;
2412 (*api)->cmds->register_rsc = lrmd_api_register_rsc;
2413 (*api)->cmds->unregister_rsc = lrmd_api_unregister_rsc;
2414 (*api)->cmds->get_rsc_info = lrmd_api_get_rsc_info;
2415 (*api)->cmds->get_recurring_ops = lrmd_api_get_recurring_ops;
2416 (*api)->cmds->set_callback = lrmd_api_set_callback;
2417 (*api)->cmds->get_metadata = lrmd_api_get_metadata;
2418 (*api)->cmds->exec = lrmd_api_exec;
2419 (*api)->cmds->cancel = lrmd_api_cancel;
2420 (*api)->cmds->list_agents = lrmd_api_list_agents;
2421 (*api)->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
2422 (*api)->cmds->list_standards = lrmd_api_list_standards;
2423 (*api)->cmds->exec_alert = lrmd_api_exec_alert;
2424 (*api)->cmds->get_metadata_params = lrmd_api_get_metadata_params;
2426 if ((nodename == NULL) && (server == NULL)) {
2429 if (nodename == NULL) {
2431 }
else if (server == NULL) {
2435 pvt->remote_nodename = strdup(nodename);
2436 pvt->server = strdup(server);
2437 if ((pvt->remote_nodename == NULL) || (pvt->server == NULL)) {
2443 if (pvt->port == 0) {
2474 if (lrmd->
cmds != NULL) {
2483 free(native->server);
2484 free(native->remote_nodename);
2485 free(native->remote);
2486 free(native->token);
2487 free(native->peer_version);
2508 struct metadata_cb *metadata_cb = (
struct metadata_cb *)
action->cb_data;
2514 metadata_cb->callback(0, &
result, metadata_cb->user_data);
2539 void (*callback)(
int pid,
2545 struct metadata_cb *metadata_cb = NULL;
2548 CRM_CHECK(callback != NULL,
return EINVAL);
2550 if ((rsc == NULL) || (rsc->
standard == NULL) || (rsc->
type == NULL)) {
2553 "Invalid resource specification");
2554 callback(0, &
result, user_data);
2562 callback, user_data);
2574 callback(0, &
result, user_data);
2580 callback(0, &
result, user_data);
2586 action->cb_data = calloc(1,
sizeof(
struct metadata_cb));
2587 if (
action->cb_data == NULL) {
2591 callback(0, &
result, user_data);
2596 metadata_cb = (
struct metadata_cb *)
action->cb_data;
2597 metadata_cb->callback = callback;
2598 metadata_cb->user_data = user_data;
2619 const char *exit_reason)
2621 if (event == NULL) {
2626 event->op_status = op_status;
2641 if (event == NULL) {
2646 event->exit_reason = NULL;
2648 free((
void *) event->
output);
2649 event->output = NULL;
2667 if (native->remote == NULL) {
2670 return native->remote->
uptime;
2679 if (native->remote == NULL) {
#define PCMK_ACTION_META_DATA
#define PCMK_DEFAULT_ACTION_TIMEOUT_MS
Default timeout (in milliseconds) for non-metadata actions.
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
#define PCMK_RESOURCE_CLASS_STONITH
#define PCMK_RESOURCE_CLASS_OCF
guint pcmk__timeout_ms2s(guint timeout_ms)
#define pcmk__assert_alloc(nmemb, size)
int pcmk__remote_ready(const pcmk__remote_t *remote, int timeout_ms)
int pcmk__remote_send_xml(pcmk__remote_t *remote, const xmlNode *msg)
int pcmk__connect_remote(const char *host, int port, int timeout_ms, int *timer_id, int *sock_fd, void *userdata, void(*callback)(void *userdata, int rc, int sock))
xmlNode * pcmk__remote_message_xml(pcmk__remote_t *remote)
int pcmk__read_remote_message(pcmk__remote_t *remote, int timeout_ms)
int crm_default_remote_port(void)
Get the default remote connection TCP port on this host.
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
enum pcmk_ipc_server type
int stonith__metadata_async(const char *agent, int timeout_sec, void(*callback)(int pid, const pcmk__action_result_t *result, void *user_data), void *user_data)
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
void stonith__key_value_freeall(stonith_key_value_t *head, bool keys, bool values)
stonith_t * stonith__api_new(void)
void crm_ipc_destroy(crm_ipc_t *client)
int crm_ipc_send(crm_ipc_t *client, const xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
long crm_ipc_read(crm_ipc_t *client)
@ crm_ipc_client_response
A response is expected in reply.
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
bool crm_ipc_connected(crm_ipc_t *client)
void crm_ipc_close(crm_ipc_t *client)
const char * crm_ipc_buffer(crm_ipc_t *client)
struct crm_ipc_s crm_ipc_t
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
int pcmk__connect_generic_ipc(crm_ipc_t *ipc)
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
@ pcmk__client_ipc
Client uses plain IPC.
@ pcmk__client_tls
Client uses TCP with TLS.
void pcmk__ipc_free_client_buffer(crm_ipc_t *client)
#define CRM_TRACE_INIT_DATA(name)
#define crm_info(fmt, args...)
#define crm_warn(fmt, args...)
#define CRM_LOG_ASSERT(expr)
#define crm_log_xml_err(xml, text)
#define crm_notice(fmt, args...)
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
#define CRM_CHECK(expr, failure_action)
#define crm_debug(fmt, args...)
#define crm_err(fmt, args...)
#define crm_log_xml_trace(xml, text)
#define crm_trace(fmt, args...)
#define LRMD_OP_NEW_CLIENT
#define LRMD_OP_GET_RECURRING
#define DEFAULT_REMOTE_KEY_LOCATION
@ lrmd_opt_notify_orig_only
Notify only the client that made the request (rather than all clients)
#define LRMD_OP_RSC_UNREG
#define LRMD_PROTOCOL_VERSION
void(* lrmd_event_callback)(lrmd_event_data_t *event)
#define LRMD_OP_RSC_CANCEL
#define LRMD_OP_ALERT_EXEC
int lrmd__metadata_async(const lrmd_rsc_info_t *rsc, void(*callback)(int pid, const pcmk__action_result_t *result, void *user_data), void *user_data)
int lrmd__init_remote_key(gnutls_datum_t *key)
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
struct lrmd_private_s lrmd_private_t
#define MAX_TLS_RECV_WAIT
int lrmd__remote_send_xml(pcmk__remote_t *session, xmlNode *msg, uint32_t id, const char *msg_type)
void lrmd__reset_result(lrmd_event_data_t *event)
void lrmd_key_value_freeall(lrmd_key_value_t *head)
bool lrmd_dispatch(lrmd_t *lrmd)
Use after lrmd_poll returns 1 to read and dispatch a message.
void lrmd_free_op_info(lrmd_op_info_t *op_info)
void lrmd__set_result(lrmd_event_data_t *event, enum ocf_exitcode rc, int op_status, const char *exit_reason)
void lrmd_api_delete(lrmd_t *lrmd)
Destroy executor connection object.
#define TLS_HANDSHAKE_TIMEOUT
time_t lrmd__uptime(lrmd_t *lrmd)
void lrmd_list_freeall(lrmd_list_t *head)
lrmd_t * lrmd_remote_api_new(const char *nodename, const char *server, int port)
Create a new TLS connection to a remote executor.
lrmd_rsc_info_t * lrmd_new_rsc_info(const char *rsc_id, const char *standard, const char *provider, const char *type)
const char * lrmd__node_start_state(lrmd_t *lrmd)
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event.
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
lrmd_t * lrmd_api_new(void)
Create a new connection to the local executor.
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *head, const char *key, const char *value)
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
Create a new lrmd_event_data_t object.
int lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash)
int lrmd__new(lrmd_t **api, const char *nodename, const char *server, int port)
int lrmd_poll(lrmd_t *lrmd, int timeout)
Check whether a message is available on an executor connection.
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
@ lrmd_event_exec_complete
Wrappers for and extensions to glib mainloop.
void mainloop_set_trigger(crm_trigger_t *source)
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
struct mainloop_io_s mainloop_io_t
crm_trigger_t * mainloop_add_trigger(int priority, int(*dispatch)(gpointer user_data), gpointer userdata)
Create a trigger to be used as a mainloop source.
struct trigger_s crm_trigger_t
void mainloop_del_ipc_client(mainloop_io_t *client)
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
GHashTable * xml2list(const xmlNode *parent)
Retrieve XML attributes as a hash table.
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Safely add hash table entry to XML as attribute or name-value pair.
#define PCMK_OPT_STONITH_WATCHDOG_TIMEOUT
#define PCMK__ENV_AUTHKEY_LOCATION
const char * pcmk__env_option(const char *option)
pcmk__action_result_t result
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
ocf_exitcode
Exit status codes for resource agents.
@ PCMK_OCF_NOT_CONFIGURED
Parameter invalid (inherently)
@ PCMK_OCF_UNKNOWN_ERROR
Unspecified error.
@ PCMK_OCF_UNKNOWN
Action is pending.
int pcmk_rc2legacy(int rc)
@ PCMK_EXEC_ERROR_FATAL
Execution failed, do not retry anywhere.
@ PCMK_EXEC_ERROR
Execution failed, may be retried.
int pcmk_legacy2rc(int legacy_rc)
void pcmk__set_result(pcmk__action_result_t *result, int exit_status, enum pcmk_exec_status exec_status, const char *exit_reason)
#define pcmk__assert(expr)
#define PCMK__UNKNOWN_RESULT
void void pcmk__set_result_output(pcmk__action_result_t *result, char *out, char *err)
#define pcmk__mem_assert(ptr)
void pcmk__reset_result(pcmk__action_result_t *result)
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
gboolean services_action_async(svc_action_t *op, void(*action_callback)(svc_action_t *))
Request asynchronous execution of an action.
gboolean services_action_sync(svc_action_t *op)
GList * resources_list_standards(void)
void services_action_free(svc_action_t *op)
GList * resources_list_providers(const char *standard)
Get a list of providers.
void services__copy_result(const svc_action_t *action, pcmk__action_result_t *result)
svc_action_t * services__create_resource_action(const char *name, const char *standard, const char *provider, const char *agent, const char *action, guint interval_ms, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
void pcmk__str_update(char **str, const char *value)
#define pcmk__str_copy(str)
int(* get_metadata_params)(lrmd_t *lrmd, const char *standard, const char *provider, const char *agent, char **output, enum lrmd_call_options options, lrmd_key_value_t *params)
Retrieve resource agent metadata synchronously with parameters.
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the executor.
const char * remote_nodename
enum lrmd_callback_event type
struct lrmd_key_value_s * next
struct lrmd_list_s * next
lrmd_api_operations_t * cmds
gnutls_session_t tls_session
int(* free)(stonith_t *st)
Destroy a fencer connection.
int(* list_agents)(stonith_t *stonith, int call_options, const char *namespace_s, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed fence agents.
int(* metadata)(stonith_t *stonith, int call_options, const char *agent, const char *namespace_s, char **output, int timeout_sec)
Retrieve a fence agent's metadata.
Key-value pair list node.
struct stonith_key_value_s * next
Fencer API connection object.
stonith_api_operations_t * cmds
Object for executing external actions.
void pcmk__tls_add_psk_key(pcmk__tls_t *tls, gnutls_datum_t *key)
int pcmk__tls_client_try_handshake(pcmk__remote_t *remote, int *gnutls_rc)
void pcmk__free_tls(pcmk__tls_t *tls)
bool pcmk__x509_enabled(void)
int pcmk__init_tls(pcmk__tls_t **tls, bool server, gnutls_credentials_type_t cred_type)
int pcmk__tls_client_handshake(pcmk__remote_t *remote, int timeout_sec, int *gnutls_rc)
void pcmk__tls_check_cert_expiration(gnutls_session_t session)
gnutls_session_t pcmk__new_tls_session(pcmk__tls_t *tls, int csock)
Wrappers for and extensions to libxml2.
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
int crm_element_value_ll(const xmlNode *data, const char *name, long long *dest)
Retrieve the long long integer value of an XML attribute.
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
const char * crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
Create an XML attribute with specified name and unsigned value.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
void pcmk__xml_free(xmlNode *xml)
xmlNode * pcmk__xml_parse(const char *input)
#define PCMK__XA_LRMD_RSC_USERDATA_STR
#define PCMK__XA_LRMD_RSC_START_DELAY
#define PCMK__XA_LRMD_RSC_DELETED
#define PCMK__XA_LRMD_RSC_INTERVAL
#define PCMK__XA_LRMD_TYPE
#define PCMK__XA_LRMD_RSC_ACTION
#define PCMK__XA_LRMD_EXEC_TIME
#define PCMK__XA_LRMD_PROTOCOL_VERSION
#define PCMK__XA_LRMD_REMOTE_MSG_ID
#define PCMK__XA_LRMD_CLIENTNAME
#define PCMK__XA_LRMD_IPC_SESSION
#define PCMK__XA_LRMD_EXEC_OP_STATUS
#define PCMK__XA_LRMD_CALLID
#define PCMK__XA_LRMD_REMOTE_MSG_TYPE
#define PCMK__XA_LRMD_WATCHDOG
#define PCMK__XA_LRMD_CLASS
#define PCMK__XE_LRMD_ALERT
#define PCMK__XA_LRMD_ALERT_PATH
#define PCMK__XE_LRMD_CALLDATA
#define PCMK__XA_LRMD_TIMEOUT
#define PCMK__XA_LRMD_RUN_TIME
#define PCMK__XA_NODE_START_STATE
#define PCMK__XA_LRMD_RSC_ID
#define PCMK__XA_LRMD_RCCHANGE_TIME
#define PCMK__XA_LRMD_QUEUE_TIME
#define PCMK__XA_LRMD_IS_IPC_PROVIDER
#define PCMK__XA_LRMD_RSC_EXIT_REASON
#define PCMK__XA_LRMD_CALLOPT
#define PCMK__XA_LRMD_RSC_OUTPUT
#define PCMK__XE_LRMD_COMMAND
#define PCMK__XA_LRMD_PROVIDER
#define PCMK__XA_LRMD_EXEC_RC
#define PCMK__XA_LRMD_ALERT_ID
#define PCMK__XA_LRMD_ORIGIN
#define PCMK__XE_ATTRIBUTES
#define PCMK__XE_LRMD_RSC_OP
#define PCMK__XA_LRMD_CLIENTID
#define PCMK__XE_LRMD_RSC