21 #include <sys/types.h>
40 #ifdef HAVE_GNUTLS_GNUTLS_H
42 # include <gnutls/gnutls.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <netinet/ip.h>
48 #include <arpa/inet.h>
51 #define MAX_TLS_RECV_WAIT 10000
55 static int lrmd_api_disconnect(
lrmd_t * lrmd);
56 static int lrmd_api_is_connected(
lrmd_t * lrmd);
60 static void lrmd_internal_proxy_dispatch(
lrmd_t *lrmd, xmlNode *msg);
63 #ifdef HAVE_GNUTLS_GNUTLS_H
64 # define LRMD_CLIENT_HANDSHAKE_TIMEOUT 5000
65 gnutls_psk_client_credentials_t psk_cred_s;
66 static void lrmd_tls_disconnect(
lrmd_t * lrmd);
67 static int global_remote_msg_id = 0;
68 static void lrmd_tls_connection_destroy(gpointer userdata);
71 typedef struct lrmd_private_s {
82 char *remote_nodename;
83 #ifdef HAVE_GNUTLS_GNUTLS_H
86 gnutls_psk_client_credentials_t psk_cred_c;
96 int expected_late_replies;
97 GList *pending_notify;
104 void (*proxy_callback)(
lrmd_t *lrmd,
void *userdata, xmlNode *msg);
105 void *proxy_callback_userdata;
110 lrmd_list_add(
lrmd_list_t * head,
const char *value)
115 p->
val = strdup(value);
118 while (end && end->
next) {
137 char *val = (
char *)head->
val;
152 p->
key = strdup(key);
153 p->
value = strdup(value);
156 while (end && end->
next) {
201 if (rsc_id != NULL) {
202 event->rsc_id = strdup(rsc_id);
206 event->op_type = strdup(task);
209 event->interval_ms = interval_ms;
225 copy->
rsc_id =
event->rsc_id ? strdup(event->
rsc_id) : NULL;
228 copy->
output =
event->output ? strdup(event->
output) : NULL;
248 free((
void *) event->
rsc_id);
253 if (event->
params != NULL) {
254 g_hash_table_destroy(event->
params);
260 lrmd_dispatch_internal(
lrmd_t * lrmd, xmlNode * msg)
267 if (proxy_session != NULL) {
269 lrmd_internal_proxy_dispatch(lrmd, msg);
271 }
else if (!native->callback) {
273 crm_trace(
"notify event received but client has not set callback");
277 event.remote_nodename = native->remote_nodename;
297 event.t_run = (
unsigned int) epoch;
300 event.t_rcchange = (
unsigned int) epoch;
324 native->callback(&event);
327 g_hash_table_destroy(event.params);
334 lrmd_ipc_dispatch(
const char *buffer, ssize_t length, gpointer userdata)
339 if (native->callback != NULL) {
342 lrmd_dispatch_internal(lrmd, msg);
348 #ifdef HAVE_GNUTLS_GNUTLS_H
350 lrmd_free_xml(gpointer userdata)
356 remote_executor_connected(
lrmd_t * lrmd)
360 return (native->remote->tls_session != NULL);
375 lrmd_tls_dispatch(gpointer userdata)
382 if (!remote_executor_connected(lrmd)) {
383 crm_trace(
"TLS dispatch triggered after disconnect");
391 if (native->pending_notify) {
394 crm_trace(
"Processing pending notifies");
395 for (iter = native->pending_notify; iter; iter = iter->next) {
396 lrmd_dispatch_internal(lrmd, iter->data);
398 g_list_free_full(native->pending_notify, lrmd_free_xml);
399 native->pending_notify = NULL;
419 lrmd_dispatch_internal(lrmd, xml);
421 if (native->expected_late_replies > 0) {
422 native->expected_late_replies--;
427 crm_err(
"Got outdated Pacemaker Remote reply %d", reply_id);
434 if (
rc == ENOTCONN) {
435 crm_info(
"Lost %s executor connection while reading data",
436 (native->remote_nodename? native->remote_nodename :
"local"));
437 lrmd_tls_disconnect(lrmd);
450 switch (native->type) {
454 #ifdef HAVE_GNUTLS_GNUTLS_H
455 case pcmk__client_tls:
456 if (native->pending_notify) {
472 crm_err(
"Unsupported executor connection type (bug?): %d",
474 return -EPROTONOSUPPORT;
487 switch (private->type) {
493 lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
497 #ifdef HAVE_GNUTLS_GNUTLS_H
498 case pcmk__client_tls:
499 lrmd_tls_dispatch(lrmd);
503 crm_err(
"Unsupported executor connection type (bug?): %d",
507 if (lrmd_api_is_connected(lrmd) == FALSE) {
516 lrmd_create_op(
const char *token,
const char *op, xmlNode *
data,
int timeout,
535 crm_trace(
"Created executor %s command with call options %.8lx (%d)",
536 op, (
long)options, options);
541 lrmd_ipc_connection_destroy(gpointer userdata)
546 crm_info(
"IPC connection destroyed");
550 native->source = NULL;
552 if (native->callback) {
555 event.remote_nodename = native->remote_nodename;
556 native->callback(&event);
560 #ifdef HAVE_GNUTLS_GNUTLS_H
562 lrmd_tls_connection_destroy(gpointer userdata)
567 crm_info(
"TLS connection destroyed");
569 if (native->remote->tls_session) {
570 gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
571 gnutls_deinit(*native->remote->tls_session);
572 gnutls_free(native->remote->tls_session);
574 if (native->psk_cred_c) {
575 gnutls_psk_free_client_credentials(native->psk_cred_c);
580 if (native->process_notify) {
582 native->process_notify = NULL;
584 if (native->pending_notify) {
585 g_list_free_full(native->pending_notify, lrmd_free_xml);
586 native->pending_notify = NULL;
589 free(native->remote->buffer);
590 native->remote->buffer = NULL;
593 native->psk_cred_c = NULL;
594 native->remote->tls_session = NULL;
597 if (native->callback) {
601 native->callback(&event);
609 const char *msg_type)
618 read_remote_reply(
lrmd_t *lrmd,
int total_timeout,
int expected_reply_id,
622 time_t start = time(NULL);
623 const char *msg_type = NULL;
625 int remaining_timeout = 0;
634 for (*reply = NULL; *reply == NULL; ) {
637 if (*reply == NULL) {
639 if (remaining_timeout) {
640 remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
642 remaining_timeout = total_timeout;
644 if (remaining_timeout <= 0) {
654 if (*reply == NULL) {
663 crm_err(
"Empty msg type received while waiting for reply");
669 native->pending_notify = g_list_append(native->pending_notify, *reply);
670 if (native->process_notify) {
677 crm_err(
"Expected a reply, got %s", msg_type);
680 }
else if (reply_id != expected_reply_id) {
681 if (native->expected_late_replies > 0) {
682 native->expected_late_replies--;
684 crm_err(
"Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
691 if (native->remote->buffer && native->process_notify) {
700 send_remote_message(
lrmd_t *lrmd, xmlNode *msg)
705 global_remote_msg_id++;
706 if (global_remote_msg_id <= 0) {
707 global_remote_msg_id = 1;
713 crm_err(
"Disconnecting because TLS message could not be sent to "
715 lrmd_tls_disconnect(lrmd);
721 lrmd_tls_send_recv(
lrmd_t * lrmd, xmlNode * msg,
int timeout, xmlNode ** reply)
726 if (!remote_executor_connected(lrmd)) {
730 rc = send_remote_message(lrmd, msg);
735 rc = read_remote_reply(lrmd,
timeout, global_remote_msg_id, &xml);
737 crm_err(
"Disconnecting remote after request %d reply not received: %s "
738 CRM_XS " rc=%d timeout=%dms",
740 lrmd_tls_disconnect(lrmd);
754 lrmd_send_xml(
lrmd_t * lrmd, xmlNode * msg,
int timeout, xmlNode ** reply)
759 switch (native->type) {
763 #ifdef HAVE_GNUTLS_GNUTLS_H
764 case pcmk__client_tls:
765 rc = lrmd_tls_send_recv(lrmd, msg,
timeout, reply);
769 crm_err(
"Unsupported executor connection type (bug?): %d",
771 rc = -EPROTONOSUPPORT;
778 lrmd_send_xml_no_reply(
lrmd_t * lrmd, xmlNode * msg)
783 switch (native->type) {
787 #ifdef HAVE_GNUTLS_GNUTLS_H
788 case pcmk__client_tls:
789 rc = send_remote_message(lrmd, msg);
794 native->expected_late_replies++;
800 crm_err(
"Unsupported executor connection type (bug?): %d",
802 rc = -EPROTONOSUPPORT;
809 lrmd_api_is_connected(
lrmd_t * lrmd)
813 switch (native->type) {
816 #ifdef HAVE_GNUTLS_GNUTLS_H
817 case pcmk__client_tls:
818 return remote_executor_connected(lrmd);
821 crm_err(
"Unsupported executor connection type (bug?): %d",
846 lrmd_send_command(
lrmd_t *lrmd,
const char *op, xmlNode *
data,
847 xmlNode **output_data,
int timeout,
852 xmlNode *op_msg = NULL;
853 xmlNode *op_reply = NULL;
855 if (!lrmd_api_is_connected(lrmd)) {
860 crm_err(
"No operation specified");
866 crm_trace(
"Sending %s op to executor", op);
868 op_msg = lrmd_create_op(native->token, op,
data,
timeout, options);
870 if (op_msg == NULL) {
875 rc = lrmd_send_xml(lrmd, op_msg,
timeout, &op_reply);
877 rc = lrmd_send_xml_no_reply(lrmd, op_msg);
885 }
else if(op_reply == NULL) {
900 *output_data = op_reply;
905 if (lrmd_api_is_connected(lrmd) == FALSE) {
906 crm_err(
"Executor disconnected");
915 lrmd_api_poke_connection(
lrmd_t * lrmd)
940 value = g_hash_table_lookup(hash,
"stonith-watchdog-timeout");
953 lrmd_handshake(
lrmd_t * lrmd,
const char *
name)
957 xmlNode *reply = NULL;
966 if (native->proxy_callback) {
970 rc = lrmd_send_xml(lrmd, hello, -1, &reply);
973 crm_perror(LOG_DEBUG,
"Couldn't complete registration with the executor API: %d",
rc);
975 }
else if (reply == NULL) {
976 crm_err(
"Did not receive registration reply");
986 crm_err(
"Executor protocol version mismatch between client (%s) and server (%s)",
991 crm_err(
"Invalid registration message: %s", msg_type);
994 }
else if (tmp_ticket == NULL) {
995 crm_err(
"No registration token provided");
999 crm_trace(
"Obtained registration token: %s", tmp_ticket);
1000 native->token = strdup(tmp_ticket);
1010 lrmd_api_disconnect(lrmd);
1016 lrmd_ipc_connect(
lrmd_t * lrmd,
int *fd)
1023 .destroy = lrmd_ipc_connection_destroy
1026 crm_info(
"Connecting to executor");
1033 }
else if (native->ipc) {
1034 crm_perror(LOG_ERR,
"Connection to executor failed");
1042 if (native->ipc == NULL) {
1043 crm_debug(
"Could not connect to the executor API");
1050 #ifdef HAVE_GNUTLS_GNUTLS_H
1052 copy_gnutls_datum(gnutls_datum_t *dest, gnutls_datum_t *source)
1054 CRM_ASSERT((dest != NULL) && (source != NULL) && (source->data != NULL));
1056 dest->data = gnutls_malloc(source->size);
1059 memcpy(dest->data, source->data, source->size);
1060 dest->size = source->size;
1064 clear_gnutls_datum(gnutls_datum_t *datum)
1066 gnutls_free(datum->data);
1071 #define KEY_READ_LEN 256
1075 read_gnutls_key(
const char *location, gnutls_datum_t *key)
1077 FILE *stream = NULL;
1078 size_t buf_len = KEY_READ_LEN;
1080 if ((location == NULL) || (key == NULL)) {
1084 stream = fopen(location,
"r");
1085 if (stream == NULL) {
1089 key->data = gnutls_malloc(buf_len);
1091 while (!feof(stream)) {
1092 int next = fgetc(stream);
1095 if (!feof(stream)) {
1096 crm_warn(
"Pacemaker Remote key read was partially successful "
1097 "(copy in memory may be corrupted)");
1101 if (key->size == buf_len) {
1102 buf_len = key->size + KEY_READ_LEN;
1103 key->data = gnutls_realloc(key->data, buf_len);
1106 key->data[key->size++] = (
unsigned char) next;
1110 if (key->size == 0) {
1111 clear_gnutls_datum(key);
1119 struct key_cache_s {
1121 const char *location;
1126 key_is_cached(
struct key_cache_s *key_cache)
1128 return key_cache->updated != 0;
1132 key_cache_expired(
struct key_cache_s *key_cache)
1134 return (time(NULL) - key_cache->updated) >= 60;
1138 clear_key_cache(
struct key_cache_s *key_cache)
1140 clear_gnutls_datum(&(key_cache->key));
1141 if ((key_cache->updated != 0) || (key_cache->location != NULL)) {
1142 key_cache->updated = 0;
1143 key_cache->location = NULL;
1144 crm_debug(
"Cleared Pacemaker Remote key cache");
1149 get_cached_key(
struct key_cache_s *key_cache, gnutls_datum_t *key)
1151 copy_gnutls_datum(key, &(key_cache->key));
1152 crm_debug(
"Using cached Pacemaker Remote key from %s",
1153 crm_str(key_cache->location));
1157 cache_key(
struct key_cache_s *key_cache, gnutls_datum_t *key,
1158 const char *location)
1160 key_cache->updated = time(NULL);
1161 key_cache->location = location;
1162 copy_gnutls_datum(&(key_cache->key), key);
1163 crm_debug(
"Using (and cacheing) Pacemaker Remote key from %s",
1178 get_remote_key(
const char *location, gnutls_datum_t *key)
1180 static struct key_cache_s key_cache = { 0, };
1183 if ((location == NULL) || (key == NULL)) {
1187 if (key_is_cached(&key_cache)) {
1188 if (key_cache_expired(&key_cache)) {
1189 clear_key_cache(&key_cache);
1191 get_cached_key(&key_cache, key);
1196 rc = read_gnutls_key(location, key);
1200 cache_key(&key_cache, key, location);
1218 lrmd__init_remote_key(gnutls_datum_t *key)
1220 static const char *env_location = NULL;
1221 static bool need_env =
true;
1227 bool env_is_default =
false;
1228 bool env_is_fallback =
false;
1231 env_location = getenv(
"PCMK_authkey_location");
1236 if (env_location != NULL) {
1237 env_rc = get_remote_key(env_location, key);
1254 if (env_is_default) {
1255 default_rc = env_rc;
1261 if (env_is_fallback) {
1272 crm_warn(
"Could not read Pacemaker Remote key from %s (%s%s%s%s%s): %s",
1274 env_is_default?
"" :
"or default location ",
1276 !env_is_default && !env_is_fallback?
" " :
"",
1277 env_is_fallback?
"" :
"or fallback location ",
1284 crm_warn(
"Could not read Pacemaker Remote key from %s "
1285 "(using %s location %s instead): %s",
1287 (default_rc ==
pcmk_rc_ok)?
"default" :
"fallback",
1295 crm_warn(
"Could not read Pacemaker Remote key from default location %s"
1296 " (or fallback location %s): %s",
1306 lrmd_gnutls_global_init(
void)
1308 static int gnutls_init = 0;
1311 crm_gnutls_global_init();
1318 report_async_connection_result(
lrmd_t * lrmd,
int rc)
1322 if (native->callback) {
1325 event.remote_nodename = native->remote_nodename;
1326 event.connection_rc =
rc;
1327 native->callback(&event);
1331 #ifdef HAVE_GNUTLS_GNUTLS_H
1335 return pcmk__tls_client_handshake(remote, LRMD_CLIENT_HANDSHAKE_TIMEOUT);
1348 add_tls_to_mainloop(
lrmd_t *lrmd,
bool do_handshake)
1354 native->server, native->port);
1358 .destroy = lrmd_tls_connection_destroy,
1362 lrmd_tls_dispatch, lrmd);
1373 rc = lrmd_handshake(lrmd,
name);
1381 lrmd_tcp_connect_cb(
void *userdata,
int rc,
int sock)
1385 gnutls_datum_t psk_key = { NULL, 0 };
1387 native->async_timer = 0;
1390 lrmd_tls_connection_destroy(lrmd);
1391 crm_info(
"Could not connect to Pacemaker Remote at %s:%d: %s "
1402 native->sock = sock;
1404 rc = lrmd__init_remote_key(&psk_key);
1406 crm_info(
"Could not connect to Pacemaker Remote at %s:%d: %s "
1409 lrmd_tls_connection_destroy(lrmd);
1414 gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1416 gnutls_free(psk_key.data);
1418 native->remote->tls_session = pcmk__new_tls_session(sock, GNUTLS_CLIENT,
1420 native->psk_cred_c);
1421 if (native->remote->tls_session == NULL) {
1422 lrmd_tls_connection_destroy(lrmd);
1423 report_async_connection_result(lrmd, -EPROTO);
1427 if (lrmd__tls_client_handshake(native->remote) !=
pcmk_rc_ok) {
1428 crm_warn(
"Disconnecting after TLS handshake with Pacemaker Remote server %s:%d failed",
1429 native->server, native->port);
1430 gnutls_deinit(*native->remote->tls_session);
1431 gnutls_free(native->remote->tls_session);
1432 native->remote->tls_session = NULL;
1433 lrmd_tls_connection_destroy(lrmd);
1438 crm_info(
"TLS connection to Pacemaker Remote server %s:%d succeeded",
1439 native->server, native->port);
1440 rc = add_tls_to_mainloop(lrmd,
true);
1451 lrmd_gnutls_global_init();
1454 &(native->sock), lrmd, lrmd_tcp_connect_cb);
1456 crm_warn(
"Pacemaker Remote connection to %s:%d failed: %s "
1461 native->async_timer = timer_id;
1466 lrmd_tls_connect(
lrmd_t * lrmd,
int *fd)
1471 gnutls_datum_t psk_key = { NULL, 0 };
1473 lrmd_gnutls_global_init();
1477 &(native->sock), NULL, NULL);
1479 crm_warn(
"Pacemaker Remote connection to %s:%d failed: %s "
1482 lrmd_tls_connection_destroy(lrmd);
1486 rc = lrmd__init_remote_key(&psk_key);
1488 lrmd_tls_connection_destroy(lrmd);
1492 gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1494 gnutls_free(psk_key.data);
1496 native->remote->tls_session = pcmk__new_tls_session(native->sock, GNUTLS_CLIENT,
1498 native->psk_cred_c);
1499 if (native->remote->tls_session == NULL) {
1500 lrmd_tls_connection_destroy(lrmd);
1504 if (lrmd__tls_client_handshake(native->remote) !=
pcmk_rc_ok) {
1505 crm_err(
"Session creation for %s:%d failed", native->server, native->port);
1506 gnutls_deinit(*native->remote->tls_session);
1507 gnutls_free(native->remote->tls_session);
1508 native->remote->tls_session = NULL;
1509 lrmd_tls_connection_destroy(lrmd);
1513 crm_info(
"Client TLS connection established with Pacemaker Remote server %s:%d", native->server,
1519 add_tls_to_mainloop(lrmd,
false);
1526 lrmd_api_connect(
lrmd_t * lrmd,
const char *
name,
int *fd)
1531 switch (native->type) {
1533 rc = lrmd_ipc_connect(lrmd, fd);
1535 #ifdef HAVE_GNUTLS_GNUTLS_H
1536 case pcmk__client_tls:
1537 rc = lrmd_tls_connect(lrmd, fd);
1541 crm_err(
"Unsupported executor connection type (bug?): %d",
1543 rc = -EPROTONOSUPPORT;
1547 rc = lrmd_handshake(lrmd,
name);
1559 CRM_CHECK(native && native->callback,
return -EINVAL);
1561 switch (native->type) {
1565 rc = lrmd_api_connect(lrmd,
name, NULL);
1567 report_async_connection_result(lrmd,
rc);
1570 #ifdef HAVE_GNUTLS_GNUTLS_H
1571 case pcmk__client_tls:
1572 rc = lrmd_tls_connect_async(lrmd,
timeout);
1575 report_async_connection_result(lrmd,
rc);
1580 crm_err(
"Unsupported executor connection type (bug?): %d",
1582 rc = -EPROTONOSUPPORT;
1589 lrmd_ipc_disconnect(
lrmd_t * lrmd)
1593 if (native->source != NULL) {
1596 native->source = NULL;
1599 }
else if (native->ipc) {
1609 #ifdef HAVE_GNUTLS_GNUTLS_H
1611 lrmd_tls_disconnect(
lrmd_t * lrmd)
1615 if (native->remote->tls_session) {
1616 gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
1617 gnutls_deinit(*native->remote->tls_session);
1618 gnutls_free(native->remote->tls_session);
1619 native->remote->tls_session = 0;
1622 if (native->async_timer) {
1623 g_source_remove(native->async_timer);
1624 native->async_timer = 0;
1627 if (native->source != NULL) {
1630 native->source = NULL;
1632 }
else if (native->sock) {
1633 close(native->sock);
1637 if (native->pending_notify) {
1638 g_list_free_full(native->pending_notify, lrmd_free_xml);
1639 native->pending_notify = NULL;
1645 lrmd_api_disconnect(
lrmd_t * lrmd)
1650 crm_info(
"Disconnecting %s %s executor connection",
1652 (native->remote_nodename? native->remote_nodename :
"local"));
1653 switch (native->type) {
1655 lrmd_ipc_disconnect(lrmd);
1657 #ifdef HAVE_GNUTLS_GNUTLS_H
1658 case pcmk__client_tls:
1659 lrmd_tls_disconnect(lrmd);
1663 crm_err(
"Unsupported executor connection type (bug?): %d",
1665 rc = -EPROTONOSUPPORT;
1668 free(native->token);
1669 native->token = NULL;
1671 free(native->peer_version);
1672 native->peer_version = NULL;
1677 lrmd_api_register_rsc(
lrmd_t * lrmd,
1683 xmlNode *
data = NULL;
1685 if (!
class || !
type || !rsc_id) {
1689 && (provider == NULL)) {
1722 const char *provider,
const char *
type)
1728 rsc_info->
id = strdup(rsc_id);
1732 rsc_info->
standard = strdup(standard);
1736 rsc_info->
provider = strdup(provider);
1760 free(rsc_info->
type);
1771 xmlNode *output = NULL;
1772 const char *
class = NULL;
1773 const char *provider = NULL;
1774 const char *
type = NULL;
1789 if (!
class || !
type) {
1816 lrmd_api_get_recurring_ops(
lrmd_t *lrmd,
const char *rsc_id,
int timeout_ms,
1819 xmlNode *
data = NULL;
1820 xmlNode *output_xml = NULL;
1823 if (output == NULL) {
1835 timeout_ms, options, TRUE);
1841 if ((
rc !=
pcmk_ok) || (output_xml == NULL)) {
1849 if (rsc_id == NULL) {
1850 crm_err(
"Could not parse recurring operation information from executor");
1858 if (op_info == NULL) {
1862 op_info->
rsc_id = strdup(rsc_id);
1868 *output = g_list_prepend(*output, op_info);
1881 native->callback = callback;
1889 native->proxy_callback = callback;
1890 native->proxy_callback_userdata = userdata;
1894 lrmd_internal_proxy_dispatch(
lrmd_t *lrmd, xmlNode *msg)
1898 if (native->proxy_callback) {
1900 native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
1913 return lrmd_send_xml_no_reply(lrmd, msg);
1917 stonith_get_metadata(
const char *provider,
const char *
type,
char **output)
1922 if (stonith_api == NULL) {
1923 crm_err(
"Could not get fence agent meta-data: API memory allocation failed");
1928 provider, output, 0);
1929 if ((
rc ==
pcmk_ok) && (*output == NULL)) {
1932 stonith_api->
cmds->
free(stonith_api);
1937 lrmd_api_get_metadata(
lrmd_t *lrmd,
const char *standard,
const char *provider,
1938 const char *
type,
char **output,
1942 output, options, NULL);
1946 lrmd_api_get_metadata_params(
lrmd_t *lrmd,
const char *standard,
1947 const char *provider,
const char *
type,
1952 GHashTable *params_table = NULL;
1954 if (!standard || !
type) {
1961 return stonith_get_metadata(provider,
type, output);
1966 g_hash_table_insert(params_table, strdup(param->key), strdup(param->value));
1983 crm_err(
"Failed to retrieve meta-data for %s:%s:%s",
1984 standard, provider,
type);
1989 if (!
action->stdout_data) {
1990 crm_err(
"Failed to receive meta-data for %s:%s:%s",
1991 standard, provider,
type);
1996 *output = strdup(
action->stdout_data);
2003 lrmd_api_exec(
lrmd_t *lrmd,
const char *rsc_id,
const char *
action,
2004 const char *userdata, guint interval_ms,
2022 for (tmp = params; tmp; tmp = tmp->
next) {
2035 lrmd_api_exec_alert(
lrmd_t *lrmd,
const char *alert_id,
const char *alert_path,
2048 for (tmp = params; tmp; tmp = tmp->
next) {
2061 lrmd_api_cancel(
lrmd_t *lrmd,
const char *rsc_id,
const char *
action,
2084 if (stonith_api == NULL) {
2085 crm_err(
"Could not list fence agents: API memory allocation failed");
2089 &stonith_resources, 0);
2090 stonith_api->
cmds->
free(stonith_api);
2092 for (dIter = stonith_resources; dIter; dIter = dIter->
next) {
2095 *resources = lrmd_list_add(*resources, dIter->
value);
2104 lrmd_api_list_agents(
lrmd_t * lrmd,
lrmd_list_t ** resources,
const char *
class,
2105 const char *provider)
2108 int stonith_count = 0;
2114 GList *gIter = NULL;
2117 for (gIter = agents; gIter != NULL; gIter = gIter->next) {
2118 *resources = lrmd_list_add(*resources, (
const char *)gIter->data);
2121 g_list_free_full(agents, free);
2128 if (stonith_count) {
2130 stonith_count = list_stonith_agents(resources);
2131 if (stonith_count > 0) {
2132 rc += stonith_count;
2136 crm_notice(
"No agents found for class %s",
class);
2137 rc = -EPROTONOSUPPORT;
2143 does_provider_have_agent(
const char *agent,
const char *provider,
const char *
class)
2146 GList *agents = NULL;
2147 GList *gIter2 = NULL;
2150 for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
2155 g_list_free_full(agents, free);
2160 lrmd_api_list_ocf_providers(
lrmd_t * lrmd,
const char *agent,
lrmd_list_t ** providers)
2163 char *provider = NULL;
2164 GList *ocf_providers = NULL;
2165 GList *gIter = NULL;
2169 for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
2170 provider = gIter->data;
2171 if (!agent || does_provider_have_agent(agent, provider,
2173 *providers = lrmd_list_add(*providers, (
const char *)gIter->data);
2178 g_list_free_full(ocf_providers, free);
2186 GList *standards = NULL;
2187 GList *gIter = NULL;
2191 for (gIter = standards; gIter != NULL; gIter = gIter->next) {
2192 *supported = lrmd_list_add(*supported, (
const char *)gIter->data);
2196 if (list_stonith_agents(NULL) > 0) {
2201 g_list_free_full(standards, free);
2236 *api = calloc(1,
sizeof(
lrmd_t));
2254 if ((pvt->remote == NULL) || ((*api)->cmds == NULL)) {
2262 (*api)->cmds->connect_async = lrmd_api_connect_async;
2263 (*api)->cmds->is_connected = lrmd_api_is_connected;
2264 (*api)->cmds->poke_connection = lrmd_api_poke_connection;
2265 (*api)->cmds->disconnect = lrmd_api_disconnect;
2266 (*api)->cmds->register_rsc = lrmd_api_register_rsc;
2267 (*api)->cmds->unregister_rsc = lrmd_api_unregister_rsc;
2268 (*api)->cmds->get_rsc_info = lrmd_api_get_rsc_info;
2269 (*api)->cmds->get_recurring_ops = lrmd_api_get_recurring_ops;
2270 (*api)->cmds->set_callback = lrmd_api_set_callback;
2271 (*api)->cmds->get_metadata = lrmd_api_get_metadata;
2272 (*api)->cmds->exec = lrmd_api_exec;
2273 (*api)->cmds->cancel = lrmd_api_cancel;
2274 (*api)->cmds->list_agents = lrmd_api_list_agents;
2275 (*api)->cmds->list_ocf_providers = lrmd_api_list_ocf_providers;
2276 (*api)->cmds->list_standards = lrmd_api_list_standards;
2277 (*api)->cmds->exec_alert = lrmd_api_exec_alert;
2278 (*api)->cmds->get_metadata_params = lrmd_api_get_metadata_params;
2280 if ((nodename == NULL) && (server == NULL)) {
2283 #ifdef HAVE_GNUTLS_GNUTLS_H
2284 if (nodename == NULL) {
2286 }
else if (server == NULL) {
2289 pvt->type = pcmk__client_tls;
2290 pvt->remote_nodename = strdup(nodename);
2291 pvt->server = strdup(server);
2292 if ((pvt->remote_nodename == NULL) || (pvt->server == NULL)) {
2298 if (pvt->port == 0) {
2302 crm_err(
"Cannot communicate with Pacemaker Remote "
2303 "because GnuTLS is not enabled for this build");
2336 if (lrmd->
cmds != NULL) {
2343 #ifdef HAVE_GNUTLS_GNUTLS_H
2344 free(native->server);
2346 free(native->remote_nodename);
2347 free(native->remote);
2348 free(native->token);
2349 free(native->peer_version);
2366 const char *exit_reason)
2368 if (event == NULL) {
2377 event->exit_reason = (exit_reason == NULL)? NULL : strdup(exit_reason);
2390 if (event == NULL) {
2395 event->exit_reason = NULL;
2397 free((
void *) event->
output);
2398 event->output = NULL;
uint32_t pcmk_get_ra_caps(const char *standard)
Get capabilities of a resource agent standard.
int pcmk__remote_ready(pcmk__remote_t *remote, int timeout_ms)
int pcmk__remote_send_xml(pcmk__remote_t *remote, 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.
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
enum crm_ais_msg_types type
#define CRMD_ACTION_METADATA
#define CRMD_METADATA_CALL_TIMEOUT
gboolean stonith__watchdog_fencing_enabled_for_node(const char *node)
void crm_ipc_destroy(crm_ipc_t *client)
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
const char * crm_ipc_buffer(crm_ipc_t *client)
long crm_ipc_read(crm_ipc_t *client)
int crm_ipc_get_fd(crm_ipc_t *client)
@ crm_ipc_client_response
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)
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
void crm_ipc_close(crm_ipc_t *client)
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
struct crm_ipc_s crm_ipc_t
const char * pcmk__client_type_str(uint64_t client_type)
#define crm_info(fmt, args...)
#define crm_warn(fmt, args...)
#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 DEFAULT_REMOTE_USERNAME
#define F_LRMD_ALERT_PATH
#define LRMD_OP_GET_RECURRING
#define DEFAULT_REMOTE_KEY_LOCATION
@ lrmd_opt_notify_orig_only
#define F_LRMD_RSC_ACTION
#define F_LRMD_REMOTE_MSG_TYPE
#define F_LRMD_RSC_RCCHANGE_TIME
#define F_LRMD_IS_IPC_PROVIDER
#define F_LRMD_CALLBACK_TOKEN
@ lrmd_event_exec_complete
#define F_LRMD_RSC_INTERVAL
#define ALT_REMOTE_KEY_LOCATION
#define F_LRMD_CLIENTNAME
#define F_LRMD_RSC_USERDATA_STR
#define F_LRMD_RSC_OUTPUT
#define F_LRMD_RSC_EXEC_TIME
#define F_LRMD_RSC_DELETED
#define LRMD_OP_RSC_UNREG
#define F_LRMD_RSC_RUN_TIME
#define F_LRMD_PROTOCOL_VERSION
#define F_LRMD_RSC_START_DELAY
#define F_LRMD_RSC_EXIT_REASON
#define F_LRMD_IPC_SESSION
#define F_LRMD_RSC_QUEUE_TIME
#define LRMD_PROTOCOL_VERSION
#define F_LRMD_REMOTE_MSG_ID
void(* lrmd_event_callback)(lrmd_event_data_t *event)
#define LRMD_OP_RSC_CANCEL
#define LRMD_OP_ALERT_EXEC
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
struct lrmd_private_s lrmd_private_t
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *head, const char *key, const char *value)
#define MAX_TLS_RECV_WAIT
lrmd_t * lrmd_remote_api_new(const char *nodename, const char *server, int port)
Create a new TLS connection to a remote executor.
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
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.
void lrmd_list_freeall(lrmd_list_t *head)
lrmd_t * lrmd_api_new(void)
Create a new connection to the local executor.
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
CRM_TRACE_INIT_DATA(lrmd)
void lrmd_free_event(lrmd_event_data_t *event)
Free an executor event.
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
int lrmd__validate_remote_settings(lrmd_t *lrmd, GHashTable *hash)
int lrmd__new(lrmd_t **api, const char *nodename, const char *server, int port)
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
lrmd_rsc_info_t * lrmd_new_rsc_info(const char *rsc_id, const char *standard, const char *provider, const char *type)
int lrmd_poll(lrmd_t *lrmd, int timeout)
Poll for a specified timeout period to determine if a message is ready for dispatch.
int lrmd__remote_send_xml(pcmk__remote_t *session, xmlNode *msg, uint32_t id, const char *msg_type)
Wrappers for and extensions to glib mainloop.
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
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.
void mainloop_set_trigger(crm_trigger_t *source)
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
struct mainloop_io_s mainloop_io_t
struct trigger_s crm_trigger_t
void mainloop_del_ipc_client(mainloop_io_t *client)
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
GHashTable * xml2list(xmlNode *parent)
Retrieve XML attributes as a hash table.
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_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond 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.
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
Add hash table entry to XML as (possibly legacy) name/value.
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_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
const char * crm_xml_add_ms(xmlNode *node, const char *name, guint ms)
Create an XML attribute with specified name and unsigned value.
int crm_element_value_epoch(const xmlNode *xml, const char *name, time_t *dest)
Retrieve the seconds-since-epoch value of an XML attribute.
ocf_exitcode
Exit status codes for resource agents.
@ PCMK_OCF_UNKNOWN
Action is pending.
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
int pcmk_rc2legacy(int rc)
int pcmk_legacy2rc(int legacy_rc)
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
gboolean services_action_sync(svc_action_t *op)
#define PCMK_RESOURCE_CLASS_STONITH
GList * resources_list_standards(void)
void services_action_free(svc_action_t *op)
#define PCMK_RESOURCE_CLASS_OCF
GList * resources_list_providers(const char *standard)
Get a list of providers.
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.
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
stonith_t * stonith_api_new(void)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
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)
Get resource metadata for a resource agent, passing parameters.
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the executor.
int(* connect)(lrmd_t *lrmd, const char *client_name, int *fd)
Connect to an 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
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready.
int(* free)(stonith_t *st)
Destroy the stonith api structure.
int(* metadata)(stonith_t *st, int options, const char *device, const char *provider, char **output, int timeout)
Get the metadata documentation for a resource.
int(* list_agents)(stonith_t *stonith, int call_options, const char *provider, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed stonith agents.
struct stonith_key_value_s * next
stonith_api_operations_t * cmds
Object for executing external actions.
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
void free_xml(xmlNode *child)
xmlNode * create_xml_node(xmlNode *parent, const char *name)
xmlNode * first_named_child(const xmlNode *parent, const char *name)
xmlNode * string2xml(const char *input)