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 #  ifndef LSB_ROOT_DIR
34 #    define LSB_ROOT_DIR "/etc/init.d"
35 #  endif
36 
37 /* TODO: Autodetect these two ?*/
38 #  ifndef SYSTEMCTL
39 #    define SYSTEMCTL "/bin/systemctl"
40 #  endif
41 
42 /* Known resource classes */
43 #define PCMK_RESOURCE_CLASS_OCF     "ocf"
44 #define PCMK_RESOURCE_CLASS_SERVICE "service"
45 #define PCMK_RESOURCE_CLASS_LSB     "lsb"
46 #define PCMK_RESOURCE_CLASS_SYSTEMD "systemd"
47 #define PCMK_RESOURCE_CLASS_UPSTART "upstart"
48 #define PCMK_RESOURCE_CLASS_NAGIOS  "nagios"
49 #define PCMK_RESOURCE_CLASS_STONITH "stonith"
50 
51 /* This is the string passed in the OCF_EXIT_REASON_PREFIX environment variable.
52  * The stderr output that occurs after this prefix is encountered is considered
53  * the exit reason for a completed operation.
54  */
55 #define PCMK_OCF_REASON_PREFIX "ocf-exit-reason:"
56 
57 // Agent version to use if agent doesn't specify one
58 #define PCMK_DEFAULT_AGENT_VERSION "0.1"
59 
60 enum lsb_exitcode {
61     PCMK_LSB_OK                  = 0,
62     PCMK_LSB_UNKNOWN_ERROR       = 1,
63     PCMK_LSB_INVALID_PARAM       = 2,
64     PCMK_LSB_UNIMPLEMENT_FEATURE = 3,
65     PCMK_LSB_INSUFFICIENT_PRIV   = 4,
66     PCMK_LSB_NOT_INSTALLED       = 5,
67     PCMK_LSB_NOT_CONFIGURED      = 6,
68     PCMK_LSB_NOT_RUNNING         = 7,
69 };
70 
71 /* The return codes for the status operation are not the same for other
72  * operatios - go figure
73  */
74 enum lsb_status_exitcode {
75     PCMK_LSB_STATUS_OK             = 0,
76     PCMK_LSB_STATUS_VAR_PID        = 1,
77     PCMK_LSB_STATUS_VAR_LOCK       = 2,
78     PCMK_LSB_STATUS_NOT_RUNNING    = 3,
79     PCMK_LSB_STATUS_UNKNOWN        = 4,
80 
81     /* custom codes should be in the 150-199 range reserved for application use */
82     PCMK_LSB_STATUS_NOT_INSTALLED      = 150,
83     PCMK_LSB_STATUS_INSUFFICIENT_PRIV  = 151,
84 };
85 
86 enum op_status {
87     PCMK_LRM_OP_UNKNOWN = -2,
88     PCMK_LRM_OP_PENDING = -1,
89     PCMK_LRM_OP_DONE,
90     PCMK_LRM_OP_CANCELLED,
91     PCMK_LRM_OP_TIMEOUT,
92     PCMK_LRM_OP_NOTSUPPORTED,
93     PCMK_LRM_OP_ERROR,
94     PCMK_LRM_OP_ERROR_HARD,
95     PCMK_LRM_OP_ERROR_FATAL,
96     PCMK_LRM_OP_NOT_INSTALLED,
97     PCMK_LRM_OP_NOT_CONNECTED,
98     PCMK_LRM_OP_INVALID,
99 };
100 
101 enum nagios_exitcode {
102     NAGIOS_STATE_OK        = 0,
103     NAGIOS_STATE_WARNING   = 1,
104     NAGIOS_STATE_CRITICAL  = 2,
105     NAGIOS_STATE_UNKNOWN   = 3,
106     NAGIOS_STATE_DEPENDENT = 4,
107 
108     NAGIOS_INSUFFICIENT_PRIV = 100,
109     NAGIOS_NOT_INSTALLED     = 101,
110 };
111 
112 enum svc_action_flags {
113     /* On timeout, only kill pid, do not kill entire pid group */
114     SVC_ACTION_LEAVE_GROUP = 0x01,
115     SVC_ACTION_NON_BLOCKED = 0x02,
116 };
117 
118 typedef struct svc_action_private_s svc_action_private_t;
119 typedef struct svc_action_s {
120     char *id;
121     char *rsc;
122     char *action;
123     guint interval_ms;
124 
125     char *standard;
126     char *provider;
127     char *agent;
128 
129     int timeout;
130     GHashTable *params; /* used for setting up environment for ocf-ra &
131                            alert agents
132                            and to be sent via stdin for fence-agents
133                          */
134 
135     int rc;
136     int pid;
137     int cancel;
138     int status;
139     int sequence;
140     int expected_rc;
141     int synchronous;
142     enum svc_action_flags flags;
143 
144     char *stderr_data;
145     char *stdout_data;
146 
147     /*!
148      * Data stored by the creator of the action.
149      *
150      * This may be used to hold data that is needed later on by a callback,
151      * for example.
152      */
153     void *cb_data;
154 
155     svc_action_private_t *opaque;
156 } svc_action_t;
157 
158 /**
159  * \brief Get a list of files or directories in a given path
160  *
161  * \param[in] root       full path to a directory to read
162  * \param[in] files      return list of files if TRUE or directories if FALSE
163  * \param[in] executable if TRUE and files is TRUE, only return executable files
164  *
165  * \return a list of what was found.  The list items are char *.
166  * \note It is the caller's responsibility to free the result with g_list_free_full(list, free).
167  */
168     GList *get_directory_list(const char *root, gboolean files, gboolean executable);
169 
170 /**
171  * Get a list of services
172  *
173  * \return a list of services.  The list items are gchar *.  This list _must_
174  *         be destroyed using g_list_free_full(list, free).
175  */
176     GList *services_list(void);
177 
178 /**
179  * \brief Get a list of providers
180  *
181  * \param[in] standard  list providers of this standard (e.g. ocf, lsb, etc.)
182  *
183  * \return a list of providers as char * list items (or NULL if standard does not support providers)
184  * \note The caller is responsible for freeing the result using 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 using this standard (e.g. ocf, lsb, etc.) (or NULL for all)
192  * \param[in] provider  list agents from this provider (or NULL for all)
193  *
194  * \return a list of resource agents.  The list items are char *.
195  * \note The caller is responsible for freeing the result using g_list_free_full(list, free).
196  */
197     GList *resources_list_agents(const char *standard, const char *provider);
198 
199 /**
200  * Get list of available standards
201  *
202  * \return a list of resource standards. The list items are char *. This list _must_
203  *         be destroyed using g_list_free_full(list, free).
204  */
205     GList *resources_list_standards(void);
206 
207 /**
208  * Does the given standard, provider, and agent describe a resource that can exist?
209  *
210  * \param[in] standard  Which class of agent does the resource belong to?
211  * \param[in] provider  What provides the agent (NULL for most standards)?
212  * \param[in] agent     What is the name of the agent?
213  *
214  * \return A boolean
215  */
216     gboolean resources_agent_exists(const char *standard, const char *provider, const char *agent);
217 
218 svc_action_t *services_action_create(const char *name, const char *action,
219                                      guint interval_ms, int timeout /* ms */);
220 
221 /**
222  * \brief Create a new resource action
223  *
224  * \param[in] name        Name of resource
225  * \param[in] standard    Resource agent standard (ocf, lsb, etc.)
226  * \param[in] provider    Resource agent provider
227  * \param[in] agent       Resource agent name
228  * \param[in] action      action (start, stop, monitor, etc.)
229  * \param[in] interval_ms How often to repeat this action (if 0, execute once)
230  * \param[in] timeout     Consider action failed if it does not complete in this many milliseconds
231  * \param[in] params      Action parameters
232  *
233  * \return newly allocated action instance
234  *
235  * \post After the call, 'params' is owned, and later free'd by the svc_action_t result
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 /* ms */, GHashTable *params,
243                                       enum svc_action_flags flags);
244 
245 /**
246  * Kick a recurring action so it is scheduled immediately for re-execution
247  */
248 gboolean services_action_kick(const char *name, const char *action,
249                               guint interval_ms);
250 
251     const char *resources_find_service_class(const char *agent);
252 
253 /**
254  * Utilize services API to execute an arbitrary command.
255  *
256  * This API has useful infrastructure in place to be able to run a command
257  * in the background and get notified via a callback when the command finishes.
258  *
259  * \param[in] exec command to execute
260  * \param[in] args arguments to the command, NULL terminated
261  *
262  * \return a svc_action_t object, used to pass to the execute function
263  * (services_action_sync() or services_action_async()) and is
264  * provided to the callback.
265  */
266     svc_action_t *services_action_create_generic(const char *exec, const char *args[]);
267 
268     void services_action_cleanup(svc_action_t * op);
269     void services_action_free(svc_action_t * op);
270     int services_action_user(svc_action_t *op, const char *user);
271 
272     gboolean services_action_sync(svc_action_t * op);
273 
274 /**
275  * Run an action asynchronously.
276  *
277  * \param[in] op services action data
278  * \param[in] action_callback callback for when the action completes
279  * \param[in] action_fork_callback callback for when action forked successfully
280  *
281  * \retval TRUE succesfully started execution
282  * \retval FALSE failed to start execution, no callback will be received
283  */
284     gboolean services_action_async_fork_notify(svc_action_t * op,
285         void (*action_callback) (svc_action_t *),
286         void (*action_fork_callback) (svc_action_t *));
287 
288     gboolean services_action_async(svc_action_t * op,
289                                    void (*action_callback) (svc_action_t *));
290 
291 gboolean services_action_cancel(const char *name, const char *action,
292                                 guint interval_ms);
293 
294 /* functions for alert agents */
295 svc_action_t *services_alert_create(const char *id, const char *exec,
296                                    int timeout, GHashTable *params,
297                                    int sequence, void *cb_data);
298 gboolean services_alert_async(svc_action_t *action,
299                               void (*cb)(svc_action_t *op));
300 
services_lrm_status_str(enum op_status status)301     static inline const char *services_lrm_status_str(enum op_status status) {
302         switch (status) {
303             case PCMK_LRM_OP_PENDING:
304                 return "pending";
305                 case PCMK_LRM_OP_DONE:return "complete";
306                 case PCMK_LRM_OP_CANCELLED:return "Cancelled";
307                 case PCMK_LRM_OP_TIMEOUT:return "Timed Out";
308                 case PCMK_LRM_OP_NOTSUPPORTED:return "NOT SUPPORTED";
309                 case PCMK_LRM_OP_ERROR:return "Error";
310                 case PCMK_LRM_OP_NOT_INSTALLED:return "Not installed";
311                 case PCMK_LRM_OP_NOT_CONNECTED:return "No executor connection";
312                 case PCMK_LRM_OP_INVALID:return "Cannot execute now";
313                 default:return "UNKNOWN!";
314         }
315     }
316 
services_ocf_exitcode_str(enum ocf_exitcode code)317     static inline const char *services_ocf_exitcode_str(enum ocf_exitcode code) {
318         switch (code) {
319             case PCMK_OCF_OK:
320                 return "ok";
321             case PCMK_OCF_UNKNOWN_ERROR:
322                 return "error";
323             case PCMK_OCF_INVALID_PARAM:
324                 return "invalid parameter";
325             case PCMK_OCF_UNIMPLEMENT_FEATURE:
326                 return "unimplemented feature";
327             case PCMK_OCF_INSUFFICIENT_PRIV:
328                 return "insufficient privileges";
329             case PCMK_OCF_NOT_INSTALLED:
330                 return "not installed";
331             case PCMK_OCF_NOT_CONFIGURED:
332                 return "not configured";
333             case PCMK_OCF_NOT_RUNNING:
334                 return "not running";
335             case PCMK_OCF_RUNNING_PROMOTED:
336                 return "promoted";
337             case PCMK_OCF_FAILED_PROMOTED:
338                 return "promoted (failed)";
339             case PCMK_OCF_SIGNAL:
340                 return "OCF_SIGNAL";
341             case PCMK_OCF_NOT_SUPPORTED:
342                 return "OCF_NOT_SUPPORTED";
343             case PCMK_OCF_PENDING:
344                 return "OCF_PENDING";
345             case PCMK_OCF_CANCELLED:
346                 return "OCF_CANCELLED";
347             case PCMK_OCF_TIMEOUT:
348                 return "OCF_TIMEOUT";
349             case PCMK_OCF_OTHER_ERROR:
350                 return "OCF_OTHER_ERROR";
351             case PCMK_OCF_DEGRADED:
352                 return "OCF_DEGRADED";
353             case PCMK_OCF_DEGRADED_PROMOTED:
354                 return "promoted (degraded)";
355             default:
356                 return "unknown";
357         }
358     }
359 
360     /**
361      * \brief Get OCF equivalent of LSB exit code
362      *
363      * \param[in] action        LSB action that produced exit code
364      * \param[in] lsb_exitcode  Exit code of LSB action
365      *
366      * \return PCMK_OCF_* constant that corresponds to LSB exit code
367      */
368     static inline enum ocf_exitcode
services_get_ocf_exitcode(const char * action,int lsb_exitcode)369     services_get_ocf_exitcode(const char *action, int lsb_exitcode)
370     {
371         /* For non-status actions, LSB and OCF share error code meaning <= 7 */
372         if (action && strcmp(action, "status") && strcmp(action, "monitor")) {
373             if ((lsb_exitcode < 0) || (lsb_exitcode > PCMK_LSB_NOT_RUNNING)) {
374                 return PCMK_OCF_UNKNOWN_ERROR;
375             }
376             return (enum ocf_exitcode)lsb_exitcode;
377         }
378 
379         /* status has different return codes */
380         switch (lsb_exitcode) {
381             case PCMK_LSB_STATUS_OK:
382                 return PCMK_OCF_OK;
383             case PCMK_LSB_STATUS_NOT_INSTALLED:
384                 return PCMK_OCF_NOT_INSTALLED;
385             case PCMK_LSB_STATUS_INSUFFICIENT_PRIV:
386                 return PCMK_OCF_INSUFFICIENT_PRIV;
387             case PCMK_LSB_STATUS_VAR_PID:
388             case PCMK_LSB_STATUS_VAR_LOCK:
389             case PCMK_LSB_STATUS_NOT_RUNNING:
390                 return PCMK_OCF_NOT_RUNNING;
391         }
392         return PCMK_OCF_UNKNOWN_ERROR;
393     }
394 
395 #  ifdef __cplusplus
396 }
397 #  endif
398 
399 #endif                          /* __PCMK_SERVICES__ */
400