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