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 //!@{
79 //! \deprecated Do not use
80
81 enum nagios_exitcode {
82 NAGIOS_STATE_OK = 0,
83 NAGIOS_STATE_WARNING = 1,
84 NAGIOS_STATE_CRITICAL = 2,
85 NAGIOS_STATE_UNKNOWN = 3,
86
87 /* This is a custom Pacemaker value (not a nagios convention), used as an
88 * intermediate value between the services library and the executor, so the
89 * executor can map it to the corresponding OCF code.
90 */
91 NAGIOS_INSUFFICIENT_PRIV = 100,
92
93 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
94 NAGIOS_STATE_DEPENDENT = 4,
95 NAGIOS_NOT_INSTALLED = 101,
96 #endif
97 };
98
99 //!@}
100
101 enum svc_action_flags {
102 /* On timeout, only kill pid, do not kill entire pid group */
103 SVC_ACTION_LEAVE_GROUP = 0x01,
104 SVC_ACTION_NON_BLOCKED = 0x02,
105 };
106
107 typedef struct svc_action_private_s svc_action_private_t;
108
109 /*!
110 * \brief Object for executing external actions
111 *
112 * \note This object should never be instantiated directly, but instead created
113 * using one of the constructor functions (resources_action_create() for
114 * resource agents, services_alert_create() for alert agents, or
115 * services_action_create_generic() for generic executables). Similarly,
116 * do not use sizeof() on this struct.
117 */
118 /*
119 * NOTE: Internally, services__create_resource_action() is preferable to
120 * resources_action_create().
121 */
122 typedef struct svc_action_s {
123 /*! Operation key (<resource>_<action>_<interval>) for resource actions,
124 * XML ID for alert actions, or NULL for generic actions
125 */
126 char *id;
127
128 //! XML ID of resource being executed for resource actions, otherwise NULL
129 char *rsc;
130
131 //! Name of action being executed for resource actions, otherwise NULL
132 char *action;
133
134 //! Action interval for recurring resource actions, otherwise 0
135 guint interval_ms;
136
137 //! Resource standard for resource actions, otherwise NULL
138 char *standard;
139
140 //! Resource provider for resource actions that require it, otherwise NULL
141 char *provider;
142
143 //! Resource agent name for resource actions, otherwise NULL
144 char *agent;
145
146 int timeout; //!< Action timeout (in milliseconds)
147
148 /*! A hash table of name/value pairs to use as parameters for resource and
149 * alert actions, otherwise NULL. These will be used to set environment
150 * variables for non-fencing resource agents and alert agents, and to send
151 * stdin to fence agents.
152 */
153 GHashTable *params;
154
155 int rc; //!< Exit status of action (set by library upon completion)
156
157 //!@{
158 //! This field should be treated as internal to Pacemaker
159 int pid; // Process ID of child
160 int cancel; // Whether this is a cancellation of a recurring action
161 //!@}
162
163 int status; //!< Execution status (enum pcmk_exec_status set by library)
164
165 /*! Action counter (set by library for resource actions, or by caller
166 * otherwise)
167 */
168 int sequence;
169
170 //!@{
171 //! This field should be treated as internal to Pacemaker
172 int expected_rc; // Unused
173 int synchronous; // Whether execution should be synchronous (blocking)
174 //!@}
175
176 enum svc_action_flags flags; //!< Flag group of enum svc_action_flags
177 char *stderr_data; //!< Action stderr (set by library)
178 char *stdout_data; //!< Action stdout (set by library)
179 void *cb_data; //!< For caller's use (not used by library)
180
181 //! This field should be treated as internal to Pacemaker
182 svc_action_private_t *opaque;
183 } svc_action_t;
184
185 /*!
186 * \brief Get a list of files or directories in a given path
187 *
188 * \param[in] root Full path to a directory to read
189 * \param[in] files Return list of files if TRUE or directories if FALSE
190 * \param[in] executable If TRUE and files is TRUE, only return executable files
191 *
192 * \return List of what was found as char * items.
193 * \note The caller is responsibile for freeing the result with
194 * g_list_free_full(list, free).
195 */
196 GList *get_directory_list(const char *root, gboolean files,
197 gboolean executable);
198
199 /*!
200 * \brief Get a list of providers
201 *
202 * \param[in] standard List providers of this resource agent standard
203 *
204 * \return List of providers as char * list items (or NULL if standard does not
205 * support providers)
206 * \note The caller is responsible for freeing the result using
207 * g_list_free_full(list, free).
208 */
209 GList *resources_list_providers(const char *standard);
210
211 /*!
212 * \brief Get a list of resource agents
213 *
214 * \param[in] standard List agents of this standard (or NULL for all)
215 * \param[in] provider List agents of this provider (or NULL for all)
216 *
217 * \return List of resource agents as char * items.
218 * \note The caller is responsible for freeing the result using
219 * g_list_free_full(list, free).
220 */
221 GList *resources_list_agents(const char *standard, const char *provider);
222
223 /*!
224 * Get list of available standards
225 *
226 * \return List of resource standards as char * items.
227 * \note The caller is responsible for freeing the result using
228 * g_list_free_full(list, free).
229 */
230 GList *resources_list_standards(void);
231
232 /*!
233 * \brief Check whether a resource agent exists on the local host
234 *
235 * \param[in] standard Resource agent standard of agent to check
236 * \param[in] provider Provider of agent to check (or NULL)
237 * \param[in] agent Name of agent to check
238 *
239 * \return TRUE if agent exists locally, otherwise FALSE
240 */
241 gboolean resources_agent_exists(const char *standard, const char *provider,
242 const char *agent);
243
244 /*!
245 * \brief Create a new resource action
246 *
247 * \param[in] name Name of resource that action is for
248 * \param[in] standard Resource agent standard
249 * \param[in] provider Resource agent provider
250 * \param[in] agent Resource agent name
251 * \param[in] action Name of action to create
252 * \param[in] interval_ms How often to repeat action (if 0, execute once)
253 * \param[in] timeout Error if not complete within this time (ms)
254 * \param[in,out] params Action parameters
255 * \param[in] flags Group of enum svc_action_flags
256 *
257 * \return Newly allocated action
258 * \note This function assumes ownership of (and may free) \p params.
259 * \note The caller is responsible for freeing the return value using
260 * services_action_free().
261 */
262 svc_action_t *resources_action_create(const char *name, const char *standard,
263 const char *provider, const char *agent,
264 const char *action, guint interval_ms,
265 int timeout, GHashTable *params,
266 enum svc_action_flags flags);
267
268 /*!
269 * \brief Reschedule a recurring action for immediate execution
270 *
271 * \param[in] name Name of resource that action is for
272 * \param[in] action Action's name
273 * \param[in] interval_ms Action's interval (in milliseconds)
274 *
275 * \return TRUE on success, otherwise FALSE
276 */
277 gboolean services_action_kick(const char *name, const char *action,
278 guint interval_ms);
279
280 const char *resources_find_service_class(const char *agent);
281
282 /*!
283 * \brief Request execution of an arbitrary command
284 *
285 * This API has useful infrastructure in place to be able to run a command
286 * in the background and get notified via a callback when the command finishes.
287 *
288 * \param[in] exec Full path to command executable
289 * \param[in] args NULL-terminated list of arguments to pass to command
290 *
291 * \return Newly allocated action object
292 */
293 svc_action_t *services_action_create_generic(const char *exec,
294 const char *args[]);
295
296 void services_action_cleanup(svc_action_t *op);
297 void services_action_free(svc_action_t *op);
298 int services_action_user(svc_action_t *op, const char *user);
299 gboolean services_action_sync(svc_action_t *op);
300
301 /*!
302 * \brief Run an action asynchronously, with callback after process is forked
303 *
304 * \param[in,out] op Action to run
305 * \param[in] action_callback Function to call when action completes
306 * (if NULL, any previously set callback will
307 * continue to be used)
308 * \param[in] action_fork_callback Function to call after child process is
309 * forked for action (if NULL, any
310 * previously set callback will continue to
311 * be used)
312 *
313 * \retval TRUE if the caller should not free or otherwise use \p op again,
314 * because one of these conditions is true:
315 *
316 * * \p op is NULL.
317 * * The action was successfully initiated, in which case
318 * \p action_fork_callback has been called, but \p action_callback has
319 * not (it will be called when the action completes).
320 * * The action's ID matched an existing recurring action. The existing
321 * action has taken over the callback and callback data from \p op
322 * and has been re-initiated asynchronously, and \p op has been freed.
323 * * Another action for the same resource is in flight, and \p op will
324 * be blocked until it completes.
325 * * The action could not be initiated, and is either non-recurring or
326 * being cancelled. \p action_fork_callback has not been called, but
327 * \p action_callback has, and \p op has been freed.
328 *
329 * \retval FALSE if \op is still valid, because the action cannot be initiated,
330 * and is a recurring action that is not being cancelled.
331 * \p action_fork_callback has not been called, but \p action_callback
332 * has, and a timer has been set for the next invocation of \p op.
333 */
334 gboolean services_action_async_fork_notify(svc_action_t *op,
335 void (*action_callback) (svc_action_t *),
336 void (*action_fork_callback) (svc_action_t *));
337
338 /*!
339 * \brief Request asynchronous execution of an action
340 *
341 * \param[in,out] op Action to execute
342 * \param[in] action_callback Function to call when the action completes
343 * (if NULL, any previously set callback will
344 * continue to be used)
345 *
346 * \retval TRUE if the caller should not free or otherwise use \p op again,
347 * because one of these conditions is true:
348 *
349 * * \p op is NULL.
350 * * The action was successfully initiated, in which case
351 * \p action_callback has not been called (it will be called when the
352 * action completes).
353 * * The action's ID matched an existing recurring action. The existing
354 * action has taken over the callback and callback data from \p op
355 * and has been re-initiated asynchronously, and \p op has been freed.
356 * * Another action for the same resource is in flight, and \p op will
357 * be blocked until it completes.
358 * * The action could not be initiated, and is either non-recurring or
359 * being cancelled. \p action_callback has been called, and \p op has
360 * been freed.
361 *
362 * \retval FALSE if \op is still valid, because the action cannot be initiated,
363 * and is a recurring action that is not being cancelled.
364 * \p action_callback has been called, and a timer has been set for the
365 * next invocation of \p op.
366 */
367 gboolean services_action_async(svc_action_t *op,
368 void (*action_callback) (svc_action_t *));
369
370 gboolean services_action_cancel(const char *name, const char *action,
371 guint interval_ms);
372
373 /* functions for alert agents */
374 svc_action_t *services_alert_create(const char *id, const char *exec,
375 int timeout, GHashTable *params,
376 int sequence, void *cb_data);
377 gboolean services_alert_async(svc_action_t *action,
378 void (*cb)(svc_action_t *op));
379
380 enum ocf_exitcode services_result2ocf(const char *standard, const char *action,
381 int exit_status);
382
383 static inline const char *services_ocf_exitcode_str(enum ocf_exitcode code) {
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
384 switch (code) {
385 case PCMK_OCF_OK:
386 return "ok";
387 case PCMK_OCF_UNKNOWN_ERROR:
388 return "error";
389 case PCMK_OCF_INVALID_PARAM:
390 return "invalid parameter";
391 case PCMK_OCF_UNIMPLEMENT_FEATURE:
392 return "unimplemented feature";
393 case PCMK_OCF_INSUFFICIENT_PRIV:
394 return "insufficient privileges";
395 case PCMK_OCF_NOT_INSTALLED:
396 return "not installed";
397 case PCMK_OCF_NOT_CONFIGURED:
398 return "not configured";
399 case PCMK_OCF_NOT_RUNNING:
400 return "not running";
401 case PCMK_OCF_RUNNING_PROMOTED:
402 return "promoted";
403 case PCMK_OCF_FAILED_PROMOTED:
404 return "promoted (failed)";
405 case PCMK_OCF_DEGRADED:
406 return "OCF_DEGRADED";
407 case PCMK_OCF_DEGRADED_PROMOTED:
408 return "promoted (degraded)";
409
410 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
411 case PCMK_OCF_NOT_SUPPORTED:
412 return "not supported (DEPRECATED STATUS)";
413 case PCMK_OCF_CANCELLED:
414 return "cancelled (DEPRECATED STATUS)";
415 case PCMK_OCF_OTHER_ERROR:
416 return "other error (DEPRECATED STATUS)";
417 case PCMK_OCF_SIGNAL:
418 return "interrupted by signal (DEPRECATED STATUS)";
419 case PCMK_OCF_PENDING:
420 return "pending (DEPRECATED STATUS)";
421 case PCMK_OCF_TIMEOUT:
422 return "timeout (DEPRECATED STATUS)";
423 #endif
424 default:
425 return "unknown";
426 }
427 }
428
429 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
430 #include <crm/services_compat.h>
431 #endif
432
433 # ifdef __cplusplus
434 }
435 # endif
436
437 #endif /* __PCMK_SERVICES__ */