| /* |
| * Copyright (c) 2012 David Vossel <davidvossel@gmail.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #ifndef LRMD__H |
| # define LRMD__H |
| |
| /** |
| * \file |
| * \brief Local Resource Manager |
| * \ingroup lrmd |
| */ |
| #include <stdbool.h> |
| #include <crm/services.h> |
| |
| typedef struct lrmd_s lrmd_t; |
| typedef struct lrmd_key_value_s { |
| char *key; |
| char *value; |
| struct lrmd_key_value_s *next; |
| } lrmd_key_value_t; |
| |
| /* This should be bumped every time there is an incompatible change that |
| * prevents older clients from connecting to this version of the server. |
| */ |
| #define LRMD_PROTOCOL_VERSION "1.1" |
| |
| /* This is the version that the client version will actually be compared |
| * against. This should be identical to LRMD_PROTOCOL_VERSION. However, we |
| * accidentally bumped LRMD_PROTOCOL_VERSION in 6424a647 (1.1.15) when we didn't |
| * need to, so for now it's different. If we ever have a truly incompatible |
| * bump, we can drop this and compare against LRMD_PROTOCOL_VERSION. |
| */ |
| #define LRMD_MIN_PROTOCOL_VERSION "1.0" |
| |
| /* *INDENT-OFF* */ |
| #define DEFAULT_REMOTE_KEY_LOCATION "/etc/pacemaker/authkey" |
| #define ALT_REMOTE_KEY_LOCATION "/etc/corosync/authkey" |
| #define DEFAULT_REMOTE_PORT 3121 |
| #define DEFAULT_REMOTE_USERNAME "lrmd" |
| |
| #define F_LRMD_OPERATION "lrmd_op" |
| #define F_LRMD_CLIENTNAME "lrmd_clientname" |
| #define F_LRMD_IS_IPC_PROVIDER "lrmd_is_ipc_provider" |
| #define F_LRMD_CLIENTID "lrmd_clientid" |
| #define F_LRMD_PROTOCOL_VERSION "lrmd_protocol_version" |
| #define F_LRMD_REMOTE_MSG_TYPE "lrmd_remote_msg_type" |
| #define F_LRMD_REMOTE_MSG_ID "lrmd_remote_msg_id" |
| #define F_LRMD_CALLBACK_TOKEN "lrmd_async_id" |
| #define F_LRMD_CALLID "lrmd_callid" |
| #define F_LRMD_CANCEL_CALLID "lrmd_cancel_callid" |
| #define F_LRMD_CALLOPTS "lrmd_callopt" |
| #define F_LRMD_CALLDATA "lrmd_calldata" |
| #define F_LRMD_RC "lrmd_rc" |
| #define F_LRMD_EXEC_RC "lrmd_exec_rc" |
| #define F_LRMD_OP_STATUS "lrmd_exec_op_status" |
| #define F_LRMD_TIMEOUT "lrmd_timeout" |
| #define F_LRMD_WATCHDOG "lrmd_watchdog" |
| #define F_LRMD_CLASS "lrmd_class" |
| #define F_LRMD_PROVIDER "lrmd_provider" |
| #define F_LRMD_TYPE "lrmd_type" |
| #define F_LRMD_ORIGIN "lrmd_origin" |
| |
| #define F_LRMD_RSC_RUN_TIME "lrmd_run_time" |
| #define F_LRMD_RSC_RCCHANGE_TIME "lrmd_rcchange_time" |
| #define F_LRMD_RSC_EXEC_TIME "lrmd_exec_time" |
| #define F_LRMD_RSC_QUEUE_TIME "lrmd_queue_time" |
| |
| #define F_LRMD_RSC_ID "lrmd_rsc_id" |
| #define F_LRMD_RSC_ACTION "lrmd_rsc_action" |
| #define F_LRMD_RSC_USERDATA_STR "lrmd_rsc_userdata_str" |
| #define F_LRMD_RSC_OUTPUT "lrmd_rsc_output" |
| #define F_LRMD_RSC_EXIT_REASON "lrmd_rsc_exit_reason" |
| #define F_LRMD_RSC_START_DELAY "lrmd_rsc_start_delay" |
| #define F_LRMD_RSC_INTERVAL "lrmd_rsc_interval" |
| #define F_LRMD_RSC_METADATA "lrmd_rsc_metadata_res" |
| #define F_LRMD_RSC_DELETED "lrmd_rsc_deleted" |
| #define F_LRMD_RSC "lrmd_rsc" |
| |
| #define F_LRMD_ALERT_ID "lrmd_alert_id" |
| #define F_LRMD_ALERT_PATH "lrmd_alert_path" |
| #define F_LRMD_ALERT "lrmd_alert" |
| |
| #define LRMD_OP_RSC_CHK_REG "lrmd_rsc_check_register" |
| #define LRMD_OP_RSC_REG "lrmd_rsc_register" |
| #define LRMD_OP_RSC_EXEC "lrmd_rsc_exec" |
| #define LRMD_OP_RSC_CANCEL "lrmd_rsc_cancel" |
| #define LRMD_OP_RSC_UNREG "lrmd_rsc_unregister" |
| #define LRMD_OP_RSC_INFO "lrmd_rsc_info" |
| #define LRMD_OP_RSC_METADATA "lrmd_rsc_metadata" |
| #define LRMD_OP_POKE "lrmd_rsc_poke" |
| #define LRMD_OP_NEW_CLIENT "lrmd_rsc_new_client" |
| #define LRMD_OP_CHECK "lrmd_check" |
| #define LRMD_OP_ALERT_EXEC "lrmd_alert_exec" |
| |
| #define LRMD_IPC_OP_NEW "new" |
| #define LRMD_IPC_OP_DESTROY "destroy" |
| #define LRMD_IPC_OP_EVENT "event" |
| #define LRMD_IPC_OP_REQUEST "request" |
| #define LRMD_IPC_OP_RESPONSE "response" |
| #define LRMD_IPC_OP_SHUTDOWN_REQ "shutdown_req" |
| #define LRMD_IPC_OP_SHUTDOWN_ACK "shutdown_ack" |
| #define LRMD_IPC_OP_SHUTDOWN_NACK "shutdown_nack" |
| |
| #define F_LRMD_IPC_OP "lrmd_ipc_op" |
| #define F_LRMD_IPC_IPC_SERVER "lrmd_ipc_server" |
| #define F_LRMD_IPC_SESSION "lrmd_ipc_session" |
| #define F_LRMD_IPC_CLIENT "lrmd_ipc_client" |
| #define F_LRMD_IPC_PROXY_NODE "lrmd_ipc_proxy_node" |
| #define F_LRMD_IPC_USER "lrmd_ipc_user" |
| #define F_LRMD_IPC_MSG "lrmd_ipc_msg" |
| #define F_LRMD_IPC_MSG_ID "lrmd_ipc_msg_id" |
| #define F_LRMD_IPC_MSG_FLAGS "lrmd_ipc_msg_flags" |
| |
| #define T_LRMD "lrmd" |
| #define T_LRMD_REPLY "lrmd_reply" |
| #define T_LRMD_NOTIFY "lrmd_notify" |
| #define T_LRMD_IPC_PROXY "lrmd_ipc_proxy" |
| /* *INDENT-ON* */ |
| |
| /*! |
| * \brief Create a new local lrmd connection |
| */ |
| lrmd_t *lrmd_api_new(void); |
| |
| /*! |
| * \brief Create a new remote lrmd connection using tls backend |
| * |
| * \param nodename name of remote node identified with this connection |
| * \param server name of server to connect to |
| * \param port port number to connect to |
| * |
| * \note nodename and server may be the same value. |
| */ |
| lrmd_t *lrmd_remote_api_new(const char *nodename, const char *server, int port); |
| |
| /*! |
| * \brief Use after lrmd_poll returns 1 to read and dispatch a message |
| * |
| * \param[in,out] lrmd lrmd connection object |
| * |
| * \return TRUE if connection is still up, FALSE if disconnected |
| */ |
| bool lrmd_dispatch(lrmd_t * lrmd); |
| |
| /*! |
| * \brief Poll for a specified timeout period to determine if a message |
| * is ready for dispatch. |
| * \retval 1 msg is ready |
| * \retval 0 timeout occurred |
| * \retval negative error code |
| */ |
| int lrmd_poll(lrmd_t * lrmd, int timeout); |
| |
| /*! |
| * \brief Destroy lrmd object |
| */ |
| void lrmd_api_delete(lrmd_t * lrmd); |
| lrmd_key_value_t *lrmd_key_value_add(lrmd_key_value_t * kvp, const char *key, const char *value); |
| |
| /* *INDENT-OFF* */ |
| /* Reserved for future use */ |
| enum lrmd_call_options { |
| lrmd_opt_none = 0x00000000, |
| /* lrmd_opt_sync_call = 0x00000001, //Not implemented, patches welcome. */ |
| /*! Only notify the client originating a exec() the results */ |
| lrmd_opt_notify_orig_only = 0x00000002, |
| /*! Drop recurring operations initiated by a client when client disconnects. |
| * This call_option is only valid when registering a resource. When used |
| * remotely with the pacemaker_remote daemon, this option means that recurring |
| * operations will be dropped once all the remote connections disconnect. */ |
| lrmd_opt_drop_recurring = 0x00000003, |
| /*! Send notifications for recurring operations only when the result changes */ |
| lrmd_opt_notify_changes_only = 0x00000004, |
| }; |
| |
| enum lrmd_callback_event { |
| lrmd_event_register, |
| lrmd_event_unregister, |
| lrmd_event_exec_complete, |
| lrmd_event_disconnect, |
| lrmd_event_connect, |
| lrmd_event_poke, |
| lrmd_event_new_client, |
| }; |
| |
| /* *INDENT-ON* */ |
| |
| typedef struct lrmd_event_data_s { |
| /*! Type of event, register, unregister, call_completed... */ |
| enum lrmd_callback_event type; |
| |
| /*! The resource this event occurred on. */ |
| const char *rsc_id; |
| /*! The action performed, start, stop, monitor... */ |
| const char *op_type; |
| /*! The userdata string given do exec() api function */ |
| const char *user_data; |
| |
| /*! The client api call id associated with this event */ |
| int call_id; |
| /*! The operation's timeout period in ms. */ |
| int timeout; |
| /*! The operation's recurring interval in ms. */ |
| int interval; |
| /*! The operation's start delay value in ms. */ |
| int start_delay; |
| /*! This operation that just completed is on a deleted rsc. */ |
| int rsc_deleted; |
| |
| /*! The executed ra return code mapped to OCF */ |
| enum ocf_exitcode rc; |
| /*! The lrmd status returned for exec_complete events */ |
| int op_status; |
| /*! stdout from resource agent operation */ |
| const char *output; |
| /*! Timestamp of when op ran */ |
| unsigned int t_run; |
| /*! Timestamp of last rc change */ |
| unsigned int t_rcchange; |
| /*! Time in length op took to execute */ |
| unsigned int exec_time; |
| /*! Time in length spent in queue */ |
| unsigned int queue_time; |
| |
| /*! int connection result. Used for connection and poke events */ |
| int connection_rc; |
| |
| /* This is a GHashTable containing the |
| * parameters given to the operation */ |
| void *params; |
| |
| /*! client node name associated with this connection |
| * (used to match actions to the proper client when there are multiple) |
| */ |
| const char *remote_nodename; |
| |
| /*! exit failure reason string from resource agent operation */ |
| const char *exit_reason; |
| } lrmd_event_data_t; |
| |
| lrmd_event_data_t *lrmd_new_event(const char *rsc_id, const char *task, |
| int interval_ms); |
| lrmd_event_data_t *lrmd_copy_event(lrmd_event_data_t * event); |
| void lrmd_free_event(lrmd_event_data_t * event); |
| |
| typedef struct lrmd_rsc_info_s { |
| char *id; |
| char *type; |
| char *class; |
| char *provider; |
| } lrmd_rsc_info_t; |
| |
| lrmd_rsc_info_t *lrmd_new_rsc_info(const char *rsc_id, const char *standard, |
| const char *provider, const char *type); |
| lrmd_rsc_info_t *lrmd_copy_rsc_info(lrmd_rsc_info_t * rsc_info); |
| void lrmd_free_rsc_info(lrmd_rsc_info_t * rsc_info); |
| |
| typedef void (*lrmd_event_callback) (lrmd_event_data_t * event); |
| |
| typedef struct lrmd_list_s { |
| const char *val; |
| struct lrmd_list_s *next; |
| } lrmd_list_t; |
| |
| void lrmd_list_freeall(lrmd_list_t * head); |
| void lrmd_key_value_freeall(lrmd_key_value_t * head); |
| |
| typedef struct lrmd_api_operations_s { |
| /*! |
| * \brief Connect from the lrmd. |
| * |
| * \retval 0, success |
| * \retval negative error code on failure |
| */ |
| int (*connect) (lrmd_t * lrmd, const char *client_name, int *fd); |
| |
| /*! |
| * \brief Establish an connection to lrmd, don't block while connecting. |
| * \note this function requires the use of mainloop. |
| * |
| * \note The is returned using the event callback. |
| * \note When this function returns 0, the callback will be invoked |
| * to report the final result of the connect. |
| * \retval 0, connect in progress, wait for event callback |
| * \retval -1, failure. |
| */ |
| int (*connect_async) (lrmd_t * lrmd, const char *client_name, int timeout /*ms */ ); |
| |
| /*! |
| * \brief Is connected to lrmd daemon? |
| * |
| * \retval 0, false |
| * \retval 1, true |
| */ |
| int (*is_connected) (lrmd_t * lrmd); |
| |
| /*! |
| * \brief Poke lrmd connection to verify it is still capable of serving requests |
| * \note The response comes in the form of a poke event to the callback. |
| * |
| * \retval 0, wait for response in callback |
| * \retval -1, connection failure, callback may not be invoked |
| */ |
| int (*poke_connection) (lrmd_t * lrmd); |
| |
| /*! |
| * \brief Disconnect from the lrmd. |
| * |
| * \retval 0, success |
| * \retval negative error code on failure |
| */ |
| int (*disconnect) (lrmd_t * lrmd); |
| |
| /*! |
| * \brief Register a resource with the lrmd. |
| * |
| * \note Synchronous, guaranteed to occur in daemon before function returns. |
| * |
| * \retval 0, success |
| * \retval negative error code on failure |
| */ |
| int (*register_rsc) (lrmd_t * lrmd, |
| const char *rsc_id, |
| const char *class, |
| const char *provider, const char *agent, enum lrmd_call_options options); |
| |
| /*! |
| * \brief Retrieve registration info for a rsc |
| * |
| * \retval info on success |
| * \retval NULL on failure |
| */ |
| lrmd_rsc_info_t *(*get_rsc_info) (lrmd_t * lrmd, |
| const char *rsc_id, enum lrmd_call_options options); |
| |
| /*! |
| * \brief Unregister a resource from the lrmd. |
| * |
| * \note All pending and recurring operations will be cancelled |
| * automatically. |
| * |
| * \note Synchronous, guaranteed to occur in daemon before function returns. |
| * |
| * \retval 0, success |
| * \retval -1, success, but operations are currently executing on the rsc which will |
| * return once they are completed. |
| * \retval negative error code on failure |
| * |
| */ |
| int (*unregister_rsc) (lrmd_t * lrmd, const char *rsc_id, enum lrmd_call_options options); |
| |
| /*! |
| * \brief Sets the callback to receive lrmd events on. |
| */ |
| void (*set_callback) (lrmd_t * lrmd, lrmd_event_callback callback); |
| |
| /*! |
| * \brief Issue a command on a resource |
| * |
| * \note Asynchronous, command is queued in daemon on function return, but |
| * execution of command is not synced. |
| * |
| * \note Operations on individual resources are guaranteed to occur |
| * in the order the client api calls them in. |
| * |
| * \note Operations between different resources are not guaranteed |
| * to occur in any specific order in relation to one another |
| * regardless of what order the client api is called in. |
| * \retval call_id to track async event result on success |
| * \retval negative error code on failure |
| */ |
| int (*exec) (lrmd_t * lrmd, const char *rsc_id, const char *action, const char *userdata, /* userdata string given back in event notification */ |
| int interval, /* ms */ |
| int timeout, /* ms */ |
| int start_delay, /* ms */ |
| enum lrmd_call_options options, lrmd_key_value_t * params); /* ownership of params is given up to api here */ |
| |
| /*! |
| * \brief Cancel a recurring command. |
| * |
| * \note Synchronous, guaranteed to occur in daemon before function returns. |
| * |
| * \note The cancel is completed async from this call. |
| * We can be guaranteed the cancel has completed once |
| * the callback receives an exec_complete event with |
| * the lrmd_op_status signifying that the operation is |
| * cancelled. |
| * \note For each resource, cancel operations and exec operations |
| * are processed in the order they are received. |
| * It is safe to assume that for a single resource, a cancel |
| * will occur in the lrmd before an exec if the client's cancel |
| * api call occurs before the exec api call. |
| * |
| * It is not however safe to assume any operation on one resource will |
| * occur before an operation on another resource regardless of |
| * the order the client api is called in. |
| * |
| * \retval 0, cancel command sent. |
| * \retval negative error code on failure |
| */ |
| int (*cancel) (lrmd_t * lrmd, const char *rsc_id, const char *action, int interval); |
| |
| /*! |
| * \brief Get resource metadata for a specified resource agent |
| * |
| * \param[in] lrmd LRMD connection (unused) |
| * \param[in] class Resource agent class |
| * \param[in] provider Resource agent provider |
| * \param[in] agent Resource agent type |
| * \param[out] output Metadata will be stored here (must not be NULL) |
| * \param[in] options Options to use with any LRMD API calls (unused) |
| * |
| * \note Caller is responsible for freeing output. This call is currently |
| * always synchronous (blocking), and always done directly by the |
| * library (not via the LRMD connection). This means that it is based |
| * on the local host environment, even if the lrmd connection is to a |
| * remote node, so (for most resource agent classes) this will fail if |
| * the agent is not installed locally. This also means that, if an |
| * external agent must be executed, it will be executed by the |
| * caller's user, not the lrmd's. |
| * \todo Add a metadata call to the LRMD API and let the server handle this. |
| * |
| * \retval lrmd_ok success |
| * \retval negative error code on failure |
| */ |
| int (*get_metadata) (lrmd_t * lrmd, |
| const char *class, |
| const char *provider, |
| const char *agent, char **output, enum lrmd_call_options options); |
| |
| /*! |
| * \brief Retrieve a list of installed resource agents. |
| * |
| * \note if class is not provided, all known agents will be returned |
| * \note list must be freed using lrmd_list_freeall() |
| * |
| * \retval num items in list on success |
| * \retval negative error code on failure |
| */ |
| int (*list_agents) (lrmd_t * lrmd, lrmd_list_t ** agents, const char *class, |
| const char *provider); |
| |
| /*! |
| * \brief Retrieve a list of resource agent providers |
| * |
| * \note When the agent is provided, only the agent's provider will be returned |
| * \note When no agent is supplied, all providers will be returned. |
| * \note List must be freed using lrmd_list_freeall() |
| * |
| * \retval num items in list on success |
| * \retval negative error code on failure |
| */ |
| int (*list_ocf_providers) (lrmd_t * lrmd, const char *agent, lrmd_list_t ** providers); |
| |
| /*! |
| * \brief Retrieve a list of standards supported by this machine/installation |
| * |
| * \note List must be freed using lrmd_list_freeall() |
| * |
| * \retval num items in list on success |
| * \retval negative error code on failure |
| */ |
| int (*list_standards) (lrmd_t * lrmd, lrmd_list_t ** standards); |
| |
| /*! |
| * \brief Execute an alert agent |
| * |
| * \note Asynchronous, command is queued in daemon on function return, but |
| * execution of command is not synced. |
| * |
| * \note Operations on individual alerts are guaranteed to occur |
| * in the order the client api calls them in. |
| * |
| * \note Operations between different alerts are not guaranteed |
| * to occur in any specific order in relation to one another |
| * regardless of what order the client api is called in. |
| * \retval call_id to track async event result on success |
| * \retval negative error code on failure |
| */ |
| int (*exec_alert) (lrmd_t *lrmd, const char *alert_id, |
| const char *alert_path, int timeout, /* ms */ |
| lrmd_key_value_t *params); /* ownership of params is given up to api here */ |
| |
| /*! |
| * \brief Get resource metadata for a resource agent, passing parameters |
| * |
| * \param[in] lrmd Executor connection (unused) |
| * \param[in] standard Resource agent class |
| * \param[in] provider Resource agent provider |
| * \param[in] agent Resource agent type |
| * \param[out] output Metadata will be stored here (must not be NULL) |
| * \param[in] options Options to use with any executor API calls (unused) |
| * \param[in] params Parameters to pass to agent via environment |
| * |
| * \note This is identical to the get_metadata() API call, except parameters |
| * will be passed to the resource agent via environment variables. |
| * \note The API will handle freeing params. |
| * |
| * \return lrmd_ok on success, negative error code on failure |
| */ |
| int (*get_metadata_params) (lrmd_t *lrmd, const char *standard, |
| const char *provider, const char *agent, |
| char **output, enum lrmd_call_options options, |
| lrmd_key_value_t *params); |
| |
| } lrmd_api_operations_t; |
| |
| struct lrmd_s { |
| lrmd_api_operations_t *cmds; |
| void *private; |
| }; |
| |
| static inline const char * |
| lrmd_event_type2str(enum lrmd_callback_event type) |
| { |
| switch (type) { |
| case lrmd_event_register: |
| return "register"; |
| case lrmd_event_unregister: |
| return "unregister"; |
| case lrmd_event_exec_complete: |
| return "exec_complete"; |
| case lrmd_event_disconnect: |
| return "disconnect"; |
| case lrmd_event_connect: |
| return "connect"; |
| case lrmd_event_poke: |
| return "poke"; |
| case lrmd_event_new_client: |
| return "new_client"; |
| } |
| return "unknown"; |
| } |
| |
| #endif |