]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: server/event_hdl: add SERVER_STATE event
authorAurelien DARRAGON <adarragon@haproxy.com>
Tue, 4 Apr 2023 19:28:07 +0000 (21:28 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 5 May 2023 14:28:32 +0000 (16:28 +0200)
Adding a new SERVER event in the event_hdl API.

SERVER_STATE is implemented as an advanced server event.
It is published each time the server's effective state changes.
(when s->cur_state changes)

SERVER_STATE data is an event_hdl_cb_data_server_state struct that
provides additional info related to the server state change, but can
be casted as a regular event_hdl_cb_data_server struct if additional
info is not needed.

include/haproxy/event_hdl-t.h
include/haproxy/server-t.h
src/event_hdl.c
src/server.c

index 77e7d933cdc8a09536fb7e3d4e7003c814fe3283..55d4da8a7d08daef9c19380976cbff634ab41533 100644 (file)
@@ -268,6 +268,8 @@ struct event_hdl_sub {
 #define EVENT_HDL_SUB_SERVER_DEL                        EVENT_HDL_SUB_TYPE(1,2)
 #define EVENT_HDL_SUB_SERVER_UP                         EVENT_HDL_SUB_TYPE(1,3)
 #define EVENT_HDL_SUB_SERVER_DOWN                       EVENT_HDL_SUB_TYPE(1,4)
+/* server state change */
+#define EVENT_HDL_SUB_SERVER_STATE                      EVENT_HDL_SUB_TYPE(1,5)
 
 /*     ---------------------------------------        */
 
index 69099b06546095d3d518a7ddcfe8910649a3191e..c9986dbd77c78edec7396e3a3f914e076cecc35d 100644 (file)
@@ -441,6 +441,7 @@ struct event_hdl_cb_data_server {
         *   EVENT_HDL_SUB_SERVER_DEL
         *   EVENT_HDL_SUB_SERVER_UP
         *   EVENT_HDL_SUB_SERVER_DOWN
+        *   EVENT_HDL_SUB_SERVER_STATE
         */
        struct {
                /* safe data can be safely used from both
@@ -468,6 +469,59 @@ struct event_hdl_cb_data_server {
        } unsafe;
 };
 
+/* check result snapshot provided through some event_hdl server events */
+struct event_hdl_cb_data_server_checkres {
+       uint8_t agent;                /* 1 = agent check, 0 = health check */
+       enum chk_result result;       /* failed, passed, condpass (CHK_RES_*) */
+       long duration;                /* total check duration in ms */
+       struct {
+               short status;         /* check status as in check->status */
+               short code;           /* provided with some check statuses */
+       } reason;
+       struct {
+               int cur;              /* dynamic (= check->health) */
+               int rise, fall;       /* config dependant */
+       } health;                     /* check's health, see check-t.h */
+};
+
+/* data provided to EVENT_HDL_SUB_SERVER_STATE handlers through
+ * event_hdl facility
+ *
+ * Note that this may be casted to regular event_hdl_cb_data_server if
+ * you don't care about state related optional info
+ */
+struct event_hdl_cb_data_server_state {
+       /* provided by:
+        *   EVENT_HDL_SUB_SERVER_STATE
+        */
+       struct event_hdl_cb_data_server server; /* must be at the beginning */
+       struct {
+               uint8_t type; /* 0 = operational, 1 = administrative */
+               enum srv_state old_state, new_state; /* updated by both operational and admin changes */
+               uint32_t requeued; /* requeued connections due to server state change */
+               union {
+                       /* state change cause:
+                        *
+                        * look for op_st_chg for operational state change,
+                        * and adm_st_chg for administrative state change
+                        */
+                       struct {
+                               enum srv_op_st_chg_cause cause;
+                               union {
+                                       /* check result is provided with
+                                        * cause == SRV_OP_STCHGC_HEALTH or cause == SRV_OP_STCHGC_AGENT
+                                        */
+                                       struct event_hdl_cb_data_server_checkres check;
+                               };
+                       } op_st_chg;
+                       struct {
+                               enum srv_adm_st_chg_cause cause;
+                       } adm_st_chg;
+               };
+       } safe;
+       /* no unsafe data */
+};
+
 /* Storage structure to load server-state lines from a flat file into
  * an ebtree, for faster processing
  */
index e2f01241e8f21bdcc43a2b0f9493cf00f680c72e..87b77ebfc3198d1f739cd9d7fe052f49a413f50e 100644 (file)
@@ -29,6 +29,7 @@ static struct event_hdl_sub_type_map event_hdl_sub_type_map[] = {
        {"SERVER_DEL",          EVENT_HDL_SUB_SERVER_DEL},
        {"SERVER_UP",           EVENT_HDL_SUB_SERVER_UP},
        {"SERVER_DOWN",         EVENT_HDL_SUB_SERVER_DOWN},
+       {"SERVER_STATE",        EVENT_HDL_SUB_SERVER_STATE},
 };
 
 /* internal types (only used in this file) */
index b634510e696cb7b068f7f028f03d33273da4b161..5bc73ccd57f5490dd917ea7704ebd765ca32f5c4 100644 (file)
@@ -189,6 +189,51 @@ static inline void _srv_event_hdl_prepare(struct event_hdl_cb_data_server *cb_da
        cb_data->unsafe.srv_lock = !thread_isolate;
 }
 
+/* take an event-check snapshot from a live check */
+void _srv_event_hdl_prepare_checkres(struct event_hdl_cb_data_server_checkres *checkres,
+                                     struct check *check)
+{
+       checkres->agent = !!(check->state & CHK_ST_AGENT);
+       checkres->result = check->result;
+       checkres->duration = check->duration;
+       checkres->reason.status = check->status;
+       checkres->reason.code = check->code;
+       checkres->health.cur = check->health;
+       checkres->health.rise = check->rise;
+       checkres->health.fall = check->fall;
+}
+
+/* Prepare SERVER_STATE event
+ *
+ * This special event will contain extra hints related to the state change
+ *
+ * Must be called with server lock held
+ */
+void _srv_event_hdl_prepare_state(struct event_hdl_cb_data_server_state *cb_data,
+                                  struct server *srv, int type, int cause,
+                                  enum srv_state prev_state, int requeued)
+{
+       /* state event provides additional info about the server state change */
+       cb_data->safe.type = type;
+       cb_data->safe.new_state = srv->cur_state;
+       cb_data->safe.old_state = prev_state;
+       cb_data->safe.requeued = requeued;
+       if (type) {
+               /* administrative */
+               cb_data->safe.adm_st_chg.cause = cause;
+       }
+       else {
+               /* operational */
+               cb_data->safe.op_st_chg.cause = cause;
+               if (cause == SRV_OP_STCHGC_HEALTH || cause == SRV_OP_STCHGC_AGENT) {
+                       struct check *check = (cause == SRV_OP_STCHGC_HEALTH) ? &srv->check : &srv->agent;
+
+                       /* provide additional check-related state change result */
+                       _srv_event_hdl_prepare_checkres(&cb_data->safe.op_st_chg.check, check);
+               }
+       }
+}
+
 /* server event publishing helper: publish in both global and
  * server dedicated subscription list.
  */
@@ -5744,11 +5789,19 @@ static void srv_update_status(struct server *s, int type, int cause)
 {
        int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
        enum srv_state srv_prev_state = s->cur_state;
+       union {
+               struct event_hdl_cb_data_server_state state;
+               struct event_hdl_cb_data_server common;
+       } cb_data;
+       int requeued;
+
+       /* prepare common server event data */
+       _srv_event_hdl_prepare(&cb_data.common, s, 0);
 
        if (type)
-               _srv_update_status_adm(s, cause);
+               requeued = _srv_update_status_adm(s, cause);
        else
-               _srv_update_status_op(s, cause);
+               requeued = _srv_update_status_op(s, cause);
 
        /* explicitly commit state changes (even if it was already applied implicitly
         * by some lb state change function), so we don't miss anything
@@ -5767,6 +5820,11 @@ static void srv_update_status(struct server *s, int type, int cause)
                        s->counters.down_trans++;
                }
                s->last_change = ns_to_sec(now_ns);
+
+               /* publish the state change */
+               _srv_event_hdl_prepare_state(&cb_data.state,
+                                            s, type, cause, srv_prev_state, requeued);
+               _srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_STATE, cb_data.state, s);
        }
 
        /* check if backend stats must be updated due to the server state change */