MINOR: hlua: Allow argument on lua-lod(-per-thread) directives

Allow per-lua file argument which makes multiples configuration
easier to handle

This patch fixes issue #1609.
This commit is contained in:
Thierry Fournier 2022-09-19 09:04:16 +02:00 committed by Christopher Faulet
parent 70e38e91b4
commit ae6b56800f
3 changed files with 73 additions and 11 deletions

View File

@ -1795,7 +1795,7 @@ log-tag <string>
Sometimes it can be useful to differentiate between multiple processes Sometimes it can be useful to differentiate between multiple processes
running on the same host. See also the per-proxy "log-tag" directive. running on the same host. See also the per-proxy "log-tag" directive.
lua-load <file> lua-load <file> [ <arg1> [ <arg2> [ ... ] ] ]
This global directive loads and executes a Lua file in the shared context This global directive loads and executes a Lua file in the shared context
that is visible to all threads. Any variable set in such a context is visible that is visible to all threads. Any variable set in such a context is visible
from any thread. This is the easiest and recommended way to load Lua programs from any thread. This is the easiest and recommended way to load Lua programs
@ -1804,7 +1804,14 @@ lua-load <file>
way will always see 0 in the "core.thread" variable. This directive can be way will always see 0 in the "core.thread" variable. This directive can be
used multiple times. used multiple times.
lua-load-per-thread <file> args are avalaible in the lua file using the code below in the body of the
file. Do not forget that Lua arrays start at index 1. A "local" variable
declared in a file is avalaible in the entire file and not avalaible on
other files.
local args = table.pack(...)
lua-load-per-thread <file> [ <arg1> [ <arg2> [ ... ] ] ]
This global directive loads and executes a Lua file into each started thread. This global directive loads and executes a Lua file into each started thread.
Any global variable has a thread-local visibility so that each thread could Any global variable has a thread-local visibility so that each thread could
see a different value. As such it is strongly recommended not to use global see a different value. As such it is strongly recommended not to use global
@ -1821,6 +1828,8 @@ lua-load-per-thread <file>
case it will be equivalent to lua-load). This directive can be used multiple case it will be equivalent to lua-load). This directive can be used multiple
times. times.
See lua-load for usage of args.
lua-prepend-path <string> [<type>] lua-prepend-path <string> [<type>]
Prepends the given string followed by a semicolon to Lua's package.<type> Prepends the given string followed by a semicolon to Lua's package.<type>
variable. variable.

View File

@ -116,6 +116,38 @@ On other terminal, you can test with telnet:
#:~ telnet 127.0.0.1 10001 #:~ telnet 127.0.0.1 10001
hello world hello world
Usage of load parameters
------------------------
HAProxy lua-load(-per-thread) directives allow a list of paramaters after
the lua file name. These parameters are accessible through an array of args
using this code `local args = table.pack(...)` in the body of loaded file.
Below, a new version of the hello world using load parameters
HAProxy configuration file (`hello_world.conf`):
::
global
lua-load hello_world.lua "this is not an hello world"
listen proxy
bind 127.0.0.1:10001
tcp-request inspect-delay 1s
tcp-request content use-service lua.hello_world
HAProxy Lua file (`hello_world.lua`):
.. code-block:: lua
local args = table.pack(...)
core.register_service("hello_world", "tcp", function(applet)
applet:send(args[1] .. "\n")
end)
Core class Core class
========== ==========

View File

@ -145,7 +145,7 @@ static struct list referenced_functions = LIST_HEAD_INIT(referenced_functions);
static int hlua_state_id; static int hlua_state_id;
/* This is a NULL-terminated list of lua file which are referenced to load per thread */ /* This is a NULL-terminated list of lua file which are referenced to load per thread */
static char **per_thread_load = NULL; static char ***per_thread_load = NULL;
lua_State *hlua_init_state(int thread_id); lua_State *hlua_init_state(int thread_id);
@ -11236,20 +11236,27 @@ static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
* We are in the configuration parsing process of HAProxy, this abort() is * We are in the configuration parsing process of HAProxy, this abort() is
* tolerated. * tolerated.
*/ */
static int hlua_load_state(char *filename, lua_State *L, char **err) static int hlua_load_state(char **args, lua_State *L, char **err)
{ {
int error; int error;
int nargs;
/* Just load and compile the file. */ /* Just load and compile the file. */
error = luaL_loadfile(L, filename); error = luaL_loadfile(L, args[0]);
if (error) { if (error) {
memprintf(err, "error in Lua file '%s': %s", filename, lua_tostring(L, -1)); memprintf(err, "error in Lua file '%s': %s", args[0], lua_tostring(L, -1));
lua_pop(L, 1); lua_pop(L, 1);
return -1; return -1;
} }
/* Push args in the Lua stack, except the first one which is the filename */
for (nargs = 1; *(args[nargs]) != 0; nargs++) {
lua_pushstring(L, args[nargs]);
}
nargs--;
/* If no syntax error where detected, execute the code. */ /* If no syntax error where detected, execute the code. */
error = lua_pcall(L, 0, LUA_MULTRET, 0); error = lua_pcall(L, nargs, LUA_MULTRET, 0);
switch (error) { switch (error) {
case LUA_OK: case LUA_OK:
break; break;
@ -11291,7 +11298,7 @@ static int hlua_load(char **args, int section_type, struct proxy *curpx,
/* loading for global state */ /* loading for global state */
hlua_state_id = 0; hlua_state_id = 0;
ha_set_thread(NULL); ha_set_thread(NULL);
return hlua_load_state(args[1], hlua_states[0], err); return hlua_load_state(&args[1], hlua_states[0], err);
} }
static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx, static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx,
@ -11299,6 +11306,7 @@ static int hlua_load_per_thread(char **args, int section_type, struct proxy *cur
char **err) char **err)
{ {
int len; int len;
int i;
if (*(args[1]) == 0) { if (*(args[1]) == 0) {
memprintf(err, "'%s' expects a file as parameter.", args[0]); memprintf(err, "'%s' expects a file as parameter.", args[0]);
@ -11323,19 +11331,32 @@ static int hlua_load_per_thread(char **args, int section_type, struct proxy *cur
memprintf(err, "out of memory error"); memprintf(err, "out of memory error");
return -1; return -1;
} }
per_thread_load[len] = strdup(args[1]);
per_thread_load[len + 1] = NULL; per_thread_load[len + 1] = NULL;
/* count args excepting the first, allocate array and copy args */
for (i = 0; *(args[i + 1]) != 0; i++);
per_thread_load[len] = calloc(i + 1, sizeof(per_thread_load[len]));
if (per_thread_load[len] == NULL) { if (per_thread_load[len] == NULL) {
memprintf(err, "out of memory error"); memprintf(err, "out of memory error");
return -1; return -1;
} }
for (i = 1; *(args[i]) != 0; i++) {
per_thread_load[len][i - 1] = strdup(args[i]);
if (per_thread_load[len][i - 1] == NULL) {
memprintf(err, "out of memory error");
return -1;
}
}
per_thread_load[len][i - 1] = strdup("");
if (per_thread_load[len][i - 1] == NULL) {
memprintf(err, "out of memory error");
return -1;
}
/* loading for thread 1 only */ /* loading for thread 1 only */
hlua_state_id = 1; hlua_state_id = 1;
ha_set_thread(NULL); ha_set_thread(NULL);
return hlua_load_state(args[1], hlua_states[1], err); return hlua_load_state(per_thread_load[len], hlua_states[1], err);
} }
/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable /* Prepend the given <path> followed by a semicolon to the `package.<type>` variable