Coverage Report

Created: 2026-08-14 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}