This source file includes following definitions.
- pcmk_pacemakerd_api_daemon_state_text2enum
- pcmk_pacemakerd_api_daemon_state_enum2text
- pcmk__pcmkd_state_enum2friendly
- new_data
- free_data
- post_connect
- post_disconnect
- reply_expected
- dispatch
- pcmk__pacemakerd_api_methods
- do_pacemakerd_api_call
- pcmk_pacemakerd_api_ping
- pcmk_pacemakerd_api_shutdown
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdlib.h>
13 #include <time.h>
14
15 #include <crm/crm.h>
16 #include <crm/msg_xml.h>
17 #include <crm/common/xml.h>
18 #include <crm/common/ipc.h>
19 #include <crm/common/ipc_internal.h>
20 #include <crm/common/ipc_pacemakerd.h>
21 #include "crmcommon_private.h"
22
23 typedef struct pacemakerd_api_private_s {
24 enum pcmk_pacemakerd_state state;
25 char *client_uuid;
26 } pacemakerd_api_private_t;
27
28 static const char *pacemakerd_state_str[] = {
29 XML_PING_ATTR_PACEMAKERDSTATE_INIT,
30 XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS,
31 XML_PING_ATTR_PACEMAKERDSTATE_WAITPING,
32 XML_PING_ATTR_PACEMAKERDSTATE_RUNNING,
33 XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN,
34 XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE
35 };
36
37 enum pcmk_pacemakerd_state
38 pcmk_pacemakerd_api_daemon_state_text2enum(const char *state)
39 {
40 int i;
41
42 if (state == NULL) {
43 return pcmk_pacemakerd_state_invalid;
44 }
45 for (i=pcmk_pacemakerd_state_init; i <= pcmk_pacemakerd_state_max;
46 i++) {
47 if (pcmk__str_eq(state, pacemakerd_state_str[i], pcmk__str_none)) {
48 return i;
49 }
50 }
51 return pcmk_pacemakerd_state_invalid;
52 }
53
54 const char *
55 pcmk_pacemakerd_api_daemon_state_enum2text(
56 enum pcmk_pacemakerd_state state)
57 {
58 if ((state >= pcmk_pacemakerd_state_init) &&
59 (state <= pcmk_pacemakerd_state_max)) {
60 return pacemakerd_state_str[state];
61 }
62 return "invalid";
63 }
64
65
66
67
68
69
70
71
72
73
74 const char *
75 pcmk__pcmkd_state_enum2friendly(enum pcmk_pacemakerd_state state)
76 {
77 switch (state) {
78 case pcmk_pacemakerd_state_init:
79 return "Initializing pacemaker";
80 case pcmk_pacemakerd_state_starting_daemons:
81 return "Pacemaker daemons are starting";
82 case pcmk_pacemakerd_state_wait_for_ping:
83 return "Waiting for startup trigger from SBD";
84 case pcmk_pacemakerd_state_running:
85 return "Pacemaker is running";
86 case pcmk_pacemakerd_state_shutting_down:
87 return "Pacemaker daemons are shutting down";
88 case pcmk_pacemakerd_state_shutdown_complete:
89
90
91
92 return "Pacemaker daemons are shut down (reporting to SBD)";
93 default:
94 return "Invalid pacemakerd state";
95 }
96 }
97
98
99 static int
100 new_data(pcmk_ipc_api_t *api)
101 {
102 struct pacemakerd_api_private_s *private = NULL;
103
104 api->api_data = calloc(1, sizeof(struct pacemakerd_api_private_s));
105
106 if (api->api_data == NULL) {
107 return errno;
108 }
109
110 private = api->api_data;
111 private->state = pcmk_pacemakerd_state_invalid;
112
113
114
115 private->client_uuid = pcmk__getpid_s();
116
117 return pcmk_rc_ok;
118 }
119
120 static void
121 free_data(void *data)
122 {
123 free(((struct pacemakerd_api_private_s *) data)->client_uuid);
124 free(data);
125 }
126
127
128 static int
129 post_connect(pcmk_ipc_api_t *api)
130 {
131 struct pacemakerd_api_private_s *private = NULL;
132
133 if (api->api_data == NULL) {
134 return EINVAL;
135 }
136 private = api->api_data;
137 private->state = pcmk_pacemakerd_state_invalid;
138
139 return pcmk_rc_ok;
140 }
141
142 static void
143 post_disconnect(pcmk_ipc_api_t *api)
144 {
145 struct pacemakerd_api_private_s *private = NULL;
146
147 if (api->api_data == NULL) {
148 return;
149 }
150 private = api->api_data;
151 private->state = pcmk_pacemakerd_state_invalid;
152
153 return;
154 }
155
156 static bool
157 reply_expected(pcmk_ipc_api_t *api, xmlNode *request)
158 {
159 const char *command = crm_element_value(request, F_CRM_TASK);
160
161 if (command == NULL) {
162 return false;
163 }
164
165
166 return pcmk__str_any_of(command, CRM_OP_PING, CRM_OP_QUIT, NULL);
167 }
168
169 static bool
170 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
171 {
172 crm_exit_t status = CRM_EX_OK;
173 xmlNode *msg_data = NULL;
174 pcmk_pacemakerd_api_reply_t reply_data = {
175 pcmk_pacemakerd_reply_unknown
176 };
177 const char *value = NULL;
178 long long value_ll = 0;
179
180 if (pcmk__str_eq((const char *) reply->name, "ack", pcmk__str_none)) {
181 long long int ack_status = 0;
182 pcmk__scan_ll(crm_element_value(reply, "status"), &ack_status, CRM_EX_OK);
183 return ack_status == CRM_EX_INDETERMINATE;
184 }
185
186 value = crm_element_value(reply, F_CRM_MSG_TYPE);
187 if (pcmk__str_empty(value)
188 || !pcmk__str_eq(value, XML_ATTR_RESPONSE, pcmk__str_none)) {
189 crm_info("Unrecognizable message from pacemakerd: "
190 "message type '%s' not '" XML_ATTR_RESPONSE "'",
191 pcmk__s(value, ""));
192 status = CRM_EX_PROTOCOL;
193 goto done;
194 }
195
196 if (pcmk__str_empty(crm_element_value(reply, XML_ATTR_REFERENCE))) {
197 crm_info("Unrecognizable message from pacemakerd: no reference");
198 status = CRM_EX_PROTOCOL;
199 goto done;
200 }
201
202 value = crm_element_value(reply, F_CRM_TASK);
203
204
205 msg_data = get_message_xml(reply, F_CRM_DATA);
206 crm_element_value_ll(msg_data, XML_ATTR_TSTAMP, &value_ll);
207
208 if (pcmk__str_eq(value, CRM_OP_PING, pcmk__str_none)) {
209 reply_data.reply_type = pcmk_pacemakerd_reply_ping;
210 reply_data.data.ping.state =
211 pcmk_pacemakerd_api_daemon_state_text2enum(
212 crm_element_value(msg_data, XML_PING_ATTR_PACEMAKERDSTATE));
213 reply_data.data.ping.status =
214 pcmk__str_eq(crm_element_value(msg_data, XML_PING_ATTR_STATUS), "ok",
215 pcmk__str_casei)?pcmk_rc_ok:pcmk_rc_error;
216 reply_data.data.ping.last_good = (value_ll < 0)? 0 : (time_t) value_ll;
217 reply_data.data.ping.sys_from = crm_element_value(msg_data,
218 XML_PING_ATTR_SYSFROM);
219 } else if (pcmk__str_eq(value, CRM_OP_QUIT, pcmk__str_none)) {
220 reply_data.reply_type = pcmk_pacemakerd_reply_shutdown;
221 reply_data.data.shutdown.status = atoi(crm_element_value(msg_data, XML_LRM_ATTR_OPSTATUS));
222 } else {
223 crm_info("Unrecognizable message from pacemakerd: "
224 "unknown command '%s'", pcmk__s(value, ""));
225 status = CRM_EX_PROTOCOL;
226 goto done;
227 }
228
229 done:
230 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
231 return false;
232 }
233
234 pcmk__ipc_methods_t *
235 pcmk__pacemakerd_api_methods(void)
236 {
237 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
238
239 if (cmds != NULL) {
240 cmds->new_data = new_data;
241 cmds->free_data = free_data;
242 cmds->post_connect = post_connect;
243 cmds->reply_expected = reply_expected;
244 cmds->dispatch = dispatch;
245 cmds->post_disconnect = post_disconnect;
246 }
247 return cmds;
248 }
249
250 static int
251 do_pacemakerd_api_call(pcmk_ipc_api_t *api, const char *ipc_name, const char *task)
252 {
253 pacemakerd_api_private_t *private;
254 xmlNode *cmd;
255 int rc;
256
257 if (api == NULL) {
258 return EINVAL;
259 }
260
261 private = api->api_data;
262 CRM_ASSERT(private != NULL);
263
264 cmd = create_request(task, NULL, NULL, CRM_SYSTEM_MCP,
265 pcmk__ipc_sys_name(ipc_name, "client"),
266 private->client_uuid);
267
268 if (cmd) {
269 rc = pcmk__send_ipc_request(api, cmd);
270 if (rc != pcmk_rc_ok) {
271 crm_debug("Couldn't send request to pacemakerd: %s rc=%d",
272 pcmk_rc_str(rc), rc);
273 }
274 free_xml(cmd);
275 } else {
276 rc = ENOMSG;
277 }
278
279 return rc;
280 }
281
282 int
283 pcmk_pacemakerd_api_ping(pcmk_ipc_api_t *api, const char *ipc_name)
284 {
285 return do_pacemakerd_api_call(api, ipc_name, CRM_OP_PING);
286 }
287
288 int
289 pcmk_pacemakerd_api_shutdown(pcmk_ipc_api_t *api, const char *ipc_name)
290 {
291 return do_pacemakerd_api_call(api, ipc_name, CRM_OP_QUIT);
292 }