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 = g_hash_table_new(g_direct_hash, g_direct_equal);
32 }
33 g_hash_table_insert(inflight_alerts, GINT_TO_POINTER(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 g_hash_table_remove(inflight_alerts, GINT_TO_POINTER(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 CRM_CHECK(cb_data != NULL,
114 rc = -ENOMEM; goto err);
115
116
117 cb_data->client_id = strdup(client->id);
118 CRM_CHECK(cb_data->client_id != NULL,
119 rc = -ENOMEM; goto err);
120
121 crm_element_value_int(request, F_LRMD_CALLID, &(cb_data->call_id));
122
123 action = services_alert_create(alert_id, alert_path, alert_timeout, params,
124 alert_sequence_no, cb_data);
125 rc = services_action_user(action, CRM_DAEMON_USER);
126 if (rc < 0) {
127 goto err;
128 }
129
130 add_inflight_alert(cb_data->call_id, alert_timeout);
131 if (services_alert_async(action, alert_complete) == FALSE) {
132 services_action_free(action);
133 }
134 return pcmk_ok;
135
136 err:
137 if (cb_data) {
138 if (cb_data->client_id) {
139 free(cb_data->client_id);
140 }
141 free(cb_data);
142 }
143 if (action) {
144 services_action_free(action);
145 }
146 return rc;
147 }
148
149 static bool
150 drain_check(guint remaining_timeout_ms)
151 {
152 if (inflight_alerts != NULL) {
153 guint count = g_hash_table_size(inflight_alerts);
154
155 if (count > 0) {
156 crm_trace("%d alerts pending (%.3fs timeout remaining)",
157 count, remaining_timeout_ms / 1000.0);
158 return TRUE;
159 }
160 }
161 return FALSE;
162 }
163
164 void
165 lrmd_drain_alerts(GMainLoop *mloop)
166 {
167 if (inflight_alerts != NULL) {
168 guint timer_ms = max_inflight_timeout() + 5000;
169
170 crm_trace("Draining in-flight alerts (timeout %.3fs)",
171 timer_ms / 1000.0);
172 draining_alerts = TRUE;
173 pcmk_drain_main_loop(mloop, timer_ms, drain_check);
174 g_hash_table_destroy(inflight_alerts);
175 inflight_alerts = NULL;
176 }
177 }