This source file includes following definitions.
- time_is_set
- get_current_time
- time_diff_ms
- cmd_original_times
- action_matches
- log_finished
- log_execute
- normalize_action_name
- build_rsc_from_xml
- create_lrmd_cmd
- stop_recurring_timer
- free_lrmd_cmd
- stonith_recurring_op_helper
- start_recurring_timer
- start_delay_helper
- find_duplicate_action
- merge_recurring_duplicate
- schedule_lrmd_cmd
- create_lrmd_reply
- send_client_notify
- send_cmd_complete_notify
- send_generic_notify
- cmd_reset
- cmd_finalize
- notify_one_client
- notify_of_new_client
- client_disconnect_cleanup
- action_complete
- stonith_action_complete
- lrmd_stonith_callback
- stonith_connection_failed
- execd_stonith_start
- execd_stonith_stop
- execd_stonith_monitor
- execute_stonith_action
- execute_nonstonith_action
- execute_resource_action
- free_rsc
- process_lrmd_signon
- process_lrmd_rsc_register
- process_lrmd_get_rsc_info
- process_lrmd_rsc_unregister
- process_lrmd_rsc_exec
- cancel_op
- cancel_all_recurring
- process_lrmd_rsc_cancel
- add_recurring_op_xml
- process_lrmd_get_recurring
- process_lrmd_message
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/fencing/internal.h>
12
13 #include <glib.h>
14
15
16 #undef PCMK__TIME_USE_CGT
17 #if HAVE_DECL_CLOCK_MONOTONIC && defined(CLOCK_MONOTONIC)
18 # define PCMK__TIME_USE_CGT
19 # include <time.h>
20 #endif
21
22 #include <unistd.h>
23
24 #include <crm/crm.h>
25 #include <crm/fencing/internal.h>
26 #include <crm/services.h>
27 #include <crm/services_internal.h>
28 #include <crm/common/mainloop.h>
29 #include <crm/common/ipc.h>
30 #include <crm/common/ipc_internal.h>
31 #include <crm/common/xml.h>
32
33 #include "pacemaker-execd.h"
34
35 GHashTable *rsc_list = NULL;
36
37 typedef struct lrmd_cmd_s {
38 int timeout;
39 guint interval_ms;
40 int start_delay;
41 int timeout_orig;
42
43 int call_id;
44
45 int call_opts;
46
47 int delay_id;
48 int stonith_recurring_id;
49
50 int rsc_deleted;
51
52 int service_flags;
53
54 char *client_id;
55 char *origin;
56 char *rsc_id;
57 char *action;
58 char *real_action;
59 char *userdata_str;
60
61 pcmk__action_result_t result;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 #ifdef PCMK__TIME_USE_CGT
80
81
82
83
84 struct timespec t_first_run;
85 struct timespec t_run;
86 struct timespec t_first_queue;
87 struct timespec t_queue;
88 #endif
89 time_t epoch_last_run;
90 time_t epoch_rcchange;
91
92 bool first_notify_sent;
93 int last_notify_rc;
94 int last_notify_op_status;
95 int last_pid;
96
97 GHashTable *params;
98 } lrmd_cmd_t;
99
100 static void cmd_finalize(lrmd_cmd_t * cmd, lrmd_rsc_t * rsc);
101 static gboolean execute_resource_action(gpointer user_data);
102 static void cancel_all_recurring(lrmd_rsc_t * rsc, const char *client_id);
103
104 #ifdef PCMK__TIME_USE_CGT
105
106
107
108
109
110
111
112
113
114 static inline bool
115 time_is_set(const struct timespec *timespec)
116 {
117 return (timespec != NULL) &&
118 ((timespec->tv_sec != 0) || (timespec->tv_nsec != 0));
119 }
120
121
122
123
124
125
126
127
128 static void
129 get_current_time(struct timespec *t_current, struct timespec *t_orig)
130 {
131 clock_gettime(CLOCK_MONOTONIC, t_current);
132 if ((t_orig != NULL) && !time_is_set(t_orig)) {
133 *t_orig = *t_current;
134 }
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148
149 static int
150 time_diff_ms(const struct timespec *now, const struct timespec *old)
151 {
152 int diff_ms = 0;
153
154 if (time_is_set(old)) {
155 struct timespec local_now = { 0, };
156
157 if (now == NULL) {
158 clock_gettime(CLOCK_MONOTONIC, &local_now);
159 now = &local_now;
160 }
161 diff_ms = (now->tv_sec - old->tv_sec) * 1000
162 + (now->tv_nsec - old->tv_nsec) / 1000000;
163 }
164 return diff_ms;
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 static void
188 cmd_original_times(lrmd_cmd_t * cmd)
189 {
190 cmd->t_run = cmd->t_first_run;
191 cmd->t_queue = cmd->t_first_queue;
192 }
193 #endif
194
195 static inline bool
196 action_matches(const lrmd_cmd_t *cmd, const char *action, guint interval_ms)
197 {
198 return (cmd->interval_ms == interval_ms)
199 && pcmk__str_eq(cmd->action, action, pcmk__str_casei);
200 }
201
202
203
204
205
206
207
208
209
210 static void
211 log_finished(const lrmd_cmd_t *cmd, int exec_time_ms, int queue_time_ms)
212 {
213 int log_level = LOG_INFO;
214 GString *str = g_string_sized_new(100);
215
216 if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR, pcmk__str_casei)) {
217 log_level = LOG_DEBUG;
218 }
219
220 g_string_append_printf(str, "%s %s (call %d",
221 cmd->rsc_id, cmd->action, cmd->call_id);
222 if (cmd->last_pid != 0) {
223 g_string_append_printf(str, ", PID %d", cmd->last_pid);
224 }
225 if (cmd->result.execution_status == PCMK_EXEC_DONE) {
226 g_string_append_printf(str, ") exited with status %d",
227 cmd->result.exit_status);
228 } else {
229 pcmk__g_strcat(str, ") could not be executed: ",
230 pcmk_exec_status_str(cmd->result.execution_status),
231 NULL);
232 }
233 if (cmd->result.exit_reason != NULL) {
234 pcmk__g_strcat(str, " (", cmd->result.exit_reason, ")", NULL);
235 }
236
237 #ifdef PCMK__TIME_USE_CGT
238 pcmk__g_strcat(str, " (execution time ",
239 pcmk__readable_interval(exec_time_ms), NULL);
240 if (queue_time_ms > 0) {
241 pcmk__g_strcat(str, " after being queued ",
242 pcmk__readable_interval(queue_time_ms), NULL);
243 }
244 g_string_append_c(str, ')');
245 #endif
246
247 do_crm_log(log_level, "%s", str->str);
248 g_string_free(str, TRUE);
249 }
250
251 static void
252 log_execute(lrmd_cmd_t * cmd)
253 {
254 int log_level = LOG_INFO;
255
256 if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR, pcmk__str_casei)) {
257 log_level = LOG_DEBUG;
258 }
259
260 do_crm_log(log_level, "executing - rsc:%s action:%s call_id:%d",
261 cmd->rsc_id, cmd->action, cmd->call_id);
262 }
263
264 static const char *
265 normalize_action_name(lrmd_rsc_t * rsc, const char *action)
266 {
267 if (pcmk__str_eq(action, PCMK_ACTION_MONITOR, pcmk__str_casei) &&
268 pcmk_is_set(pcmk_get_ra_caps(rsc->class), pcmk_ra_cap_status)) {
269 return PCMK_ACTION_STATUS;
270 }
271 return action;
272 }
273
274 static lrmd_rsc_t *
275 build_rsc_from_xml(xmlNode * msg)
276 {
277 xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, msg, LOG_ERR);
278 lrmd_rsc_t *rsc = NULL;
279
280 rsc = pcmk__assert_alloc(1, sizeof(lrmd_rsc_t));
281
282 crm_element_value_int(msg, PCMK__XA_LRMD_CALLOPT, &rsc->call_opts);
283
284 rsc->rsc_id = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_RSC_ID);
285 rsc->class = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_CLASS);
286 rsc->provider = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_PROVIDER);
287 rsc->type = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_TYPE);
288 rsc->work = mainloop_add_trigger(G_PRIORITY_HIGH, execute_resource_action,
289 rsc);
290
291
292 pcmk__set_result(&rsc->fence_probe_result, CRM_EX_ERROR,
293 PCMK_EXEC_NO_FENCE_DEVICE, NULL);
294 return rsc;
295 }
296
297 static lrmd_cmd_t *
298 create_lrmd_cmd(xmlNode *msg, pcmk__client_t *client)
299 {
300 int call_options = 0;
301 xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, msg, LOG_ERR);
302 lrmd_cmd_t *cmd = NULL;
303
304 cmd = pcmk__assert_alloc(1, sizeof(lrmd_cmd_t));
305
306 crm_element_value_int(msg, PCMK__XA_LRMD_CALLOPT, &call_options);
307 cmd->call_opts = call_options;
308 cmd->client_id = pcmk__str_copy(client->id);
309
310 crm_element_value_int(msg, PCMK__XA_LRMD_CALLID, &cmd->call_id);
311 crm_element_value_ms(rsc_xml, PCMK__XA_LRMD_RSC_INTERVAL,
312 &cmd->interval_ms);
313 crm_element_value_int(rsc_xml, PCMK__XA_LRMD_TIMEOUT, &cmd->timeout);
314 crm_element_value_int(rsc_xml, PCMK__XA_LRMD_RSC_START_DELAY,
315 &cmd->start_delay);
316 cmd->timeout_orig = cmd->timeout;
317
318 cmd->origin = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_ORIGIN);
319 cmd->action = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_RSC_ACTION);
320 cmd->userdata_str = crm_element_value_copy(rsc_xml,
321 PCMK__XA_LRMD_RSC_USERDATA_STR);
322 cmd->rsc_id = crm_element_value_copy(rsc_xml, PCMK__XA_LRMD_RSC_ID);
323
324 cmd->params = xml2list(rsc_xml);
325
326 if (pcmk__str_eq(g_hash_table_lookup(cmd->params, "CRM_meta_on_fail"),
327 PCMK_VALUE_BLOCK, pcmk__str_casei)) {
328 crm_debug("Setting flag to leave pid group on timeout and "
329 "only kill action pid for " PCMK__OP_FMT,
330 cmd->rsc_id, cmd->action, cmd->interval_ms);
331 cmd->service_flags = pcmk__set_flags_as(__func__, __LINE__,
332 LOG_TRACE, "Action",
333 cmd->action, 0,
334 SVC_ACTION_LEAVE_GROUP,
335 "SVC_ACTION_LEAVE_GROUP");
336 }
337 return cmd;
338 }
339
340 static void
341 stop_recurring_timer(lrmd_cmd_t *cmd)
342 {
343 if (cmd) {
344 if (cmd->stonith_recurring_id) {
345 g_source_remove(cmd->stonith_recurring_id);
346 }
347 cmd->stonith_recurring_id = 0;
348 }
349 }
350
351 static void
352 free_lrmd_cmd(lrmd_cmd_t * cmd)
353 {
354 stop_recurring_timer(cmd);
355 if (cmd->delay_id) {
356 g_source_remove(cmd->delay_id);
357 }
358 if (cmd->params) {
359 g_hash_table_destroy(cmd->params);
360 }
361 pcmk__reset_result(&(cmd->result));
362 free(cmd->origin);
363 free(cmd->action);
364 free(cmd->real_action);
365 free(cmd->userdata_str);
366 free(cmd->rsc_id);
367 free(cmd->client_id);
368 free(cmd);
369 }
370
371 static gboolean
372 stonith_recurring_op_helper(gpointer data)
373 {
374 lrmd_cmd_t *cmd = data;
375 lrmd_rsc_t *rsc;
376
377 cmd->stonith_recurring_id = 0;
378
379 if (!cmd->rsc_id) {
380 return FALSE;
381 }
382
383 rsc = g_hash_table_lookup(rsc_list, cmd->rsc_id);
384
385 pcmk__assert(rsc != NULL);
386
387
388 rsc->recurring_ops = g_list_remove(rsc->recurring_ops, cmd);
389 rsc->pending_ops = g_list_append(rsc->pending_ops, cmd);
390 #ifdef PCMK__TIME_USE_CGT
391 get_current_time(&(cmd->t_queue), &(cmd->t_first_queue));
392 #endif
393 mainloop_set_trigger(rsc->work);
394
395 return FALSE;
396 }
397
398 static inline void
399 start_recurring_timer(lrmd_cmd_t *cmd)
400 {
401 if (!cmd || (cmd->interval_ms <= 0)) {
402 return;
403 }
404
405 cmd->stonith_recurring_id = pcmk__create_timer(cmd->interval_ms,
406 stonith_recurring_op_helper,
407 cmd);
408 }
409
410 static gboolean
411 start_delay_helper(gpointer data)
412 {
413 lrmd_cmd_t *cmd = data;
414 lrmd_rsc_t *rsc = NULL;
415
416 cmd->delay_id = 0;
417 rsc = cmd->rsc_id ? g_hash_table_lookup(rsc_list, cmd->rsc_id) : NULL;
418
419 if (rsc) {
420 mainloop_set_trigger(rsc->work);
421 }
422
423 return FALSE;
424 }
425
426
427
428
429
430
431
432
433 static lrmd_cmd_t *
434 find_duplicate_action(const GList *action_list, const lrmd_cmd_t *cmd)
435 {
436 for (const GList *item = action_list; item != NULL; item = item->next) {
437 lrmd_cmd_t *dup = item->data;
438
439 if (action_matches(cmd, dup->action, dup->interval_ms)) {
440 return dup;
441 }
442 }
443 return NULL;
444 }
445
446 static bool
447 merge_recurring_duplicate(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
448 {
449 lrmd_cmd_t * dup = NULL;
450 bool dup_pending = true;
451
452 if (cmd->interval_ms == 0) {
453 return false;
454 }
455
456
457 dup = find_duplicate_action(rsc->pending_ops, cmd);
458 if (dup == NULL) {
459 dup_pending = false;
460 dup = find_duplicate_action(rsc->recurring_ops, cmd);
461 if (dup == NULL) {
462 return false;
463 }
464 }
465
466
467
468
469 if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH,
470 pcmk__str_casei)
471 && (dup->result.execution_status == PCMK_EXEC_CANCELLED)) {
472 return false;
473 }
474
475
476
477
478 crm_warn("Duplicate recurring op entry detected (" PCMK__OP_FMT
479 "), merging with previous op entry",
480 rsc->rsc_id, normalize_action_name(rsc, dup->action),
481 dup->interval_ms);
482
483
484 dup->first_notify_sent = false;
485 free(dup->userdata_str);
486 dup->userdata_str = cmd->userdata_str;
487 cmd->userdata_str = NULL;
488 dup->call_id = cmd->call_id;
489 free_lrmd_cmd(cmd);
490 cmd = NULL;
491
492
493
494
495
496 if (!dup_pending) {
497 if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH,
498 pcmk__str_casei)) {
499 stop_recurring_timer(dup);
500 stonith_recurring_op_helper(dup);
501 } else {
502 services_action_kick(rsc->rsc_id,
503 normalize_action_name(rsc, dup->action),
504 dup->interval_ms);
505 }
506 }
507 return true;
508 }
509
510 static void
511 schedule_lrmd_cmd(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
512 {
513 CRM_CHECK(cmd != NULL, return);
514 CRM_CHECK(rsc != NULL, return);
515
516 crm_trace("Scheduling %s on %s", cmd->action, rsc->rsc_id);
517
518 if (merge_recurring_duplicate(rsc, cmd)) {
519
520 return;
521 }
522
523
524
525
526 if (pcmk__str_eq(cmd->action, PCMK_ACTION_STOP, pcmk__str_casei)) {
527 cancel_all_recurring(rsc, NULL);
528 }
529
530 rsc->pending_ops = g_list_append(rsc->pending_ops, cmd);
531 #ifdef PCMK__TIME_USE_CGT
532 get_current_time(&(cmd->t_queue), &(cmd->t_first_queue));
533 #endif
534 mainloop_set_trigger(rsc->work);
535
536 if (cmd->start_delay) {
537 cmd->delay_id = pcmk__create_timer(cmd->start_delay, start_delay_helper, cmd);
538 }
539 }
540
541 static xmlNode *
542 create_lrmd_reply(const char *origin, int rc, int call_id)
543 {
544 xmlNode *reply = pcmk__xe_create(NULL, PCMK__XE_LRMD_REPLY);
545
546 crm_xml_add(reply, PCMK__XA_LRMD_ORIGIN, origin);
547 crm_xml_add_int(reply, PCMK__XA_LRMD_RC, rc);
548 crm_xml_add_int(reply, PCMK__XA_LRMD_CALLID, call_id);
549 return reply;
550 }
551
552 static void
553 send_client_notify(gpointer key, gpointer value, gpointer user_data)
554 {
555 xmlNode *update_msg = user_data;
556 pcmk__client_t *client = value;
557 int rc;
558 int log_level = LOG_WARNING;
559 const char *msg = NULL;
560
561 CRM_CHECK(client != NULL, return);
562 if (client->name == NULL) {
563 crm_trace("Skipping notification to client without name");
564 return;
565 }
566 if (pcmk_is_set(client->flags, pcmk__client_to_proxy)) {
567
568
569
570
571 crm_trace("Skipping executor API notification to client %s",
572 pcmk__client_name(client));
573 return;
574 }
575
576 rc = lrmd_server_send_notify(client, update_msg);
577 if (rc == pcmk_rc_ok) {
578 return;
579 }
580
581 switch (rc) {
582 case ENOTCONN:
583 case EPIPE:
584 log_level = LOG_INFO;
585 msg = "Disconnected";
586 break;
587
588 default:
589 msg = pcmk_rc_str(rc);
590 break;
591 }
592 do_crm_log(log_level, "Could not notify client %s: %s " QB_XS " rc=%d",
593 pcmk__client_name(client), msg, rc);
594 }
595
596 static void
597 send_cmd_complete_notify(lrmd_cmd_t * cmd)
598 {
599 xmlNode *notify = NULL;
600 int exec_time = 0;
601 int queue_time = 0;
602
603 #ifdef PCMK__TIME_USE_CGT
604 exec_time = time_diff_ms(NULL, &(cmd->t_run));
605 queue_time = time_diff_ms(&cmd->t_run, &(cmd->t_queue));
606 #endif
607 log_finished(cmd, exec_time, queue_time);
608
609
610
611
612 if (cmd->first_notify_sent
613 && pcmk_is_set(cmd->call_opts, lrmd_opt_notify_changes_only)
614 && (cmd->last_notify_rc == cmd->result.exit_status)
615 && (cmd->last_notify_op_status == cmd->result.execution_status)) {
616 return;
617 }
618
619 cmd->first_notify_sent = true;
620 cmd->last_notify_rc = cmd->result.exit_status;
621 cmd->last_notify_op_status = cmd->result.execution_status;
622
623 notify = pcmk__xe_create(NULL, PCMK__XE_LRMD_NOTIFY);
624
625 crm_xml_add(notify, PCMK__XA_LRMD_ORIGIN, __func__);
626 crm_xml_add_int(notify, PCMK__XA_LRMD_TIMEOUT, cmd->timeout);
627 crm_xml_add_ms(notify, PCMK__XA_LRMD_RSC_INTERVAL, cmd->interval_ms);
628 crm_xml_add_int(notify, PCMK__XA_LRMD_RSC_START_DELAY, cmd->start_delay);
629 crm_xml_add_int(notify, PCMK__XA_LRMD_EXEC_RC, cmd->result.exit_status);
630 crm_xml_add_int(notify, PCMK__XA_LRMD_EXEC_OP_STATUS,
631 cmd->result.execution_status);
632 crm_xml_add_int(notify, PCMK__XA_LRMD_CALLID, cmd->call_id);
633 crm_xml_add_int(notify, PCMK__XA_LRMD_RSC_DELETED, cmd->rsc_deleted);
634
635 crm_xml_add_ll(notify, PCMK__XA_LRMD_RUN_TIME,
636 (long long) cmd->epoch_last_run);
637 crm_xml_add_ll(notify, PCMK__XA_LRMD_RCCHANGE_TIME,
638 (long long) cmd->epoch_rcchange);
639 #ifdef PCMK__TIME_USE_CGT
640 crm_xml_add_int(notify, PCMK__XA_LRMD_EXEC_TIME, exec_time);
641 crm_xml_add_int(notify, PCMK__XA_LRMD_QUEUE_TIME, queue_time);
642 #endif
643
644 crm_xml_add(notify, PCMK__XA_LRMD_OP, LRMD_OP_RSC_EXEC);
645 crm_xml_add(notify, PCMK__XA_LRMD_RSC_ID, cmd->rsc_id);
646 if(cmd->real_action) {
647 crm_xml_add(notify, PCMK__XA_LRMD_RSC_ACTION, cmd->real_action);
648 } else {
649 crm_xml_add(notify, PCMK__XA_LRMD_RSC_ACTION, cmd->action);
650 }
651 crm_xml_add(notify, PCMK__XA_LRMD_RSC_USERDATA_STR, cmd->userdata_str);
652 crm_xml_add(notify, PCMK__XA_LRMD_RSC_EXIT_REASON, cmd->result.exit_reason);
653
654 if (cmd->result.action_stderr != NULL) {
655 crm_xml_add(notify, PCMK__XA_LRMD_RSC_OUTPUT,
656 cmd->result.action_stderr);
657
658 } else if (cmd->result.action_stdout != NULL) {
659 crm_xml_add(notify, PCMK__XA_LRMD_RSC_OUTPUT,
660 cmd->result.action_stdout);
661 }
662
663 if (cmd->params) {
664 char *key = NULL;
665 char *value = NULL;
666 GHashTableIter iter;
667
668 xmlNode *args = pcmk__xe_create(notify, PCMK__XE_ATTRIBUTES);
669
670 g_hash_table_iter_init(&iter, cmd->params);
671 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
672 hash2smartfield((gpointer) key, (gpointer) value, args);
673 }
674 }
675 if ((cmd->client_id != NULL)
676 && pcmk_is_set(cmd->call_opts, lrmd_opt_notify_orig_only)) {
677
678 pcmk__client_t *client = pcmk__find_client_by_id(cmd->client_id);
679
680 if (client != NULL) {
681 send_client_notify(client->id, client, notify);
682 }
683 } else {
684 pcmk__foreach_ipc_client(send_client_notify, notify);
685 }
686
687 pcmk__xml_free(notify);
688 }
689
690 static void
691 send_generic_notify(int rc, xmlNode * request)
692 {
693 if (pcmk__ipc_client_count() != 0) {
694 int call_id = 0;
695 xmlNode *notify = NULL;
696 xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
697 LOG_ERR);
698 const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
699 const char *op = crm_element_value(request, PCMK__XA_LRMD_OP);
700
701 crm_element_value_int(request, PCMK__XA_LRMD_CALLID, &call_id);
702
703 notify = pcmk__xe_create(NULL, PCMK__XE_LRMD_NOTIFY);
704 crm_xml_add(notify, PCMK__XA_LRMD_ORIGIN, __func__);
705 crm_xml_add_int(notify, PCMK__XA_LRMD_RC, rc);
706 crm_xml_add_int(notify, PCMK__XA_LRMD_CALLID, call_id);
707 crm_xml_add(notify, PCMK__XA_LRMD_OP, op);
708 crm_xml_add(notify, PCMK__XA_LRMD_RSC_ID, rsc_id);
709
710 pcmk__foreach_ipc_client(send_client_notify, notify);
711
712 pcmk__xml_free(notify);
713 }
714 }
715
716 static void
717 cmd_reset(lrmd_cmd_t * cmd)
718 {
719 cmd->last_pid = 0;
720 #ifdef PCMK__TIME_USE_CGT
721 memset(&cmd->t_run, 0, sizeof(cmd->t_run));
722 memset(&cmd->t_queue, 0, sizeof(cmd->t_queue));
723 #endif
724 cmd->epoch_last_run = 0;
725
726 pcmk__reset_result(&(cmd->result));
727 cmd->result.execution_status = PCMK_EXEC_DONE;
728 }
729
730 static void
731 cmd_finalize(lrmd_cmd_t * cmd, lrmd_rsc_t * rsc)
732 {
733 crm_trace("Resource operation rsc:%s action:%s completed (%p %p)", cmd->rsc_id, cmd->action,
734 rsc ? rsc->active : NULL, cmd);
735
736 if (rsc && (rsc->active == cmd)) {
737 rsc->active = NULL;
738 mainloop_set_trigger(rsc->work);
739 }
740
741 if (!rsc) {
742 cmd->rsc_deleted = 1;
743 }
744
745
746 cmd->timeout = cmd->timeout_orig;
747
748 send_cmd_complete_notify(cmd);
749
750 if ((cmd->interval_ms != 0)
751 && (cmd->result.execution_status == PCMK_EXEC_CANCELLED)) {
752
753 if (rsc) {
754 rsc->recurring_ops = g_list_remove(rsc->recurring_ops, cmd);
755 rsc->pending_ops = g_list_remove(rsc->pending_ops, cmd);
756 }
757 free_lrmd_cmd(cmd);
758 } else if (cmd->interval_ms == 0) {
759 if (rsc) {
760 rsc->pending_ops = g_list_remove(rsc->pending_ops, cmd);
761 }
762 free_lrmd_cmd(cmd);
763 } else {
764
765 cmd_reset(cmd);
766 }
767 }
768
769 struct notify_new_client_data {
770 xmlNode *notify;
771 pcmk__client_t *new_client;
772 };
773
774 static void
775 notify_one_client(gpointer key, gpointer value, gpointer user_data)
776 {
777 pcmk__client_t *client = value;
778 struct notify_new_client_data *data = user_data;
779
780 if (!pcmk__str_eq(client->id, data->new_client->id, pcmk__str_casei)) {
781 send_client_notify(key, (gpointer) client, (gpointer) data->notify);
782 }
783 }
784
785 void
786 notify_of_new_client(pcmk__client_t *new_client)
787 {
788 struct notify_new_client_data data;
789
790 data.new_client = new_client;
791 data.notify = pcmk__xe_create(NULL, PCMK__XE_LRMD_NOTIFY);
792 crm_xml_add(data.notify, PCMK__XA_LRMD_ORIGIN, __func__);
793 crm_xml_add(data.notify, PCMK__XA_LRMD_OP, LRMD_OP_NEW_CLIENT);
794 pcmk__foreach_ipc_client(notify_one_client, &data);
795 pcmk__xml_free(data.notify);
796 }
797
798 void
799 client_disconnect_cleanup(const char *client_id)
800 {
801 GHashTableIter iter;
802 lrmd_rsc_t *rsc = NULL;
803 char *key = NULL;
804
805 g_hash_table_iter_init(&iter, rsc_list);
806 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & rsc)) {
807 if (pcmk_all_flags_set(rsc->call_opts, lrmd_opt_drop_recurring)) {
808
809
810 cancel_all_recurring(rsc, client_id);
811 }
812 }
813 }
814
815 static void
816 action_complete(svc_action_t * action)
817 {
818 lrmd_rsc_t *rsc;
819 lrmd_cmd_t *cmd = action->cb_data;
820 enum ocf_exitcode code;
821
822 #ifdef PCMK__TIME_USE_CGT
823 const char *rclass = NULL;
824 bool goagain = false;
825 #endif
826
827 if (!cmd) {
828 crm_err("Completed executor action (%s) does not match any known operations",
829 action->id);
830 return;
831 }
832
833 #ifdef PCMK__TIME_USE_CGT
834 if (cmd->result.exit_status != action->rc) {
835 cmd->epoch_rcchange = time(NULL);
836 }
837 #endif
838
839 cmd->last_pid = action->pid;
840
841
842 code = services_result2ocf(action->standard, cmd->action, action->rc);
843 pcmk__set_result(&(cmd->result), (int) code,
844 action->status, services__exit_reason(action));
845
846 rsc = cmd->rsc_id ? g_hash_table_lookup(rsc_list, cmd->rsc_id) : NULL;
847
848 #ifdef PCMK__TIME_USE_CGT
849 if (rsc != NULL) {
850 rclass = rsc->class;
851 #if PCMK__ENABLE_SERVICE
852 if (pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_SERVICE,
853 pcmk__str_casei)) {
854 rclass = resources_find_service_class(rsc->type);
855 }
856 #endif
857 }
858
859 if (pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_SYSTEMD, pcmk__str_casei)) {
860 if (pcmk__result_ok(&(cmd->result))
861 && pcmk__strcase_any_of(cmd->action, PCMK_ACTION_START,
862 PCMK_ACTION_STOP, NULL)) {
863
864
865
866
867
868 goagain = true;
869 cmd->real_action = cmd->action;
870 cmd->action = pcmk__str_copy(PCMK_ACTION_MONITOR);
871
872 } else if (cmd->real_action != NULL) {
873
874 if (cmd->result.execution_status == PCMK_EXEC_PENDING) {
875 goagain = true;
876
877 } else if (pcmk__result_ok(&(cmd->result))
878 && pcmk__str_eq(cmd->real_action, PCMK_ACTION_STOP,
879 pcmk__str_casei)) {
880 goagain = true;
881
882 } else {
883 int time_sum = time_diff_ms(NULL, &(cmd->t_first_run));
884 int timeout_left = cmd->timeout_orig - time_sum;
885
886 crm_debug("%s systemd %s is now complete (elapsed=%dms, "
887 "remaining=%dms): %s (%d)",
888 cmd->rsc_id, cmd->real_action, time_sum, timeout_left,
889 crm_exit_str(cmd->result.exit_status),
890 cmd->result.exit_status);
891 cmd_original_times(cmd);
892
893
894 if ((cmd->result.execution_status == PCMK_EXEC_DONE)
895 && (cmd->result.exit_status == PCMK_OCF_NOT_RUNNING)) {
896
897 if (pcmk__str_eq(cmd->real_action, PCMK_ACTION_START,
898 pcmk__str_casei)) {
899 cmd->result.exit_status = PCMK_OCF_UNKNOWN_ERROR;
900 } else if (pcmk__str_eq(cmd->real_action, PCMK_ACTION_STOP,
901 pcmk__str_casei)) {
902 cmd->result.exit_status = PCMK_OCF_OK;
903 }
904 }
905 }
906 }
907 }
908 #endif
909
910 #ifdef PCMK__TIME_USE_CGT
911 if (goagain) {
912 int time_sum = time_diff_ms(NULL, &(cmd->t_first_run));
913 int timeout_left = cmd->timeout_orig - time_sum;
914 int delay = cmd->timeout_orig / 10;
915
916 if(delay >= timeout_left && timeout_left > 20) {
917 delay = timeout_left/2;
918 }
919
920 delay = QB_MIN(2000, delay);
921 if (delay < timeout_left) {
922 cmd->start_delay = delay;
923 cmd->timeout = timeout_left;
924
925 if (pcmk__result_ok(&(cmd->result))) {
926 crm_debug("%s %s may still be in progress: re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
927 cmd->rsc_id, cmd->real_action, time_sum, timeout_left, delay);
928
929 } else if (cmd->result.execution_status == PCMK_EXEC_PENDING) {
930 crm_info("%s %s is still in progress: re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
931 cmd->rsc_id, cmd->action, time_sum, timeout_left, delay);
932
933 } else {
934 crm_notice("%s %s failed: %s: Re-scheduling (remaining "
935 "timeout %s) " QB_XS
936 " exitstatus=%d elapsed=%dms start_delay=%dms)",
937 cmd->rsc_id, cmd->action,
938 crm_exit_str(cmd->result.exit_status),
939 pcmk__readable_interval(timeout_left),
940 cmd->result.exit_status, time_sum, delay);
941 }
942
943 cmd_reset(cmd);
944 if(rsc) {
945 rsc->active = NULL;
946 }
947 schedule_lrmd_cmd(rsc, cmd);
948
949
950 return;
951
952 } else {
953 crm_notice("Giving up on %s %s (rc=%d): timeout (elapsed=%dms, remaining=%dms)",
954 cmd->rsc_id,
955 (cmd->real_action? cmd->real_action : cmd->action),
956 cmd->result.exit_status, time_sum, timeout_left);
957 pcmk__set_result(&(cmd->result), PCMK_OCF_UNKNOWN_ERROR,
958 PCMK_EXEC_TIMEOUT,
959 "Investigate reason for timeout, and adjust "
960 "configured operation timeout if necessary");
961 cmd_original_times(cmd);
962 }
963 }
964 #endif
965
966 pcmk__set_result_output(&(cmd->result), services__grab_stdout(action),
967 services__grab_stderr(action));
968 cmd_finalize(cmd, rsc);
969 }
970
971
972
973
974
975
976
977
978
979
980 static void
981 stonith_action_complete(lrmd_cmd_t *cmd, int exit_status,
982 enum pcmk_exec_status execution_status,
983 const char *exit_reason)
984 {
985
986 lrmd_rsc_t *rsc = g_hash_table_lookup(rsc_list, cmd->rsc_id);
987
988
989 if (exit_status != CRM_EX_OK) {
990 exit_status = PCMK_OCF_UNKNOWN_ERROR;
991 }
992
993 if (cmd->result.execution_status == PCMK_EXEC_CANCELLED) {
994
995
996
997 execution_status = PCMK_EXEC_CANCELLED;
998
999 } else {
1000
1001
1002
1003
1004 switch (execution_status) {
1005 case PCMK_EXEC_NOT_CONNECTED:
1006 case PCMK_EXEC_INVALID:
1007 execution_status = PCMK_EXEC_ERROR;
1008 break;
1009
1010 case PCMK_EXEC_NO_FENCE_DEVICE:
1011
1012
1013
1014 if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR,
1015 pcmk__str_none)) {
1016 exit_status = PCMK_OCF_NOT_RUNNING;
1017
1018 } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_STOP,
1019 pcmk__str_none)) {
1020 exit_status = PCMK_OCF_OK;
1021
1022 } else {
1023 exit_status = PCMK_OCF_NOT_INSTALLED;
1024 }
1025 execution_status = PCMK_EXEC_ERROR;
1026 break;
1027
1028 case PCMK_EXEC_NOT_SUPPORTED:
1029 exit_status = PCMK_OCF_UNIMPLEMENT_FEATURE;
1030 break;
1031
1032 default:
1033 break;
1034 }
1035 }
1036
1037 pcmk__set_result(&cmd->result, exit_status, execution_status, exit_reason);
1038
1039
1040 if ((rsc != NULL) && pcmk__result_ok(&(cmd->result))) {
1041
1042 if (pcmk__str_eq(cmd->action, PCMK_ACTION_START, pcmk__str_casei)) {
1043 pcmk__set_result(&rsc->fence_probe_result, CRM_EX_OK,
1044 PCMK_EXEC_DONE, NULL);
1045
1046 } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_STOP,
1047 pcmk__str_casei)) {
1048 pcmk__set_result(&rsc->fence_probe_result, CRM_EX_ERROR,
1049 PCMK_EXEC_NO_FENCE_DEVICE, NULL);
1050 }
1051 }
1052
1053
1054
1055
1056 stop_recurring_timer(cmd);
1057
1058
1059
1060
1061
1062 if (rsc && (cmd->interval_ms > 0)
1063 && (cmd->result.execution_status != PCMK_EXEC_CANCELLED)) {
1064 start_recurring_timer(cmd);
1065 }
1066
1067 cmd_finalize(cmd, rsc);
1068 }
1069
1070 static void
1071 lrmd_stonith_callback(stonith_t * stonith, stonith_callback_data_t * data)
1072 {
1073 if ((data == NULL) || (data->userdata == NULL)) {
1074 crm_err("Ignoring fence action result: "
1075 "Invalid callback arguments (bug?)");
1076 } else {
1077 stonith_action_complete((lrmd_cmd_t *) data->userdata,
1078 stonith__exit_status(data),
1079 stonith__execution_status(data),
1080 stonith__exit_reason(data));
1081 }
1082 }
1083
1084 void
1085 stonith_connection_failed(void)
1086 {
1087 GHashTableIter iter;
1088 lrmd_rsc_t *rsc = NULL;
1089
1090 crm_warn("Connection to fencer lost (any pending operations for "
1091 "fence devices will be considered failed)");
1092
1093 g_hash_table_iter_init(&iter, rsc_list);
1094 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &rsc)) {
1095 if (!pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH,
1096 pcmk__str_none)) {
1097 continue;
1098 }
1099
1100
1101
1102
1103
1104
1105
1106
1107 if (rsc->fence_probe_result.execution_status == PCMK_EXEC_DONE) {
1108 pcmk__set_result(&rsc->fence_probe_result, CRM_EX_ERROR,
1109 PCMK_EXEC_NOT_CONNECTED,
1110 "Lost connection to fencer");
1111 }
1112
1113
1114
1115 for (GList *op = rsc->recurring_ops; op != NULL; op = op->next) {
1116 lrmd_cmd_t *cmd = op->data;
1117
1118
1119
1120
1121
1122 stonith_action_complete(cmd,
1123 CRM_EX_ERROR, PCMK_EXEC_NOT_CONNECTED,
1124 "Lost connection to fencer");
1125 }
1126
1127 if (rsc->active != NULL) {
1128 rsc->pending_ops = g_list_prepend(rsc->pending_ops, rsc->active);
1129 }
1130 while (rsc->pending_ops != NULL) {
1131
1132 stonith_action_complete((lrmd_cmd_t *) rsc->pending_ops->data,
1133 CRM_EX_ERROR, PCMK_EXEC_NOT_CONNECTED,
1134 "Lost connection to fencer");
1135 }
1136 }
1137 }
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152 static int
1153 execd_stonith_start(stonith_t *stonith_api, const lrmd_rsc_t *rsc,
1154 const lrmd_cmd_t *cmd)
1155 {
1156 char *key = NULL;
1157 char *value = NULL;
1158 stonith_key_value_t *device_params = NULL;
1159 int rc = pcmk_ok;
1160
1161
1162 if (cmd->params) {
1163 GHashTableIter iter;
1164
1165 g_hash_table_iter_init(&iter, cmd->params);
1166 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
1167 device_params = stonith_key_value_add(device_params, key, value);
1168 }
1169 }
1170
1171
1172
1173
1174
1175
1176
1177 rc = stonith_api->cmds->register_device(stonith_api, st_opt_sync_call,
1178 cmd->rsc_id, rsc->provider,
1179 rsc->type, device_params);
1180
1181 stonith_key_value_freeall(device_params, 1, 1);
1182 return rc;
1183 }
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197 static inline int
1198 execd_stonith_stop(stonith_t *stonith_api, const lrmd_rsc_t *rsc)
1199 {
1200
1201
1202
1203 return stonith_api->cmds->remove_device(stonith_api, st_opt_sync_call,
1204 rsc->rsc_id);
1205 }
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217 static inline int
1218 execd_stonith_monitor(stonith_t *stonith_api, lrmd_rsc_t *rsc, lrmd_cmd_t *cmd)
1219 {
1220 int rc = stonith_api->cmds->monitor(stonith_api, 0, cmd->rsc_id,
1221 pcmk__timeout_ms2s(cmd->timeout));
1222
1223 rc = stonith_api->cmds->register_callback(stonith_api, rc, 0, 0, cmd,
1224 "lrmd_stonith_callback",
1225 lrmd_stonith_callback);
1226 if (rc == TRUE) {
1227 rsc->active = cmd;
1228 rc = pcmk_ok;
1229 } else {
1230 rc = -pcmk_err_generic;
1231 }
1232 return rc;
1233 }
1234
1235 static void
1236 execute_stonith_action(lrmd_rsc_t *rsc, lrmd_cmd_t *cmd)
1237 {
1238 int rc = 0;
1239 bool do_monitor = FALSE;
1240
1241 stonith_t *stonith_api = get_stonith_connection();
1242
1243 if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR, pcmk__str_casei)
1244 && (cmd->interval_ms == 0)) {
1245
1246 stonith_action_complete(cmd, rsc->fence_probe_result.exit_status,
1247 rsc->fence_probe_result.execution_status,
1248 rsc->fence_probe_result.exit_reason);
1249 return;
1250
1251 } else if (stonith_api == NULL) {
1252 stonith_action_complete(cmd, PCMK_OCF_UNKNOWN_ERROR,
1253 PCMK_EXEC_NOT_CONNECTED,
1254 "No connection to fencer");
1255 return;
1256
1257 } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_START, pcmk__str_casei)) {
1258 rc = execd_stonith_start(stonith_api, rsc, cmd);
1259 if (rc == pcmk_ok) {
1260 do_monitor = TRUE;
1261 }
1262
1263 } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_STOP, pcmk__str_casei)) {
1264 rc = execd_stonith_stop(stonith_api, rsc);
1265
1266 } else if (pcmk__str_eq(cmd->action, PCMK_ACTION_MONITOR,
1267 pcmk__str_casei)) {
1268 do_monitor = TRUE;
1269
1270 } else {
1271 stonith_action_complete(cmd, PCMK_OCF_UNIMPLEMENT_FEATURE,
1272 PCMK_EXEC_ERROR,
1273 "Invalid fence device action (bug?)");
1274 return;
1275 }
1276
1277 if (do_monitor) {
1278 rc = execd_stonith_monitor(stonith_api, rsc, cmd);
1279 if (rc == pcmk_ok) {
1280
1281 return;
1282 }
1283 }
1284
1285 stonith_action_complete(cmd,
1286 ((rc == pcmk_ok)? CRM_EX_OK : CRM_EX_ERROR),
1287 stonith__legacy2status(rc),
1288 ((rc == -pcmk_err_generic)? NULL : pcmk_strerror(rc)));
1289 }
1290
1291 static void
1292 execute_nonstonith_action(lrmd_rsc_t *rsc, lrmd_cmd_t *cmd)
1293 {
1294 svc_action_t *action = NULL;
1295 GHashTable *params_copy = NULL;
1296
1297 pcmk__assert((rsc != NULL) && (cmd != NULL));
1298
1299 crm_trace("Creating action, resource:%s action:%s class:%s provider:%s agent:%s",
1300 rsc->rsc_id, cmd->action, rsc->class, rsc->provider, rsc->type);
1301
1302 params_copy = pcmk__str_table_dup(cmd->params);
1303
1304 action = services__create_resource_action(rsc->rsc_id, rsc->class, rsc->provider,
1305 rsc->type,
1306 normalize_action_name(rsc, cmd->action),
1307 cmd->interval_ms, cmd->timeout,
1308 params_copy, cmd->service_flags);
1309
1310 if (action == NULL) {
1311 pcmk__set_result(&(cmd->result), PCMK_OCF_UNKNOWN_ERROR,
1312 PCMK_EXEC_ERROR, strerror(ENOMEM));
1313 cmd_finalize(cmd, rsc);
1314 return;
1315 }
1316
1317 if (action->rc != PCMK_OCF_UNKNOWN) {
1318 pcmk__set_result(&(cmd->result), action->rc, action->status,
1319 services__exit_reason(action));
1320 services_action_free(action);
1321 cmd_finalize(cmd, rsc);
1322 return;
1323 }
1324
1325 action->cb_data = cmd;
1326
1327 if (services_action_async(action, action_complete)) {
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337 } else {
1338
1339
1340
1341
1342
1343
1344
1345 pcmk__set_result(&(cmd->result), action->rc, action->status,
1346 services__exit_reason(action));
1347 services_action_free(action);
1348 }
1349 }
1350
1351 static gboolean
1352 execute_resource_action(gpointer user_data)
1353 {
1354 lrmd_rsc_t *rsc = (lrmd_rsc_t *) user_data;
1355 lrmd_cmd_t *cmd = NULL;
1356
1357 CRM_CHECK(rsc != NULL, return FALSE);
1358
1359 if (rsc->active) {
1360 crm_trace("%s is still active", rsc->rsc_id);
1361 return TRUE;
1362 }
1363
1364 if (rsc->pending_ops) {
1365 GList *first = rsc->pending_ops;
1366
1367 cmd = first->data;
1368 if (cmd->delay_id) {
1369 crm_trace
1370 ("Command %s %s was asked to run too early, waiting for start_delay timeout of %dms",
1371 cmd->rsc_id, cmd->action, cmd->start_delay);
1372 return TRUE;
1373 }
1374 rsc->pending_ops = g_list_remove_link(rsc->pending_ops, first);
1375 g_list_free_1(first);
1376
1377 #ifdef PCMK__TIME_USE_CGT
1378 get_current_time(&(cmd->t_run), &(cmd->t_first_run));
1379 #endif
1380 cmd->epoch_last_run = time(NULL);
1381 }
1382
1383 if (!cmd) {
1384 crm_trace("Nothing further to do for %s", rsc->rsc_id);
1385 return TRUE;
1386 }
1387
1388 rsc->active = cmd;
1389 if (cmd->interval_ms) {
1390 rsc->recurring_ops = g_list_append(rsc->recurring_ops, cmd);
1391 }
1392
1393 log_execute(cmd);
1394
1395 if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
1396 execute_stonith_action(rsc, cmd);
1397 } else {
1398 execute_nonstonith_action(rsc, cmd);
1399 }
1400
1401 return TRUE;
1402 }
1403
1404 void
1405 free_rsc(gpointer data)
1406 {
1407 GList *gIter = NULL;
1408 lrmd_rsc_t *rsc = data;
1409 int is_stonith = pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH,
1410 pcmk__str_casei);
1411
1412 gIter = rsc->pending_ops;
1413 while (gIter != NULL) {
1414 GList *next = gIter->next;
1415 lrmd_cmd_t *cmd = gIter->data;
1416
1417
1418 cmd->result.execution_status = PCMK_EXEC_CANCELLED;
1419 cmd_finalize(cmd, NULL);
1420
1421 gIter = next;
1422 }
1423
1424 g_list_free(rsc->pending_ops);
1425
1426 gIter = rsc->recurring_ops;
1427 while (gIter != NULL) {
1428 GList *next = gIter->next;
1429 lrmd_cmd_t *cmd = gIter->data;
1430
1431 if (is_stonith) {
1432 cmd->result.execution_status = PCMK_EXEC_CANCELLED;
1433
1434
1435
1436
1437 if (rsc->active != cmd) {
1438 cmd_finalize(cmd, NULL);
1439 }
1440 } else {
1441
1442
1443
1444
1445 services_action_cancel(rsc->rsc_id,
1446 normalize_action_name(rsc, cmd->action),
1447 cmd->interval_ms);
1448 }
1449
1450 gIter = next;
1451 }
1452
1453 g_list_free(rsc->recurring_ops);
1454
1455 free(rsc->rsc_id);
1456 free(rsc->class);
1457 free(rsc->provider);
1458 free(rsc->type);
1459 mainloop_destroy_trigger(rsc->work);
1460
1461 free(rsc);
1462 }
1463
1464 static int
1465 process_lrmd_signon(pcmk__client_t *client, xmlNode *request, int call_id,
1466 xmlNode **reply)
1467 {
1468 int rc = pcmk_ok;
1469 time_t now = time(NULL);
1470 const char *protocol_version =
1471 crm_element_value(request, PCMK__XA_LRMD_PROTOCOL_VERSION);
1472 const char *start_state = pcmk__env_option(PCMK__ENV_NODE_START_STATE);
1473
1474 if (compare_version(protocol_version, LRMD_COMPATIBLE_PROTOCOL) < 0) {
1475 crm_err("Cluster API version must be greater than or equal to %s, not %s",
1476 LRMD_COMPATIBLE_PROTOCOL, protocol_version);
1477 rc = -EPROTO;
1478 }
1479
1480 if (pcmk__xe_attr_is_true(request, PCMK__XA_LRMD_IS_IPC_PROVIDER)) {
1481 #ifdef PCMK__COMPILE_REMOTE
1482 if ((client->remote != NULL)
1483 && pcmk_is_set(client->flags,
1484 pcmk__client_tls_handshake_complete)) {
1485 const char *op = crm_element_value(request, PCMK__XA_LRMD_OP);
1486
1487
1488 ipc_proxy_add_provider(client);
1489
1490
1491
1492
1493 if (pcmk__str_eq(op, CRM_OP_REGISTER, pcmk__str_none) &&
1494 LRMD_SUPPORTS_SCHEMA_XFER(protocol_version)) {
1495 remoted_request_cib_schema_files();
1496 }
1497 } else {
1498 rc = -EACCES;
1499 }
1500 #else
1501 rc = -EPROTONOSUPPORT;
1502 #endif
1503 }
1504
1505 *reply = create_lrmd_reply(__func__, rc, call_id);
1506 crm_xml_add(*reply, PCMK__XA_LRMD_OP, CRM_OP_REGISTER);
1507 crm_xml_add(*reply, PCMK__XA_LRMD_CLIENTID, client->id);
1508 crm_xml_add(*reply, PCMK__XA_LRMD_PROTOCOL_VERSION, LRMD_PROTOCOL_VERSION);
1509 crm_xml_add_ll(*reply, PCMK__XA_UPTIME, now - start_time);
1510
1511 if (start_state) {
1512 crm_xml_add(*reply, PCMK__XA_NODE_START_STATE, start_state);
1513 }
1514
1515 return rc;
1516 }
1517
1518 static int
1519 process_lrmd_rsc_register(pcmk__client_t *client, uint32_t id, xmlNode *request)
1520 {
1521 int rc = pcmk_ok;
1522 lrmd_rsc_t *rsc = build_rsc_from_xml(request);
1523 lrmd_rsc_t *dup = g_hash_table_lookup(rsc_list, rsc->rsc_id);
1524
1525 if (dup &&
1526 pcmk__str_eq(rsc->class, dup->class, pcmk__str_casei) &&
1527 pcmk__str_eq(rsc->provider, dup->provider, pcmk__str_casei) && pcmk__str_eq(rsc->type, dup->type, pcmk__str_casei)) {
1528
1529 crm_notice("Ignoring duplicate registration of '%s'", rsc->rsc_id);
1530 free_rsc(rsc);
1531 return rc;
1532 }
1533
1534 g_hash_table_replace(rsc_list, rsc->rsc_id, rsc);
1535 crm_info("Cached agent information for '%s'", rsc->rsc_id);
1536 return rc;
1537 }
1538
1539 static xmlNode *
1540 process_lrmd_get_rsc_info(xmlNode *request, int call_id)
1541 {
1542 int rc = pcmk_ok;
1543 xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
1544 LOG_ERR);
1545 const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1546 xmlNode *reply = NULL;
1547 lrmd_rsc_t *rsc = NULL;
1548
1549 if (rsc_id == NULL) {
1550 rc = -ENODEV;
1551 } else {
1552 rsc = g_hash_table_lookup(rsc_list, rsc_id);
1553 if (rsc == NULL) {
1554 crm_info("Agent information for '%s' not in cache", rsc_id);
1555 rc = -ENODEV;
1556 }
1557 }
1558
1559 reply = create_lrmd_reply(__func__, rc, call_id);
1560 if (rsc) {
1561 crm_xml_add(reply, PCMK__XA_LRMD_RSC_ID, rsc->rsc_id);
1562 crm_xml_add(reply, PCMK__XA_LRMD_CLASS, rsc->class);
1563 crm_xml_add(reply, PCMK__XA_LRMD_PROVIDER, rsc->provider);
1564 crm_xml_add(reply, PCMK__XA_LRMD_TYPE, rsc->type);
1565 }
1566 return reply;
1567 }
1568
1569 static int
1570 process_lrmd_rsc_unregister(pcmk__client_t *client, uint32_t id,
1571 xmlNode *request)
1572 {
1573 int rc = pcmk_ok;
1574 lrmd_rsc_t *rsc = NULL;
1575 xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
1576 LOG_ERR);
1577 const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1578
1579 if (!rsc_id) {
1580 return -ENODEV;
1581 }
1582
1583 rsc = g_hash_table_lookup(rsc_list, rsc_id);
1584 if (rsc == NULL) {
1585 crm_info("Ignoring unregistration of resource '%s', which is not registered",
1586 rsc_id);
1587 return pcmk_ok;
1588 }
1589
1590 if (rsc->active) {
1591
1592 crm_trace("Operation (%p) still in progress for unregistered resource %s",
1593 rsc->active, rsc_id);
1594 rc = -EINPROGRESS;
1595 }
1596
1597 g_hash_table_remove(rsc_list, rsc_id);
1598
1599 return rc;
1600 }
1601
1602 static int
1603 process_lrmd_rsc_exec(pcmk__client_t *client, uint32_t id, xmlNode *request)
1604 {
1605 lrmd_rsc_t *rsc = NULL;
1606 lrmd_cmd_t *cmd = NULL;
1607 xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
1608 LOG_ERR);
1609 const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1610 int call_id;
1611
1612 if (!rsc_id) {
1613 return -EINVAL;
1614 }
1615 if (!(rsc = g_hash_table_lookup(rsc_list, rsc_id))) {
1616 crm_info("Resource '%s' not found (%d active resources)",
1617 rsc_id, g_hash_table_size(rsc_list));
1618 return -ENODEV;
1619 }
1620
1621 cmd = create_lrmd_cmd(request, client);
1622 call_id = cmd->call_id;
1623
1624
1625
1626 schedule_lrmd_cmd(rsc, cmd);
1627
1628 return call_id;
1629 }
1630
1631 static int
1632 cancel_op(const char *rsc_id, const char *action, guint interval_ms)
1633 {
1634 GList *gIter = NULL;
1635 lrmd_rsc_t *rsc = g_hash_table_lookup(rsc_list, rsc_id);
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648 if (!rsc) {
1649 return -ENODEV;
1650 }
1651
1652 for (gIter = rsc->pending_ops; gIter != NULL; gIter = gIter->next) {
1653 lrmd_cmd_t *cmd = gIter->data;
1654
1655 if (action_matches(cmd, action, interval_ms)) {
1656 cmd->result.execution_status = PCMK_EXEC_CANCELLED;
1657 cmd_finalize(cmd, rsc);
1658 return pcmk_ok;
1659 }
1660 }
1661
1662 if (pcmk__str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) {
1663
1664
1665 for (gIter = rsc->recurring_ops; gIter != NULL; gIter = gIter->next) {
1666 lrmd_cmd_t *cmd = gIter->data;
1667
1668 if (action_matches(cmd, action, interval_ms)) {
1669 cmd->result.execution_status = PCMK_EXEC_CANCELLED;
1670 if (rsc->active != cmd) {
1671 cmd_finalize(cmd, rsc);
1672 }
1673 return pcmk_ok;
1674 }
1675 }
1676 } else if (services_action_cancel(rsc_id,
1677 normalize_action_name(rsc, action),
1678 interval_ms) == TRUE) {
1679
1680
1681
1682
1683 return pcmk_ok;
1684 }
1685
1686 return -EOPNOTSUPP;
1687 }
1688
1689 static void
1690 cancel_all_recurring(lrmd_rsc_t * rsc, const char *client_id)
1691 {
1692 GList *cmd_list = NULL;
1693 GList *cmd_iter = NULL;
1694
1695
1696
1697
1698
1699
1700
1701 if (rsc->recurring_ops) {
1702 cmd_list = g_list_concat(cmd_list, g_list_copy(rsc->recurring_ops));
1703 }
1704 if (rsc->pending_ops) {
1705 cmd_list = g_list_concat(cmd_list, g_list_copy(rsc->pending_ops));
1706 }
1707 if (!cmd_list) {
1708 return;
1709 }
1710
1711 for (cmd_iter = cmd_list; cmd_iter; cmd_iter = cmd_iter->next) {
1712 lrmd_cmd_t *cmd = cmd_iter->data;
1713
1714 if (cmd->interval_ms == 0) {
1715 continue;
1716 }
1717
1718 if (client_id && !pcmk__str_eq(cmd->client_id, client_id, pcmk__str_casei)) {
1719 continue;
1720 }
1721
1722 cancel_op(rsc->rsc_id, cmd->action, cmd->interval_ms);
1723 }
1724
1725 g_list_free(cmd_list);
1726 }
1727
1728 static int
1729 process_lrmd_rsc_cancel(pcmk__client_t *client, uint32_t id, xmlNode *request)
1730 {
1731 xmlNode *rsc_xml = get_xpath_object("//" PCMK__XE_LRMD_RSC, request,
1732 LOG_ERR);
1733 const char *rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1734 const char *action = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ACTION);
1735 guint interval_ms = 0;
1736
1737 crm_element_value_ms(rsc_xml, PCMK__XA_LRMD_RSC_INTERVAL, &interval_ms);
1738
1739 if (!rsc_id || !action) {
1740 return -EINVAL;
1741 }
1742
1743 return cancel_op(rsc_id, action, interval_ms);
1744 }
1745
1746 static void
1747 add_recurring_op_xml(xmlNode *reply, lrmd_rsc_t *rsc)
1748 {
1749 xmlNode *rsc_xml = pcmk__xe_create(reply, PCMK__XE_LRMD_RSC);
1750
1751 crm_xml_add(rsc_xml, PCMK__XA_LRMD_RSC_ID, rsc->rsc_id);
1752 for (GList *item = rsc->recurring_ops; item != NULL; item = item->next) {
1753 lrmd_cmd_t *cmd = item->data;
1754 xmlNode *op_xml = pcmk__xe_create(rsc_xml, PCMK__XE_LRMD_RSC_OP);
1755
1756 crm_xml_add(op_xml, PCMK__XA_LRMD_RSC_ACTION,
1757 pcmk__s(cmd->real_action, cmd->action));
1758 crm_xml_add_ms(op_xml, PCMK__XA_LRMD_RSC_INTERVAL, cmd->interval_ms);
1759 crm_xml_add_int(op_xml, PCMK__XA_LRMD_TIMEOUT, cmd->timeout_orig);
1760 }
1761 }
1762
1763 static xmlNode *
1764 process_lrmd_get_recurring(xmlNode *request, int call_id)
1765 {
1766 int rc = pcmk_ok;
1767 const char *rsc_id = NULL;
1768 lrmd_rsc_t *rsc = NULL;
1769 xmlNode *reply = NULL;
1770 xmlNode *rsc_xml = NULL;
1771
1772
1773 rsc_xml = pcmk__xe_first_child(request, PCMK__XE_LRMD_CALLDATA, NULL, NULL);
1774 if (rsc_xml) {
1775 rsc_xml = pcmk__xe_first_child(rsc_xml, PCMK__XE_LRMD_RSC, NULL, NULL);
1776 }
1777 if (rsc_xml) {
1778 rsc_id = crm_element_value(rsc_xml, PCMK__XA_LRMD_RSC_ID);
1779 }
1780
1781
1782 if (rsc_id != NULL) {
1783 rsc = g_hash_table_lookup(rsc_list, rsc_id);
1784 if (rsc == NULL) {
1785 crm_info("Resource '%s' not found (%d active resources)",
1786 rsc_id, g_hash_table_size(rsc_list));
1787 rc = -ENODEV;
1788 }
1789 }
1790
1791 reply = create_lrmd_reply(__func__, rc, call_id);
1792
1793
1794 if (rsc_id == NULL) {
1795 GHashTableIter iter;
1796 char *key = NULL;
1797
1798 g_hash_table_iter_init(&iter, rsc_list);
1799 while (g_hash_table_iter_next(&iter, (gpointer *) &key,
1800 (gpointer *) &rsc)) {
1801 add_recurring_op_xml(reply, rsc);
1802 }
1803 } else if (rsc) {
1804 add_recurring_op_xml(reply, rsc);
1805 }
1806 return reply;
1807 }
1808
1809 void
1810 process_lrmd_message(pcmk__client_t *client, uint32_t id, xmlNode *request)
1811 {
1812 int rc = pcmk_ok;
1813 int call_id = 0;
1814 const char *op = crm_element_value(request, PCMK__XA_LRMD_OP);
1815 int do_reply = 0;
1816 int do_notify = 0;
1817 xmlNode *reply = NULL;
1818
1819
1820
1821
1822
1823 bool allowed = pcmk_is_set(client->flags, pcmk__client_privileged);
1824
1825 crm_trace("Processing %s operation from %s", op, client->id);
1826 crm_element_value_int(request, PCMK__XA_LRMD_CALLID, &call_id);
1827
1828 if (pcmk__str_eq(op, CRM_OP_IPC_FWD, pcmk__str_none)) {
1829 #ifdef PCMK__COMPILE_REMOTE
1830 if (allowed) {
1831 ipc_proxy_forward_client(client, request);
1832 } else {
1833 rc = -EACCES;
1834 }
1835 #else
1836 rc = -EPROTONOSUPPORT;
1837 #endif
1838 do_reply = 1;
1839 } else if (pcmk__str_eq(op, CRM_OP_REGISTER, pcmk__str_none)) {
1840 rc = process_lrmd_signon(client, request, call_id, &reply);
1841 do_reply = 1;
1842 } else if (pcmk__str_eq(op, LRMD_OP_RSC_REG, pcmk__str_none)) {
1843 if (allowed) {
1844 rc = process_lrmd_rsc_register(client, id, request);
1845 do_notify = 1;
1846 } else {
1847 rc = -EACCES;
1848 }
1849 do_reply = 1;
1850 } else if (pcmk__str_eq(op, LRMD_OP_RSC_INFO, pcmk__str_none)) {
1851 if (allowed) {
1852 reply = process_lrmd_get_rsc_info(request, call_id);
1853 } else {
1854 rc = -EACCES;
1855 }
1856 do_reply = 1;
1857 } else if (pcmk__str_eq(op, LRMD_OP_RSC_UNREG, pcmk__str_none)) {
1858 if (allowed) {
1859 rc = process_lrmd_rsc_unregister(client, id, request);
1860
1861 if (rc == pcmk_ok || rc == -EINPROGRESS) {
1862 do_notify = 1;
1863 }
1864 } else {
1865 rc = -EACCES;
1866 }
1867 do_reply = 1;
1868 } else if (pcmk__str_eq(op, LRMD_OP_RSC_EXEC, pcmk__str_none)) {
1869 if (allowed) {
1870 rc = process_lrmd_rsc_exec(client, id, request);
1871 } else {
1872 rc = -EACCES;
1873 }
1874 do_reply = 1;
1875 } else if (pcmk__str_eq(op, LRMD_OP_RSC_CANCEL, pcmk__str_none)) {
1876 if (allowed) {
1877 rc = process_lrmd_rsc_cancel(client, id, request);
1878 } else {
1879 rc = -EACCES;
1880 }
1881 do_reply = 1;
1882 } else if (pcmk__str_eq(op, LRMD_OP_POKE, pcmk__str_none)) {
1883 do_notify = 1;
1884 do_reply = 1;
1885 } else if (pcmk__str_eq(op, LRMD_OP_CHECK, pcmk__str_none)) {
1886 if (allowed) {
1887 xmlNode *wrapper = pcmk__xe_first_child(request,
1888 PCMK__XE_LRMD_CALLDATA,
1889 NULL, NULL);
1890 xmlNode *data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
1891
1892 const char *timeout = NULL;
1893
1894 CRM_LOG_ASSERT(data != NULL);
1895 timeout = crm_element_value(data, PCMK__XA_LRMD_WATCHDOG);
1896 pcmk__valid_stonith_watchdog_timeout(timeout);
1897 } else {
1898 rc = -EACCES;
1899 }
1900 } else if (pcmk__str_eq(op, LRMD_OP_ALERT_EXEC, pcmk__str_none)) {
1901 if (allowed) {
1902 rc = process_lrmd_alert_exec(client, id, request);
1903 } else {
1904 rc = -EACCES;
1905 }
1906 do_reply = 1;
1907 } else if (pcmk__str_eq(op, LRMD_OP_GET_RECURRING, pcmk__str_none)) {
1908 if (allowed) {
1909 reply = process_lrmd_get_recurring(request, call_id);
1910 } else {
1911 rc = -EACCES;
1912 }
1913 do_reply = 1;
1914 } else {
1915 rc = -EOPNOTSUPP;
1916 do_reply = 1;
1917 crm_err("Unknown IPC request '%s' from client %s",
1918 op, pcmk__client_name(client));
1919 }
1920
1921 if (rc == -EACCES) {
1922 crm_warn("Rejecting IPC request '%s' from unprivileged client %s",
1923 op, pcmk__client_name(client));
1924 }
1925
1926 crm_debug("Processed %s operation from %s: rc=%d, reply=%d, notify=%d",
1927 op, client->id, rc, do_reply, do_notify);
1928
1929 if (do_reply) {
1930 int send_rc = pcmk_rc_ok;
1931
1932 if (reply == NULL) {
1933 reply = create_lrmd_reply(__func__, rc, call_id);
1934 }
1935 send_rc = lrmd_server_send_reply(client, id, reply);
1936 pcmk__xml_free(reply);
1937 if (send_rc != pcmk_rc_ok) {
1938 crm_warn("Reply to client %s failed: %s " QB_XS " rc=%d",
1939 pcmk__client_name(client), pcmk_rc_str(send_rc), send_rc);
1940 }
1941 }
1942
1943 if (do_notify) {
1944 send_generic_notify(rc, request);
1945 }
1946 }