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