mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-10 17:17:06 +02:00
This is achieved by moving rise and fall from struct server to struct check. After this move the behaviour of the primary check, server->check is unchanged. However, the secondary agent check, server->agent now has independent rise and fall values each of which are set to 1. The result is that receiving "fail", "stopped" or "down" just once from the agent will mark the server as down. And receiving a weight just once will allow the server to be marked up if its primary check is in good health. This opens up the scope to allow the rise and fall values of the agent check to be configurable, however this has not been implemented at this stage. Signed-off-by: Simon Horman <horms@verge.net.au>
250 lines
7.2 KiB
C
250 lines
7.2 KiB
C
/*
|
|
* Server management functions.
|
|
*
|
|
* Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
|
|
* Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*
|
|
*/
|
|
|
|
#include <common/config.h>
|
|
#include <common/errors.h>
|
|
#include <common/time.h>
|
|
|
|
#include <proto/server.h>
|
|
|
|
/* List head of all known server keywords */
|
|
static struct srv_kw_list srv_keywords = {
|
|
.list = LIST_HEAD_INIT(srv_keywords.list)
|
|
};
|
|
|
|
int srv_downtime(const struct server *s)
|
|
{
|
|
if ((s->state & SRV_RUNNING) && s->last_change < now.tv_sec) // ignore negative time
|
|
return s->down_time;
|
|
|
|
return now.tv_sec - s->last_change + s->down_time;
|
|
}
|
|
|
|
int srv_getinter(const struct check *check)
|
|
{
|
|
const struct server *s = check->server;
|
|
|
|
if ((s->state & SRV_CHECKED) && (check->health == check->rise + check->fall - 1))
|
|
return check->inter;
|
|
|
|
if (!(s->state & SRV_RUNNING) && check->health == 0)
|
|
return (check->downinter)?(check->downinter):(check->inter);
|
|
|
|
return (check->fastinter)?(check->fastinter):(check->inter);
|
|
}
|
|
|
|
/*
|
|
* Registers the server keyword list <kwl> as a list of valid keywords for next
|
|
* parsing sessions.
|
|
*/
|
|
void srv_register_keywords(struct srv_kw_list *kwl)
|
|
{
|
|
LIST_ADDQ(&srv_keywords.list, &kwl->list);
|
|
}
|
|
|
|
/* Return a pointer to the server keyword <kw>, or NULL if not found. If the
|
|
* keyword is found with a NULL ->parse() function, then an attempt is made to
|
|
* find one with a valid ->parse() function. This way it is possible to declare
|
|
* platform-dependant, known keywords as NULL, then only declare them as valid
|
|
* if some options are met. Note that if the requested keyword contains an
|
|
* opening parenthesis, everything from this point is ignored.
|
|
*/
|
|
struct srv_kw *srv_find_kw(const char *kw)
|
|
{
|
|
int index;
|
|
const char *kwend;
|
|
struct srv_kw_list *kwl;
|
|
struct srv_kw *ret = NULL;
|
|
|
|
kwend = strchr(kw, '(');
|
|
if (!kwend)
|
|
kwend = kw + strlen(kw);
|
|
|
|
list_for_each_entry(kwl, &srv_keywords.list, list) {
|
|
for (index = 0; kwl->kw[index].kw != NULL; index++) {
|
|
if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
|
|
kwl->kw[index].kw[kwend-kw] == 0) {
|
|
if (kwl->kw[index].parse)
|
|
return &kwl->kw[index]; /* found it !*/
|
|
else
|
|
ret = &kwl->kw[index]; /* may be OK */
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* Dumps all registered "server" keywords to the <out> string pointer. The
|
|
* unsupported keywords are only dumped if their supported form was not
|
|
* found.
|
|
*/
|
|
void srv_dump_kws(char **out)
|
|
{
|
|
struct srv_kw_list *kwl;
|
|
int index;
|
|
|
|
*out = NULL;
|
|
list_for_each_entry(kwl, &srv_keywords.list, list) {
|
|
for (index = 0; kwl->kw[index].kw != NULL; index++) {
|
|
if (kwl->kw[index].parse ||
|
|
srv_find_kw(kwl->kw[index].kw) == &kwl->kw[index]) {
|
|
memprintf(out, "%s[%4s] %s%s%s%s\n", *out ? *out : "",
|
|
kwl->scope,
|
|
kwl->kw[index].kw,
|
|
kwl->kw[index].skip ? " <arg>" : "",
|
|
kwl->kw[index].default_ok ? " [dflt_ok]" : "",
|
|
kwl->kw[index].parse ? "" : " (not supported)");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* parse the "id" server keyword */
|
|
static int srv_parse_id(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
|
|
{
|
|
struct eb32_node *node;
|
|
|
|
if (!*args[*cur_arg + 1]) {
|
|
memprintf(err, "'%s' : expects an integer argument", args[*cur_arg]);
|
|
return ERR_ALERT | ERR_FATAL;
|
|
}
|
|
|
|
newsrv->puid = atol(args[*cur_arg + 1]);
|
|
newsrv->conf.id.key = newsrv->puid;
|
|
|
|
if (newsrv->puid <= 0) {
|
|
memprintf(err, "'%s' : custom id has to be > 0", args[*cur_arg]);
|
|
return ERR_ALERT | ERR_FATAL;
|
|
}
|
|
|
|
node = eb32_lookup(&curproxy->conf.used_server_id, newsrv->puid);
|
|
if (node) {
|
|
struct server *target = container_of(node, struct server, conf.id);
|
|
memprintf(err, "'%s' : custom id %d already used at %s:%d ('server %s')",
|
|
args[*cur_arg], newsrv->puid, target->conf.file, target->conf.line,
|
|
target->id);
|
|
return ERR_ALERT | ERR_FATAL;
|
|
}
|
|
|
|
eb32_insert(&curproxy->conf.used_server_id, &newsrv->conf.id);
|
|
return 0;
|
|
}
|
|
|
|
/* Note: must not be declared <const> as its list will be overwritten.
|
|
* Please take care of keeping this list alphabetically sorted, doing so helps
|
|
* all code contributors.
|
|
* Optional keywords are also declared with a NULL ->parse() function so that
|
|
* the config parser can report an appropriate error when a known keyword was
|
|
* not enabled.
|
|
*/
|
|
static struct srv_kw_list srv_kws = { "ALL", { }, {
|
|
{ "id", srv_parse_id, 1, 0 }, /* set id# of server */
|
|
{ NULL, NULL, 0 },
|
|
}};
|
|
|
|
__attribute__((constructor))
|
|
static void __listener_init(void)
|
|
{
|
|
srv_register_keywords(&srv_kws);
|
|
}
|
|
|
|
/* Recomputes the server's eweight based on its state, uweight, the current time,
|
|
* and the proxy's algorihtm. To be used after updating sv->uweight. The warmup
|
|
* state is automatically disabled if the time is elapsed.
|
|
*/
|
|
void server_recalc_eweight(struct server *sv)
|
|
{
|
|
struct proxy *px = sv->proxy;
|
|
unsigned w;
|
|
|
|
if (now.tv_sec < sv->last_change || now.tv_sec >= sv->last_change + sv->slowstart) {
|
|
/* go to full throttle if the slowstart interval is reached */
|
|
sv->state &= ~SRV_WARMINGUP;
|
|
}
|
|
|
|
/* We must take care of not pushing the server to full throttle during slow starts.
|
|
* It must also start immediately, at least at the minimal step when leaving maintenance.
|
|
*/
|
|
if ((sv->state & SRV_WARMINGUP) && (px->lbprm.algo & BE_LB_PROP_DYN))
|
|
w = (px->lbprm.wdiv * (now.tv_sec - sv->last_change) + sv->slowstart) / sv->slowstart;
|
|
else
|
|
w = px->lbprm.wdiv;
|
|
|
|
sv->eweight = (sv->uweight * w + px->lbprm.wmult - 1) / px->lbprm.wmult;
|
|
|
|
/* now propagate the status change to any LB algorithms */
|
|
if (px->lbprm.update_server_eweight)
|
|
px->lbprm.update_server_eweight(sv);
|
|
else if (sv->eweight) {
|
|
if (px->lbprm.set_server_status_up)
|
|
px->lbprm.set_server_status_up(sv);
|
|
}
|
|
else {
|
|
if (px->lbprm.set_server_status_down)
|
|
px->lbprm.set_server_status_down(sv);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Parses weight_str and configures sv accordingly.
|
|
* Returns NULL on success, error message string otherwise.
|
|
*/
|
|
const char *server_parse_weight_change_request(struct server *sv,
|
|
const char *weight_str)
|
|
{
|
|
struct proxy *px;
|
|
long int w;
|
|
char *end;
|
|
|
|
px = sv->proxy;
|
|
|
|
/* if the weight is terminated with '%', it is set relative to
|
|
* the initial weight, otherwise it is absolute.
|
|
*/
|
|
if (!*weight_str)
|
|
return "Require <weight> or <weight%>.\n";
|
|
|
|
w = strtol(weight_str, &end, 10);
|
|
if (end == weight_str)
|
|
return "Empty weight string empty or preceded by garbage";
|
|
else if (end[0] == '%' && end[1] == '\0') {
|
|
if (w < 0)
|
|
return "Relative weight must be positive.\n";
|
|
/* Avoid integer overflow */
|
|
if (w > 25600)
|
|
w = 25600;
|
|
w = sv->iweight * w / 100;
|
|
if (w > 256)
|
|
w = 256;
|
|
}
|
|
else if (w < 0 || w > 256)
|
|
return "Absolute weight can only be between 0 and 256 inclusive.\n";
|
|
else if (end[0] != '\0')
|
|
return "Trailing garbage in weight string";
|
|
|
|
if (w && w != sv->iweight && !(px->lbprm.algo & BE_LB_PROP_DYN))
|
|
return "Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.\n";
|
|
|
|
sv->uweight = w;
|
|
server_recalc_eweight(sv);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-indent-level: 8
|
|
* c-basic-offset: 8
|
|
* End:
|
|
*/
|