MINOR: checks/vars: Add a check scope for variables

Add a dedicated vars scope for checks. This scope is considered as part of the
session scope for accounting purposes.

The scope can be addressed by a valid session, even embryonic. The stream is not
necessary.

The scope is initialized after the check session is created. All variables are
then pruned before the session is destroyed.
diff --git a/include/proto/checks.h b/include/proto/checks.h
index 37681f1..d949175 100644
--- a/include/proto/checks.h
+++ b/include/proto/checks.h
@@ -26,6 +26,8 @@
 #include <common/config.h>
 #include <types/mailers.h>
 
+#include <types/action.h>
+
 const char *get_check_status_description(short check_status);
 const char *get_check_status_info(short check_status);
 void __health_adjust(struct server *s, short status);
diff --git a/include/types/checks.h b/include/types/checks.h
index f92f0da..b980faa 100644
--- a/include/types/checks.h
+++ b/include/types/checks.h
@@ -159,6 +159,7 @@
 
 struct check {
 	struct session *sess;			/* Health check session. */
+	struct vars vars;			/* Health check dynamic variables. */
 	struct xprt_ops *xprt;			/* transport layer operations for health checks */
 	struct conn_stream *cs;			/* conn_stream state for health checks */
 	struct buffer bi, bo;			/* input and output buffers to send/recv check */
diff --git a/include/types/vars.h b/include/types/vars.h
index 9b166e9..a72469f 100644
--- a/include/types/vars.h
+++ b/include/types/vars.h
@@ -12,6 +12,7 @@
 	SCOPE_REQ,
 	SCOPE_RES,
 	SCOPE_PROC,
+	SCOPE_CHECK,
 };
 
 struct vars {
diff --git a/src/checks.c b/src/checks.c
index 49a0f3d..9423e2d 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -58,6 +58,7 @@
 #include <proto/signal.h>
 #include <proto/stream_interface.h>
 #include <proto/task.h>
+#include <proto/vars.h>
 #include <proto/log.h>
 #include <proto/dns.h>
 #include <proto/proto_udp.h>
@@ -3224,12 +3225,13 @@
 	}
 	else {
 		/* First evaluation, create a session */
-		check->sess = session_new(&checks_fe, NULL, NULL);
+		check->sess = session_new(&checks_fe, NULL, (check->server ? &check->server->obj_type : NULL));
 		if (!check->sess) {
 			chunk_printf(&trash, "TCPCHK error allocating check session");
 			set_server_check_status(check, HCHK_STATUS_SOCKERR, trash.area);
 			goto out_end_tcpcheck;
 		}
+		vars_init(&check->vars, SCOPE_CHECK);
 		rule = LIST_NEXT(check->tcpcheck_rules, typeof(rule), list);
 	}
 
@@ -3339,12 +3341,12 @@
 	/* cleanup before leaving */
 	check->current_step = NULL;
 	if (check->sess != NULL) {
+		vars_prune(&check->vars, check->sess, NULL);
 		session_free(check->sess);
 		check->sess = NULL;
 	}
   out:
 	return retcode;
-
 }
 
 static const char *init_check(struct check *check, int type)
diff --git a/src/vars.c b/src/vars.c
index 403cb69..0b7b990 100644
--- a/src/vars.c
+++ b/src/vars.c
@@ -14,6 +14,7 @@
 #include <proto/stream.h>
 #include <proto/tcp_rules.h>
 #include <proto/vars.h>
+#include <proto/checks.h>
 
 /* This contains a pool of struct vars */
 DECLARE_STATIC_POOL(var_pool, "vars", sizeof(struct var));
@@ -33,6 +34,7 @@
 static unsigned int var_sess_limit = 0;
 static unsigned int var_txn_limit = 0;
 static unsigned int var_reqres_limit = 0;
+static unsigned int var_check_limit = 0;
 
 __decl_rwlock(var_names_rwlock);
 
@@ -46,6 +48,11 @@
 		return &global.vars;
 	case SCOPE_SESS:
 		return &sess->vars;
+	case SCOPE_CHECK: {
+			struct server *srv = objt_server(sess->origin);
+
+			return srv ? &srv->check.vars : NULL;
+		}
 	case SCOPE_TXN:
 		return strm ? &strm->vars_txn : NULL;
 	case SCOPE_REQ:
@@ -69,7 +76,15 @@
 	case SCOPE_TXN:
 		if (strm)
 			_HA_ATOMIC_ADD(&strm->vars_txn.size, size);
+		goto scope_sess;
+	case SCOPE_CHECK: {
+			struct server *srv = objt_server(sess->origin);
+
+			if (srv != NULL)
+				_HA_ATOMIC_ADD(&srv->check.vars.size, size);
+		}
 		/* fall through */
+scope_sess:
 	case SCOPE_SESS:
 		_HA_ATOMIC_ADD(&sess->vars.size, size);
 		/* fall through */
@@ -97,7 +112,16 @@
 	case SCOPE_TXN:
 		if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit)
 			return 0;
+		goto scope_sess;
+	case SCOPE_CHECK: {
+			struct server *srv = objt_server(sess->origin);
+
+			if (var_check_limit && srv &&
+			    srv->check.vars.size + size > var_check_limit)
+				return 0;
+		}
 		/* fall through */
+scope_sess:
 	case SCOPE_SESS:
 		if (var_sess_limit && sess->vars.size + size > var_sess_limit)
 			return 0;
@@ -226,9 +250,14 @@
 		len -= 4;
 		*scope = SCOPE_RES;
 	}
+	else if (len > 6 && strncmp(name, "check.", 6) == 0) {
+		name += 6;
+		len -= 6;
+		*scope = SCOPE_CHECK;
+	}
 	else {
 		memprintf(err, "invalid variable name '%s'. A variable name must be start by its scope. "
-		               "The scope can be 'proc', 'sess', 'txn', 'req' or 'res'", name);
+		               "The scope can be 'proc', 'sess', 'txn', 'req', 'res' or 'check'", name);
 		return res;
 	}
 
@@ -827,6 +856,13 @@
 	return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_reqres_limit);
 }
 
+static int vars_max_size_check(char **args, int section_type, struct proxy *curpx,
+                                struct proxy *defpx, const char *file, int line,
+                                char **err)
+{
+	return vars_max_size(args, section_type, curpx, defpx, file, line, err, &var_check_limit);
+}
+
 static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
 
 	{ "var", smp_fetch_var, ARG1(1,STR), smp_check_var, SMP_T_STR, SMP_USE_L4CLI },
@@ -897,6 +933,7 @@
 	{ CFG_GLOBAL, "tune.vars.sess-max-size",   vars_max_size_sess   },
 	{ CFG_GLOBAL, "tune.vars.txn-max-size",    vars_max_size_txn    },
 	{ CFG_GLOBAL, "tune.vars.reqres-max-size", vars_max_size_reqres },
+	{ CFG_GLOBAL, "tune.vars.check-max-size",  vars_max_size_check  },
 	{ /* END */ }
 }};