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