1 /*
2 * Copyright 2021-2023 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
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_schedulerd.h>
21 #include "crmcommon_private.h"
22
23 typedef struct schedulerd_api_private_s {
24 char *client_uuid;
25 } schedulerd_api_private_t;
26
27 // \return Standard Pacemaker return code
28 static int
29 new_data(pcmk_ipc_api_t *api)
30 {
31 struct schedulerd_api_private_s *private = NULL;
32
33 api->api_data = calloc(1, sizeof(struct schedulerd_api_private_s));
34
35 if (api->api_data == NULL) {
36 return errno;
37 }
38
39 private = api->api_data;
40 /* See comments in ipc_pacemakerd.c. */
41 private->client_uuid = pcmk__getpid_s();
42
43 return pcmk_rc_ok;
44 }
45
46 static void
47 free_data(void *data)
48 {
49 free(((struct schedulerd_api_private_s *) data)->client_uuid);
50 free(data);
51 }
52
53 // \return Standard Pacemaker return code
54 static int
55 post_connect(pcmk_ipc_api_t *api)
56 {
57 if (api->api_data == NULL) {
58 return EINVAL;
59 }
60
61 return pcmk_rc_ok;
62 }
63
64 static bool
65 reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
66 {
67 const char *command = crm_element_value(request, F_CRM_TASK);
68
69 if (command == NULL) {
70 return false;
71 }
72
73 // We only need to handle commands that functions in this file can send
74 return pcmk__str_any_of(command, CRM_OP_PECALC, NULL);
75 }
76
77 static bool
78 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
79 {
80 crm_exit_t status = CRM_EX_OK;
81 xmlNode *msg_data = NULL;
82 pcmk_schedulerd_api_reply_t reply_data = {
83 pcmk_schedulerd_reply_unknown
84 };
85 const char *value = NULL;
86
87 if (pcmk__str_eq((const char *) reply->name, "ack", pcmk__str_casei)) {
88 return false;
89 }
90
91 value = crm_element_value(reply, F_CRM_MSG_TYPE);
92 if (!pcmk__str_eq(value, XML_ATTR_RESPONSE, pcmk__str_none)) {
93 crm_info("Unrecognizable message from schedulerd: "
94 "message type '%s' not '" XML_ATTR_RESPONSE "'",
95 pcmk__s(value, ""));
96 status = CRM_EX_PROTOCOL;
97 goto done;
98 }
99
100 if (pcmk__str_empty(crm_element_value(reply, XML_ATTR_REFERENCE))) {
101 crm_info("Unrecognizable message from schedulerd: no reference");
102 status = CRM_EX_PROTOCOL;
103 goto done;
104 }
105
106 // Parse useful info from reply
107 msg_data = get_message_xml(reply, F_CRM_DATA);
108 value = crm_element_value(reply, F_CRM_TASK);
109
110 if (pcmk__str_eq(value, CRM_OP_PECALC, pcmk__str_none)) {
111 reply_data.reply_type = pcmk_schedulerd_reply_graph;
112 reply_data.data.graph.reference = crm_element_value(reply, XML_ATTR_REFERENCE);
113 reply_data.data.graph.input = crm_element_value(reply, F_CRM_TGRAPH_INPUT);
114 reply_data.data.graph.tgraph = msg_data;
115 } else {
116 crm_info("Unrecognizable message from schedulerd: "
117 "unknown command '%s'", pcmk__s(value, ""));
118 status = CRM_EX_PROTOCOL;
119 goto done;
120 }
121
122 done:
123 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
124 return false;
125 }
126
127 pcmk__ipc_methods_t *
128 pcmk__schedulerd_api_methods(void)
129 {
130 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
131
132 if (cmds != NULL) {
133 cmds->new_data = new_data;
134 cmds->free_data = free_data;
135 cmds->post_connect = post_connect;
136 cmds->reply_expected = reply_expected;
137 cmds->dispatch = dispatch;
138 }
139 return cmds;
140 }
141
142 static int
143 do_schedulerd_api_call(pcmk_ipc_api_t *api, const char *task, xmlNode *cib, char **ref)
144 {
145 schedulerd_api_private_t *private;
146 xmlNode *cmd = NULL;
147 int rc;
148
|
(1) Event path: |
Condition "!pcmk_ipc_is_connected(api)", taking false branch. |
149 if (!pcmk_ipc_is_connected(api)) {
150 return ENOTCONN;
151 }
152
153 private = api->api_data;
|
(2) Event path: |
Condition "!(private != NULL)", taking false branch. |
154 CRM_ASSERT(private != NULL);
155
|
(3) Event path: |
Condition "crm_system_name", taking true branch. |
156 cmd = create_request(task, cib, NULL, CRM_SYSTEM_PENGINE,
157 crm_system_name? crm_system_name : "client",
158 private->client_uuid);
159
|
(4) Event path: |
Condition "cmd", taking true branch. |
160 if (cmd) {
161 rc = pcmk__send_ipc_request(api, cmd);
|
(5) Event path: |
Condition "rc != pcmk_rc_ok", taking true branch. |
162 if (rc != pcmk_rc_ok) {
|
(6) Event path: |
Switch case default. |
|
(7) Event path: |
Condition "trace_cs == NULL", taking true branch. |
|
(8) Event path: |
Condition "crm_is_callsite_active(trace_cs, _level, 0)", taking false branch. |
|
(9) Event path: |
Breaking from switch. |
163 crm_debug("Couldn't send request to schedulerd: %s rc=%d",
164 pcmk_rc_str(rc), rc);
165 }
166
|
(10) Event alloc_fn: |
Storage is returned from allocation function "strdup". |
|
(11) Event assign: |
Assigning: "*ref" = "strdup(crm_element_value(cmd, "reference"))". |
167 *ref = strdup(crm_element_value(cmd, F_CRM_REFERENCE));
168 free_xml(cmd);
|
(12) Event path: |
Falling through to end of if statement. |
169 } else {
170 rc = ENOMSG;
171 }
172
173 return rc;
174 }
175
176 int
177 pcmk_schedulerd_api_graph(pcmk_ipc_api_t *api, xmlNode *cib, char **ref)
178 {
|
(1) Event alloc_arg: |
"do_schedulerd_api_call" allocates memory that is stored into "*ref". [details] |
179 return do_schedulerd_api_call(api, CRM_OP_PECALC, cib, ref);
180 }
181