pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
ipc_schedulerd.c
Go to the documentation of this file.
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>
21 #include "crmcommon_private.h"
22 
23 typedef struct schedulerd_api_private_s {
24  char *client_uuid;
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 = {
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)) {
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 
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 
149  if (!pcmk_ipc_is_connected(api)) {
150  return ENOTCONN;
151  }
152 
153  private = api->api_data;
154  CRM_ASSERT(private != NULL);
155 
156  cmd = create_request(task, cib, NULL, CRM_SYSTEM_PENGINE,
157  crm_system_name? crm_system_name : "client",
158  private->client_uuid);
159 
160  if (cmd) {
161  rc = pcmk__send_ipc_request(api, cmd);
162  if (rc != pcmk_rc_ok) {
163  crm_debug("Couldn't send request to schedulerd: %s rc=%d",
164  pcmk_rc_str(rc), rc);
165  }
166 
167  *ref = strdup(crm_element_value(cmd, F_CRM_REFERENCE));
168  free_xml(cmd);
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 {
179  return do_schedulerd_api_call(api, CRM_OP_PECALC, cib, ref);
180 }
#define F_CRM_TASK
Definition: msg_xml.h:113
#define F_CRM_REFERENCE
Definition: msg_xml.h:119
A dumping ground.
char data[0]
Definition: cpg.c:55
#define F_CRM_MSG_TYPE
Definition: msg_xml.h:115
char * crm_system_name
Definition: utils.c:51
enum crm_exit_e crm_exit_t
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:501
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
Protocol violated.
Definition: results.h:266
#define crm_debug(fmt, args...)
Definition: logging.h:386
#define CRM_OP_PECALC
Definition: crm.h:139
enum pcmk_schedulerd_api_reply reply_type
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:447
#define F_CRM_TGRAPH_INPUT
Definition: msg_xml.h:130
G_GNUC_INTERNAL int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
Definition: ipc_client.c:668
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:106
union pcmk_schedulerd_api_reply_t::@8 data
Wrappers for and extensions to libxml2.
Success.
Definition: results.h:240
void free_xml(xmlNode *child)
Definition: xml.c:783
int(* post_connect)(pcmk_ipc_api_t *api)
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:957
xmlNode * get_message_xml(const xmlNode *msg, const char *field)
Definition: messages.c:154
#define F_CRM_DATA
Definition: msg_xml.h:112
int(* new_data)(pcmk_ipc_api_t *api)
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
bool(* reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request)
#define CRM_ASSERT(expr)
Definition: results.h:42
#define XML_ATTR_REFERENCE
Definition: msg_xml.h:179
void(* free_data)(void *api_data)
#define XML_ATTR_RESPONSE
Definition: msg_xml.h:176
IPC interface to Pacemaker daemons.
Daemon&#39;s reply to client IPC request.
Definition: ipc.h:83
pcmk__ipc_methods_t * pcmk__schedulerd_api_methods(void)
IPC commands for Schedulerd.
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition: ipc.h:43
#define crm_info(fmt, args...)
Definition: logging.h:384
struct schedulerd_api_private_s schedulerd_api_private_t
bool pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
Check whether an IPC API connection is active.
Definition: ipc_client.c:287