/src/pacemaker/lib/common/ipc_schedulerd.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2021-2026 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 <errno.h> // EINVAL, ENOMSG, ENOTCONN |
13 | | #include <stdbool.h> // bool, false |
14 | | #include <stdlib.h> // NULL, calloc, free |
15 | | #include <string.h> // strdup |
16 | | |
17 | | #include <libxml/tree.h> // xmlNode |
18 | | |
19 | | #include <crm/common/ipc.h> // pcmk_ipc_* |
20 | | #include <crm/common/ipc_schedulerd.h> |
21 | | #include <crm/common/results.h> // CRM_EX_*, pcmk_rc_* |
22 | | #include <crm/common/xml.h> |
23 | | #include <crm/crm.h> // CRM_OP_PECALC, CRM_SYSTEM_PENGINE |
24 | | |
25 | | #include "crmcommon_private.h" |
26 | | |
27 | | typedef struct { |
28 | | char *client_uuid; |
29 | | } schedulerd_api_private_t; |
30 | | |
31 | | // \return Standard Pacemaker return code |
32 | | static int |
33 | | new_data(pcmk_ipc_api_t *api) |
34 | 0 | { |
35 | 0 | schedulerd_api_private_t *private = NULL; |
36 | |
|
37 | 0 | api->api_data = calloc(1, sizeof(schedulerd_api_private_t)); |
38 | |
|
39 | 0 | if (api->api_data == NULL) { |
40 | 0 | return errno; |
41 | 0 | } |
42 | | |
43 | 0 | private = api->api_data; |
44 | | /* See comments in ipc_pacemakerd.c. */ |
45 | 0 | private->client_uuid = pcmk__getpid_s(); |
46 | |
|
47 | 0 | return pcmk_rc_ok; |
48 | 0 | } |
49 | | |
50 | | static void |
51 | | free_data(void *data) |
52 | 0 | { |
53 | 0 | free(((schedulerd_api_private_t *) data)->client_uuid); |
54 | 0 | free(data); |
55 | 0 | } |
56 | | |
57 | | // \return Standard Pacemaker return code |
58 | | static int |
59 | | post_connect(pcmk_ipc_api_t *api) |
60 | 0 | { |
61 | 0 | if (api->api_data == NULL) { |
62 | 0 | return EINVAL; |
63 | 0 | } |
64 | | |
65 | 0 | return pcmk_rc_ok; |
66 | 0 | } |
67 | | |
68 | | static bool |
69 | | reply_expected(pcmk_ipc_api_t *api, const xmlNode *request) |
70 | 0 | { |
71 | 0 | const char *command = pcmk__xe_get(request, PCMK__XA_CRM_TASK); |
72 | |
|
73 | 0 | if (command == NULL) { |
74 | 0 | return false; |
75 | 0 | } |
76 | | |
77 | | // We only need to handle commands that functions in this file can send |
78 | 0 | return pcmk__str_any_of(command, CRM_OP_PECALC, NULL); |
79 | 0 | } |
80 | | |
81 | | static bool |
82 | | dispatch(pcmk_ipc_api_t *api, xmlNode *reply) |
83 | 0 | { |
84 | 0 | crm_exit_t status = CRM_EX_OK; |
85 | 0 | xmlNode *wrapper = NULL; |
86 | 0 | xmlNode *msg_data = NULL; |
87 | 0 | pcmk_schedulerd_api_reply_t reply_data = { |
88 | 0 | pcmk_schedulerd_reply_unknown |
89 | 0 | }; |
90 | 0 | const char *value = NULL; |
91 | |
|
92 | 0 | if (pcmk__xe_is(reply, PCMK__XE_ACK)) { |
93 | 0 | return false; |
94 | 0 | } |
95 | | |
96 | 0 | value = pcmk__xe_get(reply, PCMK__XA_T); |
97 | 0 | if (pcmk__parse_server(value) != pcmk_ipc_schedulerd) { |
98 | 0 | pcmk__info("Unrecognizable message from schedulerd: unexpected message " |
99 | 0 | "type '%s'", |
100 | 0 | pcmk__s(value, "")); |
101 | 0 | status = CRM_EX_PROTOCOL; |
102 | 0 | goto done; |
103 | 0 | } |
104 | | |
105 | 0 | value = pcmk__xe_get(reply, PCMK__XA_SUBT); |
106 | 0 | if (!pcmk__str_eq(value, PCMK__VALUE_RESPONSE, pcmk__str_none)) { |
107 | 0 | pcmk__info("Unrecognizable message from schedulerd: message type '%s' " |
108 | 0 | "not '" PCMK__VALUE_RESPONSE "'", |
109 | 0 | pcmk__s(value, "")); |
110 | 0 | status = CRM_EX_PROTOCOL; |
111 | 0 | goto done; |
112 | 0 | } |
113 | | |
114 | 0 | if (pcmk__str_empty(pcmk__xe_get(reply, PCMK_XA_REFERENCE))) { |
115 | 0 | pcmk__info("Unrecognizable message from schedulerd: no reference"); |
116 | 0 | status = CRM_EX_PROTOCOL; |
117 | 0 | goto done; |
118 | 0 | } |
119 | | |
120 | | // Parse useful info from reply |
121 | 0 | wrapper = pcmk__xe_first_child(reply, PCMK__XE_CRM_XML, NULL, NULL); |
122 | 0 | msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL); |
123 | |
|
124 | 0 | value = pcmk__xe_get(reply, PCMK__XA_CRM_TASK); |
125 | |
|
126 | 0 | if (pcmk__str_eq(value, CRM_OP_PECALC, pcmk__str_none)) { |
127 | 0 | reply_data.reply_type = pcmk_schedulerd_reply_graph; |
128 | 0 | reply_data.data.graph.reference = pcmk__xe_get(reply, |
129 | 0 | PCMK_XA_REFERENCE); |
130 | 0 | reply_data.data.graph.input = pcmk__xe_get(reply, |
131 | 0 | PCMK__XA_CRM_TGRAPH_IN); |
132 | 0 | reply_data.data.graph.tgraph = msg_data; |
133 | |
|
134 | 0 | } else { |
135 | 0 | pcmk__info("Unrecognizable message from schedulerd: unknown command " |
136 | 0 | "'%s'", |
137 | 0 | pcmk__s(value, "")); |
138 | 0 | status = CRM_EX_PROTOCOL; |
139 | 0 | goto done; |
140 | 0 | } |
141 | | |
142 | 0 | done: |
143 | 0 | pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data); |
144 | 0 | return false; |
145 | 0 | } |
146 | | |
147 | | pcmk__ipc_methods_t * |
148 | | pcmk__schedulerd_api_methods(void) |
149 | 0 | { |
150 | 0 | pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t)); |
151 | |
|
152 | 0 | if (cmds == NULL) { |
153 | 0 | return NULL; |
154 | 0 | } |
155 | | |
156 | 0 | cmds->new_data = new_data; |
157 | 0 | cmds->free_data = free_data; |
158 | 0 | cmds->post_connect = post_connect; |
159 | 0 | cmds->reply_expected = reply_expected; |
160 | 0 | cmds->dispatch = dispatch; |
161 | 0 | return cmds; |
162 | 0 | } |
163 | | |
164 | | static int |
165 | | do_schedulerd_api_call(pcmk_ipc_api_t *api, const char *task, xmlNode *cib, char **ref) |
166 | 0 | { |
167 | 0 | schedulerd_api_private_t *private = NULL; |
168 | 0 | xmlNode *cmd = NULL; |
169 | 0 | int rc = pcmk_rc_ok; |
170 | 0 | char *sender_system = NULL; |
171 | |
|
172 | 0 | if (!pcmk_ipc_is_connected(api)) { |
173 | 0 | return ENOTCONN; |
174 | 0 | } |
175 | | |
176 | 0 | private = api->api_data; |
177 | 0 | pcmk__assert(private != NULL); |
178 | |
|
179 | 0 | sender_system = pcmk__assert_asprintf("%s_%s", private->client_uuid, |
180 | 0 | pcmk__s(crm_system_name, "client")); |
181 | 0 | cmd = pcmk__new_request(pcmk_ipc_schedulerd, sender_system, NULL, |
182 | 0 | CRM_SYSTEM_PENGINE, task, cib); |
183 | 0 | free(sender_system); |
184 | |
|
185 | 0 | if (cmd == NULL) { |
186 | 0 | return ENOMSG; |
187 | 0 | } |
188 | | |
189 | 0 | rc = pcmk__send_ipc_request(api, cmd); |
190 | 0 | if (rc != pcmk_rc_ok) { |
191 | 0 | pcmk__debug("Couldn't send request to schedulerd: %s rc=%d", |
192 | 0 | pcmk_rc_str(rc), rc); |
193 | 0 | } |
194 | | |
195 | 0 | *ref = strdup(pcmk__xe_get(cmd, PCMK_XA_REFERENCE)); |
196 | 0 | pcmk__xml_free(cmd); |
197 | 0 | return rc; |
198 | 0 | } |
199 | | |
200 | | int |
201 | | pcmk_schedulerd_api_graph(pcmk_ipc_api_t *api, xmlNode *cib, char **ref) |
202 | 0 | { |
203 | 0 | return do_schedulerd_api_call(api, CRM_OP_PECALC, cib, ref); |
204 | 0 | } |