]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: checks: Add a list of vars to set before executing a tpc-check ruleset
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 2 Apr 2020 16:05:11 +0000 (18:05 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 27 Apr 2020 07:39:37 +0000 (09:39 +0200)
A list of variables is now associated to each tcp-check ruleset. It is more a
less a list of set-var expressions. This list may be filled during the
configuration parsing. The listed variables will then be set during each
execution of the tcp-check healthcheck, at the begining, before execution of the
the first tcp-check rule.

This patch is mandatory to convert all protocol checks to tcp-checks. It is a
way to customize shared tcp-check rulesets.

include/proto/checks.h
include/types/checks.h
src/cfgparse-listen.c
src/checks.c
src/proxy.c

index fb33746cf561639885c17036da45c0960dfc9d6e..d0c827bd77a5bd0b9e769631752d001b7bd92028 100644 (file)
@@ -63,6 +63,8 @@ static inline void tcp_check_keywords_register(struct action_kw_list *kw_list)
 }
 
 void deinit_proxy_tcpcheck(struct proxy *px);
+int dup_tcpcheck_vars(struct list *dst, struct list *src);
+
 /* Declared here, but the definitions are in flt_spoe.c */
 int spoe_prepare_healthcheck_request(char **req, int *len);
 int spoe_handle_healthcheck_response(char *frame, size_t size, char *err, int errlen);
index 94ce5f228838dd0eb4b9858a4ec6902efde412a1..c44fe8e39009e992d7bad53e3c7d329a93e14633 100644 (file)
@@ -302,10 +302,18 @@ struct tcpcheck_rule {
 #define TCPCHK_RULES_SHARED 0x00000001 /* Set for shared list of tcp-check rules */
 #define TCPCHK_RULES_DEF    0x00000002 /* Ruleset inherited from the default section */
 
+/* A list of tcp-check vars, to be registered before executing a ruleset */
+struct tcpcheck_var {
+       struct ist name;         /* the variable name with the scope */
+       struct sample_data data; /* the data associated to the variable */
+       struct list list;        /* element to chain tcp-check vars */
+};
+
 /* a list of tcp-check rules */
 struct tcpcheck_rules {
-       unsigned int flags; /* flags applied to the rules */
-       struct list *list; /* the list of tcpcheck_rules */
+       unsigned int flags;       /* flags applied to the rules */
+       struct list *list;        /* the list of tcpcheck_rules */
+       struct list  preset_vars; /* The list of variable to preset before executing the ruleset */
 };
 
 /* A list of tcp-check rules with a name */
index f098b16b6a13bcd6952c3555e3c0305ad76b13cd..0b2ef1583c0c1e1e9be4d81653e28fe441cf959a 100644 (file)
@@ -305,6 +305,15 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
 
                        curproxy->tcpcheck_rules.flags = (defproxy.tcpcheck_rules.flags | TCPCHK_RULES_DEF);
                        curproxy->tcpcheck_rules.list  = defproxy.tcpcheck_rules.list;
+                       if (!LIST_ISEMPTY(&defproxy.tcpcheck_rules.preset_vars)) {
+                               if (!dup_tcpcheck_vars(&curproxy->tcpcheck_rules.preset_vars,
+                                                      &defproxy.tcpcheck_rules.preset_vars)) {
+                                       ha_alert("parsing [%s:%d] : failed to duplicate tcpcheck preset-vars\n",
+                                                file, linenum);
+                                       err_code |= ERR_ALERT | ERR_FATAL;
+                                       goto out;
+                               }
+                       }
 
                        if (defproxy.expect_str) {
                                curproxy->expect_str = strdup(defproxy.expect_str);
index c26f17707f6979a976ac94a08c62182558cc7e1e..6820d28749a91a1ad0118648b7f6c16af1a1f7a0 100644 (file)
@@ -3279,6 +3279,8 @@ static int tcpcheck_main(struct check *check)
                        rule = check->current_step;
        }
        else {
+               struct tcpcheck_var *var;
+
                /* First evaluation, create a session */
                check->sess = session_new(&checks_fe, NULL, (check->server ? &check->server->obj_type : NULL));
                if (!check->sess) {
@@ -3288,6 +3290,16 @@ static int tcpcheck_main(struct check *check)
                }
                vars_init(&check->vars, SCOPE_CHECK);
                rule = LIST_NEXT(check->tcpcheck_rules->list, typeof(rule), list);
+
+               /* Preset tcp-check variables */
+               list_for_each_entry(var, &check->tcpcheck_rules->preset_vars, list) {
+                       struct sample smp;
+
+                       memset(&smp, 0, sizeof(smp));
+                       smp_set_owner(&smp, check->proxy, check->sess, NULL, SMP_OPT_FINAL);
+                       smp.data = var->data;
+                       vars_set_by_name_ifexist(var->name.ptr, var->name.len, &smp);
+               }
        }
 
        list_for_each_entry_from(rule, check->tcpcheck_rules->list, list) {
@@ -3538,6 +3550,80 @@ static void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool)
                free(rule);
 }
 
+
+static __maybe_unused struct tcpcheck_var *tcpcheck_var_create(const char *name)
+{
+       struct tcpcheck_var *var = NULL;
+
+       var = calloc(1, sizeof(*var));
+       if (var == NULL)
+               return NULL;
+
+       var->name = ist2(strdup(name), strlen(name));
+       if (var->name.ptr == NULL) {
+               free(var);
+               return NULL;
+       }
+
+       LIST_INIT(&var->list);
+       return var;
+}
+
+static void tcpcheck_var_release(struct tcpcheck_var *var)
+{
+       if (!var)
+               return;
+
+       free(var->name.ptr);
+       if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN)
+               free(var->data.u.str.area);
+       else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER)
+               free(var->data.u.meth.str.area);
+       free(var);
+}
+
+int dup_tcpcheck_vars(struct list *dst, struct list *src)
+{
+       struct tcpcheck_var *var, *new = NULL;
+
+       list_for_each_entry(var, src, list) {
+               new = tcpcheck_var_create(var->name.ptr);
+               if (!new)
+                       goto error;
+               new->data.type = var->data.type;
+               if (var->data.type == SMP_T_STR || var->data.type == SMP_T_BIN) {
+                       if (chunk_dup(&new->data.u.str, &var->data.u.str) == NULL)
+                               goto error;
+                       if (var->data.type == SMP_T_STR)
+                               new->data.u.str.area[new->data.u.str.data] = 0;
+               }
+               else if (var->data.type == SMP_T_METH && var->data.u.meth.meth == HTTP_METH_OTHER) {
+                       if (chunk_dup(&new->data.u.str, &var->data.u.str) == NULL)
+                               goto error;
+                       new->data.u.str.area[new->data.u.str.data] = 0;
+                       new->data.u.meth.meth = var->data.u.meth.meth;
+               }
+               else
+                       new->data.u = var->data.u;
+               LIST_ADDQ(dst, &new->list);
+       }
+       return 1;
+
+ error:
+       free(new);
+       return 0;
+}
+
+static void free_tcpcheck_vars(struct list *vars)
+{
+       struct tcpcheck_var *var, *back;
+
+       list_for_each_entry_safe(var, back, vars, list) {
+               LIST_DEL(&var->list);
+               tcpcheck_var_release(var);
+       }
+}
+
 void email_alert_free(struct email_alert *alert)
 {
        struct tcpcheck_rule *rule, *back;
@@ -3550,6 +3636,7 @@ void email_alert_free(struct email_alert *alert)
                        LIST_DEL(&rule->list);
                        free_tcpcheck(rule, 1);
                }
+               free_tcpcheck_vars(&alert->rules.preset_vars);
                free(alert->rules.list);
                alert->rules.list = NULL;
        }
@@ -3757,6 +3844,7 @@ static int enqueue_one_email_alert(struct proxy *p, struct server *s,
        if (!alert->rules.list)
                goto error;
        LIST_INIT(alert->rules.list);
+       LIST_INIT(&alert->rules.preset_vars); /* unused for email alerts */
        alert->srv = s;
 
        if ((tcpcheck = pool_alloc(pool_head_tcpcheck_rule)) == NULL)
@@ -4122,6 +4210,7 @@ void deinit_proxy_tcpcheck(struct proxy *px)
                LIST_DEL(&chk->list);
                free_tcpcheck(chk, 0);
        }
+       free_tcpcheck_vars(&px->tcpcheck_rules.preset_vars);
        free(px->tcpcheck_rules.list);
 
   end:
index d2d6a43d607cd1fe9e27a1c1debfe8460f27be94..2614325ca8f847dcbac1268cb683f432806e71f4 100644 (file)
@@ -877,6 +877,7 @@ void init_new_proxy(struct proxy *p)
        LIST_INIT(&p->conf.errors);
        LIST_INIT(&p->conf.args.list);
        LIST_INIT(&p->filter_configs);
+       LIST_INIT(&p->tcpcheck_rules.preset_vars);
 
        /* Timeouts are defined as -1 */
        proxy_reset_timeouts(p);