On Sat, 31 Oct 2015 21:22:14 +0100
PiBa-NL <[email protected]> wrote:

> Hi Thierry, haproxy-list,


Hi Pieter,


> I've created another possibly interesting lua script, and it works :) 
> (mostly). (on my test machine..)
> 
> When i visit the 192.168.0.120:9003 website i always see the 'Hello 
> World' page. So in that regard this is usable, it is left to the browser 
> to send the request again, not sure how safe this is in regard to 
> mutations being send twice. It should probably check for POST requests 
> and then just return the error without replacing it with a redirect.. 
> Not sure if that would catch all problem cases..
> 
> Ive created a lua service that counts how many requests are made, and 
> returns a error status every 5th request.
> Second there is a lua response script that checks the status, and 
> replaces it by a redirect if it sees the faulty status 500.
> This does currently result in the connection being closed and reopened 
> probably due to the txn.res:send().?.
> 
> Though i am still struggling with what is and isn't supposed to be possible.
> For example the scripts below are running in 'mode http' and mostly just 
> changing 'headers'.
> I expected to be able to simply read the status by calling 
> txn.f:status() but this always seems to result in 'null'.
> Manually parsing the response buffer duplicate works but seems ugly..
> 
> txn.f:status()  <  it doesnt result in the actual status.


This is a bug wich I reproduce. Can you try the attached patches ?


> txn.res:set()  < if used in place of send() causes 30 second delay


This function put data in the input part of the response buffer. This
new data follows the HAProxy stream when the Lua script is finished.
It is your case.

I can't reproduce this behaviour, I suppose that its because I work
locally, and I'm not impacted by the network latency.


> txn.done()  < dumps core. (im not sure when ever to call it? the script 
> below seems to match the description that this function has.?.)


I can't reproduce too, for the same reasons, I guess.


> Am i trying to do it wrong?
> 
> p.s. Is 'health checking' using lua possible? The redis example looks 
> like a health 'ping'.. It could possibly be much much more flexible then 
> the tcp-check send  / tcp-check expect routines..


It is not possible. You can write a task which do something (like an
http request) and reuse the result in the request processing Lua code,
but this task cannot set the status of the server.

Thierry


> I'm currently testing with HA-Proxy version 1.7-dev0-e4c4b7d and the 
> following configuration files:
> 
> #### haproxy.cfg ###
> global
>      maxconn            6000
>      lua-load        /var/etc/haproxy/luascript_lua-count5error
> defaults
>      timeout connect        30000
>      timeout server        30000
>      timeout client        30000
>      mode            http
>      log            global
> frontend TEST-lua-count
>      bind            192.168.0.120:9002
>      option            http-keep-alive
>      http-request use-service lua.lua-count
> 
> frontend TEST-lua-retry-serverror
>      bind            192.168.0.120:9003
>      option            http-keep-alive
>      http-request lua.retrystorerequest
>      http-response lua.retryerrors
>      default_backend hap_9002_http_ipvANY
> 
> backend hap_9002_http_ipvANY
>      mode            http
>      retries            3
>      server            192.168.0.120_9002 192.168.0.120:9002
> 
> ### luascript_lua-count5error ###
> core.register_action("retryerrors" , { "http-res" }, function(txn)
>      local clientip = txn.f:src()
>      txn:Info("  LUA client " .. clientip)
> 
>      local s = txn.f:status() -- doesnt work?
>      if s == null then
>          core.Info("LUA txn.s:status RETURNED: NULL, fallback needed ??")
>          local req = txn.res:dup()
>          local statusstr = string.sub(req, 10, 13)
>          s = tonumber(statusstr)
>      end
>      core.Info("LUA status " .. s)
> 
>      if s ~= 200 then
>          txn:Info("LUA REDIRECT IT ! " .. s)
> 
>          local url = txn:get_priv()
>          local response = ""
>          response = response .. "HTTP/1.1 302 Moved\r\n"
>          response = response .. "Location: " .. url .."\r\n"
>          response = response .. "\r\n"
> 
>          txn.res:send(response)
>          --txn.res:set(response) -- causes 30 second delay..
>          --txn:done() --dumps core..
>      end
> end);
> 
> core.register_action("retrystorerequest" , { "http-req" }, function(txn)
>      local url = txn.f:url()
>      txn:set_priv(url);
> end);
> 
> core.register_service("lua-count", "http", function(applet)
>     if test == null then
>        test = 0
>     end
>     test = test + 1
>     local response = ""
>     if test % 5 == 0 then
>        applet:set_status(500)
>        response = "Error " .. test
>     else
>        applet:set_status(200)
>        response = "Hello World !" .. test
>     end
>     applet:add_header("content-length", string.len(response))
>     applet:add_header("content-type", "text/plain")
>     applet:start_response()
>     applet:send(response)
> end)
> 
> 
>From dbec61f7ba9c975f32c3a9ff9ac95ab9be90359e Mon Sep 17 00:00:00 2001
From: Thierry FOURNIER <[email protected]>
Date: Mon, 2 Nov 2015 09:52:54 +0100
Subject: [PATCH 1/2] CLEANUP: use direction names in place of numeric values

This patch cleanups the direction names. It replaces numeric values,
by the associated defines. It ensure the compliance with values found
somwhere else in HAProxy.

It is required by the bugfix patch which is following.
---
 src/hlua.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/hlua.c b/src/hlua.c
index 2fc492c..fb6ccf8 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -2458,17 +2458,17 @@ static void hlua_resynchonize_proto(struct stream *stream, int dir)
 	/* Protocol HTTP. */
 	if (stream->be->mode == PR_MODE_HTTP) {
 
-		if (dir == 0)
+		if (dir == SMP_OPT_DIR_REQ)
 			http_txn_reset_req(stream->txn);
-		else if (dir == 1)
+		else if (dir == SMP_OPT_DIR_RES)
 			http_txn_reset_res(stream->txn);
 
 		if (stream->txn->hdr_idx.v)
 			hdr_idx_init(&stream->txn->hdr_idx);
 
-		if (dir == 0)
+		if (dir == SMP_OPT_DIR_REQ)
 			http_msg_analyzer(&stream->txn->req, &stream->txn->hdr_idx);
-		else if (dir == 1)
+		else if (dir == SMP_OPT_DIR_RES)
 			http_msg_analyzer(&stream->txn->rsp, &stream->txn->hdr_idx);
 	}
 }
@@ -2487,13 +2487,13 @@ static int hlua_check_proto(struct stream *stream, int dir)
 	 * if the parser is still expected to run or not.
 	 */
 	if (stream->be->mode == PR_MODE_HTTP) {
-		if (dir == 0 &&
+		if (dir == SMP_OPT_DIR_REQ &&
 		    !(stream->req.analysers & AN_REQ_WAIT_HTTP) &&
 		    stream->txn->req.msg_state < HTTP_MSG_BODY) {
 			stream_int_retnclose(&stream->si[0], &msg);
 			return 0;
 		}
-		else if (dir == 1 &&
+		else if (dir == SMP_OPT_DIR_RES &&
 		         !(stream->res.analysers & AN_RES_WAIT_HTTP) &&
 		         stream->txn->rsp.msg_state < HTTP_MSG_BODY) {
 			stream_int_retnclose(&stream->si[0], &msg);
@@ -5439,10 +5439,10 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
 	int dir;
 
 	switch (rule->from) {
-	case ACT_F_TCP_REQ_CNT: analyzer = AN_REQ_INSPECT_FE     ; dir = 0; break;
-	case ACT_F_TCP_RES_CNT: analyzer = AN_RES_INSPECT        ; dir = 1; break;
-	case ACT_F_HTTP_REQ:    analyzer = AN_REQ_HTTP_PROCESS_FE; dir = 0; break;
-	case ACT_F_HTTP_RES:    analyzer = AN_RES_HTTP_PROCESS_BE; dir = 1; break;
+	case ACT_F_TCP_REQ_CNT: analyzer = AN_REQ_INSPECT_FE     ; dir = SMP_OPT_DIR_REQ; break;
+	case ACT_F_TCP_RES_CNT: analyzer = AN_RES_INSPECT        ; dir = SMP_OPT_DIR_RES; break;
+	case ACT_F_HTTP_REQ:    analyzer = AN_REQ_HTTP_PROCESS_FE; dir = SMP_OPT_DIR_REQ; break;
+	case ACT_F_HTTP_RES:    analyzer = AN_RES_HTTP_PROCESS_BE; dir = SMP_OPT_DIR_RES; break;
 	default:
 		SEND_ERR(px, "Lua: internal error while execute action.\n");
 		return ACT_RET_CONT;
-- 
2.1.4

>From aad8923ea259a3b8df260101b45a63f6d48c434d Mon Sep 17 00:00:00 2001
From: Thierry FOURNIER <[email protected]>
Date: Mon, 2 Nov 2015 10:01:59 +0100
Subject: [PATCH 2/2] BUG/MEDIUM: lua: sample fetches based on response doesn't
 work

The direction (request or response) is not propagated in the
sample fecthes called throught Lua. This patch adds the direction
status in some structs (hlua_txn and hlua_smp) to make sure that
the sample fetches will be called with all the information.

The converters can not access to a TXN object, so there are not
impacted the direction. However, the samples used as input of the
Lua converter wrapper are initiliazed with the direction. Thereby,
the struct smp stay consistent.
---
 include/types/hlua.h |  2 ++
 src/hlua.c           | 13 ++++++++-----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/include/types/hlua.h b/include/types/hlua.h
index 48f7487..5b967d7 100644
--- a/include/types/hlua.h
+++ b/include/types/hlua.h
@@ -100,6 +100,7 @@ struct hlua_rule {
 struct hlua_txn {
 	struct stream *s;
 	struct proxy *p;
+	int dir;
 };
 
 /* This struct contains the applet context. */
@@ -114,6 +115,7 @@ struct hlua_smp {
 	struct stream *s;
 	struct proxy *p;
 	int stringsafe;
+	int dir;
 };
 
 /* This struct contains data used with sleep functions. */
diff --git a/src/hlua.c b/src/hlua.c
index fb6ccf8..652365c 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -2978,6 +2978,7 @@ static int hlua_fetches_new(lua_State *L, struct hlua_txn *txn, int stringsafe)
 
 	hsmp->s = txn->s;
 	hsmp->p = txn->p;
+	hsmp->dir = txn->dir;
 	hsmp->stringsafe = stringsafe;
 
 	/* Pop a class sesison metatable and affect it to the userdata. */
@@ -3031,7 +3032,7 @@ __LJMP static int hlua_run_sample_fetch(lua_State *L)
 	smp.px = hsmp->p;
 	smp.sess = hsmp->s->sess;
 	smp.strm = hsmp->s;
-	smp.opt = 0;
+	smp.opt = hsmp->dir;
 	if (!f->process(args, &smp, f->kw, f->private)) {
 		if (hsmp->stringsafe)
 			lua_pushstring(L, "");
@@ -3085,6 +3086,7 @@ static int hlua_converters_new(lua_State *L, struct hlua_txn *txn, int stringsaf
 
 	hsmp->s = txn->s;
 	hsmp->p = txn->p;
+	hsmp->dir = txn->dir;
 	hsmp->stringsafe = stringsafe;
 
 	/* Pop a class stream metatable and affect it to the table. */
@@ -3153,7 +3155,7 @@ __LJMP static int hlua_run_sample_conv(lua_State *L)
 	smp.px = hsmp->p;
 	smp.sess = hsmp->s->sess;
 	smp.strm = hsmp->s;
-	smp.opt = 0;
+	smp.opt = hsmp->dir;
 	if (!conv->process(args, &smp, conv->private)) {
 		if (hsmp->stringsafe)
 			lua_pushstring(L, "");
@@ -4590,7 +4592,7 @@ __LJMP static int hlua_get_priv(lua_State *L)
  * return 0 if the stack does not contains free slots,
  * otherwise it returns 1.
  */
-static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p)
+static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p, int dir)
 {
 	struct hlua_txn *htxn;
 
@@ -4609,6 +4611,7 @@ static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p)
 
 	htxn->s = s;
 	htxn->p = p;
+	htxn->dir = dir;
 
 	/* Create the "f" field that contains a list of fetches. */
 	lua_pushstring(L, "f");
@@ -5240,7 +5243,7 @@ static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp
 		lua_rawgeti(stream->hlua.T, LUA_REGISTRYINDEX, fcn->function_ref);
 
 		/* push arguments in the stack. */
-		if (!hlua_txn_new(stream->hlua.T, stream, smp->px)) {
+		if (!hlua_txn_new(stream->hlua.T, stream, smp->px, smp->opt & SMP_OPT_DIR)) {
 			SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
 			RESET_SAFE_LJMP(stream->hlua.T);
 			return 0;
@@ -5481,7 +5484,7 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
 		lua_rawgeti(s->hlua.T, LUA_REGISTRYINDEX, rule->arg.hlua_rule->fcn.function_ref);
 
 		/* Create and and push object stream in the stack. */
-		if (!hlua_txn_new(s->hlua.T, s, px)) {
+		if (!hlua_txn_new(s->hlua.T, s, px, dir)) {
 			SEND_ERR(px, "Lua function '%s': full stack.\n",
 			         rule->arg.hlua_rule->fcn.name);
 			RESET_SAFE_LJMP(s->hlua.T);
-- 
2.1.4

Reply via email to