1 /*
2 * Copyright 2010-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 #ifndef PCMK__CRM_SERVICES__H
11 # define PCMK__CRM_SERVICES__H
12
13
14 # include <glib.h>
15 # include <stdio.h>
16 # include <stdint.h>
17 # include <string.h>
18 # include <stdbool.h>
19 # include <sys/types.h>
20
21 # include <crm_config.h> // OCF_ROOT_DIR
22 # include <crm/common/agents.h>
23 # include <crm/common/results.h>
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29 // NOTE: booth (as of at least 1.1) checks for the existence of this header
30
31 /*!
32 * \file
33 * \brief Services API
34 * \ingroup core
35 */
36
37 /* TODO: Autodetect these two ?*/
38 # ifndef SYSTEMCTL
39 # define SYSTEMCTL "/bin/systemctl"
40 # endif
41
42 /* This is the string passed in the OCF_EXIT_REASON_PREFIX environment variable.
43 * The stderr output that occurs after this prefix is encountered is considered
44 * the exit reason for a completed operation.
45 */
46 #define PCMK_OCF_REASON_PREFIX "ocf-exit-reason:"
47
48 // Agent version to use if agent doesn't specify one
49 #define PCMK_DEFAULT_AGENT_VERSION "0.1"
50
51 enum lsb_exitcode {
52 PCMK_LSB_OK = 0,
53
54 // NOTE: booth (as of at least 1.1) uses this value
55 PCMK_LSB_UNKNOWN_ERROR = 1,
56
57 PCMK_LSB_INVALID_PARAM = 2,
58 PCMK_LSB_UNIMPLEMENT_FEATURE = 3,
59 PCMK_LSB_INSUFFICIENT_PRIV = 4,
60 PCMK_LSB_NOT_INSTALLED = 5,
61 PCMK_LSB_NOT_CONFIGURED = 6,
62 PCMK_LSB_NOT_RUNNING = 7,
63 };
64
65 // LSB uses different return codes for status actions
66 enum lsb_status_exitcode {
67 PCMK_LSB_STATUS_OK = 0,
68 PCMK_LSB_STATUS_VAR_PID = 1,
69 PCMK_LSB_STATUS_VAR_LOCK = 2,
70 PCMK_LSB_STATUS_NOT_RUNNING = 3,
71 PCMK_LSB_STATUS_UNKNOWN = 4,
72
73 /* custom codes should be in the 150-199 range reserved for application use */
74 PCMK_LSB_STATUS_NOT_INSTALLED = 150,
75 PCMK_LSB_STATUS_INSUFFICIENT_PRIV = 151,
76 };
77
78 enum svc_action_flags {
79 /* On timeout, only kill pid, do not kill entire pid group */
80 SVC_ACTION_LEAVE_GROUP = 0x01,
81 SVC_ACTION_NON_BLOCKED = 0x02,
82 };
83
84 typedef struct svc_action_private_s svc_action_private_t;
85
86 /*!
87 * \brief Object for executing external actions
88 *
89 * \note This object should never be instantiated directly, but instead created
90 * using one of the constructor functions (resources_action_create() for
91 * resource agents, services_alert_create() for alert agents, or
92 * services_action_create_generic() for generic executables). Similarly,
93 * do not use sizeof() on this struct.
94 */
95 /*
96 * NOTE: Internally, services__create_resource_action() is preferable to
97 * resources_action_create().
98 */
99 typedef struct svc_action_s {
100 /*! Operation key (<resource>_<action>_<interval>) for resource actions,
101 * XML ID for alert actions, or NULL for generic actions
102 */
103 char *id;
104
105 //! XML ID of resource being executed for resource actions, otherwise NULL
106 char *rsc;
107
108 //! Name of action being executed for resource actions, otherwise NULL
109 char *action;
110
111 //! Action interval for recurring resource actions, otherwise 0
112 guint interval_ms;
113
114 //! Resource standard for resource actions, otherwise NULL
115 char *standard;
116
117 //! Resource provider for resource actions that require it, otherwise NULL
118 char *provider;
119
120 //! Resource agent name for resource actions, otherwise NULL
121 char *agent;
122
123 int timeout; //!< Action timeout (in milliseconds)
124
125 /*! A hash table of name/value pairs to use as parameters for resource and
126 * alert actions, otherwise NULL. These will be used to set environment
127 * variables for non-fencing resource agents and alert agents, and to send
128 * stdin to fence agents.
129 */
130 GHashTable *params;
131
132 int rc; //!< Exit status of action (set by library upon completion)
133
134 //!@{
135 //! This field should be treated as internal to Pacemaker
136 int pid; // Process ID of child
137 int cancel; // Whether this is a cancellation of a recurring action
138 //!@}
139
140 int status; //!< Execution status (enum pcmk_exec_status set by library)
141
142 /*! Action counter (set by library for resource actions, or by caller
143 * otherwise)
144 */
145 int sequence;
146
147 //!@{
148 //! This field should be treated as internal to Pacemaker
149 int expected_rc; // Unused
150 int synchronous; // Whether execution should be synchronous (blocking)
151 //!@}
152
153 enum svc_action_flags flags; //!< Flag group of enum svc_action_flags
154 char *stderr_data; //!< Action stderr (set by library)
155 char *stdout_data; //!< Action stdout (set by library)
156 void *cb_data; //!< For caller's use (not used by library)
157
158 //! This field should be treated as internal to Pacemaker
159 svc_action_private_t *opaque;
160 } svc_action_t;
161
162 /*!
163 * \brief Get a list of files or directories in a given path
164 *
165 * \param[in] root Full path to a directory to read
166 * \param[in] files Return list of files if TRUE or directories if FALSE
167 * \param[in] executable If TRUE and files is TRUE, only return executable files
168 *
169 * \return List of what was found as char * items.
170 * \note The caller is responsibile for freeing the result with
171 * g_list_free_full(list, free).
172 */
173 GList *get_directory_list(const char *root, gboolean files,
174 gboolean executable);
175
176 /*!
177 * \brief Get a list of providers
178 *
179 * \param[in] standard List providers of this resource agent standard
180 *
181 * \return List of providers as char * list items (or NULL if standard does not
182 * support providers)
183 * \note The caller is responsible for freeing the result using
184 * g_list_free_full(list, free).
185 */
186 GList *resources_list_providers(const char *standard);
187
188 /*!
189 * \brief Get a list of resource agents
190 *
191 * \param[in] standard List agents of this standard (or NULL for all)
192 * \param[in] provider List agents of this provider (or NULL for all)
193 *
194 * \return List of resource agents as char * items.
195 * \note The caller is responsible for freeing the result using
196 * g_list_free_full(list, free).
197 */
198 GList *resources_list_agents(const char *standard, const char *provider);
199
200 /*!
201 * Get list of available standards
202 *
203 * \return List of resource standards as char * items.
204 * \note The caller is responsible for freeing the result using
205 * g_list_free_full(list, free).
206 */
207 GList *resources_list_standards(void);
208
209 /*!
210 * \brief Check whether a resource agent exists on the local host
211 *
212 * \param[in] standard Resource agent standard of agent to check
213 * \param[in] provider Provider of agent to check (or NULL)
214 * \param[in] agent Name of agent to check
215 *
216 * \return TRUE if agent exists locally, otherwise FALSE
217 */
218 gboolean resources_agent_exists(const char *standard, const char *provider,
219 const char *agent);
220
221 /*!
222 * \brief Create a new resource action
223 *
224 * \param[in] name Name of resource that action is for
225 * \param[in] standard Resource agent standard
226 * \param[in] provider Resource agent provider
227 * \param[in] agent Resource agent name
228 * \param[in] action Name of action to create
229 * \param[in] interval_ms How often to repeat action (if 0, execute once)
230 * \param[in] timeout Error if not complete within this time (ms)
231 * \param[in,out] params Action parameters
232 * \param[in] flags Group of enum svc_action_flags
233 *
234 * \return Newly allocated action
235 * \note This function assumes ownership of (and may free) \p params.
236 * \note The caller is responsible for freeing the return value using
237 * services_action_free().
238 */
239 svc_action_t *resources_action_create(const char *name, const char *standard,
240 const char *provider, const char *agent,
241 const char *action, guint interval_ms,
242 int timeout, GHashTable *params,
243 enum svc_action_flags flags);
244
245 /*!
246 * \brief Reschedule a recurring action for immediate execution
247 *
248 * \param[in] name Name of resource that action is for
249 * \param[in] action Action's name
250 * \param[in] interval_ms Action's interval (in milliseconds)
251 *
252 * \return TRUE on success, otherwise FALSE
253 */
254 gboolean services_action_kick(const char *name, const char *action,
255 guint interval_ms);
256
257 const char *resources_find_service_class(const char *agent);
258
259 /*!
260 * \brief Request execution of an arbitrary command
261 *
262 * This API has useful infrastructure in place to be able to run a command
263 * in the background and get notified via a callback when the command finishes.
264 *
265 * \param[in] exec Full path to command executable
266 * \param[in] args NULL-terminated list of arguments to pass to command
267 *
268 * \return Newly allocated action object
269 */
270 svc_action_t *services_action_create_generic(const char *exec,
271 const char *args[]);
272
273 void services_action_cleanup(svc_action_t *op);
274 void services_action_free(svc_action_t *op);
275 int services_action_user(svc_action_t *op, const char *user);
276 gboolean services_action_sync(svc_action_t *op);
277
278 /*!
279 * \brief Run an action asynchronously, with callback after process is forked
280 *
281 * \param[in,out] op Action to run
282 * \param[in] action_callback Function to call when action completes
283 * (if NULL, any previously set callback will
284 * continue to be used)
285 * \param[in] action_fork_callback Function to call after child process is
286 * forked for action (if NULL, any
287 * previously set callback will continue to
288 * be used)
289 *
290 * \retval TRUE if the caller should not free or otherwise use \p op again,
291 * because one of these conditions is true:
292 *
293 * * \p op is NULL.
294 * * The action was successfully initiated, in which case
295 * \p action_fork_callback has been called, but \p action_callback has
296 * not (it will be called when the action completes).
297 * * The action's ID matched an existing recurring action. The existing
298 * action has taken over the callback and callback data from \p op
299 * and has been re-initiated asynchronously, and \p op has been freed.
300 * * Another action for the same resource is in flight, and \p op will
301 * be blocked until it completes.
302 * * The action could not be initiated, and is either non-recurring or
303 * being cancelled. \p action_fork_callback has not been called, but
304 * \p action_callback has, and \p op has been freed.
305 *
306 * \retval FALSE if \op is still valid, because the action cannot be initiated,
307 * and is a recurring action that is not being cancelled.
308 * \p action_fork_callback has not been called, but \p action_callback
309 * has, and a timer has been set for the next invocation of \p op.
310 */
311 gboolean services_action_async_fork_notify(svc_action_t *op,
312 void (*action_callback) (svc_action_t *),
313 void (*action_fork_callback) (svc_action_t *));
314
315 /*!
316 * \brief Request asynchronous execution of an action
317 *
318 * \param[in,out] op Action to execute
319 * \param[in] action_callback Function to call when the action completes
320 * (if NULL, any previously set callback will
321 * continue to be used)
322 *
323 * \retval TRUE if the caller should not free or otherwise use \p op again,
324 * because one of these conditions is true:
325 *
326 * * \p op is NULL.
327 * * The action was successfully initiated, in which case
328 * \p action_callback has not been called (it will be called when the
329 * action completes).
330 * * The action's ID matched an existing recurring action. The existing
331 * action has taken over the callback and callback data from \p op
332 * and has been re-initiated asynchronously, and \p op has been freed.
333 * * Another action for the same resource is in flight, and \p op will
334 * be blocked until it completes.
335 * * The action could not be initiated, and is either non-recurring or
336 * being cancelled. \p action_callback has been called, and \p op has
337 * been freed.
338 *
339 * \retval FALSE if \op is still valid, because the action cannot be initiated,
340 * and is a recurring action that is not being cancelled.
341 * \p action_callback has been called, and a timer has been set for the
342 * next invocation of \p op.
343 */
344 gboolean services_action_async(svc_action_t *op,
345 void (*action_callback) (svc_action_t *));
346
347 gboolean services_action_cancel(const char *name, const char *action,
348 guint interval_ms);
349
350 /* functions for alert agents */
351 svc_action_t *services_alert_create(const char *id, const char *exec,
352 int timeout, GHashTable *params,
353 int sequence, void *cb_data);
354 gboolean services_alert_async(svc_action_t *action,
355 void (*cb)(svc_action_t *op));
356
357 enum ocf_exitcode services_result2ocf(const char *standard, const char *action,
358 int exit_status);
359
360 # ifdef __cplusplus
361 }
362 # endif
363
364 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
365 #include <crm/services_compat.h>
366 #endif
367
368 #endif /* __PCMK_SERVICES__ */