29 #include <sys/types.h> 44 #ifdef HAVE_GNUTLS_GNUTLS_H 46 # include <gnutls/gnutls.h> 49 #include <sys/socket.h> 50 #include <netinet/in.h> 51 #include <netinet/ip.h> 52 #include <arpa/inet.h> 55 #define MAX_TLS_RECV_WAIT 10000 59 static int lrmd_api_disconnect(
lrmd_t * lrmd);
60 static int lrmd_api_is_connected(
lrmd_t * lrmd);
64 static void lrmd_internal_proxy_dispatch(
lrmd_t *lrmd, xmlNode *msg);
67 #ifdef HAVE_GNUTLS_GNUTLS_H 68 # define LRMD_CLIENT_HANDSHAKE_TIMEOUT 5000 69 gnutls_psk_client_credentials_t psk_cred_s;
70 int lrmd_tls_set_key(gnutls_datum_t * key);
71 static void lrmd_tls_disconnect(
lrmd_t * lrmd);
72 static int global_remote_msg_id = 0;
74 static void lrmd_tls_connection_destroy(gpointer userdata);
77 typedef struct lrmd_private_s {
88 char *remote_nodename;
89 #ifdef HAVE_GNUTLS_GNUTLS_H 92 gnutls_psk_client_credentials_t psk_cred_c;
102 int expected_late_replies;
103 GList *pending_notify;
110 void (*proxy_callback)(
lrmd_t *lrmd,
void *userdata, xmlNode *msg);
111 void *proxy_callback_userdata;
116 lrmd_list_add(
lrmd_list_t * head,
const char *value)
121 p->
val = strdup(value);
124 while (end && end->
next) {
143 char *val = (
char *)head->
val;
158 p->
key = strdup(key);
159 p->
value = strdup(value);
162 while (end && end->
next) {
190 dup_attr(gpointer key, gpointer value, gpointer user_data)
192 g_hash_table_replace(user_data, strdup(key), strdup(value));
207 copy->
rsc_id =
event->rsc_id ? strdup(event->
rsc_id) : NULL;
210 copy->
output =
event->output ? strdup(event->
output) : NULL;
218 if (copy->
params != NULL) {
219 g_hash_table_foreach(event->
params, dup_attr, copy->
params);
223 #ifdef ENABLE_VERSIONED_ATTRS 224 if (event->versioned_params) {
225 copy->versioned_params =
copy_xml(event->versioned_params);
240 free((
char *)event->
rsc_id);
243 free((
char *)event->
output);
247 g_hash_table_destroy(event->
params);
249 #ifdef ENABLE_VERSIONED_ATTRS 250 if (event->versioned_params) {
258 lrmd_dispatch_internal(
lrmd_t * lrmd, xmlNode * msg)
265 if (proxy_session != NULL) {
267 lrmd_internal_proxy_dispatch(lrmd, msg);
269 }
else if (!native->callback) {
271 crm_trace(
"notify event received but client has not set callback");
275 event.remote_nodename = native->remote_nodename;
304 #ifdef ENABLE_VERSIONED_ATTRS 315 crm_trace(
"op %s notify event received", type);
316 native->callback(&event);
319 g_hash_table_destroy(event.params);
325 lrmd_ipc_dispatch(
const char *buffer, ssize_t length, gpointer userdata)
332 if (!native->callback) {
338 rc = lrmd_dispatch_internal(lrmd, msg);
343 #ifdef HAVE_GNUTLS_GNUTLS_H 345 lrmd_free_xml(gpointer userdata)
351 lrmd_tls_connected(
lrmd_t * lrmd)
355 if (native->remote->tls_session) {
363 lrmd_tls_dispatch(gpointer userdata)
369 int disconnected = 0;
371 if (lrmd_tls_connected(lrmd) == FALSE) {
372 crm_trace(
"tls dispatch triggered after disconnect");
380 if (native->pending_notify) {
383 crm_trace(
"Processing pending notifies");
384 for (iter = native->pending_notify; iter; iter = iter->next) {
385 lrmd_dispatch_internal(lrmd, iter->data);
387 g_list_free_full(native->pending_notify, lrmd_free_xml);
388 native->pending_notify = NULL;
405 lrmd_dispatch_internal(lrmd, xml);
407 if (native->expected_late_replies > 0) {
408 native->expected_late_replies--;
413 crm_err(
"Got outdated reply %d", reply_id);
421 crm_info(
"Server disconnected while reading remote server msg.");
422 lrmd_tls_disconnect(lrmd);
435 switch (native->type) {
439 #ifdef HAVE_GNUTLS_GNUTLS_H 441 if (native->pending_notify) {
448 crm_err(
"Unsupported connection type: %d", native->type);
463 switch (private->type) {
469 lrmd_ipc_dispatch(msg, strlen(msg), lrmd);
473 #ifdef HAVE_GNUTLS_GNUTLS_H 475 lrmd_tls_dispatch(lrmd);
479 crm_err(
"Unsupported connection type: %d", private->type);
482 if (lrmd_api_is_connected(lrmd) == FALSE) {
503 crm_trace(
"Sending call options: %.8lx, %d", (
long)options, options);
514 lrmd_ipc_connection_destroy(gpointer userdata)
519 crm_info(
"IPC connection destroyed");
523 native->source = NULL;
525 if (native->callback) {
528 event.remote_nodename = native->remote_nodename;
529 native->callback(&event);
533 #ifdef HAVE_GNUTLS_GNUTLS_H 535 lrmd_tls_connection_destroy(gpointer userdata)
540 crm_info(
"TLS connection destroyed");
542 if (native->remote->tls_session) {
543 gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
544 gnutls_deinit(*native->remote->tls_session);
545 gnutls_free(native->remote->tls_session);
547 if (native->psk_cred_c) {
548 gnutls_psk_free_client_credentials(native->psk_cred_c);
553 if (native->process_notify) {
555 native->process_notify = NULL;
557 if (native->pending_notify) {
558 g_list_free_full(native->pending_notify, lrmd_free_xml);
559 native->pending_notify = NULL;
562 free(native->remote->buffer);
563 native->remote->buffer = NULL;
566 native->psk_cred_c = NULL;
567 native->remote->tls_session = NULL;
570 if (native->callback) {
574 native->callback(&event);
590 crm_err(
"Failed to send remote lrmd tls msg, rc = %d", rc);
598 lrmd_tls_recv_reply(
lrmd_t * lrmd,
int total_timeout,
int expected_reply_id,
int *disconnected)
602 time_t start = time(NULL);
603 const char *msg_type = NULL;
605 int remaining_timeout = 0;
618 if (remaining_timeout) {
619 remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
621 remaining_timeout = total_timeout;
623 if (remaining_timeout <= 0) {
624 crm_err(
"Never received the expected reply during the timeout period, disconnecting.");
625 *disconnected = TRUE;
632 crm_err(
"Unable to receive expected reply, disconnecting.");
633 *disconnected = TRUE;
635 }
else if (*disconnected) {
646 crm_err(
"Empty msg type received while waiting for reply");
652 native->pending_notify = g_list_append(native->pending_notify, xml);
653 if (native->process_notify) {
660 crm_err(
"Expected a reply, got %s", msg_type);
663 }
else if (reply_id != expected_reply_id) {
664 if (native->expected_late_replies > 0) {
665 native->expected_late_replies--;
667 crm_err(
"Got outdated reply, expected id %d got id %d", expected_reply_id, reply_id);
674 if (native->remote->buffer && native->process_notify) {
682 lrmd_tls_send(
lrmd_t * lrmd, xmlNode * msg)
687 global_remote_msg_id++;
688 if (global_remote_msg_id <= 0) {
689 global_remote_msg_id = 1;
692 rc = lrmd_tls_send_msg(native->remote, msg, global_remote_msg_id,
"request");
694 crm_err(
"Remote lrmd send failed, disconnecting");
695 lrmd_tls_disconnect(lrmd);
702 lrmd_tls_send_recv(
lrmd_t * lrmd, xmlNode * msg,
int timeout, xmlNode ** reply)
705 int disconnected = 0;
708 if (lrmd_tls_connected(lrmd) == FALSE) {
712 rc = lrmd_tls_send(lrmd, msg);
717 xml = lrmd_tls_recv_reply(lrmd, timeout, global_remote_msg_id, &disconnected);
720 crm_err(
"Remote lrmd server disconnected while waiting for reply with id %d. ",
721 global_remote_msg_id);
722 lrmd_tls_disconnect(lrmd);
725 crm_err(
"Remote lrmd never received reply for request id %d. timeout: %dms ",
726 global_remote_msg_id, timeout);
741 lrmd_send_xml(
lrmd_t * lrmd, xmlNode * msg,
int timeout, xmlNode ** reply)
746 switch (native->type) {
750 #ifdef HAVE_GNUTLS_GNUTLS_H 752 rc = lrmd_tls_send_recv(lrmd, msg, timeout, reply);
756 crm_err(
"Unsupported connection type: %d", native->type);
763 lrmd_send_xml_no_reply(
lrmd_t * lrmd, xmlNode * msg)
768 switch (native->type) {
772 #ifdef HAVE_GNUTLS_GNUTLS_H 774 rc = lrmd_tls_send(lrmd, msg);
779 native->expected_late_replies++;
784 crm_err(
"Unsupported connection type: %d", native->type);
791 lrmd_api_is_connected(
lrmd_t * lrmd)
795 switch (native->type) {
799 #ifdef HAVE_GNUTLS_GNUTLS_H 801 return lrmd_tls_connected(lrmd);
805 crm_err(
"Unsupported connection type: %d", native->type);
812 lrmd_send_command(
lrmd_t * lrmd,
const char *op, xmlNode * data, xmlNode ** output_data,
int timeout,
818 xmlNode *op_msg = NULL;
819 xmlNode *op_reply = NULL;
821 if (!lrmd_api_is_connected(lrmd)) {
826 crm_err(
"No operation specified");
834 op_msg = lrmd_create_op(native->token, op, data, options);
836 if (op_msg == NULL) {
843 rc = lrmd_send_xml(lrmd, op_msg, timeout, &op_reply);
845 rc = lrmd_send_xml_no_reply(lrmd, op_msg);
850 crm_perror(LOG_ERR,
"Couldn't perform %s operation (timeout=%d): %d", op, timeout, rc);
854 }
else if(op_reply == NULL) {
870 *output_data = op_reply;
875 if (lrmd_api_is_connected(lrmd) == FALSE) {
885 lrmd_api_poke_connection(
lrmd_t * lrmd)
908 value = g_hash_table_lookup(hash,
"stonith-watchdog-timeout");
918 lrmd_handshake(
lrmd_t * lrmd,
const char *name)
922 xmlNode *reply = NULL;
931 if (native->proxy_callback) {
935 rc = lrmd_send_xml(lrmd, hello, -1, &reply);
938 crm_perror(LOG_DEBUG,
"Couldn't complete registration with the lrmd API: %d", rc);
940 }
else if (reply == NULL) {
941 crm_err(
"Did not receive registration reply");
951 crm_err(
"LRMD protocol mismatch client version %s, server version %s",
956 crm_err(
"Invalid registration message: %s", msg_type);
959 }
else if (tmp_ticket == NULL) {
960 crm_err(
"No registration token provided");
964 crm_trace(
"Obtained registration token: %s", tmp_ticket);
965 native->token = strdup(tmp_ticket);
966 native->peer_version = strdup(version?version:
"1.0");
975 lrmd_api_disconnect(lrmd);
981 lrmd_ipc_connect(
lrmd_t * lrmd,
int *fd)
988 .destroy = lrmd_ipc_connection_destroy
998 }
else if (native->ipc) {
999 crm_perror(LOG_ERR,
"Connection to local resource manager failed");
1007 if (native->ipc == NULL) {
1008 crm_debug(
"Could not connect to the LRMD API");
1015 #ifdef HAVE_GNUTLS_GNUTLS_H 1017 set_key(gnutls_datum_t * key,
const char *location)
1022 int buf_len = read_len;
1023 static char *key_cache = NULL;
1024 static size_t key_cache_len = 0;
1025 static time_t key_cache_updated;
1027 if (location == NULL) {
1032 time_t now = time(NULL);
1034 if ((now - key_cache_updated) < 60) {
1035 key->data = gnutls_malloc(key_cache_len + 1);
1036 key->size = key_cache_len;
1037 memcpy(key->data, key_cache, key_cache_len);
1043 key_cache_updated = 0;
1050 stream = fopen(location,
"r");
1055 key->data = gnutls_malloc(read_len);
1056 while (!feof(stream)) {
1059 if (cur_len == buf_len) {
1060 buf_len = cur_len + read_len;
1061 key->data = gnutls_realloc(key->data, buf_len);
1063 next = fgetc(stream);
1064 if (next == EOF && feof(stream)) {
1068 key->data[cur_len] = next;
1073 key->size = cur_len;
1075 gnutls_free(key->data);
1081 key_cache = calloc(1, key->size + 1);
1082 memcpy(key_cache, key->data, key->size);
1084 key_cache_len = key->size;
1085 key_cache_updated = time(NULL);
1092 lrmd_tls_set_key(gnutls_datum_t * key)
1095 const char *specific_location = getenv(
"PCMK_authkey_location");
1097 if (set_key(key, specific_location) == 0) {
1098 crm_debug(
"Using custom authkey location %s", specific_location);
1101 }
else if (specific_location) {
1102 crm_err(
"No valid lrmd remote key found at %s, trying default location", specific_location);
1118 lrmd_gnutls_global_init(
void)
1120 static int gnutls_init = 0;
1123 crm_gnutls_global_init();
1130 report_async_connection_result(
lrmd_t * lrmd,
int rc)
1134 if (native->callback) {
1137 event.remote_nodename = native->remote_nodename;
1138 event.connection_rc = rc;
1139 native->callback(&event);
1143 #ifdef HAVE_GNUTLS_GNUTLS_H 1145 lrmd_tcp_connect_cb(
void *userdata,
int sock)
1149 char name[256] = { 0, };
1152 .destroy = lrmd_tls_connection_destroy,
1155 gnutls_datum_t psk_key = { NULL, 0 };
1157 native->async_timer = 0;
1160 lrmd_tls_connection_destroy(lrmd);
1161 crm_info(
"remote lrmd connect to %s at port %d failed", native->server, native->port);
1162 report_async_connection_result(lrmd, rc);
1168 native->sock = sock;
1170 if (lrmd_tls_set_key(&psk_key) != 0) {
1171 lrmd_tls_connection_destroy(lrmd);
1175 gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1177 gnutls_free(psk_key.data);
1182 crm_warn(
"Client tls handshake failed for server %s:%d. Disconnecting", native->server,
1184 gnutls_deinit(*native->remote->tls_session);
1185 gnutls_free(native->remote->tls_session);
1186 native->remote->tls_session = NULL;
1187 lrmd_tls_connection_destroy(lrmd);
1188 report_async_connection_result(lrmd, -1);
1192 crm_info(
"Remote lrmd client TLS connection established with server %s:%d", native->server,
1195 snprintf(name, 128,
"remote-lrmd-%s:%d", native->server, native->port);
1199 mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
1201 rc = lrmd_handshake(lrmd, name);
1202 report_async_connection_result(lrmd, rc);
1208 lrmd_tls_connect_async(
lrmd_t * lrmd,
int timeout )
1216 lrmd_gnutls_global_init();
1219 lrmd_tcp_connect_cb);
1222 native->sock = sock;
1224 native->async_timer = timer_id;
1231 lrmd_tls_connect(
lrmd_t * lrmd,
int *fd)
1235 .destroy = lrmd_tls_connection_destroy,
1240 gnutls_datum_t psk_key = { NULL, 0 };
1242 lrmd_gnutls_global_init();
1246 crm_warn(
"Could not establish remote lrmd connection to %s", native->server);
1247 lrmd_tls_connection_destroy(lrmd);
1251 native->sock = sock;
1253 if (lrmd_tls_set_key(&psk_key) != 0) {
1254 lrmd_tls_connection_destroy(lrmd);
1258 gnutls_psk_allocate_client_credentials(&native->psk_cred_c);
1260 gnutls_free(psk_key.data);
1265 crm_err(
"Session creation for %s:%d failed", native->server, native->port);
1266 gnutls_deinit(*native->remote->tls_session);
1267 gnutls_free(native->remote->tls_session);
1268 native->remote->tls_session = NULL;
1269 lrmd_tls_connection_destroy(lrmd);
1273 crm_info(
"Remote lrmd client TLS connection established with server %s:%d", native->server,
1279 char name[256] = { 0, };
1280 snprintf(name, 128,
"remote-lrmd-%s:%d", native->server, native->port);
1284 mainloop_add_fd(name, G_PRIORITY_HIGH, native->sock, lrmd, &lrmd_tls_callbacks);
1291 lrmd_api_connect(
lrmd_t * lrmd,
const char *name,
int *fd)
1296 switch (native->type) {
1298 rc = lrmd_ipc_connect(lrmd, fd);
1300 #ifdef HAVE_GNUTLS_GNUTLS_H 1301 case CRM_CLIENT_TLS:
1302 rc = lrmd_tls_connect(lrmd, fd);
1306 crm_err(
"Unsupported connection type: %d", native->type);
1310 rc = lrmd_handshake(lrmd, name);
1317 lrmd_api_connect_async(
lrmd_t * lrmd,
const char *name,
int timeout)
1322 if (!native->callback) {
1323 crm_err(
"Async connect not possible, no lrmd client callback set.");
1327 switch (native->type) {
1331 rc = lrmd_api_connect(lrmd, name, NULL);
1333 report_async_connection_result(lrmd, rc);
1336 #ifdef HAVE_GNUTLS_GNUTLS_H 1337 case CRM_CLIENT_TLS:
1338 rc = lrmd_tls_connect_async(lrmd, timeout);
1341 report_async_connection_result(lrmd, rc);
1346 crm_err(
"Unsupported connection type: %d", native->type);
1353 lrmd_ipc_disconnect(
lrmd_t * lrmd)
1357 if (native->source != NULL) {
1360 native->source = NULL;
1363 }
else if (native->ipc) {
1373 #ifdef HAVE_GNUTLS_GNUTLS_H 1375 lrmd_tls_disconnect(
lrmd_t * lrmd)
1379 if (native->remote->tls_session) {
1380 gnutls_bye(*native->remote->tls_session, GNUTLS_SHUT_RDWR);
1381 gnutls_deinit(*native->remote->tls_session);
1382 gnutls_free(native->remote->tls_session);
1383 native->remote->tls_session = 0;
1386 if (native->async_timer) {
1387 g_source_remove(native->async_timer);
1388 native->async_timer = 0;
1391 if (native->source != NULL) {
1394 native->source = NULL;
1396 }
else if (native->sock) {
1397 close(native->sock);
1401 if (native->pending_notify) {
1402 g_list_free_full(native->pending_notify, lrmd_free_xml);
1403 native->pending_notify = NULL;
1409 lrmd_api_disconnect(
lrmd_t * lrmd)
1413 crm_info(
"Disconnecting from %d lrmd service", native->type);
1414 switch (native->type) {
1416 lrmd_ipc_disconnect(lrmd);
1418 #ifdef HAVE_GNUTLS_GNUTLS_H 1419 case CRM_CLIENT_TLS:
1420 lrmd_tls_disconnect(lrmd);
1424 crm_err(
"Unsupported connection type: %d", native->type);
1427 free(native->token);
1428 native->token = NULL;
1430 free(native->peer_version);
1431 native->peer_version = NULL;
1436 lrmd_api_register_rsc(
lrmd_t * lrmd,
1442 xmlNode *data = NULL;
1444 if (!
class || !type || !rsc_id) {
1458 rc = lrmd_send_command(lrmd,
LRMD_OP_RSC_REG, data, NULL, 0, options, TRUE);
1485 copy->
id = strdup(rsc_info->
id);
1486 copy->
type = strdup(rsc_info->
type);
1502 free(rsc_info->
type);
1503 free(rsc_info->
class);
1513 xmlNode *output = NULL;
1514 const char *
class = NULL;
1515 const char *provider = NULL;
1516 const char *type = NULL;
1520 lrmd_send_command(lrmd,
LRMD_OP_RSC_INFO, data, &output, 0, options, TRUE);
1531 if (!
class || !type) {
1540 rsc_info->
id = strdup(rsc_id);
1541 rsc_info->
class = strdup(
class);
1543 rsc_info->
provider = strdup(provider);
1545 rsc_info->
type = strdup(type);
1556 native->callback = callback;
1564 native->proxy_callback = callback;
1565 native->proxy_callback_userdata = userdata;
1569 lrmd_internal_proxy_dispatch(
lrmd_t *lrmd, xmlNode *msg)
1573 if (native->proxy_callback) {
1575 native->proxy_callback(lrmd, native->proxy_callback_userdata, msg);
1588 return lrmd_send_xml_no_reply(lrmd, msg);
1592 stonith_get_metadata(
const char *provider,
const char *type,
char **output)
1599 stonith_api->
cmds->
free(stonith_api);
1601 if (*output == NULL) {
1607 #define lsb_metadata_template \ 1608 "<?xml version='1.0'?>\n" \ 1609 "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n" \ 1610 "<resource-agent name='%s' version='0.1'>\n" \ 1611 " <version>1.0</version>\n" \ 1612 " <longdesc lang='en'>\n" \ 1615 " <shortdesc lang='en'>%s</shortdesc>\n" \ 1617 " </parameters>\n" \ 1619 " <action name='meta-data' timeout='5' />\n" \ 1620 " <action name='start' timeout='15' />\n" \ 1621 " <action name='stop' timeout='15' />\n" \ 1622 " <action name='status' timeout='15' />\n" \ 1623 " <action name='restart' timeout='15' />\n" \ 1624 " <action name='force-reload' timeout='15' />\n" \ 1625 " <action name='monitor' timeout='15' interval='15' />\n" \ 1627 " <special tag='LSB'>\n" \ 1628 " <Provides>%s</Provides>\n" \ 1629 " <Required-Start>%s</Required-Start>\n" \ 1630 " <Required-Stop>%s</Required-Stop>\n" \ 1631 " <Should-Start>%s</Should-Start>\n" \ 1632 " <Should-Stop>%s</Should-Stop>\n" \ 1633 " <Default-Start>%s</Default-Start>\n" \ 1634 " <Default-Stop>%s</Default-Stop>\n" \ 1636 "</resource-agent>\n" 1638 #define LSB_INITSCRIPT_INFOBEGIN_TAG "### BEGIN INIT INFO" 1639 #define LSB_INITSCRIPT_INFOEND_TAG "### END INIT INFO" 1640 #define PROVIDES "# Provides:" 1641 #define REQ_START "# Required-Start:" 1642 #define REQ_STOP "# Required-Stop:" 1643 #define SHLD_START "# Should-Start:" 1644 #define SHLD_STOP "# Should-Stop:" 1645 #define DFLT_START "# Default-Start:" 1646 #define DFLT_STOP "# Default-Stop:" 1647 #define SHORT_DSCR "# Short-Description:" 1648 #define DESCRIPTION "# Description:" 1650 #define lsb_meta_helper_free_value(m) \ 1652 if ((m) != NULL) { \ 1668 static inline gboolean
1669 lsb_meta_helper_get_value(
const char *line,
char **value,
const char *prefix)
1671 if (!*value && !strncasecmp(line, prefix, strlen(prefix))) {
1672 *value = (
char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST line+strlen(prefix));
1679 lsb_get_metadata(
const char *type,
char **output)
1681 char ra_pathname[PATH_MAX] = { 0, };
1684 char *provides = NULL;
1685 char *req_start = NULL;
1686 char *req_stop = NULL;
1687 char *shld_start = NULL;
1688 char *shld_stop = NULL;
1689 char *dflt_start = NULL;
1690 char *dflt_stop = NULL;
1691 char *s_dscrpt = NULL;
1692 char *xml_l_dscrpt = NULL;
1695 char description[max];
1697 if(type[0] ==
'/') {
1698 snprintf(ra_pathname,
sizeof(ra_pathname),
"%s", type);
1700 snprintf(ra_pathname,
sizeof(ra_pathname),
"%s/%s",
LSB_ROOT_DIR, type);
1703 crm_trace(
"Looking into %s", ra_pathname);
1704 if (!(fp = fopen(ra_pathname,
"r"))) {
1709 while (fgets(buffer,
sizeof(buffer), fp)) {
1712 if (lsb_meta_helper_get_value(buffer, &provides,
PROVIDES)) {
1715 if (lsb_meta_helper_get_value(buffer, &req_start,
REQ_START)) {
1718 if (lsb_meta_helper_get_value(buffer, &req_stop,
REQ_STOP)) {
1721 if (lsb_meta_helper_get_value(buffer, &shld_start,
SHLD_START)) {
1724 if (lsb_meta_helper_get_value(buffer, &shld_stop,
SHLD_STOP)) {
1727 if (lsb_meta_helper_get_value(buffer, &dflt_start,
DFLT_START)) {
1730 if (lsb_meta_helper_get_value(buffer, &dflt_stop,
DFLT_STOP)) {
1733 if (lsb_meta_helper_get_value(buffer, &s_dscrpt,
SHORT_DSCR)) {
1744 while (fgets(buffer,
sizeof(buffer), fp)) {
1745 if (!strncmp(buffer,
"# ", 3) || !strncmp(buffer,
"#\t", 2)) {
1747 offset += snprintf(description+offset, max-offset,
"%s", buffer);
1757 if (xml_l_dscrpt == NULL && offset > 0) {
1758 xml_l_dscrpt = (
char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST(description));
1765 if (buffer[0] !=
'#') {
1772 (xml_l_dscrpt == NULL) ? type : xml_l_dscrpt,
1773 (s_dscrpt == NULL) ? type : s_dscrpt, (provides == NULL) ?
"" : provides,
1774 (req_start == NULL) ?
"" : req_start, (req_stop == NULL) ?
"" : req_stop,
1775 (shld_start == NULL) ?
"" : shld_start, (shld_stop == NULL) ?
"" : shld_stop,
1776 (dflt_start == NULL) ?
"" : dflt_start, (dflt_stop == NULL) ?
"" : dflt_stop);
1788 crm_trace(
"Created fake metadata: %llu",
1789 (
unsigned long long) strlen(*output));
1795 nagios_get_metadata(
const char *type,
char **output)
1798 FILE *file_strm = NULL;
1799 int start = 0, length = 0, read_len = 0;
1800 char *metadata_file = NULL;
1804 len += strlen(type);
1805 metadata_file = calloc(1, len);
1806 CRM_CHECK(metadata_file != NULL,
return -ENOMEM);
1809 file_strm = fopen(metadata_file,
"r");
1810 if (file_strm == NULL) {
1811 crm_err(
"Metadata file %s does not exist", metadata_file);
1812 free(metadata_file);
1817 start = ftell(file_strm);
1818 fseek(file_strm, 0L, SEEK_END);
1819 length = ftell(file_strm);
1820 fseek(file_strm, 0L, start);
1826 crm_info(
"%s was not valid", metadata_file);
1832 crm_trace(
"Reading %d bytes from file", length);
1833 *output = calloc(1, (length + 1));
1834 read_len = fread(*output, 1, length, file_strm);
1835 if (read_len != length) {
1836 crm_err(
"Calculated and read bytes differ: %d vs. %d", length, read_len);
1844 free(metadata_file);
1849 #if SUPPORT_HEARTBEAT 1865 static const char hb_metadata_template[] =
1866 "<?xml version='1.0'?>\n" 1867 "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n" 1868 "<resource-agent name='%s' version='0.1'>\n" 1869 "<version>1.0</version>\n" 1870 "<longdesc lang='en'>\n" 1873 "<shortdesc lang='en'>%s</shortdesc>\n" 1875 "<parameter name='1' unique='1' required='0'>\n" 1876 "<longdesc lang='en'>\n" 1877 "This argument will be passed as the first argument to the " 1878 "heartbeat resource agent (assuming it supports one)\n" 1880 "<shortdesc lang='en'>argv[1]</shortdesc>\n" 1881 "<content type='string' default=' ' />\n" 1883 "<parameter name='2' unique='1' required='0'>\n" 1884 "<longdesc lang='en'>\n" 1885 "This argument will be passed as the second argument to the " 1886 "heartbeat resource agent (assuming it supports one)\n" 1888 "<shortdesc lang='en'>argv[2]</shortdesc>\n" 1889 "<content type='string' default=' ' />\n" 1891 "<parameter name='3' unique='1' required='0'>\n" 1892 "<longdesc lang='en'>\n" 1893 "This argument will be passed as the third argument to the " 1894 "heartbeat resource agent (assuming it supports one)\n" 1896 "<shortdesc lang='en'>argv[3]</shortdesc>\n" 1897 "<content type='string' default=' ' />\n" 1899 "<parameter name='4' unique='1' required='0'>\n" 1900 "<longdesc lang='en'>\n" 1901 "This argument will be passed as the fourth argument to the " 1902 "heartbeat resource agent (assuming it supports one)\n" 1904 "<shortdesc lang='en'>argv[4]</shortdesc>\n" 1905 "<content type='string' default=' ' />\n" 1907 "<parameter name='5' unique='1' required='0'>\n" 1908 "<longdesc lang='en'>\n" 1909 "This argument will be passed as the fifth argument to the " 1910 "heartbeat resource agent (assuming it supports one)\n" 1912 "<shortdesc lang='en'>argv[5]</shortdesc>\n" 1913 "<content type='string' default=' ' />\n" 1917 "<action name='start' timeout='15' />\n" 1918 "<action name='stop' timeout='15' />\n" 1919 "<action name='status' timeout='15' />\n" 1920 "<action name='monitor' timeout='15' interval='15' start-delay='15' />\n" 1921 "<action name='meta-data' timeout='5' />\n" 1923 "<special tag='heartbeat'>\n" 1925 "</resource-agent>\n";
1928 heartbeat_get_metadata(
const char *type,
char **output)
1931 crm_trace(
"Created fake metadata: %llu",
1932 (
unsigned long long) strlen(*output));
1938 generic_get_metadata(
const char *standard,
const char *provider,
const char *type,
char **output)
1943 "meta-data", 0, 30000, NULL, 0);
1944 if (action == NULL) {
1945 crm_err(
"Unable to retrieve meta-data for %s:%s:%s", standard, provider, type);
1951 crm_err(
"Failed to retrieve meta-data for %s:%s:%s", standard, provider, type);
1957 crm_err(
"Failed to receive meta-data for %s:%s:%s", standard, provider, type);
1969 lrmd_api_get_metadata(
lrmd_t * lrmd,
1971 const char *provider,
1974 if (!
class || !type) {
1979 class = resources_find_service_class(type);
1983 return stonith_get_metadata(provider, type, output);
1985 return lsb_get_metadata(type, output);
1988 return nagios_get_metadata(type, output);
1990 #if SUPPORT_HEARTBEAT 1992 return heartbeat_get_metadata(type, output);
1995 return generic_get_metadata(
class, provider, type, output);
1999 lrmd_api_exec(
lrmd_t * lrmd,
const char *rsc_id,
const char *action,
const char *userdata,
int interval,
2008 #ifdef ENABLE_VERSIONED_ATTRS 2009 const char *versioned_args_key =
"#" XML_TAG_VER_ATTRS;
2020 for (tmp = params; tmp; tmp = tmp->
next) {
2021 #ifdef ENABLE_VERSIONED_ATTRS 2025 if (versioned_args) {
2031 #ifdef ENABLE_VERSIONED_ATTRS 2036 rc = lrmd_send_command(lrmd,
LRMD_OP_RSC_EXEC, data, NULL, timeout, options, TRUE);
2044 lrmd_api_cancel(
lrmd_t * lrmd,
const char *rsc_id,
const char *action,
int interval)
2068 stonith_api->
cmds->
free(stonith_api);
2071 for (dIter = stonith_resources; dIter; dIter = dIter->
next) {
2074 *resources = lrmd_list_add(*resources, dIter->
value);
2083 lrmd_api_list_agents(
lrmd_t * lrmd,
lrmd_list_t ** resources,
const char *
class,
2084 const char *provider)
2089 rc += list_stonith_agents(resources);
2095 for (gIter = agents; gIter != NULL; gIter = gIter->next) {
2096 *resources = lrmd_list_add(*resources, (
const char *)gIter->data);
2099 g_list_free_full(agents, free);
2102 rc += list_stonith_agents(resources);
2107 crm_notice(
"No agents found for class %s",
class);
2108 rc = -EPROTONOSUPPORT;
2114 does_provider_have_agent(
const char *agent,
const char *provider,
const char *
class)
2117 GList *agents = NULL;
2121 for (gIter2 = agents; gIter2 != NULL; gIter2 = gIter2->next) {
2126 g_list_free_full(agents, free);
2132 lrmd_api_list_ocf_providers(
lrmd_t * lrmd,
const char *agent,
lrmd_list_t ** providers)
2135 char *provider = NULL;
2136 GList *ocf_providers = NULL;
2141 for (gIter = ocf_providers; gIter != NULL; gIter = gIter->next) {
2142 provider = gIter->data;
2143 if (!agent || does_provider_have_agent(agent, provider,
2145 *providers = lrmd_list_add(*providers, (
const char *)gIter->data);
2150 g_list_free_full(ocf_providers, free);
2158 GList *standards = NULL;
2163 for (gIter = standards; gIter != NULL; gIter = gIter->next) {
2164 *supported = lrmd_list_add(*supported, (
const char *)gIter->data);
2168 if (list_stonith_agents(NULL) > 0) {
2173 g_list_free_full(standards, free);
2183 new_lrmd = calloc(1,
sizeof(
lrmd_t));
2201 new_lrmd->
cmds->
exec = lrmd_api_exec;
2213 #ifdef HAVE_GNUTLS_GNUTLS_H 2217 if (!nodename && !server) {
2222 native->type = CRM_CLIENT_TLS;
2223 native->remote_nodename = nodename ? strdup(nodename) : strdup(server);
2224 native->server = server ? strdup(server) : strdup(nodename);
2225 native->port = port;
2226 if (native->port == 0) {
2227 const char *remote_port_str = getenv(
"PCMK_remote_port");
2233 crm_err(
"GNUTLS is not enabled for this build, remote LRMD client can not be created");
2250 #ifdef HAVE_GNUTLS_GNUTLS_H 2251 free(native->server);
2253 free(native->remote_nodename);
2254 free(native->remote);
2255 free(native->token);
2256 free(native->peer_version);
#define CRM_CHECK(expr, failure_action)
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
#define crm_notice(fmt, args...)
GHashTable * xml2list(xmlNode *parent)
lrmd_event_data_t * lrmd_copy_event(lrmd_event_data_t *event)
gboolean safe_str_neq(const char *a, const char *b)
void services_action_free(svc_action_t *op)
int crm_remote_ready(crm_remote_t *remote, int total_timeout)
gboolean crm_remote_recv(crm_remote_t *remote, int total_timeout, int *disconnected)
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
#define F_LRMD_IS_IPC_PROVIDER
#define F_LRMD_IPC_SESSION
#define F_LRMD_RSC_EXEC_TIME
int(* list_agents)(stonith_t *stonith, int call_options, const char *namespace, stonith_key_value_t **devices, int timeout)
Retrieve a list of installed stonith agents.
#define F_LRMD_RSC_ACTION
#define LRMD_OP_RSC_CANCEL
int crm_ipc_get_fd(crm_ipc_t *client)
#define F_LRMD_RSC_OUTPUT
int(* connect_async)(lrmd_t *lrmd, const char *client_name, int timeout)
Establish an connection to lrmd, don't block while connecting.
void(* lrmd_event_callback)(lrmd_event_data_t *event)
svc_action_t * resources_action_create(const char *name, const char *standard, const char *provider, const char *agent, const char *action, int interval, int timeout, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
struct stonith_key_value_s * next
void lrmd_key_value_freeall(lrmd_key_value_t *head)
struct mainloop_io_s mainloop_io_t
void mainloop_set_trigger(crm_trigger_t *source)
#define DEFAULT_REMOTE_USERNAME
#define MAX_TLS_RECV_WAIT
int lrmd_internal_proxy_send(lrmd_t *lrmd, xmlNode *msg)
lrmd_rsc_info_t * lrmd_copy_rsc_info(lrmd_rsc_info_t *rsc_info)
long crm_ipc_read(crm_ipc_t *client)
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
int(* cancel)(lrmd_t *lrmd, const char *rsc_id, const char *action, int interval)
Cancel a recurring command.
int crm_remote_tcp_connect(const char *host, int port)
Wrappers for and extensions to glib mainloop.
#define F_LRMD_PROTOCOL_VERSION
lrmd_t * lrmd_remote_api_new(const char *nodename, const char *server, int port)
Create a new remote lrmd connection using tls backend.
stonith_t * stonith_api_new(void)
xmlNode * string2xml(const char *input)
const char * crm_ipc_buffer(crm_ipc_t *client)
int remote_proxy_check(lrmd_t *lrmd, GHashTable *hash)
#define LRMD_OP_RSC_UNREG
#define DEFAULT_REMOTE_PORT
#define DEFAULT_REMOTE_KEY_LOCATION
struct trigger_s crm_trigger_t
void hash2smartfield(gpointer key, gpointer value, gpointer user_data)
struct lrmd_private_s lrmd_private_t
xmlNode * copy_xml(xmlNode *src_node)
int(* free)(stonith_t *st)
Destroy the stonith api structure.
int(* dispatch)(gpointer userdata)
#define crm_warn(fmt, args...)
int(* poke_connection)(lrmd_t *lrmd)
Poke lrmd connection to verify it is still capable of serving requests.
#define PCMK_RESOURCE_CLASS_OCF
#define crm_debug(fmt, args...)
int crm_initiate_client_tls_handshake(crm_remote_t *remote, int timeout_ms)
#define lsb_metadata_template
struct crm_ipc_s crm_ipc_t
#define F_LRMD_RSC_EXIT_REASON
#define ALT_REMOTE_KEY_LOCATION
bool lrmd_dispatch(lrmd_t *lrmd)
Use after lrmd_poll returns 1 to read and dispatch a message.
struct lrmd_list_s * next
gboolean services_action_sync(svc_action_t *op)
#define LRMD_PROTOCOL_VERSION
xmlNode * crm_remote_parse_buffer(crm_remote_t *remote)
int(* get_metadata)(lrmd_t *lrmd, const char *class, const char *provider, const char *agent, char **output, enum lrmd_call_options options)
Get the metadata documentation for a resource.
lrmd_rsc_info_t *(* get_rsc_info)(lrmd_t *lrmd, const char *rsc_id, enum lrmd_call_options options)
Retrieve registration info for a rsc.
void lrmd_list_freeall(lrmd_list_t *head)
#define PCMK_RESOURCE_CLASS_SERVICE
int(* connect)(lrmd_t *lrmd, const char *client_name, int *fd)
Connect from the lrmd.
#define crm_trace(fmt, args...)
crm_trigger_t * mainloop_add_trigger(int priority, int(*dispatch)(gpointer user_data), gpointer userdata)
#define LRMD_OP_NEW_CLIENT
xmlNode * create_xml_node(xmlNode *parent, const char *name)
int crm_element_value_int(xmlNode *data, const char *name, int *dest)
const char * crm_element_value(xmlNode *data, const char *name)
void stonith_key_value_freeall(stonith_key_value_t *kvp, int keys, int values)
void mainloop_del_ipc_client(mainloop_io_t *client)
void crm_ipc_destroy(crm_ipc_t *client)
GList * resources_list_providers(const char *standard)
Get a list of providers.
lrmd_t * lrmd_api_new(void)
Create a new local lrmd connection.
#define LSB_INITSCRIPT_INFOEND_TAG
struct lrmd_key_value_s * next
#define F_LRMD_RSC_USERDATA_STR
gboolean add_message_xml(xmlNode *msg, const char *field, xmlNode *xml)
void free_xml(xmlNode *child)
#define F_LRMD_RSC_INTERVAL
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
int crm_remote_tcp_connect_async(const char *host, int port, int timeout, int *timer_id, void *userdata, void(*callback)(void *userdata, int sock))
CRM_TRACE_INIT_DATA(lrmd)
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
int(* unregister_rsc)(lrmd_t *lrmd, const char *rsc_id, enum lrmd_call_options options)
Unregister a resource from the lrmd.
#define F_LRMD_RSC_START_DELAY
int(* disconnect)(lrmd_t *lrmd)
Disconnect from the lrmd.
bool crm_ipc_connected(crm_ipc_t *client)
int lrmd_poll(lrmd_t *lrmd, int timeout)
Poll for a specified timeout period to determine if a message is ready for dispatch.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
#define PCMK_RESOURCE_CLASS_STONITH
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
#define F_LRMD_RSC_RCCHANGE_TIME
int(* list_agents)(lrmd_t *lrmd, lrmd_list_t **agents, const char *class, const char *provider)
Retrieve a list of installed resource agents.
#define lsb_meta_helper_free_value(m)
#define crm_log_xml_err(xml, text)
void lrmd_api_delete(lrmd_t *lrmd)
Destroy lrmd object.
#define PCMK_RESOURCE_CLASS_NAGIOS
#define F_LRMD_REMOTE_MSG_ID
#define PCMK_RESOURCE_CLASS_LSB
#define crm_perror(level, fmt, args...)
Log a system error message.
const char * remote_nodename
lrmd_api_operations_t * cmds
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
GList * resources_list_standards(void)
#define crm_err(fmt, args...)
enum lrmd_callback_event type
lrmd_key_value_t * lrmd_key_value_add(lrmd_key_value_t *head, const char *key, const char *value)
stonith_api_operations_t * cmds
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
#define PCMK_RESOURCE_CLASS_HB
int(* list_standards)(lrmd_t *lrmd, lrmd_list_t **standards)
Retrieve a list of standards supported by this machine/installation.
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
void * create_psk_tls_session(int csock, int type, void *credentials)
#define F_LRMD_RSC_RUN_TIME
int add_node_nocopy(xmlNode *parent, const char *name, xmlNode *child)
int(* register_rsc)(lrmd_t *lrmd, const char *rsc_id, const char *class, const char *provider, const char *agent, enum lrmd_call_options options)
Register a resource with the lrmd.
int(* list_ocf_providers)(lrmd_t *lrmd, const char *agent, lrmd_list_t **providers)
Retrieve a list of resource agent providers.
void lrmd_internal_set_proxy_callback(lrmd_t *lrmd, void *userdata, void(*callback)(lrmd_t *lrmd, void *userdata, xmlNode *msg))
#define crm_log_xml_trace(xml, text)
xmlNode * first_named_child(xmlNode *parent, const char *name)
#define F_LRMD_CLIENTNAME
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
#define F_LRMD_RSC_QUEUE_TIME
#define F_LRMD_RSC_DELETED
#define safe_str_eq(a, b)
#define F_LRMD_CALLBACK_TOKEN
int(* metadata)(stonith_t *st, int options, const char *device, const char *namespace, char **output, int timeout)
Get the metadata documentation for a resource.
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
void lrmd_free_event(lrmd_event_data_t *event)
#define F_LRMD_REMOTE_MSG_TYPE
void crm_ipc_close(crm_ipc_t *client)
int crm_remote_send(crm_remote_t *remote, xmlNode *msg)
#define crm_info(fmt, args...)
#define NAGIOS_METADATA_DIR
int(* is_connected)(lrmd_t *lrmd)
Is connected to lrmd daemon?
void g_hash_destroy_str(gpointer data)
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
void(* set_callback)(lrmd_t *lrmd, lrmd_event_callback callback)
Sets the callback to receive lrmd events on.
enum crm_ais_msg_types type
int(* exec)(lrmd_t *lrmd, const char *rsc_id, const char *action, const char *userdata, int interval, int timeout, int start_delay, enum lrmd_call_options options, lrmd_key_value_t *params)
Issue a command on a resource.