]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: hlua_fcn: dynamic server iteration and indexing
authorThierry Fournier <tfournier@arpalert.org>
Fri, 7 Oct 2022 11:25:51 +0000 (13:25 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 5 Apr 2023 06:58:16 +0000 (08:58 +0200)
This patch proposes to enumerate servers using internal HAProxy list.
Also, remove the flag SRV_F_NON_PURGEABLE which makes the server non
purgeable each time Lua uses the server.

Removing reg-tests/cli_delete_server_lua.vtc since this test is no
longer relevant (we don't set the SRV_F_NON_PURGEABLE flag anymore)
and we already have a more generic test:
  reg-tests/server/cli_delete_server.vtc

Co-authored-by: Aurelien DARRAGON <adarragon@haproxy.com>
include/haproxy/hlua-t.h
reg-tests/server/cli_delete_server_lua.vtc [deleted file]
src/hlua_fcn.c

index af716d9c3d1daaf272b920994bc5cd41215e57d0..66c4b80491a78d6988958d91f617bdb1688fea93 100644 (file)
@@ -54,6 +54,7 @@
 #define CLASS_STKTABLE     "StickTable"
 #define CLASS_CERTCACHE    "CertCache"
 #define CLASS_PROXY_LIST   "ProxyList"
+#define CLASS_SERVER_LIST  "ServerList"
 
 struct stream;
 
@@ -212,6 +213,15 @@ struct hlua_proxy_list_iterator_context {
        char capabilities;
 };
 
+struct hlua_server_list {
+       struct proxy *px;
+};
+
+struct hlua_server_list_iterator_context {
+       struct server *cur;
+       struct proxy *px;
+};
+
 #else /* USE_LUA */
 /************************ For use when Lua is disabled ********************/
 
diff --git a/reg-tests/server/cli_delete_server_lua.vtc b/reg-tests/server/cli_delete_server_lua.vtc
deleted file mode 100644 (file)
index 396cd21..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# This script is to check that servers that are referenced by a lua script
-# cannot be removed at runtime.
-varnishtest "Delete lua server via cli"
-
-feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(2.5-dev0)'"
-feature cmd "$HAPROXY_PROGRAM -cc 'feature(LUA)'"
-feature ignore_unknown_macro
-
-server s1 {
-       rxreq
-       txresp
-} -start
-
-haproxy h1 -conf {
-       global
-               lua-load ${testdir}/get_srv_stats.lua
-
-       defaults
-               mode http
-               timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
-               timeout client  "${HAPROXY_TEST_TIMEOUT-5s}"
-               timeout server  "${HAPROXY_TEST_TIMEOUT-5s}"
-
-       frontend fe
-               bind "fd@${feS}"
-               default_backend test
-
-       backend test
-               http-request add-header s1-stats %[lua.get_srv_stats(s1)]
-               server s1 ${s1_addr}:${s1_port}          # referenced in lua script
-} -start
-
-# make a request to force the execution of the lua script which references a
-# server
-client c1 -connect ${h1_feS_sock} {
-       txreq
-       rxresp
-} -run
-
-haproxy h1 -cli {
-       send "experimental-mode on; del server test/s1"
-       expect ~ "This server cannot be removed at runtime due to other configuration elements pointing to it."
-}
index c12300fed7bce11fd675c56f77d1149e00b8a4f8..4eb28ae1e7e776353fd91db2bc5c48ca726fc9ed 100644 (file)
@@ -47,6 +47,7 @@ static int class_listener_ref;
 static int class_regex_ref;
 static int class_stktable_ref;
 static int class_proxy_list_ref;
+static int class_server_list_ref;
 
 #define STATS_LEN (MAX((int)ST_F_TOTAL_FIELDS, (int)INF_TOTAL_FIELDS))
 
@@ -890,6 +891,9 @@ int hlua_fcn_new_server(lua_State *L, struct server *srv)
 
        lua_newtable(L);
 
+       /* increment server refcount */
+       srv_take(srv);
+
        /* Pop a class sesison metatable and affect it to the userdata. */
        lua_rawgeti(L, LUA_REGISTRYINDEX, class_server_ref);
        lua_setmetatable(L, -2);
@@ -911,10 +915,20 @@ int hlua_fcn_new_server(lua_State *L, struct server *srv)
        return 1;
 }
 
+int hlua_server_gc(lua_State *L)
+{
+       struct server *srv = hlua_checkudata(L, 1, class_server_ref);
+
+       srv_drop(srv); /* srv_drop allows NULL srv */
+       return 0;
+}
+
 static struct server *hlua_check_server(lua_State *L, int ud)
 {
        struct server *srv = hlua_checkudata(L, ud, class_server_ref);
-       srv->flags |= SRV_F_NON_PURGEABLE;
+       if (srv->flags & SRV_F_DELETED) {
+               return NULL;
+       }
        return srv;
 }
 
@@ -924,6 +938,10 @@ int hlua_server_get_stats(lua_State *L)
        int i;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
 
        if (!srv->proxy) {
                lua_pushnil(L);
@@ -950,6 +968,10 @@ int hlua_server_get_addr(lua_State *L)
        luaL_Buffer b;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
 
        luaL_buffinit(L, &b);
 
@@ -988,6 +1010,10 @@ int hlua_server_get_puid(lua_State *L)
        char buffer[12];
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
 
        snprintf(buffer, sizeof(buffer), "%d", srv->puid);
        lua_pushstring(L, buffer);
@@ -999,6 +1025,11 @@ int hlua_server_get_name(lua_State *L)
        struct server *srv;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
+
        lua_pushstring(L, srv->id);
        return 1;
 }
@@ -1008,6 +1039,11 @@ int hlua_server_is_draining(lua_State *L)
        struct server *srv;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
+
        lua_pushinteger(L, server_is_draining(srv));
        return 1;
 }
@@ -1019,6 +1055,11 @@ int hlua_server_set_maxconn(lua_State *L)
        const char *err;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
+
        maxconn = luaL_checkstring(L, 2);
 
        HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
@@ -1036,6 +1077,11 @@ int hlua_server_get_maxconn(lua_State *L)
        struct server *srv;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
+
        lua_pushinteger(L, srv->maxconn);
        return 1;
 }
@@ -1047,6 +1093,11 @@ int hlua_server_set_weight(lua_State *L)
        const char *err;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
+
        weight = luaL_checkstring(L, 2);
 
        HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
@@ -1064,6 +1115,11 @@ int hlua_server_get_weight(lua_State *L)
        struct server *srv;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
+
        lua_pushinteger(L, srv->uweight);
        return 1;
 }
@@ -1076,6 +1132,11 @@ int hlua_server_set_addr(lua_State *L)
        const char *err;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
+
        addr = luaL_checkstring(L, 2);
        if (lua_gettop(L) >= 3)
                port = luaL_checkstring(L, 3);
@@ -1097,6 +1158,9 @@ int hlua_server_shut_sess(lua_State *L)
        struct server *srv;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
        srv_shutdown_streams(srv, SF_ERR_KILLED);
        HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
@@ -1108,6 +1172,9 @@ int hlua_server_set_drain(lua_State *L)
        struct server *srv;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
        srv_adm_set_drain(srv);
        HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
@@ -1119,6 +1186,9 @@ int hlua_server_set_maint(lua_State *L)
        struct server *srv;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
        srv_adm_set_maint(srv);
        HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
@@ -1130,6 +1200,9 @@ int hlua_server_set_ready(lua_State *L)
        struct server *srv;
 
        srv = hlua_check_server(L, 1);
+       if (srv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
        srv_adm_set_ready(srv);
        HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
@@ -1141,6 +1214,9 @@ int hlua_server_check_enable(lua_State *L)
        struct server *sv;
 
        sv = hlua_check_server(L, 1);
+       if (sv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
        if (sv->check.state & CHK_ST_CONFIGURED) {
                sv->check.state |= CHK_ST_ENABLED;
@@ -1154,6 +1230,9 @@ int hlua_server_check_disable(lua_State *L)
        struct server *sv;
 
        sv = hlua_check_server(L, 1);
+       if (sv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
        if (sv->check.state & CHK_ST_CONFIGURED) {
                sv->check.state &= ~CHK_ST_ENABLED;
@@ -1167,6 +1246,9 @@ int hlua_server_check_force_up(lua_State *L)
        struct server *sv;
 
        sv = hlua_check_server(L, 1);
+       if (sv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
        if (!(sv->track)) {
                sv->check.health = sv->check.rise + sv->check.fall - 1;
@@ -1181,6 +1263,9 @@ int hlua_server_check_force_nolb(lua_State *L)
        struct server *sv;
 
        sv = hlua_check_server(L, 1);
+       if (sv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
        if (!(sv->track)) {
                sv->check.health = sv->check.rise + sv->check.fall - 1;
@@ -1195,6 +1280,9 @@ int hlua_server_check_force_down(lua_State *L)
        struct server *sv;
 
        sv = hlua_check_server(L, 1);
+       if (sv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
        if (!(sv->track)) {
                sv->check.health = 0;
@@ -1209,6 +1297,9 @@ int hlua_server_agent_enable(lua_State *L)
        struct server *sv;
 
        sv = hlua_check_server(L, 1);
+       if (sv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
        if (sv->agent.state & CHK_ST_CONFIGURED) {
                sv->agent.state |= CHK_ST_ENABLED;
@@ -1222,6 +1313,9 @@ int hlua_server_agent_disable(lua_State *L)
        struct server *sv;
 
        sv = hlua_check_server(L, 1);
+       if (sv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
        if (sv->agent.state & CHK_ST_CONFIGURED) {
                sv->agent.state &= ~CHK_ST_ENABLED;
@@ -1235,6 +1329,9 @@ int hlua_server_agent_force_up(lua_State *L)
        struct server *sv;
 
        sv = hlua_check_server(L, 1);
+       if (sv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
        if (sv->agent.state & CHK_ST_ENABLED) {
                sv->agent.health = sv->agent.rise + sv->agent.fall - 1;
@@ -1249,6 +1346,9 @@ int hlua_server_agent_force_down(lua_State *L)
        struct server *sv;
 
        sv = hlua_check_server(L, 1);
+       if (sv == NULL) {
+               return 0;
+       }
        HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
        if (sv->agent.state & CHK_ST_ENABLED) {
                sv->agent.health = 0;
@@ -1258,9 +1358,110 @@ int hlua_server_agent_force_down(lua_State *L)
        return 0;
 }
 
-int hlua_fcn_new_proxy(lua_State *L, struct proxy *px)
+static struct hlua_server_list *hlua_check_server_list(lua_State *L, int ud)
+{
+       return hlua_checkudata(L, ud, class_server_list_ref);
+}
+
+/* does nothing and returns 0, only prevents insertions in the
+ * table which represents the list of servers
+ */
+int hlua_listable_servers_newindex(lua_State *L) {
+       return 0;
+}
+
+/* first arg is the table (struct hlua_server_list * in metadata)
+ * second arg is the required index
+ */
+int hlua_listable_servers_index(lua_State *L)
 {
+       struct hlua_server_list *hlua_srv;
+       const char *name;
        struct server *srv;
+
+       hlua_srv = hlua_check_server_list(L, 1);
+       name = luaL_checkstring(L, 2);
+
+       /* Perform a server lookup in px list */
+       srv = server_find_by_name(hlua_srv->px, name);
+       if (srv == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
+
+       hlua_fcn_new_server(L, srv);
+       return 1;
+}
+
+/* iterator must return key as string and value as server
+ * object, if we reach end of list, it returns nil.
+ * The context knows the last returned server. if the
+ * context contains srv == NULL, we start enumeration.
+ * Then, use 'srv->next' ptr to iterate through the list
+ */
+int hlua_listable_servers_pairs_iterator(lua_State *L)
+{
+       int context_index;
+       struct hlua_server_list_iterator_context *ctx;
+
+       context_index = lua_upvalueindex(1);
+       ctx = lua_touserdata(L, context_index);
+
+       if (ctx->cur == NULL) {
+               /* First iteration, initialize list on the first server */
+               ctx->cur = ctx->px->srv;
+       } else {
+
+               /* Next server (next ptr is always valid, even if current
+                * server has the SRV_F_DELETED flag set)
+                */
+               ctx->cur = ctx->cur->next;
+       }
+
+       /* next server is null, end of iteration */
+       if (ctx->cur == NULL) {
+               lua_pushnil(L);
+               return 1;
+       }
+
+       lua_pushstring(L, ctx->cur->id);
+       hlua_fcn_new_server(L, ctx->cur);
+       return 2;
+}
+
+/* init the iterator context, return iterator function
+ * with context as closure. The only argument is a
+ * server list object.
+ */
+int hlua_listable_servers_pairs(lua_State *L)
+{
+       struct hlua_server_list_iterator_context *ctx;
+       struct hlua_server_list *hlua_srv_list;
+
+       hlua_srv_list = hlua_check_server_list(L, 1);
+
+       ctx = lua_newuserdata(L, sizeof(*ctx));
+       ctx->px = hlua_srv_list->px;
+       ctx->cur = NULL;
+
+       lua_pushcclosure(L, hlua_listable_servers_pairs_iterator, 1);
+       return 1;
+}
+
+void hlua_listable_servers(lua_State *L, struct proxy *px)
+{
+       struct hlua_server_list *list;
+
+       lua_newtable(L);
+       list = lua_newuserdata(L, sizeof(*list));
+       list->px = px;
+       lua_rawseti(L, -2, 0);
+       lua_rawgeti(L, LUA_REGISTRYINDEX, class_server_list_ref);
+       lua_setmetatable(L, -2);
+}
+
+int hlua_fcn_new_proxy(lua_State *L, struct proxy *px)
+{
        struct listener *lst;
        int lid;
        char buffer[17];
@@ -1287,12 +1488,7 @@ int hlua_fcn_new_proxy(lua_State *L, struct proxy *px)
 
        /* Browse and register servers. */
        lua_pushstring(L, "servers");
-       lua_newtable(L);
-       for (srv = px->srv; srv; srv = srv->next) {
-               lua_pushstring(L, srv->id);
-               hlua_fcn_new_server(L, srv);
-               lua_settable(L, -3);
-       }
+       hlua_listable_servers(L, px);
        lua_settable(L, -3);
 
        /* Browse and register listeners. */
@@ -1819,6 +2015,7 @@ void hlua_fcn_reg_core_fcn(lua_State *L)
 
        /* Create server object. */
        lua_newtable(L);
+       hlua_class_function(L, "__gc", hlua_server_gc);
        lua_pushstring(L, "__index");
        lua_newtable(L);
        hlua_class_function(L, "get_name", hlua_server_get_name);
@@ -1893,4 +2090,13 @@ void hlua_fcn_reg_core_fcn(lua_State *L)
        lua_pushstring(L, "backends");
        hlua_listable_proxies(L, PR_CAP_BE);
        lua_settable(L, -3);
+
+       /* list of server. This object is similar to
+        * CLASS_PROXY_LIST
+        */
+       lua_newtable(L);
+       hlua_class_function(L, "__index", hlua_listable_servers_index);
+       hlua_class_function(L, "__newindex", hlua_listable_servers_newindex);
+       hlua_class_function(L, "__pairs", hlua_listable_servers_pairs);
+       class_server_list_ref = hlua_register_metatable(L, CLASS_SERVER_LIST);
 }