diff --git a/doc/configuration.txt b/doc/configuration.txt index 3e2278b92..44b32d50a 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -18561,6 +18561,18 @@ hash-key uses "hash-type consistent", and the quality of the distribution will depend on the quality of the keys. +healthchec + May be used in the following contexts: tcp, http + + Specify the health-check sectino to use to perform check on the server. + + Argument : + is the health-check section name. + + Thanks to this option, it is possible to use a pre-server health-check + configuration instead of using the proxy configuration. See also "healthcheck + section". + id May be used in the following contexts: tcp, http, log @@ -32251,6 +32263,81 @@ Example: map virt@acme +12.9. Healthchecks +------------------ + +It is possible to globally declare several health-checks that could be used by +servers across all the configuration, overriding the local proxy configuration. + +healthcheck + Created a new healthcheck with name . This name must be unique. It + should be used on server line to reference a specific health-check section. + +type + Defines the health-check type. This parameter is mandatory. Following types + of health-check are supported: + + * tcp-check + * httpchk + * ssl-hello-chk + * smtpchk + * pgsql-check + * redis-check + * mysql-check + * ldap-check + * spop-check + + Each type uses the same parameters, if any, than the corresponding proxy's + option. For instance, the method, the uri... may be speficied for the + "httpchk" type: + + Examples : + healthcheck my-http-check + type httpchk GET /health HTTP/1.1 %[srv_name] + + See also : "option tcp-check", "option httpchk", "option ssl-hello-chk", + "option smtpchk", "option mysql-check", "option pgsql-check", + "option redis-check", "option ldap-check and "option spop-check" + +http-check comment +http-check connect [default] [port ] [addr ] [send-proxy] + [via-socks4] [ssl] [sni ] [alpn ] [linger] + [proto ] [comment ] +http-check disable-on-404 +http-check expect [min-recv ] [comment ] + [ok-status ] [error-status ] [tout-status ] + [on-success ] [on-error ] [status-code ] + [!] +http-check send [meth ] [{ uri | uri-lf }>] [ver ] + [hdr ]* [{ body | body-lf }] + [comment ] +http-check send-state +http-check set-var([,...]) +http-check set-var-fmt([,...]) +http-check unset-var() + Add a specific http-check rule for a "httpchk" healthcheck. The same syntax + than the corresponding proxy's directives is used. See the corresponding proxy + documentation for details. + +tcp-check comment +tcp-check connect [default] [port ] [addr ] [send-proxy] [via-socks4] + [ssl] [sni ] [alpn ] [linger] + [proto ] [comment ] +tcp-check expect [min-recv ] [comment ] + [ok-status ] [error-status ] [tout-status ] + [on-success ] [on-error ] [status-code ] + [!] +tcp-check send [comment ] +tcp-check send-lf [comment ] +tcp-check send-binary [comment ] +tcp-check send-binary-lf [comment ] +tcp-check set-var([,...]) +tcp-check set-var-fmt([,...]) +tcp-check unset-var() + Add a specific tcp-check rule for a "tcp-check" healthcheck. The same syntax + than the corresponding proxy's directives is used. See the corresponding proxy + documentation for details. + /* * Local variables: * fill-column: 79 diff --git a/include/haproxy/tcpcheck-t.h b/include/haproxy/tcpcheck-t.h index 6ff78ffc5..dec0c90b4 100644 --- a/include/haproxy/tcpcheck-t.h +++ b/include/haproxy/tcpcheck-t.h @@ -248,6 +248,7 @@ struct tcpcheck_ruleset { struct tcpcheck { struct tcpcheck_ruleset *rs; /* The tcp-check ruleset to use */ + char *healthcheck; /* name of the healthcheck section (NULL if not used) */ struct list preset_vars; /* The list of variable to preset before executing the ruleset */ unsigned int flags; /* TCPCHECK_FL_* */ }; diff --git a/src/check.c b/src/check.c index b13a9f8ee..6a29ebe57 100644 --- a/src/check.c +++ b/src/check.c @@ -1552,8 +1552,9 @@ void free_check(struct check *check) * done for health-check : the proxy is the owner of the rules / vars * in this case. */ - if (check->state & CHK_ST_AGENT) { + if (check->state & CHK_ST_AGENT || check->tcpcheck->healthcheck) { free_tcpcheck_vars(&check->tcpcheck->preset_vars); + ha_free(&check->tcpcheck->healthcheck); ha_free(&check->tcpcheck); } diff --git a/src/proxy.c b/src/proxy.c index c028e348c..8dd10fb6f 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -2537,6 +2537,10 @@ int proxy_finalize(struct proxy *px, int *err_code) srv_minmax_conn_apply(newsrv); + *err_code |= check_server_tcpcheck(newsrv); + if (*err_code & (ERR_ABORT|ERR_FATAL)) + goto out; + /* this will also properly set the transport layer for * prod and checks * if default-server have use_ssl, prerare ssl init diff --git a/src/tcpcheck.c b/src/tcpcheck.c index ed604609b..c88705289 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -4164,6 +4164,35 @@ static int check_proxy_tcpcheck(struct proxy *px) return ret; } +int check_server_tcpcheck(struct server *srv) +{ + struct tcpcheck_ruleset *rs; + int err_code = 0; + + if (srv->check.tcpcheck->healthcheck) { + rs = find_tcpcheck_ruleset(srv->check.tcpcheck->healthcheck); + if (!rs) { + ha_alert("parsing [%s:%d]: healthcheck section '%s' not found for server '%s'.\n", + srv->conf.file, srv->conf.line, srv->check.tcpcheck->healthcheck, srv->id); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + if (!dup_tcpcheck_vars(&srv->check.tcpcheck->preset_vars, &rs->conf.preset_vars)) { + ha_alert("parsing [%s:%d]: unable to duplicate preset variables for server '%s'.\n", + srv->conf.file, srv->conf.line, srv->id); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + srv->check.tcpcheck->rs = rs; + srv->check.tcpcheck->flags = rs->conf.flags; + + err_code = check_tcpcheck_ruleset(srv->proxy, rs); + } + + out: + return err_code; +} + void deinit_proxy_tcpcheck(struct proxy *px) { free_tcpcheck_vars(&px->tcpcheck.preset_vars); @@ -5920,6 +5949,43 @@ int cfg_post_parse_healthchecks() return err_code; } +/* Parse the "healthcheck" server keyword */ +static int srv_parse_healthcheck(char **args, int *cur_arg, struct proxy *curpx, struct server *srv, + char **errmsg) +{ + int err_code = 0; + + if (!*args[*cur_arg+1]) { + memprintf(errmsg, "'%s' expects a healthcheck name as argument.", args[*cur_arg]); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + + if (srv->check.tcpcheck->healthcheck) { + /* a healthcheck section was already defined. Replace it */ + ha_free(&srv->check.tcpcheck->healthcheck); + } + else { + srv->check.tcpcheck = calloc(1, sizeof(*srv->check.tcpcheck)); + if (srv->check.tcpcheck == NULL) { + memprintf(errmsg, "out of memory"); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + LIST_INIT(&srv->check.tcpcheck->preset_vars); + } + + if (!memprintf(&srv->check.tcpcheck->healthcheck, "*healthcheck-%s", args[*cur_arg+1])) { + ha_free(&srv->check.tcpcheck); + memprintf(errmsg, "out of memory"); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + out: + return err_code; +} + static struct cfg_kw_list cfg_kws = {ILH, { { CFG_LISTEN, "http-check", proxy_parse_httpcheck }, { CFG_LISTEN, "tcp-check", proxy_parse_tcpcheck }, @@ -5932,3 +5998,11 @@ REGISTER_POST_DEINIT(deinit_tcpchecks); INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws); REGISTER_CONFIG_SECTION("healthcheck", cfg_parse_healthchecks, cfg_post_parse_healthchecks); + +/* register "server" line keywords */ +static struct srv_kw_list srv_kws = { "CHK", { }, { + { "healthcheck", srv_parse_healthcheck, 1, 1, 1 }, /* The healthcheck section to use */ + { NULL, NULL, 0 }, +}}; + +INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws);