1 /*
2 * Copyright 2010-2021 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_SERVICES__
11 # define __PCMK_SERVICES__
12
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16
17 /**
18 * \file
19 * \brief Services API
20 * \ingroup core
21 */
22
23 # include <glib.h>
24 # include <stdio.h>
25 # include <stdint.h>
26 # include <string.h>
27 # include <stdbool.h>
28 # include <sys/types.h>
29
30 # include <crm_config.h> // OCF_ROOT_DIR
31 # include "common/results.h"
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
47 /* This is the string passed in the OCF_EXIT_REASON_PREFIX environment variable.
48 * The stderr output that occurs after this prefix is encountered is considered
49 * the exit reason for a completed operation.
50 */
51 #define PCMK_OCF_REASON_PREFIX "ocf-exit-reason:"
52
53 // Agent version to use if agent doesn't specify one
54 #define PCMK_DEFAULT_AGENT_VERSION "0.1"
55
56 enum lsb_exitcode {
57 PCMK_LSB_OK = 0,
58 PCMK_LSB_UNKNOWN_ERROR = 1,
59 PCMK_LSB_INVALID_PARAM = 2,
60 PCMK_LSB_UNIMPLEMENT_FEATURE = 3,
61 PCMK_LSB_INSUFFICIENT_PRIV = 4,
62 PCMK_LSB_NOT_INSTALLED = 5,
63 PCMK_LSB_NOT_CONFIGURED = 6,
64 PCMK_LSB_NOT_RUNNING = 7,
65 };
66
67 /* The return codes for the status operation are not the same for other
68 * operatios - go figure
69 */
70 enum lsb_status_exitcode {
71 PCMK_LSB_STATUS_OK = 0,
72 PCMK_LSB_STATUS_VAR_PID = 1,
73 PCMK_LSB_STATUS_VAR_LOCK = 2,
74 PCMK_LSB_STATUS_NOT_RUNNING = 3,
75 PCMK_LSB_STATUS_UNKNOWN = 4,
76
77 /* custom codes should be in the 150-199 range reserved for application use */
78 PCMK_LSB_STATUS_NOT_INSTALLED = 150,
79 PCMK_LSB_STATUS_INSUFFICIENT_PRIV = 151,
80 };
81
82 enum nagios_exitcode {
83 NAGIOS_STATE_OK = 0,
84 NAGIOS_STATE_WARNING = 1,
85 NAGIOS_STATE_CRITICAL = 2,
86 NAGIOS_STATE_UNKNOWN = 3,
87
88 /* This is a custom Pacemaker value (not a nagios convention), used as an
89 * intermediate value between the services library and the executor, so the
90 * executor can map it to the corresponding OCF code.
91 */
92 NAGIOS_INSUFFICIENT_PRIV = 100,
93
94 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
95 NAGIOS_STATE_DEPENDENT = 4, //! \deprecated Unused
96 NAGIOS_NOT_INSTALLED = 101, //! \deprecated Unused
97 #endif
98 };
99
100 enum svc_action_flags {
101 /* On timeout, only kill pid, do not kill entire pid group */
102 SVC_ACTION_LEAVE_GROUP = 0x01,
103 SVC_ACTION_NON_BLOCKED = 0x02,
104 };
105
106 typedef struct svc_action_private_s svc_action_private_t;
107
108 /*!
109 * \brief Object for executing external actions
110 *
111 * \note This object should never be instantiated directly, but instead created
112 * using one of the constructor functions (resources_action_create() for
113 * resource agents, services_alert_create() for alert agents, or
114 * services_action_create_generic() for generic executables). Similarly,
115 * do not use sizeof() on this struct.
116 *
117 * \internal Internally, services__create_resource_action() is preferable to
118 * resources_action_create().
119 */
120 typedef struct svc_action_s {
121 /*! Operation key (<resource>_<action>_<interval>) for resource actions,
122 * XML ID for alert actions, or NULL for generic actions
123 */
124 char *id;
125
126 //! XML ID of resource being executed for resource actions, otherwise NULL
127 char *rsc;
128
129 //! Name of action being executed for resource actions, otherwise NULL
130 char *action;
131
132 //! Action interval for recurring resource actions, otherwise 0
133 guint interval_ms;
134
135 //! Resource standard for resource actions, otherwise NULL
136 char *standard;
137
138 //! Resource provider for resource actions that require it, otherwise NULL
139 char *provider;
140
141 //! Resource agent name for resource actions, otherwise NULL
142 char *agent;
143
144 int timeout; //!< Action timeout (in milliseconds)
145
146 /*! A hash table of name/value pairs to use as parameters for resource and
147 * alert actions, otherwise NULL. These will be used to set environment
148 * variables for non-fencing resource agents and alert agents, and to send
149 * stdin to fence agents.
150 */
151 GHashTable *params;
152
153 int rc; //!< Exit status of action (set by library upon completion)
154
155 //!@{
156 //! This field should be treated as internal to Pacemaker
157 int pid; // Process ID of child
158 int cancel; // Whether this is a cancellation of a recurring action
159 //!@}
160
161 int status; //!< Execution status (enum pcmk_exec_status set by library)
162
163 /*! Action counter (set by library for resource actions, or by caller
164 * otherwise)
165 */
166 int sequence;
167
168 //!@{
169 //! This field should be treated as internal to Pacemaker
170 int expected_rc; // Unused
171 int synchronous; // Whether execution should be synchronous (blocking)
172 //!@}
173
174 enum svc_action_flags flags; //!< Flag group of enum svc_action_flags
175 char *stderr_data; //!< Action stderr (set by library)
176 char *stdout_data; //!< Action stdout (set by library)
177 void *cb_data; //!< For caller's use (not used by library)
178
179 //! This field should be treated as internal to Pacemaker
180 svc_action_private_t *opaque;
181 } svc_action_t;
182
183 /**
184 * \brief Get a list of files or directories in a given path
185 *
186 * \param[in] root full path to a directory to read
187 * \param[in] files return list of files if TRUE or directories if FALSE
188 * \param[in] executable if TRUE and files is TRUE, only return executable files
189 *
190 * \return a list of what was found. The list items are char *.
191 * \note It is the caller's responsibility to free the result with g_list_free_full(list, free).
192 */
193 GList *get_directory_list(const char *root, gboolean files, gboolean executable);
194
195 /**
196 * \brief Get a list of providers
197 *
198 * \param[in] standard list providers of this standard (e.g. ocf, lsb, etc.)
199 *
200 * \return a list of providers as char * list items (or NULL if standard does not support providers)
201 * \note The caller is responsible for freeing the result using g_list_free_full(list, free).
202 */
203 GList *resources_list_providers(const char *standard);
204
205 /**
206 * \brief Get a list of resource agents
207 *
208 * \param[in] standard list agents using this standard (e.g. ocf, lsb, etc.) (or NULL for all)
209 * \param[in] provider list agents from this provider (or NULL for all)
210 *
211 * \return a list of resource agents. The list items are char *.
212 * \note The caller is responsible for freeing the result using g_list_free_full(list, free).
213 */
214 GList *resources_list_agents(const char *standard, const char *provider);
215
216 /**
217 * Get list of available standards
218 *
219 * \return a list of resource standards. The list items are char *. This list _must_
220 * be destroyed using g_list_free_full(list, free).
221 */
222 GList *resources_list_standards(void);
223
224 /**
225 * Does the given standard, provider, and agent describe a resource that can exist?
226 *
227 * \param[in] standard Which class of agent does the resource belong to?
228 * \param[in] provider What provides the agent (NULL for most standards)?
229 * \param[in] agent What is the name of the agent?
230 *
231 * \return A boolean
232 */
233 gboolean resources_agent_exists(const char *standard, const char *provider, const char *agent);
234
235 /**
236 * \brief Create a new resource action
237 *
238 * \param[in] name Name of resource
239 * \param[in] standard Resource agent standard (ocf, lsb, etc.)
240 * \param[in] provider Resource agent provider
241 * \param[in] agent Resource agent name
242 * \param[in] action action (start, stop, monitor, etc.)
243 * \param[in] interval_ms How often to repeat this action (if 0, execute once)
244 * \param[in] timeout Consider action failed if it does not complete in this many milliseconds
245 * \param[in] params Action parameters
246 *
247 * \return newly allocated action instance
248 *
249 * \post After the call, 'params' is owned, and later free'd by the svc_action_t result
250 * \note The caller is responsible for freeing the return value using
251 * services_action_free().
252 */
253 svc_action_t *resources_action_create(const char *name, const char *standard,
254 const char *provider, const char *agent,
255 const char *action, guint interval_ms,
256 int timeout /* ms */, GHashTable *params,
257 enum svc_action_flags flags);
258
259 /**
260 * Kick a recurring action so it is scheduled immediately for re-execution
261 */
262 gboolean services_action_kick(const char *name, const char *action,
263 guint interval_ms);
264
265 const char *resources_find_service_class(const char *agent);
266
267 /**
268 * Utilize services API to execute an arbitrary command.
269 *
270 * This API has useful infrastructure in place to be able to run a command
271 * in the background and get notified via a callback when the command finishes.
272 *
273 * \param[in] exec command to execute
274 * \param[in] args arguments to the command, NULL terminated
275 *
276 * \return a svc_action_t object, used to pass to the execute function
277 * (services_action_sync() or services_action_async()) and is
278 * provided to the callback.
279 */
280 svc_action_t *services_action_create_generic(const char *exec, const char *args[]);
281
282 void services_action_cleanup(svc_action_t * op);
283 void services_action_free(svc_action_t * op);
284 int services_action_user(svc_action_t *op, const char *user);
285
286 gboolean services_action_sync(svc_action_t * op);
287
288 /**
289 * \brief Run an action asynchronously
290 *
291 * \param[in] op Action to run
292 * \param[in] action_callback Function to call when the action completes
293 * \param[in] action_fork_callback Function to call after action process forks
294 *
295 * \return TRUE if execution was successfully initiated, FALSE otherwise (in
296 * which case the callback will not be called)
297 */
298 gboolean services_action_async_fork_notify(svc_action_t * op,
299 void (*action_callback) (svc_action_t *),
300 void (*action_fork_callback) (svc_action_t *));
301
302 gboolean services_action_async(svc_action_t * op,
303 void (*action_callback) (svc_action_t *));
304
305 gboolean services_action_cancel(const char *name, const char *action,
306 guint interval_ms);
307
308 /* functions for alert agents */
309 svc_action_t *services_alert_create(const char *id, const char *exec,
310 int timeout, GHashTable *params,
311 int sequence, void *cb_data);
312 gboolean services_alert_async(svc_action_t *action,
313 void (*cb)(svc_action_t *op));
314
315 enum ocf_exitcode services_result2ocf(const char *standard, const char *action,
316 int exit_status);
317
318 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)
*/
319 switch (code) {
320 case PCMK_OCF_OK:
321 return "ok";
322 case PCMK_OCF_UNKNOWN_ERROR:
323 return "error";
324 case PCMK_OCF_INVALID_PARAM:
325 return "invalid parameter";
326 case PCMK_OCF_UNIMPLEMENT_FEATURE:
327 return "unimplemented feature";
328 case PCMK_OCF_INSUFFICIENT_PRIV:
329 return "insufficient privileges";
330 case PCMK_OCF_NOT_INSTALLED:
331 return "not installed";
332 case PCMK_OCF_NOT_CONFIGURED:
333 return "not configured";
334 case PCMK_OCF_NOT_RUNNING:
335 return "not running";
336 case PCMK_OCF_RUNNING_PROMOTED:
337 return "promoted";
338 case PCMK_OCF_FAILED_PROMOTED:
339 return "promoted (failed)";
340 case PCMK_OCF_DEGRADED:
341 return "OCF_DEGRADED";
342 case PCMK_OCF_DEGRADED_PROMOTED:
343 return "promoted (degraded)";
344
345 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
346 case PCMK_OCF_NOT_SUPPORTED:
347 return "not supported (DEPRECATED STATUS)";
348 case PCMK_OCF_CANCELLED:
349 return "cancelled (DEPRECATED STATUS)";
350 case PCMK_OCF_OTHER_ERROR:
351 return "other error (DEPRECATED STATUS)";
352 case PCMK_OCF_SIGNAL:
353 return "interrupted by signal (DEPRECATED STATUS)";
354 case PCMK_OCF_PENDING:
355 return "pending (DEPRECATED STATUS)";
356 case PCMK_OCF_TIMEOUT:
357 return "timeout (DEPRECATED STATUS)";
358 #endif
359 default:
360 return "unknown";
361 }
362 }
363
364 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
365 #include <crm/services_compat.h>
366 #endif
367
368 # ifdef __cplusplus
369 }
370 # endif
371
372 #endif /* __PCMK_SERVICES__ */