From c99f3adf10df63cf8bb92b63a0aaa076d3f976a6 Mon Sep 17 00:00:00 2001 From: Aurelien DARRAGON Date: Wed, 12 Apr 2023 15:47:16 +0200 Subject: [PATCH] MINOR: hlua: expose SERVER_STATE event Exposing SERVER_STATE event in lua and updating the documentation. --- doc/lua-api/index.rst | 113 +++++++++++++++++++++++++++++++++++- src/hlua.c | 129 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 2 deletions(-) diff --git a/doc/lua-api/index.rst b/doc/lua-api/index.rst index d470491c7..333c351b4 100644 --- a/doc/lua-api/index.rst +++ b/doc/lua-api/index.rst @@ -946,10 +946,14 @@ Core class * **SERVER_DEL**: when a server is removed * **SERVER_DOWN**: when a server state goes from UP to DOWN * **SERVER_UP**: when a server state goes from DOWN to UP + * **SERVER_STATE**: when a server state changes .. Note:: - You may also use **SERVER** in **event_types** to subscribe to all server - events types at once. + Use **SERVER** in **event_types** to subscribe to all server events types + at once. Note that this should only be used for testing purposes since a + single event source could result in multiple events types being generated. + (e.g.: SERVER_STATE will always be generated for each SERVER_DOWN or + SERVER_UP) The prototype of the Lua function used as argument is: @@ -1522,6 +1526,111 @@ See :js:func:`core.event_sub()` for more info. (Will never be set for SERVER_DEL event since the server does not exist anymore) +.. js:attribute:: ServerEvent.state + + A :ref:`server_event_state_class` + + .. Note:: + Only available for SERVER_STATE event + +.. _server_event_checkres_class: + +ServerEventCheckRes class +========================= + +.. js:class:: ServerEventCheckRes + +This class describes the result of a server's check. + +.. js:attribute:: ServerEventCheckRes.result + + Effective check result. + + Check result is a string and will be set to one of the following values: + - "FAILED": the check failed + - "PASSED": the check succeeded + - "CONDPASS": the check conditionally passed + +.. js:attribute:: ServerEventCheckRes.agent + + Boolean set to true if the check is an agent check. + Else it is a health check. + +.. js:attribute:: ServerEventCheckRes.duration + + Check's duration in milliseconds + +.. js:attribute:: ServerEventCheckRes.reason + + Check's status. An array containing three fields: + - **short**: a string representing check status short name + - **desc**: a string representing check status description + - **code**: an integer, this extra information is provided for checks + that went through the data analysis stage (>= layer 5) + +.. js:attribute:: ServerEventCheckRes.health + + An array containing values about check's health (integers): + - **cur**: current health counter: + - 0 to (**rise** - 1) = BAD + - **rise** to (**rise** + **fall** - 1) = GOOD + - **rise**: server will be considered as operational after **rise** + consecutive successful checks + - **fall**: server will be considered as dead after **fall** consecutive + unsuccessful checks + +.. _server_event_state_class: + +ServerEventState class +====================== + +.. js:class:: ServerEventState + +This class contains additional info related to **SERVER_STATE** event. + +.. js:attribute:: ServerEventState.admin + + Boolean set to true if the server state change is due to an administrative + change. Else it is an operational change. + +.. js:attribute:: ServerEventState.check + + A :ref:`server_event_checkres_class`, provided if the state change is + due to a server check (must be an operational change). + +.. js:attribute:: ServerEventState.cause + + Printable state change cause. Might be empty. + +.. js:attribute:: ServerEventState.new_state + + New server state due to operational or admin change. + + It is a string that can be any of the following values: + - "STOPPED": The server is down + - "STOPPING": The server is up but soft-stopping + - "STARTING": The server is warming up + - "RUNNING": The server is fully up + +.. js:attribute:: ServerEventState.old_state + + Previous server state prior to the operational or admin change. + + Can be any value described in **new_state**, but they should differ. + +.. js:attribute:: ServerEventState.requeued + + Number of connections that were requeued due to the server state change. + + For a server going DOWN: it is the number of pending server connections + that are requeued to the backend (such connections will be redispatched + to any server that is suitable according to the configured load balancing + algorithm). + + For a server doing UP: it is the number of pending connections on the + backend that may be redispatched to the server according to the load + balancing algorithm that is in use. + .. _concat_class: Concat class diff --git a/src/hlua.c b/src/hlua.c index 973e27726..34ad3c834 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -66,6 +66,7 @@ #include #include #include +#include /* Lua uses longjmp to perform yield or throwing errors. This * macro is used only for identifying the function that can @@ -9029,6 +9030,67 @@ static void hlua_event_handler(struct hlua *hlua) } } +__LJMP static void hlua_event_hdl_cb_push_event_checkres(lua_State *L, + struct event_hdl_cb_data_server_checkres *check) +{ + lua_pushstring(L, "agent"); + lua_pushboolean(L, check->agent); + lua_settable(L, -3); + lua_pushstring(L, "result"); + switch (check->result) { + case CHK_RES_FAILED: + lua_pushstring(L, "FAILED"); + break; + case CHK_RES_PASSED: + lua_pushstring(L, "PASSED"); + break; + case CHK_RES_CONDPASS: + lua_pushstring(L, "CONDPASS"); + break; + default: + lua_pushnil(L); + break; + } + lua_settable(L, -3); + + lua_pushstring(L, "duration"); + lua_pushinteger(L, check->duration); + lua_settable(L, -3); + + lua_pushstring(L, "reason"); + lua_newtable(L); + + lua_pushstring(L, "short"); + lua_pushstring(L, get_check_status_info(check->reason.status)); + lua_settable(L, -3); + lua_pushstring(L, "desc"); + lua_pushstring(L, get_check_status_description(check->reason.status)); + lua_settable(L, -3); + if (check->reason.status >= HCHK_STATUS_L57DATA) { + /* code only available when the check reached data analysis stage */ + lua_pushstring(L, "code"); + lua_pushinteger(L, check->reason.code); + lua_settable(L, -3); + } + + lua_settable(L, -3); /* reason table */ + + lua_pushstring(L, "health"); + lua_newtable(L); + + lua_pushstring(L, "cur"); + lua_pushinteger(L, check->health.cur); + lua_settable(L, -3); + lua_pushstring(L, "rise"); + lua_pushinteger(L, check->health.rise); + lua_settable(L, -3); + lua_pushstring(L, "fall"); + lua_pushinteger(L, check->health.fall); + lua_settable(L, -3); + + lua_settable(L, -3); /* health table */ +} + /* This function pushes various arguments such as event type and event data to * the lua function that will be called to consume the event. */ @@ -9072,6 +9134,73 @@ __LJMP static void hlua_event_hdl_cb_push_args(struct hlua_event_sub *hlua_sub, lua_pushinteger(hlua->T, e_server->safe.proxy_uuid); lua_settable(hlua->T, -3); + /* special events, fetch additional info with explicit type casting */ + if (event_hdl_sub_type_equal(EVENT_HDL_SUB_SERVER_STATE, event)) { + struct event_hdl_cb_data_server_state *state = data; + int it; + + if (!lua_checkstack(hlua->T, 20)) + WILL_LJMP(luaL_error(hlua->T, "Lua out of memory error.")); + + /* state subclass */ + lua_pushstring(hlua->T, "state"); + lua_newtable(hlua->T); + + lua_pushstring(hlua->T, "admin"); + lua_pushboolean(hlua->T, state->safe.type); + lua_settable(hlua->T, -3); + + /* is it because of a check ? */ + if (!state->safe.type && + (state->safe.op_st_chg.cause == SRV_OP_STCHGC_HEALTH || + state->safe.op_st_chg.cause == SRV_OP_STCHGC_AGENT)) { + /* yes, provide check result */ + lua_pushstring(hlua->T, "check"); + lua_newtable(hlua->T); + hlua_event_hdl_cb_push_event_checkres(hlua->T, &state->safe.op_st_chg.check); + lua_settable(hlua->T, -3); /* check table */ + } + + lua_pushstring(hlua->T, "cause"); + if (state->safe.type) + lua_pushstring(hlua->T, srv_adm_st_chg_cause(state->safe.adm_st_chg.cause)); + else + lua_pushstring(hlua->T, srv_op_st_chg_cause(state->safe.op_st_chg.cause)); + lua_settable(hlua->T, -3); + + /* old_state, new_state */ + for (it = 0; it < 2; it++) { + enum srv_state srv_state = (!it) ? state->safe.old_state : state->safe.new_state; + + lua_pushstring(hlua->T, (!it) ? "old_state" : "new_state"); + switch (srv_state) { + case SRV_ST_STOPPED: + lua_pushstring(hlua->T, "STOPPED"); + break; + case SRV_ST_STOPPING: + lua_pushstring(hlua->T, "STOPPING"); + break; + case SRV_ST_STARTING: + lua_pushstring(hlua->T, "STARTING"); + break; + case SRV_ST_RUNNING: + lua_pushstring(hlua->T, "RUNNING"); + break; + default: + lua_pushnil(hlua->T); + break; + } + lua_settable(hlua->T, -3); + } + + /* requeued */ + lua_pushstring(hlua->T, "requeued"); + lua_pushinteger(hlua->T, state->safe.requeued); + lua_settable(hlua->T, -3); + + lua_settable(hlua->T, -3); /* state table */ + } + /* attempt to provide reference server object * (if it wasn't removed yet, SERVER_DEL will never succeed here) */