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