pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
ipc_schedulerd.c
Go to the documentation of this file.
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>
20 #include "crmcommon_private.h"
21 
22 typedef struct schedulerd_api_private_s {
23  char *client_uuid;
25 
26 // \return Standard Pacemaker return code
27 static int
28 new_data(pcmk_ipc_api_t *api)
29 {
30  struct schedulerd_api_private_s *private = NULL;
31 
32  api->api_data = calloc(1, sizeof(struct schedulerd_api_private_s));
33 
34  if (api->api_data == NULL) {
35  return errno;
36  }
37 
38  private = api->api_data;
39  /* See comments in ipc_pacemakerd.c. */
40  private->client_uuid = pcmk__getpid_s();
41 
42  return pcmk_rc_ok;
43 }
44 
45 static void
46 free_data(void *data)
47 {
48  free(((struct schedulerd_api_private_s *) data)->client_uuid);
49  free(data);
50 }
51 
52 // \return Standard Pacemaker return code
53 static int
54 post_connect(pcmk_ipc_api_t *api)
55 {
56  if (api->api_data == NULL) {
57  return EINVAL;
58  }
59 
60  return pcmk_rc_ok;
61 }
62 
63 static bool
64 reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
65 {
66  const char *command = crm_element_value(request, PCMK__XA_CRM_TASK);
67 
68  if (command == NULL) {
69  return false;
70  }
71 
72  // We only need to handle commands that functions in this file can send
73  return pcmk__str_any_of(command, CRM_OP_PECALC, NULL);
74 }
75 
76 static bool
77 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
78 {
79  crm_exit_t status = CRM_EX_OK;
80  xmlNode *wrapper = NULL;
81  xmlNode *msg_data = NULL;
82  pcmk_schedulerd_api_reply_t reply_data = {
84  };
85  const char *value = NULL;
86 
87  if (pcmk__xe_is(reply, PCMK__XE_ACK)) {
88  return false;
89  }
90 
91  value = crm_element_value(reply, PCMK__XA_T);
93  crm_info("Unrecognizable message from schedulerd: "
94  "unexpected message type '%s'",
95  pcmk__s(value, ""));
96  status = CRM_EX_PROTOCOL;
97  goto done;
98  }
99 
100  value = crm_element_value(reply, PCMK__XA_SUBT);
101  if (!pcmk__str_eq(value, PCMK__VALUE_RESPONSE, pcmk__str_none)) {
102  crm_info("Unrecognizable message from schedulerd: "
103  "message type '%s' not '" PCMK__VALUE_RESPONSE "'",
104  pcmk__s(value, ""));
105  status = CRM_EX_PROTOCOL;
106  goto done;
107  }
108 
109  if (pcmk__str_empty(crm_element_value(reply, PCMK_XA_REFERENCE))) {
110  crm_info("Unrecognizable message from schedulerd: no reference");
111  status = CRM_EX_PROTOCOL;
112  goto done;
113  }
114 
115  // Parse useful info from reply
116  wrapper = pcmk__xe_first_child(reply, PCMK__XE_CRM_XML, NULL, NULL);
117  msg_data = pcmk__xe_first_child(wrapper, NULL, NULL, NULL);
118 
119  value = crm_element_value(reply, PCMK__XA_CRM_TASK);
120 
121  if (pcmk__str_eq(value, CRM_OP_PECALC, pcmk__str_none)) {
123  reply_data.data.graph.reference = crm_element_value(reply,
125  reply_data.data.graph.input = crm_element_value(reply,
127  reply_data.data.graph.tgraph = msg_data;
128  } else {
129  crm_info("Unrecognizable message from schedulerd: "
130  "unknown command '%s'", pcmk__s(value, ""));
131  status = CRM_EX_PROTOCOL;
132  goto done;
133  }
134 
135 done:
136  pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
137  return false;
138 }
139 
142 {
143  pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
144 
145  if (cmds != NULL) {
146  cmds->new_data = new_data;
147  cmds->free_data = free_data;
148  cmds->post_connect = post_connect;
149  cmds->reply_expected = reply_expected;
150  cmds->dispatch = dispatch;
151  }
152  return cmds;
153 }
154 
155 static int
156 do_schedulerd_api_call(pcmk_ipc_api_t *api, const char *task, xmlNode *cib, char **ref)
157 {
158  schedulerd_api_private_t *private;
159  xmlNode *cmd = NULL;
160  int rc;
161  char *sender_system = NULL;
162 
163  if (!pcmk_ipc_is_connected(api)) {
164  return ENOTCONN;
165  }
166 
167  private = api->api_data;
168  pcmk__assert(private != NULL);
169 
170  sender_system = crm_strdup_printf("%s_%s", private->client_uuid,
171  pcmk__s(crm_system_name, "client"));
172  cmd = pcmk__new_request(pcmk_ipc_schedulerd, sender_system, NULL,
173  CRM_SYSTEM_PENGINE, task, cib);
174  free(sender_system);
175 
176  if (cmd) {
177  rc = pcmk__send_ipc_request(api, cmd);
178  if (rc != pcmk_rc_ok) {
179  crm_debug("Couldn't send request to schedulerd: %s rc=%d",
180  pcmk_rc_str(rc), rc);
181  }
182 
183  *ref = strdup(crm_element_value(cmd, PCMK_XA_REFERENCE));
184  pcmk__xml_free(cmd);
185  } else {
186  rc = ENOMSG;
187  }
188 
189  return rc;
190 }
191 
192 int
193 pcmk_schedulerd_api_graph(pcmk_ipc_api_t *api, xmlNode *cib, char **ref)
194 {
195  return do_schedulerd_api_call(api, CRM_OP_PECALC, cib, ref);
196 }
A dumping ground.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition: xml_element.c:42
#define PCMK__VALUE_RESPONSE
char data[0]
Definition: cpg.c:58
Scheduler.
Definition: ipc.h:56
#define PCMK_XA_REFERENCE
Definition: xml_names.h:372
char * crm_system_name
Definition: utils.c:44
enum crm_exit_e crm_exit_t
#define PCMK__XA_SUBT
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:609
struct pcmk_schedulerd_api_reply_t::@8::@9 graph
G_GNUC_INTERNAL void pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
Definition: ipc_client.c:150
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
#define PCMK__XA_CRM_TASK
Protocol violated.
Definition: results.h:257
#define crm_debug(fmt, args...)
Definition: logging.h:370
#define CRM_OP_PECALC
Definition: crm.h:118
enum pcmk_schedulerd_api_reply reply_type
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
Definition: ipc_client.c:658
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: xml_element.c:1168
int pcmk_schedulerd_api_graph(pcmk_ipc_api_t *api, xmlNode *cib, char **ref)
Make an IPC request to the scheduler for the transition graph.
#define CRM_SYSTEM_PENGINE
Definition: crm.h:86
union pcmk_schedulerd_api_reply_t::@8 data
Wrappers for and extensions to libxml2.
enum pcmk_ipc_server pcmk__parse_server(const char *text)
Definition: servers.c:178
#define pcmk__new_request(server, sender_system, recipient_node, recipient_system, task, data)
Success.
Definition: results.h:231
int(* post_connect)(pcmk_ipc_api_t *api)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1051
#define pcmk__assert(expr)
int(* new_data)(pcmk_ipc_api_t *api)
#define PCMK__XE_CRM_XML
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
bool(* reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request)
#define PCMK__XE_ACK
void(* free_data)(void *api_data)
IPC interface to Pacemaker daemons.
#define PCMK__XA_T
Daemon&#39;s reply to client IPC request.
Definition: ipc.h:68
pcmk__ipc_methods_t * pcmk__schedulerd_api_methods(void)
#define PCMK__XA_CRM_TGRAPH_IN
IPC commands for Schedulerd.
#define crm_info(fmt, args...)
Definition: logging.h:367
struct schedulerd_api_private_s schedulerd_api_private_t
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
bool pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
Check whether an IPC API connection is active.
Definition: ipc_client.c:277