mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-14 01:30:54 +00:00
BUG/MEDIUM: server/checks: Init server check during config validity check
The options and directives related to the configuration of checks in a backend may be defined after the servers declarations. So, initialization of the check of each server must not be performed during configuration parsing, because some info may be missing. Instead, it must be done during the configuration validity check. Thus, callback functions are registered to be called for each server after the config validity check, one for the server check and another one for the server agent-check. In addition deinit callback functions are also registered to release these checks. This patch should be backported as far as 1.7. But per-server post_check callback functions are only supported since the 2.1. And the initcall mechanism does not exist before the 1.9. Finally, in 1.7, the code is totally different. So the backport will be harder on older versions.
This commit is contained in:
parent
f61f33a1b2
commit
8892e5d30b
@ -3265,9 +3265,6 @@ out_uri_auth_compat:
|
||||
proxy_type_str(curproxy), curproxy->id,
|
||||
newsrv->id);
|
||||
|
||||
/* set the check type on the server */
|
||||
newsrv->check.type = curproxy->options2 & PR_O2_CHK_ANY;
|
||||
|
||||
if (newsrv->trackit) {
|
||||
struct proxy *px;
|
||||
struct server *srv, *loop;
|
||||
@ -3304,9 +3301,7 @@ out_uri_auth_compat:
|
||||
goto next_srv;
|
||||
}
|
||||
|
||||
if (!(srv->check.state & CHK_ST_CONFIGURED) &&
|
||||
!(srv->agent.state & CHK_ST_CONFIGURED) &&
|
||||
!srv->track && !srv->trackit) {
|
||||
if (!srv->do_check && !srv->do_agent && !srv->track && !srv->trackit) {
|
||||
ha_alert("config : %s '%s', server '%s': unable to use %s/%s for "
|
||||
"tracking as it does not have any check nor agent enabled.\n",
|
||||
proxy_type_str(curproxy), curproxy->id,
|
||||
|
140
src/checks.c
140
src/checks.c
@ -3310,6 +3310,10 @@ const char *init_check(struct check *check, int type)
|
||||
|
||||
void free_check(struct check *check)
|
||||
{
|
||||
task_destroy(check->task);
|
||||
if (check->wait_list.tasklet)
|
||||
tasklet_free(check->wait_list.tasklet);
|
||||
|
||||
free(check->bi.area);
|
||||
free(check->bo.area);
|
||||
if (check->cs) {
|
||||
@ -3441,7 +3445,6 @@ int init_email_alert(struct mailers *mls, struct proxy *p, char **err)
|
||||
struct email_alertq *q = &queues[i];
|
||||
struct check *check = &q->check;
|
||||
|
||||
task_destroy(check->task);
|
||||
free_check(check);
|
||||
}
|
||||
free(queues);
|
||||
@ -3664,17 +3667,6 @@ int srv_check_healthcheck_port(struct check *chk)
|
||||
|
||||
srv = chk->server;
|
||||
|
||||
/* If neither a port nor an addr was specified and no check transport
|
||||
* layer is forced, then the transport layer used by the checks is the
|
||||
* same as for the production traffic. Otherwise we use raw_sock by
|
||||
* default, unless one is specified.
|
||||
*/
|
||||
if (!chk->port && !is_addr(&chk->addr)) {
|
||||
if (!chk->use_ssl)
|
||||
chk->use_ssl = srv->use_ssl;
|
||||
chk->send_proxy |= (srv->pp_opts);
|
||||
}
|
||||
|
||||
/* by default, we use the health check port ocnfigured */
|
||||
if (chk->port > 0)
|
||||
return chk->port;
|
||||
@ -3701,6 +3693,130 @@ int srv_check_healthcheck_port(struct check *chk)
|
||||
|
||||
REGISTER_POST_CHECK(start_checks);
|
||||
|
||||
static int init_srv_check(struct server *srv)
|
||||
{
|
||||
const char *err;
|
||||
struct tcpcheck_rule *r;
|
||||
int ret = 0;
|
||||
|
||||
if (!srv->do_check)
|
||||
goto out;
|
||||
|
||||
|
||||
/* If neither a port nor an addr was specified and no check transport
|
||||
* layer is forced, then the transport layer used by the checks is the
|
||||
* same as for the production traffic. Otherwise we use raw_sock by
|
||||
* default, unless one is specified.
|
||||
*/
|
||||
if (!srv->check.port && !is_addr(&srv->check.addr)) {
|
||||
if (!srv->check.use_ssl && srv->use_ssl != -1) {
|
||||
srv->check.use_ssl = srv->use_ssl;
|
||||
srv->check.xprt = srv->xprt;
|
||||
}
|
||||
else if (srv->check.use_ssl == 1)
|
||||
srv->check.xprt = xprt_get(XPRT_SSL);
|
||||
|
||||
srv->check.send_proxy |= (srv->pp_opts);
|
||||
}
|
||||
|
||||
/* validate <srv> server health-check settings */
|
||||
|
||||
/* We need at least a service port, a check port or the first tcp-check
|
||||
* rule must be a 'connect' one when checking an IPv4/IPv6 server.
|
||||
*/
|
||||
if ((srv_check_healthcheck_port(&srv->check) != 0) ||
|
||||
(!is_inet_addr(&srv->check.addr) && (is_addr(&srv->check.addr) || !is_inet_addr(&srv->addr))))
|
||||
goto init;
|
||||
|
||||
if (!LIST_ISEMPTY(&srv->proxy->tcpcheck_rules)) {
|
||||
ha_alert("config: %s '%s': server '%s' has neither service port nor check port.\n",
|
||||
proxy_type_str(srv->proxy), srv->proxy->id, srv->id);
|
||||
ret |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* search the first action (connect / send / expect) in the list */
|
||||
r = get_first_tcpcheck_rule(&srv->proxy->tcpcheck_rules);
|
||||
if (!r || (r->action != TCPCHK_ACT_CONNECT) || !r->port) {
|
||||
ha_alert("config: %s '%s': server '%s' has neither service port nor check port "
|
||||
"nor tcp_check rule 'connect' with port information.\n",
|
||||
proxy_type_str(srv->proxy), srv->proxy->id, srv->id);
|
||||
ret |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* scan the tcp-check ruleset to ensure a port has been configured */
|
||||
list_for_each_entry(r, &srv->proxy->tcpcheck_rules, list) {
|
||||
if ((r->action == TCPCHK_ACT_CONNECT) && (!r->port)) {
|
||||
ha_alert("config: %s '%s': server '%s' has neither service port nor check port, "
|
||||
"and a tcp_check rule 'connect' with no port information.\n",
|
||||
proxy_type_str(srv->proxy), srv->proxy->id, srv->id);
|
||||
ret |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
init:
|
||||
err = init_check(&srv->check, srv->proxy->options2 & PR_O2_CHK_ANY);
|
||||
if (err) {
|
||||
ha_alert("config: %s '%s': unable to init check for server '%s' (%s).\n",
|
||||
proxy_type_str(srv->proxy), srv->proxy->id, srv->id, err);
|
||||
ret |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
srv->check.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED;
|
||||
global.maxsock++;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int init_srv_agent_check(struct server *srv)
|
||||
{
|
||||
const char *err;
|
||||
int ret = 0;
|
||||
|
||||
if (!srv->do_agent)
|
||||
goto out;
|
||||
|
||||
err = init_check(&srv->agent, PR_O2_LB_AGENT_CHK);
|
||||
if (err) {
|
||||
ha_alert("config: %s '%s': unable to init agent-check for server '%s' (%s).\n",
|
||||
proxy_type_str(srv->proxy), srv->proxy->id, srv->id, err);
|
||||
ret |= ERR_ALERT | ERR_ABORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!srv->agent.inter)
|
||||
srv->agent.inter = srv->check.inter;
|
||||
|
||||
srv->agent.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_AGENT;
|
||||
global.maxsock++;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void deinit_srv_check(struct server *srv)
|
||||
{
|
||||
if (srv->do_check)
|
||||
free_check(&srv->check);
|
||||
}
|
||||
|
||||
|
||||
static void deinit_srv_agent_check(struct server *srv)
|
||||
{
|
||||
if (srv->do_agent)
|
||||
free_check(&srv->agent);
|
||||
free(srv->agent.send_string);
|
||||
}
|
||||
|
||||
REGISTER_POST_SERVER_CHECK(init_srv_check);
|
||||
REGISTER_POST_SERVER_CHECK(init_srv_agent_check);
|
||||
|
||||
REGISTER_SERVER_DEINIT(deinit_srv_check);
|
||||
REGISTER_SERVER_DEINIT(deinit_srv_agent_check);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
|
@ -2662,23 +2662,11 @@ void deinit(void)
|
||||
while (s) {
|
||||
s_next = s->next;
|
||||
|
||||
task_destroy(s->check.task);
|
||||
task_destroy(s->agent.task);
|
||||
|
||||
if (s->check.wait_list.tasklet)
|
||||
tasklet_free(s->check.wait_list.tasklet);
|
||||
if (s->agent.wait_list.tasklet)
|
||||
tasklet_free(s->agent.wait_list.tasklet);
|
||||
|
||||
task_destroy(s->warmup);
|
||||
|
||||
free(s->id);
|
||||
free(s->cookie);
|
||||
free(s->check.bi.area);
|
||||
free(s->check.bo.area);
|
||||
free(s->agent.bi.area);
|
||||
free(s->agent.bo.area);
|
||||
free(s->agent.send_string);
|
||||
free(s->hostname_dn);
|
||||
free((char*)s->conf.file);
|
||||
free(s->idle_conns);
|
||||
|
172
src/server.c
172
src/server.c
@ -1880,154 +1880,6 @@ struct server *new_server(struct proxy *proxy)
|
||||
return srv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate <srv> server health-check settings.
|
||||
* Returns 0 if everything is OK, -1 if not.
|
||||
*/
|
||||
static int server_healthcheck_validate(const char *file, int linenum, struct server *srv)
|
||||
{
|
||||
struct tcpcheck_rule *r = NULL;
|
||||
struct list *l;
|
||||
|
||||
/*
|
||||
* We need at least a service port, a check port or the first tcp-check rule must
|
||||
* be a 'connect' one when checking an IPv4/IPv6 server.
|
||||
*/
|
||||
if ((srv_check_healthcheck_port(&srv->check) != 0) ||
|
||||
(!is_inet_addr(&srv->check.addr) && (is_addr(&srv->check.addr) || !is_inet_addr(&srv->addr))))
|
||||
return 0;
|
||||
|
||||
r = (struct tcpcheck_rule *)srv->proxy->tcpcheck_rules.n;
|
||||
if (!r) {
|
||||
ha_alert("parsing [%s:%d] : server %s has neither service port nor check port. "
|
||||
"Check has been disabled.\n",
|
||||
file, linenum, srv->id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* search the first action (connect / send / expect) in the list */
|
||||
l = &srv->proxy->tcpcheck_rules;
|
||||
list_for_each_entry(r, l, list) {
|
||||
if (r->action != TCPCHK_ACT_COMMENT)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((r->action != TCPCHK_ACT_CONNECT) || !r->port) {
|
||||
ha_alert("parsing [%s:%d] : server %s has neither service port nor check port "
|
||||
"nor tcp_check rule 'connect' with port information. Check has been disabled.\n",
|
||||
file, linenum, srv->id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* scan the tcp-check ruleset to ensure a port has been configured */
|
||||
l = &srv->proxy->tcpcheck_rules;
|
||||
list_for_each_entry(r, l, list) {
|
||||
if ((r->action == TCPCHK_ACT_CONNECT) && (!r->port)) {
|
||||
ha_alert("parsing [%s:%d] : server %s has neither service port nor check port, "
|
||||
"and a tcp_check rule 'connect' with no port information. Check has been disabled.\n",
|
||||
file, linenum, srv->id);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize <srv> health-check structure.
|
||||
* Returns the error string in case of memory allocation failure, NULL if not.
|
||||
*/
|
||||
static const char *do_health_check_init(struct server *srv, int check_type, int state)
|
||||
{
|
||||
const char *ret;
|
||||
|
||||
if (!srv->do_check)
|
||||
return NULL;
|
||||
|
||||
ret = init_check(&srv->check, check_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
srv->check.state |= state;
|
||||
global.maxsock++;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int server_health_check_init(const char *file, int linenum,
|
||||
struct server *srv, struct proxy *curproxy)
|
||||
{
|
||||
const char *ret;
|
||||
|
||||
if (!srv->do_check)
|
||||
return 0;
|
||||
|
||||
if (srv->trackit) {
|
||||
ha_alert("parsing [%s:%d]: unable to enable checks and tracking at the same time!\n",
|
||||
file, linenum);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
if (server_healthcheck_validate(file, linenum, srv) < 0)
|
||||
return ERR_ALERT | ERR_ABORT;
|
||||
|
||||
/* note: check type will be set during the config review phase */
|
||||
ret = do_health_check_init(srv, 0, CHK_ST_CONFIGURED | CHK_ST_ENABLED);
|
||||
if (ret) {
|
||||
ha_alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
|
||||
return ERR_ALERT | ERR_ABORT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize <srv> agent check structure.
|
||||
* Returns the error string in case of memory allocation failure, NULL if not.
|
||||
*/
|
||||
static const char *do_server_agent_check_init(struct server *srv, int state)
|
||||
{
|
||||
const char *ret;
|
||||
|
||||
if (!srv->do_agent)
|
||||
return NULL;
|
||||
|
||||
ret = init_check(&srv->agent, PR_O2_LB_AGENT_CHK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!srv->agent.inter)
|
||||
srv->agent.inter = srv->check.inter;
|
||||
|
||||
srv->agent.state |= state;
|
||||
global.maxsock++;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int server_agent_check_init(const char *file, int linenum,
|
||||
struct server *srv, struct proxy *curproxy)
|
||||
{
|
||||
const char *ret;
|
||||
|
||||
if (!srv->do_agent)
|
||||
return 0;
|
||||
|
||||
if (!srv->agent.port) {
|
||||
ha_alert("parsing [%s:%d] : server %s does not have agent port. Agent check has been disabled.\n",
|
||||
file, linenum, srv->id);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
ret = do_server_agent_check_init(srv, CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_AGENT);
|
||||
if (ret) {
|
||||
ha_alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
|
||||
return ERR_ALERT | ERR_ABORT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
static int server_sni_expr_init(const char *file, int linenum, char **args, int cur_arg,
|
||||
struct server *srv, struct proxy *proxy)
|
||||
@ -2059,9 +1911,16 @@ static int server_finalize_init(const char *file, int linenum, char **args, int
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = server_health_check_init(file, linenum, srv, px)) != 0 ||
|
||||
(ret = server_agent_check_init(file, linenum, srv, px)) != 0) {
|
||||
return ret;
|
||||
if (srv->do_check && srv->trackit) {
|
||||
ha_alert("parsing [%s:%d]: unable to enable checks and tracking at the same time!\n",
|
||||
file, linenum);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
if (srv->do_agent && !srv->agent.port) {
|
||||
ha_alert("parsing [%s:%d] : server %s does not have agent port. Agent check has been disabled.\n",
|
||||
file, linenum, srv->id);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
@ -2129,9 +1988,6 @@ static int server_template_init(struct server *srv, struct proxy *px)
|
||||
struct server *newsrv;
|
||||
|
||||
for (i = srv->tmpl_info.nb_low + 1; i <= srv->tmpl_info.nb_high; i++) {
|
||||
int check_init_state;
|
||||
int agent_init_state;
|
||||
|
||||
newsrv = new_server(px);
|
||||
if (!newsrv)
|
||||
goto err;
|
||||
@ -2148,14 +2004,6 @@ static int server_template_init(struct server *srv, struct proxy *px)
|
||||
/* Set this new server ID. */
|
||||
srv_set_id_from_prefix(newsrv, srv->tmpl_info.prefix, i);
|
||||
|
||||
/* Initial checks states. */
|
||||
check_init_state = CHK_ST_CONFIGURED | CHK_ST_ENABLED;
|
||||
agent_init_state = CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_AGENT;
|
||||
|
||||
if (do_health_check_init(newsrv, px->options2 & PR_O2_CHK_ANY, check_init_state) ||
|
||||
do_server_agent_check_init(newsrv, agent_init_state))
|
||||
goto err;
|
||||
|
||||
/* Linked backwards first. This will be restablished after parsing. */
|
||||
newsrv->next = px->srv;
|
||||
px->srv = newsrv;
|
||||
|
@ -5927,8 +5927,6 @@ int ssl_sock_prepare_srv_ctx(struct server *srv)
|
||||
}
|
||||
if (srv->use_ssl == 1)
|
||||
srv->xprt = &ssl_sock;
|
||||
if (srv->check.use_ssl == 1)
|
||||
srv->check.xprt = &ssl_sock;
|
||||
|
||||
ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (!ctx) {
|
||||
|
Loading…
Reference in New Issue
Block a user