This source file includes following definitions.
- add_inflight_alert
- remove_inflight_alert
- max_inflight_timeout
- alert_complete
- process_lrmd_alert_exec
- drain_check
- lrmd_drain_alerts
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <glib.h>
13 #include <libxml/tree.h>
14
15 #include <crm/crm.h>
16 #include <crm/services.h>
17 #include <crm/services_internal.h>
18 #include <crm/common/ipc.h>
19 #include <crm/common/ipc_internal.h>
20 #include <crm/common/alerts_internal.h>
21 #include <crm/common/xml.h>
22
23 #include "pacemaker-execd.h"
24
25
26 static GHashTable *inflight_alerts;
27 static gboolean draining_alerts = FALSE;
28
29 static inline void
30 add_inflight_alert(int call_id, int timeout)
31 {
32 if (inflight_alerts == NULL) {
33 inflight_alerts = pcmk__intkey_table(NULL);
34 }
35 pcmk__intkey_table_insert(inflight_alerts, call_id,
36 GINT_TO_POINTER(timeout));
37 }
38
39 static inline void
40 remove_inflight_alert(int call_id)
41 {
42 if (inflight_alerts != NULL) {
43 pcmk__intkey_table_remove(inflight_alerts, call_id);
44 }
45 }
46
47 static int
48 max_inflight_timeout(void)
49 {
50 GHashTableIter iter;
51 gpointer timeout;
52 int max_timeout = 0;
53
54 if (inflight_alerts) {
55 g_hash_table_iter_init(&iter, inflight_alerts);
56 while (g_hash_table_iter_next(&iter, NULL, &timeout)) {
57 if (GPOINTER_TO_INT(timeout) > max_timeout) {
58 max_timeout = GPOINTER_TO_INT(timeout);
59 }
60 }
61 }
62 return max_timeout;
63 }
64
65 struct alert_cb_s {
66 char *client_id;
67 int call_id;
68 };
69
70 static void
71 alert_complete(svc_action_t *action)
72 {
73 struct alert_cb_s *cb_data = (struct alert_cb_s *) (action->cb_data);
74
75 CRM_CHECK(cb_data != NULL, return);
76
77 remove_inflight_alert(cb_data->call_id);
78
79 if (action->status != PCMK_EXEC_DONE) {
80 const char *reason = services__exit_reason(action);
81
82 crm_notice("Could not send alert: %s%s%s%s " QB_XS " client=%s",
83 pcmk_exec_status_str(action->status),
84 (reason == NULL)? "" : " (",
85 (reason == NULL)? "" : reason,
86 (reason == NULL)? "" : ")",
87 cb_data->client_id);
88
89 } else if (action->rc != 0) {
90 crm_notice("Alert [%d] completed but exited with status %d "
91 QB_XS " client=%s",
92 action->pid, action->rc, cb_data->client_id);
93
94 } else {
95 crm_debug("Alert [%d] completed " QB_XS " client=%s",
96 action->pid, cb_data->client_id);
97 }
98
99 free(cb_data->client_id);
100 free(action->cb_data);
101 action->cb_data = NULL;
102 }
103
104 int
105 process_lrmd_alert_exec(pcmk__client_t *client, uint32_t id, xmlNode *request)
106 {
107 static int alert_sequence_no = 0;
108
109 xmlNode *alert_xml = pcmk__xpath_find_one(request->doc,
110 "//" PCMK__XE_LRMD_ALERT,
111 LOG_ERR);
112 const char *alert_id = crm_element_value(alert_xml, PCMK__XA_LRMD_ALERT_ID);
113 const char *alert_path = crm_element_value(alert_xml,
114 PCMK__XA_LRMD_ALERT_PATH);
115 svc_action_t *action = NULL;
116 int alert_timeout = 0;
117 int rc = pcmk_ok;
118 GHashTable *params = NULL;
119 struct alert_cb_s *cb_data = NULL;
120
121 if ((alert_id == NULL) || (alert_path == NULL) ||
122 (client == NULL) || (client->id == NULL)) {
123 rc = -EINVAL;
124 goto err;
125 }
126 if (draining_alerts) {
127 return pcmk_ok;
128 }
129
130 crm_element_value_int(alert_xml, PCMK__XA_LRMD_TIMEOUT, &alert_timeout);
131
132 crm_info("Executing alert %s for %s", alert_id, client->id);
133
134 params = xml2list(alert_xml);
135 pcmk__add_alert_key_int(params, PCMK__alert_key_node_sequence,
136 ++alert_sequence_no);
137
138 cb_data = pcmk__assert_alloc(1, sizeof(struct alert_cb_s));
139
140 cb_data->client_id = pcmk__str_copy(client->id);
141
142 crm_element_value_int(request, PCMK__XA_LRMD_CALLID, &(cb_data->call_id));
143
144 action = services_alert_create(alert_id, alert_path, alert_timeout, params,
145 alert_sequence_no, cb_data);
146 if (action->rc != PCMK_OCF_UNKNOWN) {
147 rc = -E2BIG;
148 goto err;
149 }
150
151 rc = services_action_user(action, CRM_DAEMON_USER);
152 if (rc < 0) {
153 goto err;
154 }
155
156 add_inflight_alert(cb_data->call_id, alert_timeout);
157 if (services_alert_async(action, alert_complete) == FALSE) {
158 services_action_free(action);
159 }
160 return pcmk_ok;
161
162 err:
163 if (cb_data) {
164 free(cb_data->client_id);
165 free(cb_data);
166 }
167 services_action_free(action);
168 return rc;
169 }
170
171 static bool
172 drain_check(guint remaining_timeout_ms)
173 {
174 if (inflight_alerts != NULL) {
175 guint count = g_hash_table_size(inflight_alerts);
176
177 if (count > 0) {
178 crm_trace("%d alerts pending (%.3fs timeout remaining)",
179 count, remaining_timeout_ms / 1000.0);
180 return TRUE;
181 }
182 }
183 return FALSE;
184 }
185
186 void
187 lrmd_drain_alerts(GMainLoop *mloop)
188 {
189 if (inflight_alerts != NULL) {
190 guint timer_ms = max_inflight_timeout() + 5000;
191
192 crm_trace("Draining in-flight alerts (timeout %.3fs)",
193 timer_ms / 1000.0);
194 draining_alerts = TRUE;
195 pcmk_drain_main_loop(mloop, timer_ms, drain_check);
196 g_hash_table_destroy(inflight_alerts);
197 inflight_alerts = NULL;
198 }
199 }