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