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/common/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("//" PCMK__XE_LRMD_ALERT, request,
109 LOG_ERR);
110 const char *alert_id = crm_element_value(alert_xml, PCMK__XA_LRMD_ALERT_ID);
111 const char *alert_path = crm_element_value(alert_xml,
112 PCMK__XA_LRMD_ALERT_PATH);
113 svc_action_t *action = NULL;
114 int alert_timeout = 0;
115 int rc = pcmk_ok;
116 GHashTable *params = NULL;
117 struct alert_cb_s *cb_data = NULL;
118
119 if ((alert_id == NULL) || (alert_path == NULL) ||
120 (client == NULL) || (client->id == NULL)) {
121 rc = -EINVAL;
122 goto err;
123 }
124 if (draining_alerts) {
125 return pcmk_ok;
126 }
127
128 crm_element_value_int(alert_xml, PCMK__XA_LRMD_TIMEOUT, &alert_timeout);
129
130 crm_info("Executing alert %s for %s", alert_id, client->id);
131
132 params = xml2list(alert_xml);
133 pcmk__add_alert_key_int(params, PCMK__alert_key_node_sequence,
134 ++alert_sequence_no);
135
136 cb_data = pcmk__assert_alloc(1, sizeof(struct alert_cb_s));
137
138 cb_data->client_id = pcmk__str_copy(client->id);
139
140 crm_element_value_int(request, PCMK__XA_LRMD_CALLID, &(cb_data->call_id));
141
142 action = services_alert_create(alert_id, alert_path, alert_timeout, params,
143 alert_sequence_no, cb_data);
144 if (action->rc != PCMK_OCF_UNKNOWN) {
145 rc = -E2BIG;
146 goto err;
147 }
148
149 rc = services_action_user(action, CRM_DAEMON_USER);
150 if (rc < 0) {
151 goto err;
152 }
153
154 add_inflight_alert(cb_data->call_id, alert_timeout);
155 if (services_alert_async(action, alert_complete) == FALSE) {
156 services_action_free(action);
157 }
158 return pcmk_ok;
159
160 err:
161 if (cb_data) {
162 free(cb_data->client_id);
163 free(cb_data);
164 }
165 services_action_free(action);
166 return rc;
167 }
168
169 static bool
170 drain_check(guint remaining_timeout_ms)
171 {
172 if (inflight_alerts != NULL) {
173 guint count = g_hash_table_size(inflight_alerts);
174
175 if (count > 0) {
176 crm_trace("%d alerts pending (%.3fs timeout remaining)",
177 count, remaining_timeout_ms / 1000.0);
178 return TRUE;
179 }
180 }
181 return FALSE;
182 }
183
184 void
185 lrmd_drain_alerts(GMainLoop *mloop)
186 {
187 if (inflight_alerts != NULL) {
188 guint timer_ms = max_inflight_timeout() + 5000;
189
190 crm_trace("Draining in-flight alerts (timeout %.3fs)",
191 timer_ms / 1000.0);
192 draining_alerts = TRUE;
193 pcmk_drain_main_loop(mloop, timer_ms, drain_check);
194 g_hash_table_destroy(inflight_alerts);
195 inflight_alerts = NULL;
196 }
197 }