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