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