1 /*
2 * Copyright (C) 2010 Andrew Beekhof <andrew@beekhof.net>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 /**
20 * \file
21 * \brief Services API
22 * \ingroup core
23 */
24
25 #ifndef __PCMK_SERVICES__
26 # define __PCMK_SERVICES__
27
28 # ifdef __cplusplus
29 extern "C" {
30 # endif
31
32 # include <glib.h>
33 # include <stdio.h>
34 # include <string.h>
35 # include <stdbool.h>
36 # include <sys/types.h>
37
38 # ifndef OCF_ROOT_DIR
39 # define OCF_ROOT_DIR "/usr/lib/ocf"
40 # endif
41
42 # ifndef LSB_ROOT_DIR
43 # define LSB_ROOT_DIR "/etc/init.d"
44 # endif
45
46 /* TODO: Autodetect these two ?*/
47 # ifndef SYSTEMCTL
48 # define SYSTEMCTL "/bin/systemctl"
49 # endif
50
51 /* Deprecated and unused by Pacemaker, kept for API backward compatibility */
52 # ifndef SERVICE_SCRIPT
53 # define SERVICE_SCRIPT "/sbin/service"
54 # endif
55
56 /* Known resource classes */
57 #define PCMK_RESOURCE_CLASS_OCF "ocf"
58 #define PCMK_RESOURCE_CLASS_SERVICE "service"
59 #define PCMK_RESOURCE_CLASS_LSB "lsb"
60 #define PCMK_RESOURCE_CLASS_SYSTEMD "systemd"
61 #define PCMK_RESOURCE_CLASS_UPSTART "upstart"
62 #define PCMK_RESOURCE_CLASS_HB "heartbeat"
63 #define PCMK_RESOURCE_CLASS_NAGIOS "nagios"
64 #define PCMK_RESOURCE_CLASS_STONITH "stonith"
65
66 /* This is the string passed in the OCF_EXIT_REASON_PREFIX
67 * environment variable. The stderr output that occurs
68 * after this prefix is encountered is considered the exit
69 * reason for a completed operationt */
70 #define PCMK_OCF_REASON_PREFIX "ocf-exit-reason:"
71
72 // Agent version to use if agent doesn't specify one
73 #define PCMK_DEFAULT_AGENT_VERSION "0.1"
74
75 enum lsb_exitcode {
76 PCMK_LSB_OK = 0,
77 PCMK_LSB_UNKNOWN_ERROR = 1,
78 PCMK_LSB_INVALID_PARAM = 2,
79 PCMK_LSB_UNIMPLEMENT_FEATURE = 3,
80 PCMK_LSB_INSUFFICIENT_PRIV = 4,
81 PCMK_LSB_NOT_INSTALLED = 5,
82 PCMK_LSB_NOT_CONFIGURED = 6,
83 PCMK_LSB_NOT_RUNNING = 7,
84 };
85
86 /* The return codes for the status operation are not the same for other
87 * operatios - go figure
88 */
89 enum lsb_status_exitcode {
90 PCMK_LSB_STATUS_OK = 0,
91 PCMK_LSB_STATUS_VAR_PID = 1,
92 PCMK_LSB_STATUS_VAR_LOCK = 2,
93 PCMK_LSB_STATUS_NOT_RUNNING = 3,
94 PCMK_LSB_STATUS_UNKNOWN = 4,
95
96 /* custom codes should be in the 150-199 range reserved for application use */
97 PCMK_LSB_STATUS_NOT_INSTALLED = 150,
98 PCMK_LSB_STATUS_INSUFFICIENT_PRIV = 151,
99 };
100
101 /* Uniform exit codes
102 * Everything is mapped to its OCF equivalent so that Pacemaker only deals with one set of codes
103 */
104 enum ocf_exitcode {
105 PCMK_OCF_OK = 0,
106 PCMK_OCF_UNKNOWN_ERROR = 1,
107 PCMK_OCF_INVALID_PARAM = 2,
108 PCMK_OCF_UNIMPLEMENT_FEATURE = 3,
109 PCMK_OCF_INSUFFICIENT_PRIV = 4,
110 PCMK_OCF_NOT_INSTALLED = 5,
111 PCMK_OCF_NOT_CONFIGURED = 6,
112 PCMK_OCF_NOT_RUNNING = 7, /* End of overlap with LSB */
113 PCMK_OCF_RUNNING_MASTER = 8,
114 PCMK_OCF_FAILED_MASTER = 9,
115
116
117 /* 150-199 reserved for application use */
118 PCMK_OCF_CONNECTION_DIED = 189, /* Operation failure implied by disconnection of the LRM API to a local or remote node */
119
120 PCMK_OCF_DEGRADED = 190, /* Active resource that is no longer 100% functional */
121 PCMK_OCF_DEGRADED_MASTER = 191, /* Promoted resource that is no longer 100% functional */
122
123 PCMK_OCF_EXEC_ERROR = 192, /* Generic problem invoking the agent */
124 PCMK_OCF_UNKNOWN = 193, /* State of the service is unknown - used for recording in-flight operations */
125 PCMK_OCF_SIGNAL = 194,
126 PCMK_OCF_NOT_SUPPORTED = 195,
127 PCMK_OCF_PENDING = 196,
128 PCMK_OCF_CANCELLED = 197,
129 PCMK_OCF_TIMEOUT = 198,
130 PCMK_OCF_OTHER_ERROR = 199, /* Keep the same codes as PCMK_LSB */
131 };
132
133 enum op_status {
134 PCMK_LRM_OP_PENDING = -1,
135 PCMK_LRM_OP_DONE,
136 PCMK_LRM_OP_CANCELLED,
137 PCMK_LRM_OP_TIMEOUT,
138 PCMK_LRM_OP_NOTSUPPORTED,
139 PCMK_LRM_OP_ERROR,
140 PCMK_LRM_OP_ERROR_HARD,
141 PCMK_LRM_OP_ERROR_FATAL,
142 PCMK_LRM_OP_NOT_INSTALLED,
143 };
144
145 enum nagios_exitcode {
146 NAGIOS_STATE_OK = 0,
147 NAGIOS_STATE_WARNING = 1,
148 NAGIOS_STATE_CRITICAL = 2,
149 NAGIOS_STATE_UNKNOWN = 3,
150 NAGIOS_STATE_DEPENDENT = 4,
151
152 NAGIOS_INSUFFICIENT_PRIV = 100,
153 NAGIOS_NOT_INSTALLED = 101,
154 };
155
156 enum svc_action_flags {
157 /* On timeout, only kill pid, do not kill entire pid group */
158 SVC_ACTION_LEAVE_GROUP = 0x01,
159 };
160
161 typedef struct svc_action_private_s svc_action_private_t;
162 typedef struct svc_action_s {
163 char *id;
164 char *rsc;
165 char *action;
166 int interval;
167
168 char *standard;
169 char *provider;
170 char *agent;
171
172 int timeout;
173 GHashTable *params; /* used by OCF agents and alert agents */
174
175 int rc;
176 int pid;
177 int cancel;
178 int status;
179 int sequence;
180 int expected_rc;
181 int synchronous;
182 enum svc_action_flags flags;
183
184 char *stderr_data;
185 char *stdout_data;
186
187 /*!
188 * Data stored by the creator of the action.
189 *
190 * This may be used to hold data that is needed later on by a callback,
191 * for example.
192 */
193 void *cb_data;
194
195 svc_action_private_t *opaque;
196 } svc_action_t;
197
198 /**
199 * \brief Get a list of files or directories in a given path
200 *
201 * \param[in] root full path to a directory to read
202 * \param[in] files return list of files if TRUE or directories if FALSE
203 * \param[in] executable if TRUE and files is TRUE, only return executable files
204 *
205 * \return a list of what was found. The list items are char *.
206 * \note It is the caller's responsibility to free the result with g_list_free_full(list, free).
207 */
208 GList *get_directory_list(const char *root, gboolean files, gboolean executable);
209
210 /**
211 * Get a list of services
212 *
213 * \return a list of services. The list items are gchar *. This list _must_
214 * be destroyed using g_list_free_full(list, free).
215 */
216 GList *services_list(void);
217
218 /**
219 * \brief Get a list of providers
220 *
221 * \param[in] standard list providers of this standard (e.g. ocf, lsb, etc.)
222 *
223 * \return a list of providers as char * list items (or NULL if standard does not support providers)
224 * \note The caller is responsible for freeing the result using g_list_free_full(list, free).
225 */
226 GList *resources_list_providers(const char *standard);
227
228 /**
229 * \brief Get a list of resource agents
230 *
231 * \param[in] standard list agents using this standard (e.g. ocf, lsb, etc.) (or NULL for all)
232 * \param[in] provider list agents from this provider (or NULL for all)
233 *
234 * \return a list of resource agents. The list items are char *.
235 * \note The caller is responsible for freeing the result using g_list_free_full(list, free).
236 */
237 GList *resources_list_agents(const char *standard, const char *provider);
238
239 /**
240 * Get list of available standards
241 *
242 * \return a list of resource standards. The list items are char *. This list _must_
243 * be destroyed using g_list_free_full(list, free).
244 */
245 GList *resources_list_standards(void);
246
247 svc_action_t *services_action_create(const char *name, const char *action,
248 int interval /* ms */ , int timeout /* ms */ );
249
250 /**
251 * \brief Create a new resource action
252 *
253 * \param[in] name name of resource
254 * \param[in] standard resource agent standard (ocf, lsb, etc.)
255 * \param[in] provider resource agent provider
256 * \param[in] agent resource agent name
257 * \param[in] action action (start, stop, monitor, etc.)
258 * \param[in] interval how often to repeat this action, in milliseconds (if 0, execute only once)
259 * \param[in] timeout consider action failed if it does not complete in this many milliseconds
260 * \param[in] params action parameters
261 *
262 * \return newly allocated action instance
263 *
264 * \post After the call, 'params' is owned, and later free'd by the svc_action_t result
265 * \note The caller is responsible for freeing the return value using
266 * services_action_free().
267 */
268 svc_action_t *resources_action_create(const char *name, const char *standard,
269 const char *provider, const char *agent,
270 const char *action, int interval /* ms */ ,
271 int timeout /* ms */ , GHashTable * params,
272 enum svc_action_flags flags);
273
274 /**
275 * Kick a recurring action so it is scheduled immediately for re-execution
276 */
277 gboolean services_action_kick(const char *name, const char *action, int interval /* ms */);
278
279 const char *resources_find_service_class(const char *agent);
280
281 /**
282 * Utilize services API to execute an arbitrary command.
283 *
284 * This API has useful infrastructure in place to be able to run a command
285 * in the background and get notified via a callback when the command finishes.
286 *
287 * \param[in] exec command to execute
288 * \param[in] args arguments to the command, NULL terminated
289 *
290 * \return a svc_action_t object, used to pass to the execute function
291 * (services_action_sync() or services_action_async()) and is
292 * provided to the callback.
293 */
294 svc_action_t *services_action_create_generic(const char *exec, 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
300 gboolean services_action_sync(svc_action_t * op);
301
302 /**
303 * Run an action asynchronously.
304 *
305 * \param[in] op services action data
306 * \param[in] action_callback callback for when the action completes
307 *
308 * \retval TRUE succesfully started execution
309 * \retval FALSE failed to start execution, no callback will be received
310 */
311 gboolean services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *));
312
313 gboolean services_action_cancel(const char *name, const char *action, int interval);
314
315 /* functions for alert agents */
316 svc_action_t *services_alert_create(const char *id, const char *exec,
317 int timeout, GHashTable *params,
318 int sequence, void *cb_data);
319 gboolean services_alert_async(svc_action_t *action,
320 void (*cb)(svc_action_t *op));
321
322 static inline const char *services_lrm_status_str(enum op_status status) {
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
323 switch (status) {
324 case PCMK_LRM_OP_PENDING:
325 return "pending";
326 case PCMK_LRM_OP_DONE:return "complete";
327 case PCMK_LRM_OP_CANCELLED:return "Cancelled";
328 case PCMK_LRM_OP_TIMEOUT:return "Timed Out";
329 case PCMK_LRM_OP_NOTSUPPORTED:return "NOT SUPPORTED";
330 case PCMK_LRM_OP_ERROR:return "Error";
331 case PCMK_LRM_OP_NOT_INSTALLED:return "Not installed";
332 default:return "UNKNOWN!";
333 }
334 }
335
336 static inline const char *services_ocf_exitcode_str(enum ocf_exitcode code) {
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
337 switch (code) {
338 case PCMK_OCF_OK:
339 return "ok";
340 case PCMK_OCF_UNKNOWN_ERROR:
341 return "unknown error";
342 case PCMK_OCF_INVALID_PARAM:
343 return "invalid parameter";
344 case PCMK_OCF_UNIMPLEMENT_FEATURE:
345 return "unimplemented feature";
346 case PCMK_OCF_INSUFFICIENT_PRIV:
347 return "insufficient privileges";
348 case PCMK_OCF_NOT_INSTALLED:
349 return "not installed";
350 case PCMK_OCF_NOT_CONFIGURED:
351 return "not configured";
352 case PCMK_OCF_NOT_RUNNING:
353 return "not running";
354 case PCMK_OCF_RUNNING_MASTER:
355 return "master";
356 case PCMK_OCF_FAILED_MASTER:
357 return "master (failed)";
358 case PCMK_OCF_SIGNAL:
359 return "OCF_SIGNAL";
360 case PCMK_OCF_NOT_SUPPORTED:
361 return "OCF_NOT_SUPPORTED";
362 case PCMK_OCF_PENDING:
363 return "OCF_PENDING";
364 case PCMK_OCF_CANCELLED:
365 return "OCF_CANCELLED";
366 case PCMK_OCF_TIMEOUT:
367 return "OCF_TIMEOUT";
368 case PCMK_OCF_OTHER_ERROR:
369 return "OCF_OTHER_ERROR";
370 case PCMK_OCF_DEGRADED:
371 return "OCF_DEGRADED";
372 case PCMK_OCF_DEGRADED_MASTER:
373 return "OCF_DEGRADED_MASTER";
374 default:
375 return "unknown";
376 }
377 }
378
379 /**
380 * \brief Get OCF equivalent of LSB exit code
381 *
382 * \param[in] action LSB action that produced exit code
383 * \param[in] lsb_exitcode Exit code of LSB action
384 *
385 * \return PCMK_OCF_* constant that corresponds to LSB exit code
386 */
387 static inline enum ocf_exitcode
388 services_get_ocf_exitcode(const char *action, int lsb_exitcode)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
389 {
390 /* For non-status actions, LSB and OCF share error code meaning <= 7 */
391 if (action && strcmp(action, "status") && strcmp(action, "monitor")) {
392 if ((lsb_exitcode < 0) || (lsb_exitcode > PCMK_LSB_NOT_RUNNING)) {
393 return PCMK_OCF_UNKNOWN_ERROR;
394 }
395 return (enum ocf_exitcode)lsb_exitcode;
396 }
397
398 /* status has different return codes */
399 switch (lsb_exitcode) {
400 case PCMK_LSB_STATUS_OK:
401 return PCMK_OCF_OK;
402 case PCMK_LSB_STATUS_NOT_INSTALLED:
403 return PCMK_OCF_NOT_INSTALLED;
404 case PCMK_LSB_STATUS_INSUFFICIENT_PRIV:
405 return PCMK_OCF_INSUFFICIENT_PRIV;
406 case PCMK_LSB_STATUS_VAR_PID:
407 case PCMK_LSB_STATUS_VAR_LOCK:
408 case PCMK_LSB_STATUS_NOT_RUNNING:
409 return PCMK_OCF_NOT_RUNNING;
410 }
411 return PCMK_OCF_UNKNOWN_ERROR;
412 }
413
414 # ifdef __cplusplus
415 }
416 # endif
417
418 #endif /* __PCMK_SERVICES__ */