This source file includes following definitions.
- add_inflight_alert
- remove_inflight_alert
- max_inflight_timeout
- alert_complete
- process_lrmd_alert_exec
- alert_drain_timeout_callback
- lrmd_drain_alerts
1
2
3
4
5
6
7
8 #include <crm_internal.h>
9
10 #include <glib.h>
11
12 #include <crm/crm.h>
13 #include <crm/services.h>
14 #include <crm/common/ipc.h>
15 #include <crm/common/ipcs.h>
16 #include <crm/common/alerts_internal.h>
17 #include <crm/msg_xml.h>
18
19 #include <lrmd_private.h>
20
21
22 static GHashTable *inflight_alerts;
23 static gboolean draining_alerts = FALSE;
24
25 static inline void
26 add_inflight_alert(int call_id, int timeout)
27 {
28 if (inflight_alerts == NULL) {
29 inflight_alerts = g_hash_table_new(g_direct_hash, g_direct_equal);
30 }
31 g_hash_table_insert(inflight_alerts, GINT_TO_POINTER(call_id),
32 GINT_TO_POINTER(timeout));
33 }
34
35 static inline void
36 remove_inflight_alert(int call_id)
37 {
38 if (inflight_alerts != NULL) {
39 g_hash_table_remove(inflight_alerts, GINT_TO_POINTER(call_id));
40 }
41 }
42
43 static int
44 max_inflight_timeout()
45 {
46 GHashTableIter iter;
47 gpointer timeout;
48 int max_timeout = 0;
49
50 if (inflight_alerts) {
51 g_hash_table_iter_init(&iter, inflight_alerts);
52 while (g_hash_table_iter_next(&iter, NULL, &timeout)) {
53 if (GPOINTER_TO_INT(timeout) > max_timeout) {
54 max_timeout = GPOINTER_TO_INT(timeout);
55 }
56 }
57 }
58 return max_timeout;
59 }
60
61 struct alert_cb_s {
62 char *client_id;
63 int call_id;
64 };
65
66 static void
67 alert_complete(svc_action_t *action)
68 {
69 struct alert_cb_s *cb_data = (struct alert_cb_s *) (action->cb_data);
70
71 remove_inflight_alert(cb_data->call_id);
72 crm_debug("Alert pid %d for %s completed with rc=%d",
73 action->pid, cb_data->client_id, action->rc);
74
75 free(cb_data->client_id);
76 free(action->cb_data);
77 action->cb_data = NULL;
78 }
79
80 int
81 process_lrmd_alert_exec(crm_client_t *client, uint32_t id, xmlNode *request)
82 {
83 static int alert_sequence_no = 0;
84
85 xmlNode *alert_xml = get_xpath_object("//" F_LRMD_ALERT, request, LOG_ERR);
86 const char *alert_id = crm_element_value(alert_xml, F_LRMD_ALERT_ID);
87 const char *alert_path = crm_element_value(alert_xml, F_LRMD_ALERT_PATH);
88 svc_action_t *action = NULL;
89 int alert_timeout = 0;
90 int rc = pcmk_ok;
91 GHashTable *params = NULL;
92 struct alert_cb_s *cb_data = NULL;
93
94 if ((alert_id == NULL) || (alert_path == NULL)) {
95 return -EINVAL;
96 }
97 if (draining_alerts) {
98 return pcmk_ok;
99 }
100
101 crm_element_value_int(alert_xml, F_LRMD_TIMEOUT, &alert_timeout);
102
103 crm_info("Executing alert %s for %s", alert_id, client->id);
104
105 params = xml2list(alert_xml);
106 crm_insert_alert_key_int(params, CRM_alert_node_sequence,
107 ++alert_sequence_no);
108
109 cb_data = calloc(1, sizeof(struct alert_cb_s));
110 CRM_CHECK(cb_data != NULL,
111 rc = -ENOMEM; goto err);
112
113 cb_data->client_id = strdup(client->id);
114 CRM_CHECK(cb_data->client_id != NULL,
115 rc = -ENOMEM; goto err);
116
117 crm_element_value_int(request, F_LRMD_CALLID, &(cb_data->call_id));
118
119 action = services_alert_create(alert_id, alert_path, alert_timeout, params,
120 alert_sequence_no, cb_data);
121 rc = services_action_user(action, CRM_DAEMON_USER);
122 if (rc < 0) {
123 goto err;
124 }
125
126 add_inflight_alert(cb_data->call_id, alert_timeout);
127 if (services_alert_async(action, alert_complete) == FALSE) {
128 services_action_free(action);
129 }
130 return pcmk_ok;
131
132 err:
133 if (cb_data) {
134 if (cb_data->client_id) {
135 free(cb_data->client_id);
136 }
137 free(cb_data);
138 }
139 if (action) {
140 services_action_free(action);
141 }
142 return rc;
143 }
144
145 static gboolean
146 alert_drain_timeout_callback(gpointer user_data)
147 {
148 gboolean *timeout_popped = (gboolean *) user_data;
149
150 *timeout_popped = TRUE;
151 return FALSE;
152 }
153
154 void
155 lrmd_drain_alerts(GMainContext *ctx)
156 {
157 guint timer, count;
158 gboolean timeout_popped = FALSE;
159 int timer_ms;
160
161 draining_alerts = TRUE;
162 if (inflight_alerts == NULL) {
163 return;
164 }
165
166 timer_ms = max_inflight_timeout() + 5000;
167 timer = g_timeout_add(timer_ms, alert_drain_timeout_callback,
168 (gpointer) &timeout_popped);
169
170 while (!timeout_popped) {
171 count = g_hash_table_size(inflight_alerts);
172 if (count == 0) {
173 break;
174 }
175 crm_trace("Draining mainloop while still %d alerts are in flight (timeout=%dms)",
176 count, timer_ms);
177 g_main_context_iteration(ctx, TRUE);
178 }
179
180 if (!timeout_popped && (timer > 0)) {
181 g_source_remove(timer);
182 }
183
184 g_hash_table_destroy(inflight_alerts);
185 inflight_alerts = NULL;
186 }