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