blob: 7b12e4dbe0f29493804a71143c06e73d0502d9fc [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Server management functions.
3 *
Willy Tarreau21faa912012-10-10 08:27:36 +02004 * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +01005 * Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
Willy Tarreaubaaee002006-06-26 02:48:02 +02006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
Willy Tarreau272adea2014-03-31 10:39:59 +020014#include <ctype.h>
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +020015#include <errno.h>
Frédéric Lécaille5c3cd972017-03-15 16:36:09 +010016#include <netinet/tcp.h>
Willy Tarreau272adea2014-03-31 10:39:59 +020017
Olivier Houchard4e694042017-03-14 20:01:29 +010018#include <import/xxhash.h>
19
Willy Tarreau272adea2014-03-31 10:39:59 +020020#include <common/cfgparse.h>
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020021#include <common/config.h>
Willy Tarreaudff55432012-10-10 17:51:05 +020022#include <common/errors.h>
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010023#include <common/namespace.h>
Krzysztof Oledzki85130942007-10-22 16:21:10 +020024#include <common/time.h>
25
William Lallemand222baf22016-11-19 02:00:33 +010026#include <types/applet.h>
27#include <types/cli.h>
Willy Tarreau272adea2014-03-31 10:39:59 +020028#include <types/global.h>
Willy Tarreau21b069d2016-11-23 17:15:08 +010029#include <types/cli.h>
Baptiste Assmanna68ca962015-04-14 01:15:08 +020030#include <types/dns.h>
William Lallemand222baf22016-11-19 02:00:33 +010031#include <types/stats.h>
Willy Tarreau272adea2014-03-31 10:39:59 +020032
William Lallemand222baf22016-11-19 02:00:33 +010033#include <proto/applet.h>
34#include <proto/cli.h>
Simon Hormanb1900d52015-01-30 11:22:54 +090035#include <proto/checks.h>
Willy Tarreau272adea2014-03-31 10:39:59 +020036#include <proto/port_range.h>
37#include <proto/protocol.h>
Willy Tarreau4aac7db2014-05-16 11:48:10 +020038#include <proto/queue.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020039#include <proto/server.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020040#include <proto/stream.h>
William Lallemand222baf22016-11-19 02:00:33 +010041#include <proto/stream_interface.h>
42#include <proto/stats.h>
Willy Tarreau4aac7db2014-05-16 11:48:10 +020043#include <proto/task.h>
Baptiste Assmanna68ca962015-04-14 01:15:08 +020044#include <proto/dns.h>
Willy Tarreau4aac7db2014-05-16 11:48:10 +020045
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +020046static void srv_update_state(struct server *srv, int version, char **params);
Baptiste Assmann83cbaa52016-11-02 15:34:05 +010047static int srv_apply_lastaddr(struct server *srv, int *err_code);
Willy Tarreaubaaee002006-06-26 02:48:02 +020048
Willy Tarreau21faa912012-10-10 08:27:36 +020049/* List head of all known server keywords */
50static struct srv_kw_list srv_keywords = {
51 .list = LIST_HEAD_INIT(srv_keywords.list)
52};
Krzysztof Oledzki85130942007-10-22 16:21:10 +020053
Simon Hormana3608442013-11-01 16:46:15 +090054int srv_downtime(const struct server *s)
Willy Tarreau21faa912012-10-10 08:27:36 +020055{
Willy Tarreau892337c2014-05-13 23:41:20 +020056 if ((s->state != SRV_ST_STOPPED) && s->last_change < now.tv_sec) // ignore negative time
Krzysztof Oledzki85130942007-10-22 16:21:10 +020057 return s->down_time;
58
59 return now.tv_sec - s->last_change + s->down_time;
60}
Willy Tarreaubaaee002006-06-26 02:48:02 +020061
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -050062int srv_lastsession(const struct server *s)
63{
64 if (s->counters.last_sess)
65 return now.tv_sec - s->counters.last_sess;
66
67 return -1;
68}
69
Simon Horman4a741432013-02-23 15:35:38 +090070int srv_getinter(const struct check *check)
Willy Tarreau21faa912012-10-10 08:27:36 +020071{
Simon Horman4a741432013-02-23 15:35:38 +090072 const struct server *s = check->server;
73
Willy Tarreauff5ae352013-12-11 20:36:34 +010074 if ((check->state & CHK_ST_CONFIGURED) && (check->health == check->rise + check->fall - 1))
Simon Horman4a741432013-02-23 15:35:38 +090075 return check->inter;
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +010076
Willy Tarreau892337c2014-05-13 23:41:20 +020077 if ((s->state == SRV_ST_STOPPED) && check->health == 0)
Simon Horman4a741432013-02-23 15:35:38 +090078 return (check->downinter)?(check->downinter):(check->inter);
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +010079
Simon Horman4a741432013-02-23 15:35:38 +090080 return (check->fastinter)?(check->fastinter):(check->inter);
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +010081}
82
Olivier Houchard4e694042017-03-14 20:01:29 +010083void srv_set_dyncookie(struct server *s)
84{
85 struct proxy *p = s->proxy;
86 struct server *tmpserv;
87 char *tmpbuf;
88 unsigned long long hash_value;
Olivier Houchard2cb49eb2017-03-15 15:11:06 +010089 size_t key_len;
Olivier Houchard4e694042017-03-14 20:01:29 +010090 size_t buffer_len;
91 int addr_len;
92 int port;
93
94 if ((s->flags & SRV_F_COOKIESET) ||
95 !(s->proxy->ck_opts & PR_CK_DYNAMIC) ||
96 s->proxy->dyncookie_key == NULL)
97 return;
Olivier Houchard2cb49eb2017-03-15 15:11:06 +010098 key_len = strlen(p->dyncookie_key);
Olivier Houchard4e694042017-03-14 20:01:29 +010099
100 if (s->addr.ss_family != AF_INET &&
101 s->addr.ss_family != AF_INET6)
102 return;
103 /*
104 * Buffer to calculate the cookie value.
105 * The buffer contains the secret key + the server IP address
106 * + the TCP port.
107 */
108 addr_len = (s->addr.ss_family == AF_INET) ? 4 : 16;
109 /*
110 * The TCP port should use only 2 bytes, but is stored in
111 * an unsigned int in struct server, so let's use 4, to be
112 * on the safe side.
113 */
114 buffer_len = key_len + addr_len + 4;
115 tmpbuf = trash.str;
116 memcpy(tmpbuf, p->dyncookie_key, key_len);
117 memcpy(&(tmpbuf[key_len]),
118 s->addr.ss_family == AF_INET ?
119 (void *)&((struct sockaddr_in *)&s->addr)->sin_addr.s_addr :
120 (void *)&(((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr),
121 addr_len);
122 /*
123 * Make sure it's the same across all the load balancers,
124 * no matter their endianness.
125 */
126 port = htonl(s->svc_port);
127 memcpy(&tmpbuf[key_len + addr_len], &port, 4);
128 hash_value = XXH64(tmpbuf, buffer_len, 0);
129 memprintf(&s->cookie, "%016llx", hash_value);
130 if (!s->cookie)
131 return;
132 s->cklen = 16;
133 /*
134 * Check that we did not get a hash collision.
135 * Unlikely, but it can happen.
136 */
137 for (p = proxy; p != NULL; p = p->next)
138 for (tmpserv = proxy->srv; tmpserv != NULL;
139 tmpserv = tmpserv->next) {
140 if (tmpserv == s)
141 continue;
142 if (tmpserv->cookie &&
143 strcmp(tmpserv->cookie, s->cookie) == 0) {
144 Warning("We generated two equal cookies for two different servers.\n"
145 "Please change the secret key for '%s'.\n",
146 s->proxy->id);
147 }
148 }
149}
150
Willy Tarreau21faa912012-10-10 08:27:36 +0200151/*
152 * Registers the server keyword list <kwl> as a list of valid keywords for next
153 * parsing sessions.
154 */
155void srv_register_keywords(struct srv_kw_list *kwl)
156{
157 LIST_ADDQ(&srv_keywords.list, &kwl->list);
158}
159
160/* Return a pointer to the server keyword <kw>, or NULL if not found. If the
161 * keyword is found with a NULL ->parse() function, then an attempt is made to
162 * find one with a valid ->parse() function. This way it is possible to declare
163 * platform-dependant, known keywords as NULL, then only declare them as valid
164 * if some options are met. Note that if the requested keyword contains an
165 * opening parenthesis, everything from this point is ignored.
166 */
167struct srv_kw *srv_find_kw(const char *kw)
168{
169 int index;
170 const char *kwend;
171 struct srv_kw_list *kwl;
172 struct srv_kw *ret = NULL;
173
174 kwend = strchr(kw, '(');
175 if (!kwend)
176 kwend = kw + strlen(kw);
177
178 list_for_each_entry(kwl, &srv_keywords.list, list) {
179 for (index = 0; kwl->kw[index].kw != NULL; index++) {
180 if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
181 kwl->kw[index].kw[kwend-kw] == 0) {
182 if (kwl->kw[index].parse)
183 return &kwl->kw[index]; /* found it !*/
184 else
185 ret = &kwl->kw[index]; /* may be OK */
186 }
187 }
188 }
189 return ret;
190}
191
192/* Dumps all registered "server" keywords to the <out> string pointer. The
193 * unsupported keywords are only dumped if their supported form was not
194 * found.
195 */
196void srv_dump_kws(char **out)
197{
198 struct srv_kw_list *kwl;
199 int index;
200
201 *out = NULL;
202 list_for_each_entry(kwl, &srv_keywords.list, list) {
203 for (index = 0; kwl->kw[index].kw != NULL; index++) {
204 if (kwl->kw[index].parse ||
205 srv_find_kw(kwl->kw[index].kw) == &kwl->kw[index]) {
206 memprintf(out, "%s[%4s] %s%s%s%s\n", *out ? *out : "",
207 kwl->scope,
208 kwl->kw[index].kw,
209 kwl->kw[index].skip ? " <arg>" : "",
210 kwl->kw[index].default_ok ? " [dflt_ok]" : "",
211 kwl->kw[index].parse ? "" : " (not supported)");
212 }
213 }
214 }
215}
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100216
Frédéric Lécaillef5bf9032017-03-10 11:51:05 +0100217/* Parse the "backup" server keyword */
218static int srv_parse_backup(char **args, int *cur_arg,
219 struct proxy *curproxy, struct server *newsrv, char **err)
220{
221 newsrv->flags |= SRV_F_BACKUP;
222 return 0;
223}
224
Frédéric Lécaille65aa3562017-03-14 11:20:13 +0100225/* Parse the "check" server keyword */
226static int srv_parse_check(char **args, int *cur_arg,
227 struct proxy *curproxy, struct server *newsrv, char **err)
228{
229 newsrv->do_check = 1;
230 return 0;
231}
232
Frédéric Lécaille25df8902017-03-10 14:04:31 +0100233/* Parse the "check-send-proxy" server keyword */
234static int srv_parse_check_send_proxy(char **args, int *cur_arg,
235 struct proxy *curproxy, struct server *newsrv, char **err)
236{
237 newsrv->check.send_proxy = 1;
238 return 0;
239}
240
Frédéric Lécaille9d1b95b2017-03-15 09:13:33 +0100241/* Parse the "cookie" server keyword */
242static int srv_parse_cookie(char **args, int *cur_arg,
243 struct proxy *curproxy, struct server *newsrv, char **err)
244{
245 char *arg;
246
247 arg = args[*cur_arg + 1];
248 if (!*arg) {
249 memprintf(err, "'%s' expects <value> as argument.\n", args[*cur_arg]);
250 return ERR_ALERT | ERR_FATAL;
251 }
252
253 free(newsrv->cookie);
254 newsrv->cookie = strdup(arg);
255 newsrv->cklen = strlen(arg);
256 newsrv->flags |= SRV_F_COOKIESET;
257 return 0;
258}
259
Willy Tarreaudff55432012-10-10 17:51:05 +0200260/* parse the "id" server keyword */
261static int srv_parse_id(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
262{
263 struct eb32_node *node;
264
265 if (!*args[*cur_arg + 1]) {
266 memprintf(err, "'%s' : expects an integer argument", args[*cur_arg]);
267 return ERR_ALERT | ERR_FATAL;
268 }
269
270 newsrv->puid = atol(args[*cur_arg + 1]);
271 newsrv->conf.id.key = newsrv->puid;
272
273 if (newsrv->puid <= 0) {
274 memprintf(err, "'%s' : custom id has to be > 0", args[*cur_arg]);
275 return ERR_ALERT | ERR_FATAL;
276 }
277
278 node = eb32_lookup(&curproxy->conf.used_server_id, newsrv->puid);
279 if (node) {
280 struct server *target = container_of(node, struct server, conf.id);
281 memprintf(err, "'%s' : custom id %d already used at %s:%d ('server %s')",
282 args[*cur_arg], newsrv->puid, target->conf.file, target->conf.line,
283 target->id);
284 return ERR_ALERT | ERR_FATAL;
285 }
286
287 eb32_insert(&curproxy->conf.used_server_id, &newsrv->conf.id);
Baptiste Assmann7cc419a2015-07-07 22:02:20 +0200288 newsrv->flags |= SRV_F_FORCED_ID;
Willy Tarreaudff55432012-10-10 17:51:05 +0200289 return 0;
290}
291
Frédéric Lécaille22f41a22017-03-16 17:17:36 +0100292/* Parse the "namespace" server keyword */
293static int srv_parse_namespace(char **args, int *cur_arg,
294 struct proxy *curproxy, struct server *newsrv, char **err)
295{
296#ifdef CONFIG_HAP_NS
297 char *arg;
298
299 arg = args[*cur_arg + 1];
300 if (!*arg) {
301 memprintf(err, "'%s' : expects <name> as argument", args[*cur_arg]);
302 return ERR_ALERT | ERR_FATAL;
303 }
304
305 if (!strcmp(arg, "*")) {
306 /* Use the namespace associated with the connection (if present). */
307 newsrv->flags |= SRV_F_USE_NS_FROM_PP;
308 return 0;
309 }
310
311 /*
312 * As this parser may be called several times for the same 'default-server'
313 * object, or for a new 'server' instance deriving from a 'default-server'
314 * one with SRV_F_USE_NS_FROM_PP flag enabled, let's reset it.
315 */
316 newsrv->flags &= ~SRV_F_USE_NS_FROM_PP;
317
318 newsrv->netns = netns_store_lookup(arg, strlen(arg));
319 if (!newsrv->netns)
320 newsrv->netns = netns_store_insert(arg);
321
322 if (!newsrv->netns) {
323 memprintf(err, "Cannot open namespace '%s'", arg);
324 return ERR_ALERT | ERR_FATAL;
325 }
326
327 return 0;
328#else
329 memprintf(err, "'%s': '%s' option not implemented", args[0], args[*cur_arg]);
330 return ERR_ALERT | ERR_FATAL;
331#endif
332}
333
Frédéric Lécaillef5bf9032017-03-10 11:51:05 +0100334/* Parse the "no-backup" server keyword */
335static int srv_parse_no_backup(char **args, int *cur_arg,
336 struct proxy *curproxy, struct server *newsrv, char **err)
337{
338 newsrv->flags &= ~SRV_F_BACKUP;
339 return 0;
340}
341
Frédéric Lécaille65aa3562017-03-14 11:20:13 +0100342/* Parse the "no-check" server keyword */
343static int srv_parse_no_check(char **args, int *cur_arg,
344 struct proxy *curproxy, struct server *newsrv, char **err)
345{
346 free_check(&newsrv->check);
347 newsrv->check.state &= ~CHK_ST_CONFIGURED & ~CHK_ST_ENABLED;
348 newsrv->do_check = 0;
349 return 0;
350}
351
Frédéric Lécaille25df8902017-03-10 14:04:31 +0100352/* Parse the "no-check-send-proxy" server keyword */
353static int srv_parse_no_check_send_proxy(char **args, int *cur_arg,
354 struct proxy *curproxy, struct server *newsrv, char **err)
355{
356 newsrv->check.send_proxy = 0;
357 return 0;
358}
359
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100360/* Disable server PROXY protocol flags. */
361static int inline srv_disable_pp_flags(struct server *srv, unsigned int flags)
362{
363 srv->pp_opts &= ~flags;
364 return 0;
365}
366
367/* Parse the "no-send-proxy" server keyword */
368static int srv_parse_no_send_proxy(char **args, int *cur_arg,
369 struct proxy *curproxy, struct server *newsrv, char **err)
370{
371 return srv_disable_pp_flags(newsrv, SRV_PP_V1);
372}
373
374/* Parse the "no-send-proxy-v2" server keyword */
375static int srv_parse_no_send_proxy_v2(char **args, int *cur_arg,
376 struct proxy *curproxy, struct server *newsrv, char **err)
377{
378 return srv_disable_pp_flags(newsrv, SRV_PP_V2);
379}
380
Frédéric Lécaillef9bc1d62017-03-10 15:50:49 +0100381/* Parse the "non-stick" server keyword */
382static int srv_parse_non_stick(char **args, int *cur_arg,
383 struct proxy *curproxy, struct server *newsrv, char **err)
384{
385 newsrv->flags |= SRV_F_NON_STICK;
386 return 0;
387}
388
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100389/* Enable server PROXY protocol flags. */
390static int inline srv_enable_pp_flags(struct server *srv, unsigned int flags)
391{
392 srv->pp_opts |= flags;
393 return 0;
394}
395
Frédéric Lécaille547356e2017-03-15 08:55:39 +0100396/* Parse the "observe" server keyword */
397static int srv_parse_observe(char **args, int *cur_arg,
398 struct proxy *curproxy, struct server *newsrv, char **err)
399{
400 char *arg;
401
402 arg = args[*cur_arg + 1];
403 if (!*arg) {
404 memprintf(err, "'%s' expects <mode> as argument.\n", args[*cur_arg]);
405 return ERR_ALERT | ERR_FATAL;
406 }
407
408 if (!strcmp(arg, "none")) {
409 newsrv->observe = HANA_OBS_NONE;
410 }
411 else if (!strcmp(arg, "layer4")) {
412 newsrv->observe = HANA_OBS_LAYER4;
413 }
414 else if (!strcmp(arg, "layer7")) {
415 if (curproxy->mode != PR_MODE_HTTP) {
416 memprintf(err, "'%s' can only be used in http proxies.\n", arg);
417 return ERR_ALERT;
418 }
419 newsrv->observe = HANA_OBS_LAYER7;
420 }
421 else {
422 memprintf(err, "'%s' expects one of 'none', 'layer4', 'layer7' "
423 "but got '%s'\n", args[*cur_arg], arg);
424 return ERR_ALERT | ERR_FATAL;
425 }
426
427 return 0;
428}
429
Frédéric Lécaille16186232017-03-14 16:42:49 +0100430/* Parse the "redir" server keyword */
431static int srv_parse_redir(char **args, int *cur_arg,
432 struct proxy *curproxy, struct server *newsrv, char **err)
433{
434 char *arg;
435
436 arg = args[*cur_arg + 1];
437 if (!*arg) {
438 memprintf(err, "'%s' expects <prefix> as argument.\n", args[*cur_arg]);
439 return ERR_ALERT | ERR_FATAL;
440 }
441
442 free(newsrv->rdr_pfx);
443 newsrv->rdr_pfx = strdup(arg);
444 newsrv->rdr_len = strlen(arg);
445
446 return 0;
447}
448
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100449/* Parse the "send-proxy" server keyword */
450static int srv_parse_send_proxy(char **args, int *cur_arg,
451 struct proxy *curproxy, struct server *newsrv, char **err)
452{
453 return srv_enable_pp_flags(newsrv, SRV_PP_V1);
454}
455
456/* Parse the "send-proxy-v2" server keyword */
457static int srv_parse_send_proxy_v2(char **args, int *cur_arg,
458 struct proxy *curproxy, struct server *newsrv, char **err)
459{
460 return srv_enable_pp_flags(newsrv, SRV_PP_V2);
461}
462
Frédéric Lécaillef9bc1d62017-03-10 15:50:49 +0100463/* Parse the "stick" server keyword */
464static int srv_parse_stick(char **args, int *cur_arg,
465 struct proxy *curproxy, struct server *newsrv, char **err)
466{
467 newsrv->flags &= ~SRV_F_NON_STICK;
468 return 0;
469}
470
Frédéric Lécaille67e0e612017-03-14 15:21:31 +0100471/* Parse the "track" server keyword */
472static int srv_parse_track(char **args, int *cur_arg,
473 struct proxy *curproxy, struct server *newsrv, char **err)
474{
475 char *arg;
476
477 arg = args[*cur_arg + 1];
478 if (!*arg) {
479 memprintf(err, "'track' expects [<proxy>/]<server> as argument.\n");
480 return ERR_ALERT | ERR_FATAL;
481 }
482
483 free(newsrv->trackit);
484 newsrv->trackit = strdup(arg);
485
486 return 0;
487}
488
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200489/* Shutdown all connections of a server. The caller must pass a termination
Willy Tarreaue7dff022015-04-03 01:14:29 +0200490 * code in <why>, which must be one of SF_ERR_* indicating the reason for the
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200491 * shutdown.
492 */
Willy Tarreau87b09662015-04-03 00:22:06 +0200493void srv_shutdown_streams(struct server *srv, int why)
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200494{
Willy Tarreau87b09662015-04-03 00:22:06 +0200495 struct stream *stream, *stream_bck;
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200496
Willy Tarreau87b09662015-04-03 00:22:06 +0200497 list_for_each_entry_safe(stream, stream_bck, &srv->actconns, by_srv)
498 if (stream->srv_conn == srv)
499 stream_shutdown(stream, why);
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200500}
501
502/* Shutdown all connections of all backup servers of a proxy. The caller must
Willy Tarreaue7dff022015-04-03 01:14:29 +0200503 * pass a termination code in <why>, which must be one of SF_ERR_* indicating
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200504 * the reason for the shutdown.
505 */
Willy Tarreau87b09662015-04-03 00:22:06 +0200506void srv_shutdown_backup_streams(struct proxy *px, int why)
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200507{
508 struct server *srv;
509
510 for (srv = px->srv; srv != NULL; srv = srv->next)
511 if (srv->flags & SRV_F_BACKUP)
Willy Tarreau87b09662015-04-03 00:22:06 +0200512 srv_shutdown_streams(srv, why);
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200513}
514
Willy Tarreaubda92272014-05-20 21:55:30 +0200515/* Appends some information to a message string related to a server going UP or
516 * DOWN. If both <forced> and <reason> are null and the server tracks another
517 * one, a "via" information will be provided to know where the status came from.
518 * If <reason> is non-null, the entire string will be appended after a comma and
519 * a space (eg: to report some information from the check that changed the state).
Willy Tarreau87b09662015-04-03 00:22:06 +0200520 * If <xferred> is non-negative, some information about requeued streams are
Willy Tarreaubda92272014-05-20 21:55:30 +0200521 * provided.
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200522 */
Willy Tarreaubda92272014-05-20 21:55:30 +0200523void srv_append_status(struct chunk *msg, struct server *s, const char *reason, int xferred, int forced)
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200524{
Willy Tarreaubda92272014-05-20 21:55:30 +0200525 if (reason)
526 chunk_appendf(msg, ", %s", reason);
527 else if (!forced && s->track)
528 chunk_appendf(msg, " via %s/%s", s->track->proxy->id, s->track->id);
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200529
530 if (xferred >= 0) {
531 if (s->state == SRV_ST_STOPPED)
532 chunk_appendf(msg, ". %d active and %d backup servers left.%s"
533 " %d sessions active, %d requeued, %d remaining in queue",
534 s->proxy->srv_act, s->proxy->srv_bck,
535 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
536 s->cur_sess, xferred, s->nbpend);
537 else
538 chunk_appendf(msg, ". %d active and %d backup servers online.%s"
539 " %d sessions requeued, %d total in queue",
540 s->proxy->srv_act, s->proxy->srv_bck,
541 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
542 xferred, s->nbpend);
543 }
544}
545
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200546/* Marks server <s> down, regardless of its checks' statuses, notifies by all
547 * available means, recounts the remaining servers on the proxy and transfers
Willy Tarreau87b09662015-04-03 00:22:06 +0200548 * queued streams whenever possible to other servers. It automatically
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200549 * recomputes the number of servers, but not the map. Maintenance servers are
550 * ignored. It reports <reason> if non-null as the reason for going down. Note
551 * that it makes use of the trash to build the log strings, so <reason> must
552 * not be placed there.
553 */
554void srv_set_stopped(struct server *s, const char *reason)
555{
556 struct server *srv;
557 int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
558 int srv_was_stopping = (s->state == SRV_ST_STOPPING);
Simon Horman64e34162015-02-06 11:11:57 +0900559 int log_level;
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200560 int xferred;
561
562 if ((s->admin & SRV_ADMF_MAINT) || s->state == SRV_ST_STOPPED)
563 return;
564
565 s->last_change = now.tv_sec;
566 s->state = SRV_ST_STOPPED;
567 if (s->proxy->lbprm.set_server_status_down)
568 s->proxy->lbprm.set_server_status_down(s);
569
570 if (s->onmarkeddown & HANA_ONMARKEDDOWN_SHUTDOWNSESSIONS)
Willy Tarreaue7dff022015-04-03 01:14:29 +0200571 srv_shutdown_streams(s, SF_ERR_DOWN);
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200572
Willy Tarreau87b09662015-04-03 00:22:06 +0200573 /* we might have streams queued on this server and waiting for
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200574 * a connection. Those which are redispatchable will be queued
575 * to another server or to the proxy itself.
576 */
577 xferred = pendconn_redistribute(s);
578
579 chunk_printf(&trash,
580 "%sServer %s/%s is DOWN", s->flags & SRV_F_BACKUP ? "Backup " : "",
581 s->proxy->id, s->id);
582
583 srv_append_status(&trash, s, reason, xferred, 0);
584 Warning("%s.\n", trash.str);
585
586 /* we don't send an alert if the server was previously paused */
Simon Horman64e34162015-02-06 11:11:57 +0900587 log_level = srv_was_stopping ? LOG_NOTICE : LOG_ALERT;
588 send_log(s->proxy, log_level, "%s.\n", trash.str);
589 send_email_alert(s, log_level, "%s", trash.str);
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200590
591 if (prev_srv_count && s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
592 set_backend_down(s->proxy);
593
594 s->counters.down_trans++;
595
596 for (srv = s->trackers; srv; srv = srv->tracknext)
597 srv_set_stopped(srv, NULL);
598}
599
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200600/* Marks server <s> up regardless of its checks' statuses and provided it isn't
601 * in maintenance. Notifies by all available means, recounts the remaining
602 * servers on the proxy and tries to grab requests from the proxy. It
603 * automatically recomputes the number of servers, but not the map. Maintenance
604 * servers are ignored. It reports <reason> if non-null as the reason for going
605 * up. Note that it makes use of the trash to build the log strings, so <reason>
606 * must not be placed there.
607 */
608void srv_set_running(struct server *s, const char *reason)
609{
610 struct server *srv;
611 int xferred;
612
613 if (s->admin & SRV_ADMF_MAINT)
614 return;
615
616 if (s->state == SRV_ST_STARTING || s->state == SRV_ST_RUNNING)
617 return;
618
619 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
620 if (s->proxy->last_change < now.tv_sec) // ignore negative times
621 s->proxy->down_time += now.tv_sec - s->proxy->last_change;
622 s->proxy->last_change = now.tv_sec;
623 }
624
625 if (s->state == SRV_ST_STOPPED && s->last_change < now.tv_sec) // ignore negative times
626 s->down_time += now.tv_sec - s->last_change;
627
628 s->last_change = now.tv_sec;
629
630 s->state = SRV_ST_STARTING;
631 if (s->slowstart > 0)
632 task_schedule(s->warmup, tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20))));
633 else
634 s->state = SRV_ST_RUNNING;
635
636 server_recalc_eweight(s);
637
638 /* If the server is set with "on-marked-up shutdown-backup-sessions",
639 * and it's not a backup server and its effective weight is > 0,
Willy Tarreau87b09662015-04-03 00:22:06 +0200640 * then it can accept new connections, so we shut down all streams
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200641 * on all backup servers.
642 */
643 if ((s->onmarkedup & HANA_ONMARKEDUP_SHUTDOWNBACKUPSESSIONS) &&
644 !(s->flags & SRV_F_BACKUP) && s->eweight)
Willy Tarreaue7dff022015-04-03 01:14:29 +0200645 srv_shutdown_backup_streams(s->proxy, SF_ERR_UP);
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200646
647 /* check if we can handle some connections queued at the proxy. We
648 * will take as many as we can handle.
649 */
650 xferred = pendconn_grab_from_px(s);
651
652 chunk_printf(&trash,
653 "%sServer %s/%s is UP", s->flags & SRV_F_BACKUP ? "Backup " : "",
654 s->proxy->id, s->id);
655
656 srv_append_status(&trash, s, reason, xferred, 0);
657 Warning("%s.\n", trash.str);
658 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
Simon Horman4cd477f2015-04-30 13:10:34 +0900659 send_email_alert(s, LOG_NOTICE, "%s", trash.str);
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200660
661 for (srv = s->trackers; srv; srv = srv->tracknext)
662 srv_set_running(srv, NULL);
663}
664
Willy Tarreau8eb77842014-05-21 13:54:57 +0200665/* Marks server <s> stopping regardless of its checks' statuses and provided it
666 * isn't in maintenance. Notifies by all available means, recounts the remaining
667 * servers on the proxy and tries to grab requests from the proxy. It
668 * automatically recomputes the number of servers, but not the map. Maintenance
669 * servers are ignored. It reports <reason> if non-null as the reason for going
670 * up. Note that it makes use of the trash to build the log strings, so <reason>
671 * must not be placed there.
672 */
673void srv_set_stopping(struct server *s, const char *reason)
674{
675 struct server *srv;
676 int xferred;
677
678 if (s->admin & SRV_ADMF_MAINT)
679 return;
680
681 if (s->state == SRV_ST_STOPPING)
682 return;
683
684 s->last_change = now.tv_sec;
685 s->state = SRV_ST_STOPPING;
686 if (s->proxy->lbprm.set_server_status_down)
687 s->proxy->lbprm.set_server_status_down(s);
688
Willy Tarreau87b09662015-04-03 00:22:06 +0200689 /* we might have streams queued on this server and waiting for
Willy Tarreau8eb77842014-05-21 13:54:57 +0200690 * a connection. Those which are redispatchable will be queued
691 * to another server or to the proxy itself.
692 */
693 xferred = pendconn_redistribute(s);
694
695 chunk_printf(&trash,
696 "%sServer %s/%s is stopping", s->flags & SRV_F_BACKUP ? "Backup " : "",
697 s->proxy->id, s->id);
698
699 srv_append_status(&trash, s, reason, xferred, 0);
700
701 Warning("%s.\n", trash.str);
702 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
703
704 if (!s->proxy->srv_bck && !s->proxy->srv_act)
705 set_backend_down(s->proxy);
706
707 for (srv = s->trackers; srv; srv = srv->tracknext)
708 srv_set_stopping(srv, NULL);
709}
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200710
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200711/* Enables admin flag <mode> (among SRV_ADMF_*) on server <s>. This is used to
712 * enforce either maint mode or drain mode. It is not allowed to set more than
713 * one flag at once. The equivalent "inherited" flag is propagated to all
714 * tracking servers. Maintenance mode disables health checks (but not agent
715 * checks). When either the flag is already set or no flag is passed, nothing
Willy Tarreau8b428482016-11-07 15:53:43 +0100716 * is done. If <cause> is non-null, it will be displayed at the end of the log
717 * lines to justify the state change.
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200718 */
Willy Tarreau8b428482016-11-07 15:53:43 +0100719void srv_set_admin_flag(struct server *s, enum srv_admin mode, const char *cause)
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200720{
721 struct check *check = &s->check;
722 struct server *srv;
723 int xferred;
724
725 if (!mode)
726 return;
727
728 /* stop going down as soon as we meet a server already in the same state */
729 if (s->admin & mode)
730 return;
731
732 s->admin |= mode;
733
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200734 /* stop going down if the equivalent flag was already present (forced or inherited) */
735 if (((mode & SRV_ADMF_MAINT) && (s->admin & ~mode & SRV_ADMF_MAINT)) ||
736 ((mode & SRV_ADMF_DRAIN) && (s->admin & ~mode & SRV_ADMF_DRAIN)))
737 return;
738
739 /* Maintenance must also disable health checks */
740 if (mode & SRV_ADMF_MAINT) {
741 if (s->check.state & CHK_ST_ENABLED) {
742 s->check.state |= CHK_ST_PAUSED;
743 check->health = 0;
744 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200745
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200746 if (s->state == SRV_ST_STOPPED) { /* server was already down */
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200747 chunk_printf(&trash,
Willy Tarreau8b428482016-11-07 15:53:43 +0100748 "%sServer %s/%s was DOWN and now enters maintenance%s%s%s",
749 s->flags & SRV_F_BACKUP ? "Backup " : "", s->proxy->id, s->id,
750 cause ? " (" : "", cause ? cause : "", cause ? ")" : "");
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200751
Willy Tarreaubda92272014-05-20 21:55:30 +0200752 srv_append_status(&trash, s, NULL, -1, (mode & SRV_ADMF_FMAINT));
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200753
Willy Tarreau6fb8dc12016-11-03 19:42:36 +0100754 if (!(global.mode & MODE_STARTING)) {
755 Warning("%s.\n", trash.str);
756 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
757 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200758 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200759 else { /* server was still running */
760 int srv_was_stopping = (s->state == SRV_ST_STOPPING) || (s->admin & SRV_ADMF_DRAIN);
761 int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
762
763 check->health = 0; /* failure */
764 s->last_change = now.tv_sec;
765 s->state = SRV_ST_STOPPED;
766 if (s->proxy->lbprm.set_server_status_down)
767 s->proxy->lbprm.set_server_status_down(s);
768
769 if (s->onmarkeddown & HANA_ONMARKEDDOWN_SHUTDOWNSESSIONS)
Willy Tarreaue7dff022015-04-03 01:14:29 +0200770 srv_shutdown_streams(s, SF_ERR_DOWN);
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200771
Willy Tarreau87b09662015-04-03 00:22:06 +0200772 /* we might have streams queued on this server and waiting for
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200773 * a connection. Those which are redispatchable will be queued
774 * to another server or to the proxy itself.
775 */
776 xferred = pendconn_redistribute(s);
777
778 chunk_printf(&trash,
Willy Tarreau8b428482016-11-07 15:53:43 +0100779 "%sServer %s/%s is going DOWN for maintenance%s%s%s",
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200780 s->flags & SRV_F_BACKUP ? "Backup " : "",
Willy Tarreau8b428482016-11-07 15:53:43 +0100781 s->proxy->id, s->id,
782 cause ? " (" : "", cause ? cause : "", cause ? ")" : "");
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200783
784 srv_append_status(&trash, s, NULL, xferred, (mode & SRV_ADMF_FMAINT));
785
Willy Tarreau6fb8dc12016-11-03 19:42:36 +0100786 if (!(global.mode & MODE_STARTING)) {
787 Warning("%s.\n", trash.str);
788 send_log(s->proxy, srv_was_stopping ? LOG_NOTICE : LOG_ALERT, "%s.\n", trash.str);
789 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200790
791 if (prev_srv_count && s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
792 set_backend_down(s->proxy);
793
794 s->counters.down_trans++;
795 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200796 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200797
798 /* drain state is applied only if not yet in maint */
799 if ((mode & SRV_ADMF_DRAIN) && !(s->admin & SRV_ADMF_MAINT)) {
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200800 int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
801
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200802 s->last_change = now.tv_sec;
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200803 if (s->proxy->lbprm.set_server_status_down)
804 s->proxy->lbprm.set_server_status_down(s);
805
Willy Tarreau87b09662015-04-03 00:22:06 +0200806 /* we might have streams queued on this server and waiting for
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200807 * a connection. Those which are redispatchable will be queued
808 * to another server or to the proxy itself.
809 */
810 xferred = pendconn_redistribute(s);
811
Willy Tarreau8b428482016-11-07 15:53:43 +0100812 chunk_printf(&trash, "%sServer %s/%s enters drain state%s%s%s",
813 s->flags & SRV_F_BACKUP ? "Backup " : "", s->proxy->id, s->id,
814 cause ? " (" : "", cause ? cause : "", cause ? ")" : "");
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200815
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200816 srv_append_status(&trash, s, NULL, xferred, (mode & SRV_ADMF_FDRAIN));
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200817
Willy Tarreau6fb8dc12016-11-03 19:42:36 +0100818 if (!(global.mode & MODE_STARTING)) {
819 Warning("%s.\n", trash.str);
820 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
821 send_email_alert(s, LOG_NOTICE, "%s", trash.str);
822 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200823 if (prev_srv_count && s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
824 set_backend_down(s->proxy);
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200825 }
826
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200827 /* compute the inherited flag to propagate */
828 if (mode & SRV_ADMF_MAINT)
829 mode = SRV_ADMF_IMAINT;
830 else if (mode & SRV_ADMF_DRAIN)
831 mode = SRV_ADMF_IDRAIN;
832
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200833 for (srv = s->trackers; srv; srv = srv->tracknext)
Willy Tarreau8b428482016-11-07 15:53:43 +0100834 srv_set_admin_flag(srv, mode, cause);
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200835}
836
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200837/* Disables admin flag <mode> (among SRV_ADMF_*) on server <s>. This is used to
838 * stop enforcing either maint mode or drain mode. It is not allowed to set more
839 * than one flag at once. The equivalent "inherited" flag is propagated to all
840 * tracking servers. Leaving maintenance mode re-enables health checks. When
841 * either the flag is already cleared or no flag is passed, nothing is done.
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200842 */
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200843void srv_clr_admin_flag(struct server *s, enum srv_admin mode)
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200844{
845 struct check *check = &s->check;
846 struct server *srv;
847 int xferred = -1;
848
849 if (!mode)
850 return;
851
852 /* stop going down as soon as we see the flag is not there anymore */
853 if (!(s->admin & mode))
854 return;
855
856 s->admin &= ~mode;
857
858 if (s->admin & SRV_ADMF_MAINT) {
859 /* remaining in maintenance mode, let's inform precisely about the
860 * situation.
861 */
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200862 if (mode & SRV_ADMF_FMAINT) {
863 chunk_printf(&trash,
864 "%sServer %s/%s is leaving forced maintenance but remains in maintenance",
865 s->flags & SRV_F_BACKUP ? "Backup " : "",
866 s->proxy->id, s->id);
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200867
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200868 if (s->track) /* normally it's mandatory here */
869 chunk_appendf(&trash, " via %s/%s",
870 s->track->proxy->id, s->track->id);
871 Warning("%s.\n", trash.str);
872 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
873 }
Willy Tarreaue6599732016-11-07 15:42:33 +0100874 if (mode & SRV_ADMF_RMAINT) {
875 chunk_printf(&trash,
876 "%sServer %s/%s ('%s') resolves again but remains in maintenance",
877 s->flags & SRV_F_BACKUP ? "Backup " : "",
878 s->proxy->id, s->id, s->hostname);
879
880 if (s->track) /* normally it's mandatory here */
881 chunk_appendf(&trash, " via %s/%s",
882 s->track->proxy->id, s->track->id);
883 Warning("%s.\n", trash.str);
884 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
885 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200886 else if (mode & SRV_ADMF_IMAINT) {
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200887 chunk_printf(&trash,
888 "%sServer %s/%s remains in forced maintenance",
889 s->flags & SRV_F_BACKUP ? "Backup " : "",
890 s->proxy->id, s->id);
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200891 Warning("%s.\n", trash.str);
892 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
893 }
894 /* don't report anything when leaving drain mode and remaining in maintenance */
895 }
896 else if (mode & SRV_ADMF_MAINT) {
897 /* OK here we're leaving maintenance, we have many things to check,
898 * because the server might possibly be coming back up depending on
899 * its state. In practice, leaving maintenance means that we should
900 * immediately turn to UP (more or less the slowstart) under the
901 * following conditions :
902 * - server is neither checked nor tracked
903 * - server tracks another server which is not checked
904 * - server tracks another server which is already up
905 * Which sums up as something simpler :
906 * "either the tracking server is up or the server's checks are disabled
907 * or up". Otherwise we only re-enable health checks. There's a special
908 * case associated to the stopping state which can be inherited. Note
909 * that the server might still be in drain mode, which is naturally dealt
910 * with by the lower level functions.
911 */
912
913 if (s->check.state & CHK_ST_ENABLED) {
914 s->check.state &= ~CHK_ST_PAUSED;
915 check->health = check->rise; /* start OK but check immediately */
916 }
917
918 if ((!s->track || s->track->state != SRV_ST_STOPPED) &&
919 (!(s->agent.state & CHK_ST_ENABLED) || (s->agent.health >= s->agent.rise)) &&
920 (!(s->check.state & CHK_ST_ENABLED) || (s->check.health >= s->check.rise))) {
921 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
922 if (s->proxy->last_change < now.tv_sec) // ignore negative times
923 s->proxy->down_time += now.tv_sec - s->proxy->last_change;
924 s->proxy->last_change = now.tv_sec;
925 }
926
927 if (s->last_change < now.tv_sec) // ignore negative times
928 s->down_time += now.tv_sec - s->last_change;
929 s->last_change = now.tv_sec;
930
931 if (s->track && s->track->state == SRV_ST_STOPPING)
932 s->state = SRV_ST_STOPPING;
933 else {
934 s->state = SRV_ST_STARTING;
935 if (s->slowstart > 0)
936 task_schedule(s->warmup, tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20))));
937 else
938 s->state = SRV_ST_RUNNING;
939 }
940
941 server_recalc_eweight(s);
942
943 /* If the server is set with "on-marked-up shutdown-backup-sessions",
944 * and it's not a backup server and its effective weight is > 0,
Willy Tarreau87b09662015-04-03 00:22:06 +0200945 * then it can accept new connections, so we shut down all streams
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200946 * on all backup servers.
947 */
948 if ((s->onmarkedup & HANA_ONMARKEDUP_SHUTDOWNBACKUPSESSIONS) &&
949 !(s->flags & SRV_F_BACKUP) && s->eweight)
Willy Tarreaue7dff022015-04-03 01:14:29 +0200950 srv_shutdown_backup_streams(s->proxy, SF_ERR_UP);
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200951
952 /* check if we can handle some connections queued at the proxy. We
953 * will take as many as we can handle.
954 */
955 xferred = pendconn_grab_from_px(s);
956 }
957
958 if (mode & SRV_ADMF_FMAINT) {
959 chunk_printf(&trash,
960 "%sServer %s/%s is %s/%s (leaving forced maintenance)",
961 s->flags & SRV_F_BACKUP ? "Backup " : "",
962 s->proxy->id, s->id,
963 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP",
964 (s->admin & SRV_ADMF_DRAIN) ? "DRAIN" : "READY");
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200965 }
Willy Tarreaue6599732016-11-07 15:42:33 +0100966 else if (mode & SRV_ADMF_RMAINT) {
967 chunk_printf(&trash,
968 "%sServer %s/%s ('%s') is %s/%s (resolves again)",
969 s->flags & SRV_F_BACKUP ? "Backup " : "",
970 s->proxy->id, s->id, s->hostname,
971 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP",
972 (s->admin & SRV_ADMF_DRAIN) ? "DRAIN" : "READY");
973 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200974 else {
975 chunk_printf(&trash,
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200976 "%sServer %s/%s is %s/%s (leaving maintenance)",
977 s->flags & SRV_F_BACKUP ? "Backup " : "",
978 s->proxy->id, s->id,
979 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP",
980 (s->admin & SRV_ADMF_DRAIN) ? "DRAIN" : "READY");
981 srv_append_status(&trash, s, NULL, xferred, 0);
982 }
983 Warning("%s.\n", trash.str);
984 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
985 }
986 else if ((mode & SRV_ADMF_DRAIN) && (s->admin & SRV_ADMF_DRAIN)) {
987 /* remaining in drain mode after removing one of its flags */
988
989 if (mode & SRV_ADMF_FDRAIN) {
990 chunk_printf(&trash,
991 "%sServer %s/%s is leaving forced drain but remains in drain mode",
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200992 s->flags & SRV_F_BACKUP ? "Backup " : "",
993 s->proxy->id, s->id);
994
995 if (s->track) /* normally it's mandatory here */
996 chunk_appendf(&trash, " via %s/%s",
997 s->track->proxy->id, s->track->id);
998 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200999 else {
1000 chunk_printf(&trash,
1001 "%sServer %s/%s remains in forced drain mode",
1002 s->flags & SRV_F_BACKUP ? "Backup " : "",
1003 s->proxy->id, s->id);
1004 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001005 Warning("%s.\n", trash.str);
1006 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001007 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001008 else if (mode & SRV_ADMF_DRAIN) {
1009 /* OK completely leaving drain mode */
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001010 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
1011 if (s->proxy->last_change < now.tv_sec) // ignore negative times
1012 s->proxy->down_time += now.tv_sec - s->proxy->last_change;
1013 s->proxy->last_change = now.tv_sec;
1014 }
1015
1016 if (s->last_change < now.tv_sec) // ignore negative times
1017 s->down_time += now.tv_sec - s->last_change;
1018 s->last_change = now.tv_sec;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001019 server_recalc_eweight(s);
1020
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001021 if (mode & SRV_ADMF_FDRAIN) {
1022 chunk_printf(&trash,
1023 "%sServer %s/%s is %s (leaving forced drain)",
1024 s->flags & SRV_F_BACKUP ? "Backup " : "",
1025 s->proxy->id, s->id,
1026 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP");
1027 }
1028 else {
1029 chunk_printf(&trash,
1030 "%sServer %s/%s is %s (leaving drain)",
1031 s->flags & SRV_F_BACKUP ? "Backup " : "",
1032 s->proxy->id, s->id,
1033 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP");
1034 if (s->track) /* normally it's mandatory here */
1035 chunk_appendf(&trash, " via %s/%s",
1036 s->track->proxy->id, s->track->id);
1037 }
1038 Warning("%s.\n", trash.str);
1039 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001040 }
1041
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001042 /* stop going down if the equivalent flag is still present (forced or inherited) */
1043 if (((mode & SRV_ADMF_MAINT) && (s->admin & SRV_ADMF_MAINT)) ||
1044 ((mode & SRV_ADMF_DRAIN) && (s->admin & SRV_ADMF_DRAIN)))
1045 return;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001046
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001047 if (mode & SRV_ADMF_MAINT)
1048 mode = SRV_ADMF_IMAINT;
1049 else if (mode & SRV_ADMF_DRAIN)
1050 mode = SRV_ADMF_IDRAIN;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001051
1052 for (srv = s->trackers; srv; srv = srv->tracknext)
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001053 srv_clr_admin_flag(srv, mode);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001054}
1055
Willy Tarreau757478e2016-11-03 19:22:19 +01001056/* principle: propagate maint and drain to tracking servers. This is useful
1057 * upon startup so that inherited states are correct.
1058 */
1059static void srv_propagate_admin_state(struct server *srv)
1060{
1061 struct server *srv2;
1062
1063 if (!srv->trackers)
1064 return;
1065
1066 for (srv2 = srv->trackers; srv2; srv2 = srv2->tracknext) {
1067 if (srv->admin & (SRV_ADMF_MAINT | SRV_ADMF_CMAINT))
Willy Tarreau8b428482016-11-07 15:53:43 +01001068 srv_set_admin_flag(srv2, SRV_ADMF_IMAINT, NULL);
Willy Tarreau757478e2016-11-03 19:22:19 +01001069
1070 if (srv->admin & SRV_ADMF_DRAIN)
Willy Tarreau8b428482016-11-07 15:53:43 +01001071 srv_set_admin_flag(srv2, SRV_ADMF_IDRAIN, NULL);
Willy Tarreau757478e2016-11-03 19:22:19 +01001072 }
1073}
1074
1075/* Compute and propagate the admin states for all servers in proxy <px>.
1076 * Only servers *not* tracking another one are considered, because other
1077 * ones will be handled when the server they track is visited.
1078 */
1079void srv_compute_all_admin_states(struct proxy *px)
1080{
1081 struct server *srv;
1082
1083 for (srv = px->srv; srv; srv = srv->next) {
1084 if (srv->track)
1085 continue;
1086 srv_propagate_admin_state(srv);
1087 }
1088}
1089
Willy Tarreaudff55432012-10-10 17:51:05 +02001090/* Note: must not be declared <const> as its list will be overwritten.
1091 * Please take care of keeping this list alphabetically sorted, doing so helps
1092 * all code contributors.
1093 * Optional keywords are also declared with a NULL ->parse() function so that
1094 * the config parser can report an appropriate error when a known keyword was
1095 * not enabled.
1096 */
1097static struct srv_kw_list srv_kws = { "ALL", { }, {
Frédéric Lécaille1502cfd2017-03-10 15:36:14 +01001098 { "backup", srv_parse_backup, 0, 1 }, /* Flag as backup server */
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01001099 { "check", srv_parse_check, 0, 1 }, /* enable health checks */
Frédéric Lécaille25df8902017-03-10 14:04:31 +01001100 { "check-send-proxy", srv_parse_check_send_proxy, 0, 1 }, /* enable PROXY protocol for health checks */
Frédéric Lécaille9d1b95b2017-03-15 09:13:33 +01001101 { "cookie", srv_parse_cookie, 1, 1 }, /* Assign a cookie to the server */
Frédéric Lécaille1502cfd2017-03-10 15:36:14 +01001102 { "id", srv_parse_id, 1, 0 }, /* set id# of server */
Frédéric Lécaille22f41a22017-03-16 17:17:36 +01001103 { "namespace", srv_parse_namespace, 1, 1 }, /* Namespace the server socket belongs to (if supported) */
Frédéric Lécaille1502cfd2017-03-10 15:36:14 +01001104 { "no-backup", srv_parse_no_backup, 0, 1 }, /* Flag as non-backup server */
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01001105 { "no-check", srv_parse_no_check, 0, 1 }, /* disable health checks */
Frédéric Lécaille25df8902017-03-10 14:04:31 +01001106 { "no-check-send-proxy", srv_parse_no_check_send_proxy, 0, 1 }, /* disable PROXY protol for health checks */
Frédéric Lécaille31045e42017-03-10 16:40:00 +01001107 { "no-send-proxy", srv_parse_no_send_proxy, 0, 1 }, /* Disable use of PROXY V1 protocol */
1108 { "no-send-proxy-v2", srv_parse_no_send_proxy_v2, 0, 1 }, /* Disable use of PROXY V2 protocol */
Frédéric Lécaillef9bc1d62017-03-10 15:50:49 +01001109 { "non-stick", srv_parse_non_stick, 0, 1 }, /* Disable stick-table persistence */
Frédéric Lécaille547356e2017-03-15 08:55:39 +01001110 { "observe", srv_parse_observe, 1, 1 }, /* Enables health adjusting based on observing communication with the server */
Frédéric Lécaille16186232017-03-14 16:42:49 +01001111 { "redir", srv_parse_redir, 1, 1 }, /* Enable redirection mode */
Frédéric Lécaille31045e42017-03-10 16:40:00 +01001112 { "send-proxy", srv_parse_send_proxy, 0, 1 }, /* Enforce use of PROXY V1 protocol */
1113 { "send-proxy-v2", srv_parse_send_proxy_v2, 0, 1 }, /* Enforce use of PROXY V2 protocol */
Frédéric Lécaillef9bc1d62017-03-10 15:50:49 +01001114 { "stick", srv_parse_stick, 0, 1 }, /* Enable stick-table persistence */
Frédéric Lécaille67e0e612017-03-14 15:21:31 +01001115 { "track", srv_parse_track, 1, 1 }, /* Set the current state of the server, tracking another one */
Willy Tarreaudff55432012-10-10 17:51:05 +02001116 { NULL, NULL, 0 },
1117}};
1118
1119__attribute__((constructor))
1120static void __listener_init(void)
1121{
1122 srv_register_keywords(&srv_kws);
1123}
1124
Willy Tarreau004e0452013-11-21 11:22:01 +01001125/* Recomputes the server's eweight based on its state, uweight, the current time,
1126 * and the proxy's algorihtm. To be used after updating sv->uweight. The warmup
1127 * state is automatically disabled if the time is elapsed.
1128 */
1129void server_recalc_eweight(struct server *sv)
1130{
1131 struct proxy *px = sv->proxy;
1132 unsigned w;
1133
1134 if (now.tv_sec < sv->last_change || now.tv_sec >= sv->last_change + sv->slowstart) {
1135 /* go to full throttle if the slowstart interval is reached */
Willy Tarreau892337c2014-05-13 23:41:20 +02001136 if (sv->state == SRV_ST_STARTING)
1137 sv->state = SRV_ST_RUNNING;
Willy Tarreau004e0452013-11-21 11:22:01 +01001138 }
1139
1140 /* We must take care of not pushing the server to full throttle during slow starts.
1141 * It must also start immediately, at least at the minimal step when leaving maintenance.
1142 */
Willy Tarreau892337c2014-05-13 23:41:20 +02001143 if ((sv->state == SRV_ST_STARTING) && (px->lbprm.algo & BE_LB_PROP_DYN))
Willy Tarreau004e0452013-11-21 11:22:01 +01001144 w = (px->lbprm.wdiv * (now.tv_sec - sv->last_change) + sv->slowstart) / sv->slowstart;
1145 else
1146 w = px->lbprm.wdiv;
1147
1148 sv->eweight = (sv->uweight * w + px->lbprm.wmult - 1) / px->lbprm.wmult;
1149
1150 /* now propagate the status change to any LB algorithms */
1151 if (px->lbprm.update_server_eweight)
1152 px->lbprm.update_server_eweight(sv);
Willy Tarreau9943d312014-05-22 16:20:59 +02001153 else if (srv_is_usable(sv)) {
Willy Tarreau004e0452013-11-21 11:22:01 +01001154 if (px->lbprm.set_server_status_up)
1155 px->lbprm.set_server_status_up(sv);
1156 }
1157 else {
1158 if (px->lbprm.set_server_status_down)
1159 px->lbprm.set_server_status_down(sv);
1160 }
1161}
1162
Willy Tarreaubaaee002006-06-26 02:48:02 +02001163/*
Simon Horman7d09b9a2013-02-12 10:45:51 +09001164 * Parses weight_str and configures sv accordingly.
1165 * Returns NULL on success, error message string otherwise.
1166 */
1167const char *server_parse_weight_change_request(struct server *sv,
1168 const char *weight_str)
1169{
1170 struct proxy *px;
Simon Hormanb796afa2013-02-12 10:45:53 +09001171 long int w;
1172 char *end;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001173
1174 px = sv->proxy;
1175
1176 /* if the weight is terminated with '%', it is set relative to
1177 * the initial weight, otherwise it is absolute.
1178 */
1179 if (!*weight_str)
1180 return "Require <weight> or <weight%>.\n";
1181
Simon Hormanb796afa2013-02-12 10:45:53 +09001182 w = strtol(weight_str, &end, 10);
1183 if (end == weight_str)
1184 return "Empty weight string empty or preceded by garbage";
1185 else if (end[0] == '%' && end[1] == '\0') {
Simon Horman58b5d292013-02-12 10:45:52 +09001186 if (w < 0)
Simon Horman7d09b9a2013-02-12 10:45:51 +09001187 return "Relative weight must be positive.\n";
Simon Horman58b5d292013-02-12 10:45:52 +09001188 /* Avoid integer overflow */
1189 if (w > 25600)
1190 w = 25600;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001191 w = sv->iweight * w / 100;
Simon Horman58b5d292013-02-12 10:45:52 +09001192 if (w > 256)
1193 w = 256;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001194 }
1195 else if (w < 0 || w > 256)
1196 return "Absolute weight can only be between 0 and 256 inclusive.\n";
Simon Hormanb796afa2013-02-12 10:45:53 +09001197 else if (end[0] != '\0')
1198 return "Trailing garbage in weight string";
Simon Horman7d09b9a2013-02-12 10:45:51 +09001199
1200 if (w && w != sv->iweight && !(px->lbprm.algo & BE_LB_PROP_DYN))
1201 return "Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.\n";
1202
1203 sv->uweight = w;
Willy Tarreau004e0452013-11-21 11:22:01 +01001204 server_recalc_eweight(sv);
Simon Horman7d09b9a2013-02-12 10:45:51 +09001205
1206 return NULL;
1207}
1208
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001209/*
Thierry Fournier09a91782016-02-24 08:25:39 +01001210 * Parses <addr_str> and configures <sv> accordingly. <from> precise
1211 * the source of the change in the associated message log.
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001212 * Returns:
1213 * - error string on error
1214 * - NULL on success
1215 */
1216const char *server_parse_addr_change_request(struct server *sv,
Thierry Fournier09a91782016-02-24 08:25:39 +01001217 const char *addr_str, const char *updater)
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001218{
1219 unsigned char ip[INET6_ADDRSTRLEN];
1220
1221 if (inet_pton(AF_INET6, addr_str, ip)) {
Thierry Fournier09a91782016-02-24 08:25:39 +01001222 update_server_addr(sv, ip, AF_INET6, updater);
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001223 return NULL;
1224 }
1225 if (inet_pton(AF_INET, addr_str, ip)) {
Thierry Fournier09a91782016-02-24 08:25:39 +01001226 update_server_addr(sv, ip, AF_INET, updater);
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001227 return NULL;
1228 }
1229
1230 return "Could not understand IP address format.\n";
1231}
1232
Nenad Merdanovic174dd372016-04-24 23:10:06 +02001233const char *server_parse_maxconn_change_request(struct server *sv,
1234 const char *maxconn_str)
1235{
1236 long int v;
1237 char *end;
1238
1239 if (!*maxconn_str)
1240 return "Require <maxconn>.\n";
1241
1242 v = strtol(maxconn_str, &end, 10);
1243 if (end == maxconn_str)
1244 return "maxconn string empty or preceded by garbage";
1245 else if (end[0] != '\0')
1246 return "Trailing garbage in maxconn string";
1247
1248 if (sv->maxconn == sv->minconn) { // static maxconn
1249 sv->maxconn = sv->minconn = v;
1250 } else { // dynamic maxconn
1251 sv->maxconn = v;
1252 }
1253
1254 if (may_dequeue_tasks(sv, sv->proxy))
1255 process_srv_queue(sv);
1256
1257 return NULL;
1258}
1259
Willy Tarreau272adea2014-03-31 10:39:59 +02001260int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
1261{
1262 struct server *newsrv = NULL;
1263 const char *err;
1264 char *errmsg = NULL;
1265 int err_code = 0;
1266 unsigned val;
Willy Tarreau07101d52015-09-08 16:16:35 +02001267 char *fqdn = NULL;
Willy Tarreau272adea2014-03-31 10:39:59 +02001268
1269 if (!strcmp(args[0], "server") || !strcmp(args[0], "default-server")) { /* server address */
1270 int cur_arg;
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01001271 int do_agent = 0, defsrv = (*args[0] == 'd');
Willy Tarreau272adea2014-03-31 10:39:59 +02001272
1273 if (!defsrv && curproxy == defproxy) {
1274 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1275 err_code |= ERR_ALERT | ERR_FATAL;
1276 goto out;
1277 }
1278 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1279 err_code |= ERR_ALERT | ERR_FATAL;
1280
Frédéric Lécaille8065b6d2017-03-09 14:01:02 +01001281 if (!defsrv && !*args[2]) {
Willy Tarreau272adea2014-03-31 10:39:59 +02001282 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
1283 file, linenum, args[0]);
1284 err_code |= ERR_ALERT | ERR_FATAL;
1285 goto out;
1286 }
1287
1288 err = invalid_char(args[1]);
1289 if (err && !defsrv) {
1290 Alert("parsing [%s:%d] : character '%c' is not permitted in server name '%s'.\n",
1291 file, linenum, *err, args[1]);
1292 err_code |= ERR_ALERT | ERR_FATAL;
1293 goto out;
1294 }
1295
1296 if (!defsrv) {
1297 struct sockaddr_storage *sk;
Willy Tarreau6ecb10a2017-01-06 18:36:06 +01001298 int port1, port2, port;
Willy Tarreau272adea2014-03-31 10:39:59 +02001299 struct protocol *proto;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001300 struct dns_resolution *curr_resolution;
Willy Tarreau272adea2014-03-31 10:39:59 +02001301
Vincent Bernat02779b62016-04-03 13:48:43 +02001302 if ((newsrv = calloc(1, sizeof(*newsrv))) == NULL) {
Willy Tarreau272adea2014-03-31 10:39:59 +02001303 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1304 err_code |= ERR_ALERT | ERR_ABORT;
1305 goto out;
1306 }
1307
1308 /* the servers are linked backwards first */
1309 newsrv->next = curproxy->srv;
1310 curproxy->srv = newsrv;
1311 newsrv->proxy = curproxy;
1312 newsrv->conf.file = strdup(file);
1313 newsrv->conf.line = linenum;
1314
1315 newsrv->obj_type = OBJ_TYPE_SERVER;
1316 LIST_INIT(&newsrv->actconns);
1317 LIST_INIT(&newsrv->pendconns);
Willy Tarreau600802a2015-08-04 17:19:06 +02001318 LIST_INIT(&newsrv->priv_conns);
Willy Tarreau173a1c62015-08-05 10:31:57 +02001319 LIST_INIT(&newsrv->idle_conns);
Willy Tarreau7017cb02015-08-05 16:35:23 +02001320 LIST_INIT(&newsrv->safe_conns);
Willy Tarreau272adea2014-03-31 10:39:59 +02001321 do_agent = 0;
Willy Tarreauc93cd162014-05-13 15:54:22 +02001322 newsrv->flags = 0;
Willy Tarreau20125212014-05-13 19:44:56 +02001323 newsrv->admin = 0;
Willy Tarreau892337c2014-05-13 23:41:20 +02001324 newsrv->state = SRV_ST_RUNNING; /* early server setup */
Willy Tarreau272adea2014-03-31 10:39:59 +02001325 newsrv->last_change = now.tv_sec;
1326 newsrv->id = strdup(args[1]);
1327
1328 /* several ways to check the port component :
1329 * - IP => port=+0, relative (IPv4 only)
1330 * - IP: => port=+0, relative
1331 * - IP:N => port=N, absolute
1332 * - IP:+N => port=+N, relative
1333 * - IP:-N => port=-N, relative
1334 */
Willy Tarreau6ecb10a2017-01-06 18:36:06 +01001335 sk = str2sa_range(args[2], &port, &port1, &port2, &errmsg, NULL, &fqdn, 0);
Willy Tarreau272adea2014-03-31 10:39:59 +02001336 if (!sk) {
1337 Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
1338 err_code |= ERR_ALERT | ERR_FATAL;
1339 goto out;
1340 }
1341
1342 proto = protocol_by_family(sk->ss_family);
Willy Tarreau9698f4b2017-01-06 18:42:57 +01001343 if (!fqdn && (!proto || !proto->connect)) {
Willy Tarreau272adea2014-03-31 10:39:59 +02001344 Alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
1345 file, linenum, args[0], args[1]);
1346 err_code |= ERR_ALERT | ERR_FATAL;
1347 goto out;
1348 }
1349
1350 if (!port1 || !port2) {
1351 /* no port specified, +offset, -offset */
Willy Tarreauc93cd162014-05-13 15:54:22 +02001352 newsrv->flags |= SRV_F_MAPPORTS;
Willy Tarreau272adea2014-03-31 10:39:59 +02001353 }
1354 else if (port1 != port2) {
1355 /* port range */
1356 Alert("parsing [%s:%d] : '%s %s' : port ranges are not allowed in '%s'\n",
1357 file, linenum, args[0], args[1], args[2]);
1358 err_code |= ERR_ALERT | ERR_FATAL;
1359 goto out;
1360 }
Willy Tarreau272adea2014-03-31 10:39:59 +02001361
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001362 /* save hostname and create associated name resolution */
Willy Tarreau07101d52015-09-08 16:16:35 +02001363 newsrv->hostname = fqdn;
1364 if (!fqdn)
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001365 goto skip_name_resolution;
1366
Willy Tarreau07101d52015-09-08 16:16:35 +02001367 fqdn = NULL;
Vincent Bernat02779b62016-04-03 13:48:43 +02001368 if ((curr_resolution = calloc(1, sizeof(*curr_resolution))) == NULL)
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001369 goto skip_name_resolution;
1370
1371 curr_resolution->hostname_dn_len = dns_str_to_dn_label_len(newsrv->hostname);
1372 if ((curr_resolution->hostname_dn = calloc(curr_resolution->hostname_dn_len + 1, sizeof(char))) == NULL)
1373 goto skip_name_resolution;
1374 if ((dns_str_to_dn_label(newsrv->hostname, curr_resolution->hostname_dn, curr_resolution->hostname_dn_len + 1)) == NULL) {
1375 Alert("parsing [%s:%d] : Invalid hostname '%s'\n",
1376 file, linenum, args[2]);
1377 err_code |= ERR_ALERT | ERR_FATAL;
1378 goto out;
1379 }
1380
1381 curr_resolution->requester = newsrv;
1382 curr_resolution->requester_cb = snr_resolution_cb;
1383 curr_resolution->requester_error_cb = snr_resolution_error_cb;
1384 curr_resolution->status = RSLV_STATUS_NONE;
1385 curr_resolution->step = RSLV_STEP_NONE;
1386 /* a first resolution has been done by the configuration parser */
Baptiste Assmannf046f112015-08-27 22:12:46 +02001387 curr_resolution->last_resolution = 0;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001388 newsrv->resolution = curr_resolution;
1389
1390 skip_name_resolution:
Willy Tarreau272adea2014-03-31 10:39:59 +02001391 newsrv->addr = *sk;
Willy Tarreau6ecb10a2017-01-06 18:36:06 +01001392 newsrv->svc_port = port;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01001393 newsrv->xprt = newsrv->check.xprt = newsrv->agent.xprt = xprt_get(XPRT_RAW);
Willy Tarreau272adea2014-03-31 10:39:59 +02001394
Willy Tarreau9698f4b2017-01-06 18:42:57 +01001395 if (!newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) {
Willy Tarreau272adea2014-03-31 10:39:59 +02001396 Alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n",
1397 file, linenum, newsrv->addr.ss_family, args[2]);
1398 err_code |= ERR_ALERT | ERR_FATAL;
1399 goto out;
1400 }
1401
Frédéric Lécaille31045e42017-03-10 16:40:00 +01001402 newsrv->pp_opts = curproxy->defsrv.pp_opts;
Frédéric Lécaille16186232017-03-14 16:42:49 +01001403 if (curproxy->defsrv.rdr_pfx != NULL) {
1404 newsrv->rdr_pfx = strdup(curproxy->defsrv.rdr_pfx);
1405 newsrv->rdr_len = curproxy->defsrv.rdr_len;
1406 }
Frédéric Lécaille9d1b95b2017-03-15 09:13:33 +01001407 if (curproxy->defsrv.cookie != NULL) {
1408 newsrv->cookie = strdup(curproxy->defsrv.cookie);
1409 newsrv->cklen = curproxy->defsrv.cklen;
1410 }
Willy Tarreau141ad852016-12-22 18:38:00 +01001411 newsrv->use_ssl = curproxy->defsrv.use_ssl;
Willy Tarreau272adea2014-03-31 10:39:59 +02001412 newsrv->check.use_ssl = curproxy->defsrv.check.use_ssl;
1413 newsrv->check.port = curproxy->defsrv.check.port;
Frédéric Lécaillef5bf9032017-03-10 11:51:05 +01001414 /* Note: 'flags' field has potentially been already initialized. */
1415 newsrv->flags |= curproxy->defsrv.flags;
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01001416 newsrv->do_check = curproxy->defsrv.do_check;
Baptiste Assmann6b453f12016-08-11 23:12:18 +02001417 if (newsrv->check.port)
1418 newsrv->flags |= SRV_F_CHECKPORT;
Willy Tarreau272adea2014-03-31 10:39:59 +02001419 newsrv->check.inter = curproxy->defsrv.check.inter;
1420 newsrv->check.fastinter = curproxy->defsrv.check.fastinter;
1421 newsrv->check.downinter = curproxy->defsrv.check.downinter;
1422 newsrv->agent.use_ssl = curproxy->defsrv.agent.use_ssl;
1423 newsrv->agent.port = curproxy->defsrv.agent.port;
James Brown55f9ff12015-10-21 18:19:05 -07001424 if (curproxy->defsrv.agent.send_string != NULL)
1425 newsrv->agent.send_string = strdup(curproxy->defsrv.agent.send_string);
1426 newsrv->agent.send_string_len = curproxy->defsrv.agent.send_string_len;
Willy Tarreau272adea2014-03-31 10:39:59 +02001427 newsrv->agent.inter = curproxy->defsrv.agent.inter;
1428 newsrv->agent.fastinter = curproxy->defsrv.agent.fastinter;
1429 newsrv->agent.downinter = curproxy->defsrv.agent.downinter;
1430 newsrv->maxqueue = curproxy->defsrv.maxqueue;
1431 newsrv->minconn = curproxy->defsrv.minconn;
1432 newsrv->maxconn = curproxy->defsrv.maxconn;
1433 newsrv->slowstart = curproxy->defsrv.slowstart;
Frédéric Lécaille547356e2017-03-15 08:55:39 +01001434 newsrv->observe = curproxy->defsrv.observe;
Willy Tarreau272adea2014-03-31 10:39:59 +02001435 newsrv->onerror = curproxy->defsrv.onerror;
1436 newsrv->onmarkeddown = curproxy->defsrv.onmarkeddown;
1437 newsrv->onmarkedup = curproxy->defsrv.onmarkedup;
Frédéric Lécaille67e0e612017-03-14 15:21:31 +01001438 if (curproxy->defsrv.trackit != NULL)
1439 newsrv->trackit = strdup(curproxy->defsrv.trackit);
Willy Tarreau272adea2014-03-31 10:39:59 +02001440 newsrv->consecutive_errors_limit
1441 = curproxy->defsrv.consecutive_errors_limit;
Willy Tarreau272adea2014-03-31 10:39:59 +02001442 newsrv->uweight = newsrv->iweight
1443 = curproxy->defsrv.iweight;
1444
1445 newsrv->check.status = HCHK_STATUS_INI;
Frédéric Lécaille25df8902017-03-10 14:04:31 +01001446 newsrv->check.send_proxy = curproxy->defsrv.check.send_proxy;
Willy Tarreau272adea2014-03-31 10:39:59 +02001447 newsrv->check.rise = curproxy->defsrv.check.rise;
1448 newsrv->check.fall = curproxy->defsrv.check.fall;
1449 newsrv->check.health = newsrv->check.rise; /* up, but will fall down at first failure */
1450 newsrv->check.server = newsrv;
Simon Hormane16c1b32015-01-30 11:22:57 +09001451 newsrv->check.tcpcheck_rules = &curproxy->tcpcheck_rules;
Willy Tarreau272adea2014-03-31 10:39:59 +02001452
1453 newsrv->agent.status = HCHK_STATUS_INI;
1454 newsrv->agent.rise = curproxy->defsrv.agent.rise;
1455 newsrv->agent.fall = curproxy->defsrv.agent.fall;
1456 newsrv->agent.health = newsrv->agent.rise; /* up, but will fall down at first failure */
1457 newsrv->agent.server = newsrv;
Thierry Fournierada34842016-02-17 21:25:09 +01001458 newsrv->dns_opts.family_prio = curproxy->defsrv.dns_opts.family_prio;
1459 if (newsrv->dns_opts.family_prio == AF_UNSPEC)
1460 newsrv->dns_opts.family_prio = AF_INET6;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001461 memcpy(newsrv->dns_opts.pref_net,
1462 curproxy->defsrv.dns_opts.pref_net,
1463 sizeof(newsrv->dns_opts.pref_net));
1464 newsrv->dns_opts.pref_net_nb = curproxy->defsrv.dns_opts.pref_net_nb;
Baptiste Assmann25938272016-09-21 20:26:16 +02001465 newsrv->init_addr_methods = curproxy->defsrv.init_addr_methods;
1466 newsrv->init_addr = curproxy->defsrv.init_addr;
Frédéric Lécaille7c8cd582017-03-13 13:41:16 +01001467#if defined(USE_OPENSSL)
1468 /* SSL config. */
Frédéric Lécaille5e576432017-03-14 15:52:04 +01001469 if (curproxy->defsrv.ssl_ctx.ca_file != NULL)
1470 newsrv->ssl_ctx.ca_file = strdup(curproxy->defsrv.ssl_ctx.ca_file);
1471 if (curproxy->defsrv.ssl_ctx.crl_file != NULL)
1472 newsrv->ssl_ctx.crl_file = strdup(curproxy->defsrv.ssl_ctx.crl_file);
1473 if (curproxy->defsrv.ssl_ctx.client_crt != NULL)
1474 newsrv->ssl_ctx.client_crt = strdup(curproxy->defsrv.ssl_ctx.crl_file);
Frédéric Lécaille7c8cd582017-03-13 13:41:16 +01001475 newsrv->ssl_ctx.verify = curproxy->defsrv.ssl_ctx.verify;
Frédéric Lécaille273f3212017-03-13 15:52:01 +01001476 if (curproxy->defsrv.ssl_ctx.verify_host != NULL)
1477 newsrv->ssl_ctx.verify_host = strdup(curproxy->defsrv.ssl_ctx.verify_host);
Frédéric Lécaillebcaf1d72017-03-15 16:20:02 +01001478 if (curproxy->defsrv.ssl_ctx.ciphers != NULL)
1479 newsrv->ssl_ctx.ciphers = strdup(curproxy->defsrv.ssl_ctx.ciphers);
Frédéric Lécaille7c8cd582017-03-13 13:41:16 +01001480#endif
Willy Tarreau272adea2014-03-31 10:39:59 +02001481
Frédéric Lécaille5c3cd972017-03-15 16:36:09 +01001482#ifdef TCP_USER_TIMEOUT
1483 newsrv->tcp_ut = curproxy->defsrv.tcp_ut;
1484#endif
1485
Willy Tarreau272adea2014-03-31 10:39:59 +02001486 cur_arg = 3;
1487 } else {
1488 newsrv = &curproxy->defsrv;
1489 cur_arg = 1;
Thierry Fournierada34842016-02-17 21:25:09 +01001490 newsrv->dns_opts.family_prio = AF_INET6;
Willy Tarreau272adea2014-03-31 10:39:59 +02001491 }
1492
1493 while (*args[cur_arg]) {
1494 if (!strcmp(args[cur_arg], "agent-check")) {
1495 global.maxsock++;
1496 do_agent = 1;
1497 cur_arg += 1;
1498 } else if (!strcmp(args[cur_arg], "agent-inter")) {
1499 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
1500 if (err) {
1501 Alert("parsing [%s:%d] : unexpected character '%c' in 'agent-inter' argument of server %s.\n",
1502 file, linenum, *err, newsrv->id);
1503 err_code |= ERR_ALERT | ERR_FATAL;
1504 goto out;
1505 }
1506 if (val <= 0) {
1507 Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n",
1508 file, linenum, val, args[cur_arg], newsrv->id);
1509 err_code |= ERR_ALERT | ERR_FATAL;
1510 goto out;
1511 }
1512 newsrv->agent.inter = val;
1513 cur_arg += 2;
1514 }
Misiekea849332017-01-09 09:39:51 +01001515 else if (!strcmp(args[cur_arg], "agent-addr")) {
1516 if(str2ip(args[cur_arg + 1], &newsrv->agent.addr) == NULL) {
1517 Alert("parsing agent-addr failed. Check if %s is correct address.\n", args[cur_arg + 1]);
1518 goto out;
1519 }
1520
1521 cur_arg += 2;
1522 }
Willy Tarreau272adea2014-03-31 10:39:59 +02001523 else if (!strcmp(args[cur_arg], "agent-port")) {
1524 global.maxsock++;
1525 newsrv->agent.port = atol(args[cur_arg + 1]);
1526 cur_arg += 2;
1527 }
James Brown55f9ff12015-10-21 18:19:05 -07001528 else if (!strcmp(args[cur_arg], "agent-send")) {
1529 global.maxsock++;
1530 free(newsrv->agent.send_string);
1531 newsrv->agent.send_string_len = strlen(args[cur_arg + 1]);
1532 newsrv->agent.send_string = calloc(1, newsrv->agent.send_string_len + 1);
1533 memcpy(newsrv->agent.send_string, args[cur_arg + 1], newsrv->agent.send_string_len);
1534 cur_arg += 2;
1535 }
Baptiste Assmann25938272016-09-21 20:26:16 +02001536 else if (!strcmp(args[cur_arg], "init-addr")) {
1537 char *p, *end;
1538 int done;
Willy Tarreau4310d362016-11-02 15:05:56 +01001539 struct sockaddr_storage sa;
Baptiste Assmann25938272016-09-21 20:26:16 +02001540
1541 newsrv->init_addr_methods = 0;
1542 memset(&newsrv->init_addr, 0, sizeof(newsrv->init_addr));
1543
1544 for (p = args[cur_arg + 1]; *p; p = end) {
1545 /* cut on next comma */
1546 for (end = p; *end && *end != ','; end++);
1547 if (*end)
1548 *(end++) = 0;
1549
Willy Tarreau4310d362016-11-02 15:05:56 +01001550 memset(&sa, 0, sizeof(sa));
Baptiste Assmann25938272016-09-21 20:26:16 +02001551 if (!strcmp(p, "libc")) {
1552 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_LIBC);
1553 }
1554 else if (!strcmp(p, "last")) {
1555 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_LAST);
1556 }
Willy Tarreau37ebe122016-11-04 15:17:58 +01001557 else if (!strcmp(p, "none")) {
1558 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_NONE);
1559 }
Willy Tarreau4310d362016-11-02 15:05:56 +01001560 else if (str2ip2(p, &sa, 0)) {
1561 if (is_addr(&newsrv->init_addr)) {
1562 Alert("parsing [%s:%d]: '%s' : initial address already specified, cannot add '%s'.\n",
1563 file, linenum, args[cur_arg], p);
1564 err_code |= ERR_ALERT | ERR_FATAL;
1565 goto out;
1566 }
1567 newsrv->init_addr = sa;
1568 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_IP);
1569 }
Baptiste Assmann25938272016-09-21 20:26:16 +02001570 else {
Willy Tarreau37ebe122016-11-04 15:17:58 +01001571 Alert("parsing [%s:%d]: '%s' : unknown init-addr method '%s', supported methods are 'libc', 'last', 'none'.\n",
Baptiste Assmann25938272016-09-21 20:26:16 +02001572 file, linenum, args[cur_arg], p);
1573 err_code |= ERR_ALERT | ERR_FATAL;
1574 goto out;
1575 }
1576 if (!done) {
1577 Alert("parsing [%s:%d]: '%s' : too many init-addr methods when trying to add '%s'\n",
1578 file, linenum, args[cur_arg], p);
1579 err_code |= ERR_ALERT | ERR_FATAL;
1580 goto out;
1581 }
1582 }
1583 cur_arg += 2;
1584 }
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001585 else if (!strcmp(args[cur_arg], "resolvers")) {
1586 newsrv->resolvers_id = strdup(args[cur_arg + 1]);
1587 cur_arg += 2;
1588 }
1589 else if (!strcmp(args[cur_arg], "resolve-prefer")) {
1590 if (!strcmp(args[cur_arg + 1], "ipv4"))
Thierry Fournierada34842016-02-17 21:25:09 +01001591 newsrv->dns_opts.family_prio = AF_INET;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001592 else if (!strcmp(args[cur_arg + 1], "ipv6"))
Thierry Fournierada34842016-02-17 21:25:09 +01001593 newsrv->dns_opts.family_prio = AF_INET6;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001594 else {
1595 Alert("parsing [%s:%d]: '%s' expects either ipv4 or ipv6 as argument.\n",
1596 file, linenum, args[cur_arg]);
1597 err_code |= ERR_ALERT | ERR_FATAL;
1598 goto out;
1599 }
1600 cur_arg += 2;
1601 }
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001602 else if (!strcmp(args[cur_arg], "resolve-net")) {
1603 char *p, *e;
1604 unsigned char mask;
1605 struct dns_options *opt;
1606
1607 if (!args[cur_arg + 1] || args[cur_arg + 1][0] == '\0') {
1608 Alert("parsing [%s:%d]: '%s' expects a list of networks.\n",
1609 file, linenum, args[cur_arg]);
1610 err_code |= ERR_ALERT | ERR_FATAL;
1611 goto out;
1612 }
1613
1614 opt = &newsrv->dns_opts;
1615
1616 /* Split arguments by comma, and convert it from ipv4 or ipv6
1617 * string network in in_addr or in6_addr.
1618 */
1619 p = args[cur_arg + 1];
1620 e = p;
1621 while (*p != '\0') {
1622 /* If no room avalaible, return error. */
David Carlierd10025c2016-04-08 10:26:44 +01001623 if (opt->pref_net_nb >= SRV_MAX_PREF_NET) {
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001624 Alert("parsing [%s:%d]: '%s' exceed %d networks.\n",
1625 file, linenum, args[cur_arg], SRV_MAX_PREF_NET);
1626 err_code |= ERR_ALERT | ERR_FATAL;
1627 goto out;
1628 }
1629 /* look for end or comma. */
1630 while (*e != ',' && *e != '\0')
1631 e++;
1632 if (*e == ',') {
1633 *e = '\0';
1634 e++;
1635 }
1636 if (str2net(p, 0, &opt->pref_net[opt->pref_net_nb].addr.in4,
1637 &opt->pref_net[opt->pref_net_nb].mask.in4)) {
1638 /* Try to convert input string from ipv4 or ipv6 network. */
1639 opt->pref_net[opt->pref_net_nb].family = AF_INET;
1640 } else if (str62net(p, &opt->pref_net[opt->pref_net_nb].addr.in6,
1641 &mask)) {
1642 /* Try to convert input string from ipv6 network. */
1643 len2mask6(mask, &opt->pref_net[opt->pref_net_nb].mask.in6);
1644 opt->pref_net[opt->pref_net_nb].family = AF_INET6;
1645 } else {
1646 /* All network conversions fail, retrun error. */
1647 Alert("parsing [%s:%d]: '%s': invalid network '%s'.\n",
1648 file, linenum, args[cur_arg], p);
1649 err_code |= ERR_ALERT | ERR_FATAL;
1650 goto out;
1651 }
1652 opt->pref_net_nb++;
1653 p = e;
1654 }
1655
1656 cur_arg += 2;
1657 }
Willy Tarreau272adea2014-03-31 10:39:59 +02001658 else if (!strcmp(args[cur_arg], "rise")) {
1659 if (!*args[cur_arg + 1]) {
1660 Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
1661 file, linenum, args[cur_arg]);
1662 err_code |= ERR_ALERT | ERR_FATAL;
1663 goto out;
1664 }
1665
1666 newsrv->check.rise = atol(args[cur_arg + 1]);
1667 if (newsrv->check.rise <= 0) {
1668 Alert("parsing [%s:%d]: '%s' has to be > 0.\n",
1669 file, linenum, args[cur_arg]);
1670 err_code |= ERR_ALERT | ERR_FATAL;
1671 goto out;
1672 }
1673
1674 if (newsrv->check.health)
1675 newsrv->check.health = newsrv->check.rise;
1676 cur_arg += 2;
1677 }
1678 else if (!strcmp(args[cur_arg], "fall")) {
1679 newsrv->check.fall = atol(args[cur_arg + 1]);
1680
1681 if (!*args[cur_arg + 1]) {
1682 Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
1683 file, linenum, args[cur_arg]);
1684 err_code |= ERR_ALERT | ERR_FATAL;
1685 goto out;
1686 }
1687
1688 if (newsrv->check.fall <= 0) {
1689 Alert("parsing [%s:%d]: '%s' has to be > 0.\n",
1690 file, linenum, args[cur_arg]);
1691 err_code |= ERR_ALERT | ERR_FATAL;
1692 goto out;
1693 }
1694
1695 cur_arg += 2;
1696 }
1697 else if (!strcmp(args[cur_arg], "inter")) {
1698 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
1699 if (err) {
1700 Alert("parsing [%s:%d] : unexpected character '%c' in 'inter' argument of server %s.\n",
1701 file, linenum, *err, newsrv->id);
1702 err_code |= ERR_ALERT | ERR_FATAL;
1703 goto out;
1704 }
1705 if (val <= 0) {
1706 Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n",
1707 file, linenum, val, args[cur_arg], newsrv->id);
1708 err_code |= ERR_ALERT | ERR_FATAL;
1709 goto out;
1710 }
1711 newsrv->check.inter = val;
1712 cur_arg += 2;
1713 }
1714 else if (!strcmp(args[cur_arg], "fastinter")) {
1715 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
1716 if (err) {
1717 Alert("parsing [%s:%d]: unexpected character '%c' in 'fastinter' argument of server %s.\n",
1718 file, linenum, *err, newsrv->id);
1719 err_code |= ERR_ALERT | ERR_FATAL;
1720 goto out;
1721 }
1722 if (val <= 0) {
1723 Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n",
1724 file, linenum, val, args[cur_arg], newsrv->id);
1725 err_code |= ERR_ALERT | ERR_FATAL;
1726 goto out;
1727 }
1728 newsrv->check.fastinter = val;
1729 cur_arg += 2;
1730 }
1731 else if (!strcmp(args[cur_arg], "downinter")) {
1732 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
1733 if (err) {
1734 Alert("parsing [%s:%d]: unexpected character '%c' in 'downinter' argument of server %s.\n",
1735 file, linenum, *err, newsrv->id);
1736 err_code |= ERR_ALERT | ERR_FATAL;
1737 goto out;
1738 }
1739 if (val <= 0) {
1740 Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n",
1741 file, linenum, val, args[cur_arg], newsrv->id);
1742 err_code |= ERR_ALERT | ERR_FATAL;
1743 goto out;
1744 }
1745 newsrv->check.downinter = val;
1746 cur_arg += 2;
1747 }
1748 else if (!defsrv && !strcmp(args[cur_arg], "addr")) {
1749 struct sockaddr_storage *sk;
1750 int port1, port2;
1751 struct protocol *proto;
1752
Willy Tarreau48ef4c92017-01-06 18:32:38 +01001753 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
Willy Tarreau272adea2014-03-31 10:39:59 +02001754 if (!sk) {
1755 Alert("parsing [%s:%d] : '%s' : %s\n",
1756 file, linenum, args[cur_arg], errmsg);
1757 err_code |= ERR_ALERT | ERR_FATAL;
1758 goto out;
1759 }
1760
1761 proto = protocol_by_family(sk->ss_family);
1762 if (!proto || !proto->connect) {
1763 Alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
1764 file, linenum, args[cur_arg], args[cur_arg + 1]);
1765 err_code |= ERR_ALERT | ERR_FATAL;
1766 goto out;
1767 }
1768
1769 if (port1 != port2) {
1770 Alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
1771 file, linenum, args[cur_arg], args[cur_arg + 1]);
1772 err_code |= ERR_ALERT | ERR_FATAL;
1773 goto out;
1774 }
1775
Simon Horman41f58762015-01-30 11:22:56 +09001776 newsrv->check.addr = newsrv->agent.addr = *sk;
Baptiste Assmann6b453f12016-08-11 23:12:18 +02001777 newsrv->flags |= SRV_F_CHECKADDR;
1778 newsrv->flags |= SRV_F_AGENTADDR;
Willy Tarreau272adea2014-03-31 10:39:59 +02001779 cur_arg += 2;
1780 }
1781 else if (!strcmp(args[cur_arg], "port")) {
1782 newsrv->check.port = atol(args[cur_arg + 1]);
Baptiste Assmann6b453f12016-08-11 23:12:18 +02001783 newsrv->flags |= SRV_F_CHECKPORT;
Willy Tarreau272adea2014-03-31 10:39:59 +02001784 cur_arg += 2;
1785 }
Willy Tarreau272adea2014-03-31 10:39:59 +02001786 else if (!strcmp(args[cur_arg], "weight")) {
1787 int w;
1788 w = atol(args[cur_arg + 1]);
1789 if (w < 0 || w > SRV_UWGHT_MAX) {
1790 Alert("parsing [%s:%d] : weight of server %s is not within 0 and %d (%d).\n",
1791 file, linenum, newsrv->id, SRV_UWGHT_MAX, w);
1792 err_code |= ERR_ALERT | ERR_FATAL;
1793 goto out;
1794 }
1795 newsrv->uweight = newsrv->iweight = w;
1796 cur_arg += 2;
1797 }
1798 else if (!strcmp(args[cur_arg], "minconn")) {
1799 newsrv->minconn = atol(args[cur_arg + 1]);
1800 cur_arg += 2;
1801 }
1802 else if (!strcmp(args[cur_arg], "maxconn")) {
1803 newsrv->maxconn = atol(args[cur_arg + 1]);
1804 cur_arg += 2;
1805 }
1806 else if (!strcmp(args[cur_arg], "maxqueue")) {
1807 newsrv->maxqueue = atol(args[cur_arg + 1]);
1808 cur_arg += 2;
1809 }
1810 else if (!strcmp(args[cur_arg], "slowstart")) {
1811 /* slowstart is stored in seconds */
1812 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
1813 if (err) {
1814 Alert("parsing [%s:%d] : unexpected character '%c' in 'slowstart' argument of server %s.\n",
1815 file, linenum, *err, newsrv->id);
1816 err_code |= ERR_ALERT | ERR_FATAL;
1817 goto out;
1818 }
1819 newsrv->slowstart = (val + 999) / 1000;
1820 cur_arg += 2;
1821 }
Willy Tarreau272adea2014-03-31 10:39:59 +02001822 else if (!defsrv && !strcmp(args[cur_arg], "disabled")) {
Baptiste Assmann9f5ada32015-08-08 15:49:13 +02001823 newsrv->admin |= SRV_ADMF_CMAINT;
Baptiste Assmann54a47302015-09-18 10:30:03 +02001824 newsrv->admin |= SRV_ADMF_FMAINT;
Willy Tarreau892337c2014-05-13 23:41:20 +02001825 newsrv->state = SRV_ST_STOPPED;
Willy Tarreau272adea2014-03-31 10:39:59 +02001826 newsrv->check.state |= CHK_ST_PAUSED;
1827 newsrv->check.health = 0;
Willy Tarreau272adea2014-03-31 10:39:59 +02001828 cur_arg += 1;
1829 }
Willy Tarreau272adea2014-03-31 10:39:59 +02001830 else if (!strcmp(args[cur_arg], "on-error")) {
1831 if (!strcmp(args[cur_arg + 1], "fastinter"))
1832 newsrv->onerror = HANA_ONERR_FASTINTER;
1833 else if (!strcmp(args[cur_arg + 1], "fail-check"))
1834 newsrv->onerror = HANA_ONERR_FAILCHK;
1835 else if (!strcmp(args[cur_arg + 1], "sudden-death"))
1836 newsrv->onerror = HANA_ONERR_SUDDTH;
1837 else if (!strcmp(args[cur_arg + 1], "mark-down"))
1838 newsrv->onerror = HANA_ONERR_MARKDWN;
1839 else {
1840 Alert("parsing [%s:%d]: '%s' expects one of 'fastinter', "
1841 "'fail-check', 'sudden-death' or 'mark-down' but got '%s'\n",
1842 file, linenum, args[cur_arg], args[cur_arg + 1]);
1843 err_code |= ERR_ALERT | ERR_FATAL;
1844 goto out;
1845 }
1846
1847 cur_arg += 2;
1848 }
1849 else if (!strcmp(args[cur_arg], "on-marked-down")) {
1850 if (!strcmp(args[cur_arg + 1], "shutdown-sessions"))
1851 newsrv->onmarkeddown = HANA_ONMARKEDDOWN_SHUTDOWNSESSIONS;
1852 else {
1853 Alert("parsing [%s:%d]: '%s' expects 'shutdown-sessions' but got '%s'\n",
1854 file, linenum, args[cur_arg], args[cur_arg + 1]);
1855 err_code |= ERR_ALERT | ERR_FATAL;
1856 goto out;
1857 }
1858
1859 cur_arg += 2;
1860 }
1861 else if (!strcmp(args[cur_arg], "on-marked-up")) {
1862 if (!strcmp(args[cur_arg + 1], "shutdown-backup-sessions"))
1863 newsrv->onmarkedup = HANA_ONMARKEDUP_SHUTDOWNBACKUPSESSIONS;
1864 else {
1865 Alert("parsing [%s:%d]: '%s' expects 'shutdown-backup-sessions' but got '%s'\n",
1866 file, linenum, args[cur_arg], args[cur_arg + 1]);
1867 err_code |= ERR_ALERT | ERR_FATAL;
1868 goto out;
1869 }
1870
1871 cur_arg += 2;
1872 }
1873 else if (!strcmp(args[cur_arg], "error-limit")) {
1874 if (!*args[cur_arg + 1]) {
1875 Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
1876 file, linenum, args[cur_arg]);
1877 err_code |= ERR_ALERT | ERR_FATAL;
1878 goto out;
1879 }
1880
1881 newsrv->consecutive_errors_limit = atoi(args[cur_arg + 1]);
1882
1883 if (newsrv->consecutive_errors_limit <= 0) {
1884 Alert("parsing [%s:%d]: %s has to be > 0.\n",
1885 file, linenum, args[cur_arg]);
1886 err_code |= ERR_ALERT | ERR_FATAL;
1887 goto out;
1888 }
1889 cur_arg += 2;
1890 }
1891 else if (!defsrv && !strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */
1892 int port_low, port_high;
1893 struct sockaddr_storage *sk;
1894 struct protocol *proto;
1895
1896 if (!*args[cur_arg + 1]) {
1897 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>[-<port>]], and optionally '%s' <addr>, and '%s' <name> as argument.\n",
1898 file, linenum, "source", "usesrc", "interface");
1899 err_code |= ERR_ALERT | ERR_FATAL;
1900 goto out;
1901 }
1902
1903 newsrv->conn_src.opts |= CO_SRC_BIND;
Willy Tarreau48ef4c92017-01-06 18:32:38 +01001904 sk = str2sa_range(args[cur_arg + 1], NULL, &port_low, &port_high, &errmsg, NULL, NULL, 1);
Willy Tarreau272adea2014-03-31 10:39:59 +02001905 if (!sk) {
1906 Alert("parsing [%s:%d] : '%s %s' : %s\n",
1907 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
1908 err_code |= ERR_ALERT | ERR_FATAL;
1909 goto out;
1910 }
1911
1912 proto = protocol_by_family(sk->ss_family);
1913 if (!proto || !proto->connect) {
1914 Alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
1915 file, linenum, args[cur_arg], args[cur_arg+1]);
1916 err_code |= ERR_ALERT | ERR_FATAL;
1917 goto out;
1918 }
1919
1920 newsrv->conn_src.source_addr = *sk;
1921
1922 if (port_low != port_high) {
1923 int i;
1924
1925 if (!port_low || !port_high) {
1926 Alert("parsing [%s:%d] : %s does not support port offsets (found '%s').\n",
1927 file, linenum, args[cur_arg], args[cur_arg + 1]);
1928 err_code |= ERR_ALERT | ERR_FATAL;
1929 goto out;
1930 }
1931
1932 if (port_low <= 0 || port_low > 65535 ||
1933 port_high <= 0 || port_high > 65535 ||
1934 port_low > port_high) {
1935 Alert("parsing [%s:%d] : invalid source port range %d-%d.\n",
1936 file, linenum, port_low, port_high);
1937 err_code |= ERR_ALERT | ERR_FATAL;
1938 goto out;
1939 }
1940 newsrv->conn_src.sport_range = port_range_alloc_range(port_high - port_low + 1);
1941 for (i = 0; i < newsrv->conn_src.sport_range->size; i++)
1942 newsrv->conn_src.sport_range->ports[i] = port_low + i;
1943 }
1944
1945 cur_arg += 2;
1946 while (*(args[cur_arg])) {
1947 if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */
Willy Tarreau29fbe512015-08-20 19:35:14 +02001948#if defined(CONFIG_HAP_TRANSPARENT)
Willy Tarreau272adea2014-03-31 10:39:59 +02001949 if (!*args[cur_arg + 1]) {
1950 Alert("parsing [%s:%d] : '%s' expects <addr>[:<port>], 'client', 'clientip', or 'hdr_ip(name,#)' as argument.\n",
1951 file, linenum, "usesrc");
1952 err_code |= ERR_ALERT | ERR_FATAL;
1953 goto out;
1954 }
1955 if (!strcmp(args[cur_arg + 1], "client")) {
1956 newsrv->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
1957 newsrv->conn_src.opts |= CO_SRC_TPROXY_CLI;
1958 } else if (!strcmp(args[cur_arg + 1], "clientip")) {
1959 newsrv->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
1960 newsrv->conn_src.opts |= CO_SRC_TPROXY_CIP;
1961 } else if (!strncmp(args[cur_arg + 1], "hdr_ip(", 7)) {
1962 char *name, *end;
1963
1964 name = args[cur_arg+1] + 7;
1965 while (isspace(*name))
1966 name++;
1967
1968 end = name;
1969 while (*end && !isspace(*end) && *end != ',' && *end != ')')
1970 end++;
1971
1972 newsrv->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
1973 newsrv->conn_src.opts |= CO_SRC_TPROXY_DYN;
1974 newsrv->conn_src.bind_hdr_name = calloc(1, end - name + 1);
1975 newsrv->conn_src.bind_hdr_len = end - name;
1976 memcpy(newsrv->conn_src.bind_hdr_name, name, end - name);
1977 newsrv->conn_src.bind_hdr_name[end-name] = '\0';
1978 newsrv->conn_src.bind_hdr_occ = -1;
1979
1980 /* now look for an occurrence number */
1981 while (isspace(*end))
1982 end++;
1983 if (*end == ',') {
1984 end++;
1985 name = end;
1986 if (*end == '-')
1987 end++;
1988 while (isdigit((int)*end))
1989 end++;
1990 newsrv->conn_src.bind_hdr_occ = strl2ic(name, end-name);
1991 }
1992
1993 if (newsrv->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
1994 Alert("parsing [%s:%d] : usesrc hdr_ip(name,num) does not support negative"
1995 " occurrences values smaller than %d.\n",
1996 file, linenum, MAX_HDR_HISTORY);
1997 err_code |= ERR_ALERT | ERR_FATAL;
1998 goto out;
1999 }
2000 } else {
2001 struct sockaddr_storage *sk;
2002 int port1, port2;
2003
Willy Tarreau48ef4c92017-01-06 18:32:38 +01002004 sk = str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
Willy Tarreau272adea2014-03-31 10:39:59 +02002005 if (!sk) {
2006 Alert("parsing [%s:%d] : '%s %s' : %s\n",
2007 file, linenum, args[cur_arg], args[cur_arg+1], errmsg);
2008 err_code |= ERR_ALERT | ERR_FATAL;
2009 goto out;
2010 }
2011
2012 proto = protocol_by_family(sk->ss_family);
2013 if (!proto || !proto->connect) {
2014 Alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
2015 file, linenum, args[cur_arg], args[cur_arg+1]);
2016 err_code |= ERR_ALERT | ERR_FATAL;
2017 goto out;
2018 }
2019
2020 if (port1 != port2) {
2021 Alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n",
2022 file, linenum, args[cur_arg], args[cur_arg + 1]);
2023 err_code |= ERR_ALERT | ERR_FATAL;
2024 goto out;
2025 }
2026 newsrv->conn_src.tproxy_addr = *sk;
2027 newsrv->conn_src.opts |= CO_SRC_TPROXY_ADDR;
2028 }
2029 global.last_checks |= LSTCHK_NETADM;
Willy Tarreau272adea2014-03-31 10:39:59 +02002030 cur_arg += 2;
2031 continue;
2032#else /* no TPROXY support */
2033 Alert("parsing [%s:%d] : '%s' not allowed here because support for TPROXY was not compiled in.\n",
2034 file, linenum, "usesrc");
2035 err_code |= ERR_ALERT | ERR_FATAL;
2036 goto out;
Willy Tarreau29fbe512015-08-20 19:35:14 +02002037#endif /* defined(CONFIG_HAP_TRANSPARENT) */
Willy Tarreau272adea2014-03-31 10:39:59 +02002038 } /* "usesrc" */
2039
2040 if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */
2041#ifdef SO_BINDTODEVICE
2042 if (!*args[cur_arg + 1]) {
2043 Alert("parsing [%s:%d] : '%s' : missing interface name.\n",
2044 file, linenum, args[0]);
2045 err_code |= ERR_ALERT | ERR_FATAL;
2046 goto out;
2047 }
2048 free(newsrv->conn_src.iface_name);
2049 newsrv->conn_src.iface_name = strdup(args[cur_arg + 1]);
2050 newsrv->conn_src.iface_len = strlen(newsrv->conn_src.iface_name);
2051 global.last_checks |= LSTCHK_NETADM;
2052#else
2053 Alert("parsing [%s:%d] : '%s' : '%s' option not implemented.\n",
2054 file, linenum, args[0], args[cur_arg]);
2055 err_code |= ERR_ALERT | ERR_FATAL;
2056 goto out;
2057#endif
2058 cur_arg += 2;
2059 continue;
2060 }
2061 /* this keyword in not an option of "source" */
2062 break;
2063 } /* while */
2064 }
2065 else if (!defsrv && !strcmp(args[cur_arg], "usesrc")) { /* address to use outside: needs "source" first */
2066 Alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
2067 file, linenum, "usesrc", "source");
2068 err_code |= ERR_ALERT | ERR_FATAL;
2069 goto out;
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002070 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002071 else {
2072 static int srv_dumped;
2073 struct srv_kw *kw;
2074 char *err;
2075
2076 kw = srv_find_kw(args[cur_arg]);
2077 if (kw) {
2078 char *err = NULL;
2079 int code;
2080
2081 if (!kw->parse) {
2082 Alert("parsing [%s:%d] : '%s %s' : '%s' option is not implemented in this version (check build options).\n",
2083 file, linenum, args[0], args[1], args[cur_arg]);
2084 cur_arg += 1 + kw->skip ;
2085 err_code |= ERR_ALERT | ERR_FATAL;
2086 goto out;
2087 }
2088
2089 if (defsrv && !kw->default_ok) {
2090 Alert("parsing [%s:%d] : '%s %s' : '%s' option is not accepted in default-server sections.\n",
2091 file, linenum, args[0], args[1], args[cur_arg]);
2092 cur_arg += 1 + kw->skip ;
2093 err_code |= ERR_ALERT;
2094 continue;
2095 }
2096
2097 code = kw->parse(args, &cur_arg, curproxy, newsrv, &err);
2098 err_code |= code;
2099
2100 if (code) {
2101 if (err && *err) {
2102 indent_msg(&err, 2);
2103 Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], err);
2104 }
2105 else
2106 Alert("parsing [%s:%d] : '%s %s' : error encountered while processing '%s'.\n",
2107 file, linenum, args[0], args[1], args[cur_arg]);
2108 if (code & ERR_FATAL) {
2109 free(err);
2110 cur_arg += 1 + kw->skip;
2111 goto out;
2112 }
2113 }
2114 free(err);
2115 cur_arg += 1 + kw->skip;
2116 continue;
2117 }
2118
2119 err = NULL;
2120 if (!srv_dumped) {
2121 srv_dump_kws(&err);
2122 indent_msg(&err, 4);
2123 srv_dumped = 1;
2124 }
2125
2126 Alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'.%s%s\n",
2127 file, linenum, args[0], args[1], args[cur_arg],
2128 err ? " Registered keywords :" : "", err ? err : "");
2129 free(err);
2130
2131 err_code |= ERR_ALERT | ERR_FATAL;
2132 goto out;
2133 }
2134 }
2135
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01002136 /* This check is done only for 'server' instances. */
2137 if (!defsrv && newsrv->do_check) {
Simon Hormanb1900d52015-01-30 11:22:54 +09002138 const char *ret;
Willy Tarreau272adea2014-03-31 10:39:59 +02002139
2140 if (newsrv->trackit) {
2141 Alert("parsing [%s:%d]: unable to enable checks and tracking at the same time!\n",
2142 file, linenum);
2143 err_code |= ERR_ALERT | ERR_FATAL;
2144 goto out;
2145 }
2146
Willy Tarreau272adea2014-03-31 10:39:59 +02002147 /*
2148 * We need at least a service port, a check port or the first tcp-check rule must
Willy Tarreau5cf0b522014-05-09 23:59:19 +02002149 * be a 'connect' one when checking an IPv4/IPv6 server.
Willy Tarreau272adea2014-03-31 10:39:59 +02002150 */
Baptiste Assmann95db2bc2016-06-13 14:15:41 +02002151 if ((srv_check_healthcheck_port(&newsrv->check) == 0) &&
Simon Horman41f58762015-01-30 11:22:56 +09002152 (is_inet_addr(&newsrv->check.addr) ||
2153 (!is_addr(&newsrv->check.addr) && is_inet_addr(&newsrv->addr)))) {
Willy Tarreau1a786d72016-03-08 15:20:25 +01002154 struct tcpcheck_rule *r = NULL;
Willy Tarreau272adea2014-03-31 10:39:59 +02002155 struct list *l;
2156
2157 r = (struct tcpcheck_rule *)newsrv->proxy->tcpcheck_rules.n;
2158 if (!r) {
2159 Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
2160 file, linenum, newsrv->id);
2161 err_code |= ERR_ALERT | ERR_FATAL;
2162 goto out;
2163 }
Baptiste Assmannbaf97942015-12-04 06:49:31 +01002164 /* search the first action (connect / send / expect) in the list */
2165 l = &newsrv->proxy->tcpcheck_rules;
Willy Tarreau1a786d72016-03-08 15:20:25 +01002166 list_for_each_entry(r, l, list) {
Baptiste Assmannbaf97942015-12-04 06:49:31 +01002167 if (r->action != TCPCHK_ACT_COMMENT)
2168 break;
2169 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002170 if ((r->action != TCPCHK_ACT_CONNECT) || !r->port) {
2171 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",
2172 file, linenum, newsrv->id);
2173 err_code |= ERR_ALERT | ERR_FATAL;
2174 goto out;
2175 }
2176 else {
2177 /* scan the tcp-check ruleset to ensure a port has been configured */
2178 l = &newsrv->proxy->tcpcheck_rules;
Willy Tarreau1a786d72016-03-08 15:20:25 +01002179 list_for_each_entry(r, l, list) {
Willy Tarreau272adea2014-03-31 10:39:59 +02002180 if ((r->action == TCPCHK_ACT_CONNECT) && (!r->port)) {
2181 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",
2182 file, linenum, newsrv->id);
2183 err_code |= ERR_ALERT | ERR_FATAL;
2184 goto out;
2185 }
2186 }
2187 }
2188 }
2189
2190 /* note: check type will be set during the config review phase */
Simon Hormanb1900d52015-01-30 11:22:54 +09002191 ret = init_check(&newsrv->check, 0);
Willy Tarreau272adea2014-03-31 10:39:59 +02002192 if (ret) {
Simon Hormanb1900d52015-01-30 11:22:54 +09002193 Alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
2194 err_code |= ERR_ALERT | ERR_ABORT;
Willy Tarreau272adea2014-03-31 10:39:59 +02002195 goto out;
2196 }
2197
Baptiste Assmanna68ca962015-04-14 01:15:08 +02002198 if (newsrv->resolution)
Thierry Fournierada34842016-02-17 21:25:09 +01002199 newsrv->resolution->opts = &newsrv->dns_opts;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02002200
Willy Tarreau272adea2014-03-31 10:39:59 +02002201 newsrv->check.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED;
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01002202 global.maxsock++;
Willy Tarreau272adea2014-03-31 10:39:59 +02002203 }
2204
2205 if (do_agent) {
Simon Hormanb1900d52015-01-30 11:22:54 +09002206 const char *ret;
Willy Tarreau272adea2014-03-31 10:39:59 +02002207
2208 if (!newsrv->agent.port) {
2209 Alert("parsing [%s:%d] : server %s does not have agent port. Agent check has been disabled.\n",
2210 file, linenum, newsrv->id);
2211 err_code |= ERR_ALERT | ERR_FATAL;
2212 goto out;
2213 }
2214
2215 if (!newsrv->agent.inter)
2216 newsrv->agent.inter = newsrv->check.inter;
2217
Simon Hormanb1900d52015-01-30 11:22:54 +09002218 ret = init_check(&newsrv->agent, PR_O2_LB_AGENT_CHK);
Willy Tarreau272adea2014-03-31 10:39:59 +02002219 if (ret) {
Simon Hormanb1900d52015-01-30 11:22:54 +09002220 Alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
2221 err_code |= ERR_ALERT | ERR_ABORT;
Willy Tarreau272adea2014-03-31 10:39:59 +02002222 goto out;
2223 }
2224
2225 newsrv->agent.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_AGENT;
2226 }
2227
2228 if (!defsrv) {
Willy Tarreauc93cd162014-05-13 15:54:22 +02002229 if (newsrv->flags & SRV_F_BACKUP)
Willy Tarreau272adea2014-03-31 10:39:59 +02002230 curproxy->srv_bck++;
2231 else
2232 curproxy->srv_act++;
2233
Willy Tarreauc5150da2014-05-13 19:27:31 +02002234 srv_lb_commit_status(newsrv);
Willy Tarreau272adea2014-03-31 10:39:59 +02002235 }
2236 }
Willy Tarreau07101d52015-09-08 16:16:35 +02002237 free(fqdn);
Willy Tarreau272adea2014-03-31 10:39:59 +02002238 return 0;
2239
2240 out:
Willy Tarreau07101d52015-09-08 16:16:35 +02002241 free(fqdn);
Willy Tarreau272adea2014-03-31 10:39:59 +02002242 free(errmsg);
2243 return err_code;
2244}
2245
Baptiste Assmann19a106d2015-07-08 22:03:56 +02002246/* Returns a pointer to the first server matching either id <id>.
2247 * NULL is returned if no match is found.
2248 * the lookup is performed in the backend <bk>
2249 */
2250struct server *server_find_by_id(struct proxy *bk, int id)
2251{
2252 struct eb32_node *eb32;
2253 struct server *curserver;
2254
2255 if (!bk || (id ==0))
2256 return NULL;
2257
2258 /* <bk> has no backend capabilities, so it can't have a server */
2259 if (!(bk->cap & PR_CAP_BE))
2260 return NULL;
2261
2262 curserver = NULL;
2263
2264 eb32 = eb32_lookup(&bk->conf.used_server_id, id);
2265 if (eb32)
2266 curserver = container_of(eb32, struct server, conf.id);
2267
2268 return curserver;
2269}
2270
2271/* Returns a pointer to the first server matching either name <name>, or id
2272 * if <name> starts with a '#'. NULL is returned if no match is found.
2273 * the lookup is performed in the backend <bk>
2274 */
2275struct server *server_find_by_name(struct proxy *bk, const char *name)
2276{
2277 struct server *curserver;
2278
2279 if (!bk || !name)
2280 return NULL;
2281
2282 /* <bk> has no backend capabilities, so it can't have a server */
2283 if (!(bk->cap & PR_CAP_BE))
2284 return NULL;
2285
2286 curserver = NULL;
2287 if (*name == '#') {
2288 curserver = server_find_by_id(bk, atoi(name + 1));
2289 if (curserver)
2290 return curserver;
2291 }
2292 else {
2293 curserver = bk->srv;
2294
2295 while (curserver && (strcmp(curserver->id, name) != 0))
2296 curserver = curserver->next;
2297
2298 if (curserver)
2299 return curserver;
2300 }
2301
2302 return NULL;
2303}
2304
2305struct server *server_find_best_match(struct proxy *bk, char *name, int id, int *diff)
2306{
2307 struct server *byname;
2308 struct server *byid;
2309
2310 if (!name && !id)
2311 return NULL;
2312
2313 if (diff)
2314 *diff = 0;
2315
2316 byname = byid = NULL;
2317
2318 if (name) {
2319 byname = server_find_by_name(bk, name);
2320 if (byname && (!id || byname->puid == id))
2321 return byname;
2322 }
2323
2324 /* remaining possibilities :
2325 * - name not set
2326 * - name set but not found
2327 * - name found but ID doesn't match
2328 */
2329 if (id) {
2330 byid = server_find_by_id(bk, id);
2331 if (byid) {
2332 if (byname) {
2333 /* use id only if forced by configuration */
2334 if (byid->flags & SRV_F_FORCED_ID) {
2335 if (diff)
2336 *diff |= 2;
2337 return byid;
2338 }
2339 else {
2340 if (diff)
2341 *diff |= 1;
2342 return byname;
2343 }
2344 }
2345
2346 /* remaining possibilities:
2347 * - name not set
2348 * - name set but not found
2349 */
2350 if (name && diff)
2351 *diff |= 2;
2352 return byid;
2353 }
2354
2355 /* id bot found */
2356 if (byname) {
2357 if (diff)
2358 *diff |= 1;
2359 return byname;
2360 }
2361 }
2362
2363 return NULL;
2364}
2365
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002366/* Update a server state using the parameters available in the params list */
2367static void srv_update_state(struct server *srv, int version, char **params)
2368{
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002369 char *p;
Willy Tarreau31138fa2015-09-29 18:38:47 +02002370 struct chunk *msg;
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002371
2372 /* fields since version 1
2373 * and common to all other upcoming versions
2374 */
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002375 enum srv_state srv_op_state;
2376 enum srv_admin srv_admin_state;
2377 unsigned srv_uweight, srv_iweight;
2378 unsigned long srv_last_time_change;
2379 short srv_check_status;
2380 enum chk_result srv_check_result;
2381 int srv_check_health;
2382 int srv_check_state, srv_agent_state;
2383 int bk_f_forced_id;
2384 int srv_f_forced_id;
2385
Willy Tarreau31138fa2015-09-29 18:38:47 +02002386 msg = get_trash_chunk();
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002387 switch (version) {
2388 case 1:
2389 /*
2390 * now we can proceed with server's state update:
2391 * srv_addr: params[0]
2392 * srv_op_state: params[1]
2393 * srv_admin_state: params[2]
2394 * srv_uweight: params[3]
2395 * srv_iweight: params[4]
2396 * srv_last_time_change: params[5]
2397 * srv_check_status: params[6]
2398 * srv_check_result: params[7]
2399 * srv_check_health: params[8]
2400 * srv_check_state: params[9]
2401 * srv_agent_state: params[10]
2402 * bk_f_forced_id: params[11]
2403 * srv_f_forced_id: params[12]
2404 */
2405
2406 /* validating srv_op_state */
2407 p = NULL;
2408 errno = 0;
2409 srv_op_state = strtol(params[1], &p, 10);
2410 if ((p == params[1]) || errno == EINVAL || errno == ERANGE ||
2411 (srv_op_state != SRV_ST_STOPPED &&
2412 srv_op_state != SRV_ST_STARTING &&
2413 srv_op_state != SRV_ST_RUNNING &&
2414 srv_op_state != SRV_ST_STOPPING)) {
2415 chunk_appendf(msg, ", invalid srv_op_state value '%s'", params[1]);
2416 }
2417
2418 /* validating srv_admin_state */
2419 p = NULL;
2420 errno = 0;
2421 srv_admin_state = strtol(params[2], &p, 10);
Willy Tarreau757478e2016-11-03 19:22:19 +01002422
2423 /* inherited statuses will be recomputed later */
2424 srv_admin_state &= ~SRV_ADMF_IDRAIN & ~SRV_ADMF_IMAINT;
2425
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002426 if ((p == params[2]) || errno == EINVAL || errno == ERANGE ||
2427 (srv_admin_state != 0 &&
2428 srv_admin_state != SRV_ADMF_FMAINT &&
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002429 srv_admin_state != SRV_ADMF_CMAINT &&
2430 srv_admin_state != (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT) &&
Willy Tarreaue1bde142016-11-03 18:33:25 +01002431 srv_admin_state != (SRV_ADMF_CMAINT | SRV_ADMF_FDRAIN) &&
Willy Tarreau757478e2016-11-03 19:22:19 +01002432 srv_admin_state != SRV_ADMF_FDRAIN)) {
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002433 chunk_appendf(msg, ", invalid srv_admin_state value '%s'", params[2]);
2434 }
2435
2436 /* validating srv_uweight */
2437 p = NULL;
2438 errno = 0;
2439 srv_uweight = strtol(params[3], &p, 10);
Willy Tarreaue1aebb22015-09-29 18:32:57 +02002440 if ((p == params[3]) || errno == EINVAL || errno == ERANGE || (srv_uweight > SRV_UWGHT_MAX))
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002441 chunk_appendf(msg, ", invalid srv_uweight value '%s'", params[3]);
2442
2443 /* validating srv_iweight */
2444 p = NULL;
2445 errno = 0;
2446 srv_iweight = strtol(params[4], &p, 10);
Willy Tarreaue1aebb22015-09-29 18:32:57 +02002447 if ((p == params[4]) || errno == EINVAL || errno == ERANGE || (srv_iweight > SRV_UWGHT_MAX))
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002448 chunk_appendf(msg, ", invalid srv_iweight value '%s'", params[4]);
2449
2450 /* validating srv_last_time_change */
2451 p = NULL;
2452 errno = 0;
2453 srv_last_time_change = strtol(params[5], &p, 10);
2454 if ((p == params[5]) || errno == EINVAL || errno == ERANGE)
2455 chunk_appendf(msg, ", invalid srv_last_time_change value '%s'", params[5]);
2456
2457 /* validating srv_check_status */
2458 p = NULL;
2459 errno = 0;
2460 srv_check_status = strtol(params[6], &p, 10);
2461 if (p == params[6] || errno == EINVAL || errno == ERANGE ||
2462 (srv_check_status >= HCHK_STATUS_SIZE))
2463 chunk_appendf(msg, ", invalid srv_check_status value '%s'", params[6]);
2464
2465 /* validating srv_check_result */
2466 p = NULL;
2467 errno = 0;
2468 srv_check_result = strtol(params[7], &p, 10);
2469 if ((p == params[7]) || errno == EINVAL || errno == ERANGE ||
2470 (srv_check_result != CHK_RES_UNKNOWN &&
2471 srv_check_result != CHK_RES_NEUTRAL &&
2472 srv_check_result != CHK_RES_FAILED &&
2473 srv_check_result != CHK_RES_PASSED &&
2474 srv_check_result != CHK_RES_CONDPASS)) {
2475 chunk_appendf(msg, ", invalid srv_check_result value '%s'", params[7]);
2476 }
2477
2478 /* validating srv_check_health */
2479 p = NULL;
2480 errno = 0;
2481 srv_check_health = strtol(params[8], &p, 10);
2482 if (p == params[8] || errno == EINVAL || errno == ERANGE)
2483 chunk_appendf(msg, ", invalid srv_check_health value '%s'", params[8]);
2484
2485 /* validating srv_check_state */
2486 p = NULL;
2487 errno = 0;
2488 srv_check_state = strtol(params[9], &p, 10);
2489 if (p == params[9] || errno == EINVAL || errno == ERANGE ||
2490 (srv_check_state & ~(CHK_ST_INPROGRESS | CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_PAUSED | CHK_ST_AGENT)))
2491 chunk_appendf(msg, ", invalid srv_check_state value '%s'", params[9]);
2492
2493 /* validating srv_agent_state */
2494 p = NULL;
2495 errno = 0;
2496 srv_agent_state = strtol(params[10], &p, 10);
2497 if (p == params[10] || errno == EINVAL || errno == ERANGE ||
2498 (srv_agent_state & ~(CHK_ST_INPROGRESS | CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_PAUSED | CHK_ST_AGENT)))
2499 chunk_appendf(msg, ", invalid srv_agent_state value '%s'", params[10]);
2500
2501 /* validating bk_f_forced_id */
2502 p = NULL;
2503 errno = 0;
2504 bk_f_forced_id = strtol(params[11], &p, 10);
2505 if (p == params[11] || errno == EINVAL || errno == ERANGE || !((bk_f_forced_id == 0) || (bk_f_forced_id == 1)))
2506 chunk_appendf(msg, ", invalid bk_f_forced_id value '%s'", params[11]);
2507
2508 /* validating srv_f_forced_id */
2509 p = NULL;
2510 errno = 0;
2511 srv_f_forced_id = strtol(params[12], &p, 10);
2512 if (p == params[12] || errno == EINVAL || errno == ERANGE || !((srv_f_forced_id == 0) || (srv_f_forced_id == 1)))
2513 chunk_appendf(msg, ", invalid srv_f_forced_id value '%s'", params[12]);
2514
2515
2516 /* don't apply anything if one error has been detected */
Willy Tarreau31138fa2015-09-29 18:38:47 +02002517 if (msg->len)
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002518 goto out;
2519
2520 /* recover operational state and apply it to this server
2521 * and all servers tracking this one */
2522 switch (srv_op_state) {
2523 case SRV_ST_STOPPED:
2524 srv->check.health = 0;
2525 srv_set_stopped(srv, "changed from server-state after a reload");
2526 break;
2527 case SRV_ST_STARTING:
2528 srv->state = srv_op_state;
2529 break;
2530 case SRV_ST_STOPPING:
2531 srv->check.health = srv->check.rise + srv->check.fall - 1;
2532 srv_set_stopping(srv, "changed from server-state after a reload");
2533 break;
2534 case SRV_ST_RUNNING:
2535 srv->check.health = srv->check.rise + srv->check.fall - 1;
2536 srv_set_running(srv, "");
2537 break;
2538 }
2539
2540 /* When applying server state, the following rules apply:
2541 * - in case of a configuration change, we apply the setting from the new
2542 * configuration, regardless of old running state
2543 * - if no configuration change, we apply old running state only if old running
2544 * state is different from new configuration state
2545 */
2546 /* configuration has changed */
2547 if ((srv_admin_state & SRV_ADMF_CMAINT) != (srv->admin & SRV_ADMF_CMAINT)) {
2548 if (srv->admin & SRV_ADMF_CMAINT)
2549 srv_adm_set_maint(srv);
2550 else
2551 srv_adm_set_ready(srv);
2552 }
2553 /* configuration is the same, let's compate old running state and new conf state */
2554 else {
2555 if (srv_admin_state & SRV_ADMF_FMAINT && !(srv->admin & SRV_ADMF_CMAINT))
2556 srv_adm_set_maint(srv);
2557 else if (!(srv_admin_state & SRV_ADMF_FMAINT) && (srv->admin & SRV_ADMF_CMAINT))
2558 srv_adm_set_ready(srv);
2559 }
2560 /* apply drain mode if server is currently enabled */
2561 if (!(srv->admin & SRV_ADMF_FMAINT) && (srv_admin_state & SRV_ADMF_FDRAIN)) {
2562 /* The SRV_ADMF_FDRAIN flag is inherited when srv->iweight is 0
Willy Tarreau22cace22016-11-03 18:19:49 +01002563 * (srv->iweight is the weight set up in configuration).
2564 * There are two possible reasons for FDRAIN to have been present :
2565 * - previous config weight was zero
2566 * - "set server b/s drain" was sent to the CLI
2567 *
2568 * In the first case, we simply want to drop this drain state
2569 * if the new weight is not zero anymore, meaning the administrator
2570 * has intentionally turned the weight back to a positive value to
2571 * enable the server again after an operation. In the second case,
2572 * the drain state was forced on the CLI regardless of the config's
2573 * weight so we don't want a change to the config weight to lose this
2574 * status. What this means is :
2575 * - if previous weight was 0 and new one is >0, drop the DRAIN state.
2576 * - if the previous weight was >0, keep it.
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002577 */
Willy Tarreau22cace22016-11-03 18:19:49 +01002578 if (srv_iweight > 0 || srv->iweight == 0)
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002579 srv_adm_set_drain(srv);
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002580 }
2581
2582 srv->last_change = date.tv_sec - srv_last_time_change;
2583 srv->check.status = srv_check_status;
2584 srv->check.result = srv_check_result;
2585 srv->check.health = srv_check_health;
2586
2587 /* Only case we want to apply is removing ENABLED flag which could have been
2588 * done by the "disable health" command over the stats socket
2589 */
2590 if ((srv->check.state & CHK_ST_CONFIGURED) &&
2591 (srv_check_state & CHK_ST_CONFIGURED) &&
2592 !(srv_check_state & CHK_ST_ENABLED))
2593 srv->check.state &= ~CHK_ST_ENABLED;
2594
2595 /* Only case we want to apply is removing ENABLED flag which could have been
2596 * done by the "disable agent" command over the stats socket
2597 */
2598 if ((srv->agent.state & CHK_ST_CONFIGURED) &&
2599 (srv_agent_state & CHK_ST_CONFIGURED) &&
2600 !(srv_agent_state & CHK_ST_ENABLED))
2601 srv->agent.state &= ~CHK_ST_ENABLED;
2602
Baptiste Assmann6076d1c2015-09-17 22:53:59 +02002603 /* We want to apply the previous 'running' weight (srv_uweight) only if there
2604 * was no change in the configuration: both previous and new iweight are equals
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002605 *
Baptiste Assmann6076d1c2015-09-17 22:53:59 +02002606 * It means that a configuration file change has precedence over a unix socket change
2607 * for server's weight
2608 *
2609 * by default, HAProxy applies the following weight when parsing the configuration
2610 * srv->uweight = srv->iweight
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002611 */
Baptiste Assmann6076d1c2015-09-17 22:53:59 +02002612 if (srv_iweight == srv->iweight) {
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002613 srv->uweight = srv_uweight;
2614 }
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002615 server_recalc_eweight(srv);
2616
Willy Tarreaue5a60682016-11-09 14:54:53 +01002617 /* load server IP address */
2618 srv->lastaddr = strdup(params[0]);
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002619 break;
2620 default:
2621 chunk_appendf(msg, ", version '%d' not supported", version);
2622 }
2623
2624 out:
Baptiste Assmann0821bb92016-01-21 00:20:50 +01002625 if (msg->len) {
2626 chunk_appendf(msg, "\n");
Willy Tarreau31138fa2015-09-29 18:38:47 +02002627 Warning("server-state application failed for server '%s/%s'%s",
2628 srv->proxy->id, srv->id, msg->str);
Baptiste Assmann0821bb92016-01-21 00:20:50 +01002629 }
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002630}
2631
2632/* This function parses all the proxies and only take care of the backends (since we're looking for server)
2633 * For each proxy, it does the following:
2634 * - opens its server state file (either one or local one)
2635 * - read whole file, line by line
2636 * - analyse each line to check if it matches our current backend:
2637 * - backend name matches
2638 * - backend id matches if id is forced and name doesn't match
2639 * - if the server pointed by the line is found, then state is applied
2640 *
2641 * If the running backend uuid or id differs from the state file, then HAProxy reports
2642 * a warning.
2643 */
2644void apply_server_state(void)
2645{
2646 char *cur, *end;
2647 char mybuf[SRV_STATE_LINE_MAXLEN];
2648 int mybuflen;
2649 char *params[SRV_STATE_FILE_MAX_FIELDS];
2650 char *srv_params[SRV_STATE_FILE_MAX_FIELDS];
2651 int arg, srv_arg, version, diff;
2652 FILE *f;
2653 char *filepath;
2654 char globalfilepath[MAXPATHLEN + 1];
2655 char localfilepath[MAXPATHLEN + 1];
2656 int len, fileopenerr, globalfilepathlen, localfilepathlen;
2657 extern struct proxy *proxy;
2658 struct proxy *curproxy, *bk;
2659 struct server *srv;
2660
2661 globalfilepathlen = 0;
2662 /* create the globalfilepath variable */
2663 if (global.server_state_file) {
2664 /* absolute path or no base directory provided */
2665 if ((global.server_state_file[0] == '/') || (!global.server_state_base)) {
2666 len = strlen(global.server_state_file);
2667 if (len > MAXPATHLEN) {
2668 globalfilepathlen = 0;
2669 goto globalfileerror;
2670 }
2671 memcpy(globalfilepath, global.server_state_file, len);
2672 globalfilepath[len] = '\0';
2673 globalfilepathlen = len;
2674 }
2675 else if (global.server_state_base) {
2676 len = strlen(global.server_state_base);
2677 globalfilepathlen += len;
2678
2679 if (globalfilepathlen > MAXPATHLEN) {
2680 globalfilepathlen = 0;
2681 goto globalfileerror;
2682 }
2683 strncpy(globalfilepath, global.server_state_base, len);
2684 globalfilepath[globalfilepathlen] = 0;
2685
2686 /* append a slash if needed */
2687 if (!globalfilepathlen || globalfilepath[globalfilepathlen - 1] != '/') {
2688 if (globalfilepathlen + 1 > MAXPATHLEN) {
2689 globalfilepathlen = 0;
2690 goto globalfileerror;
2691 }
2692 globalfilepath[globalfilepathlen++] = '/';
2693 }
2694
2695 len = strlen(global.server_state_file);
2696 if (globalfilepathlen + len > MAXPATHLEN) {
2697 globalfilepathlen = 0;
2698 goto globalfileerror;
2699 }
2700 memcpy(globalfilepath + globalfilepathlen, global.server_state_file, len);
2701 globalfilepathlen += len;
2702 globalfilepath[globalfilepathlen++] = 0;
2703 }
2704 }
2705 globalfileerror:
2706 if (globalfilepathlen == 0)
2707 globalfilepath[0] = '\0';
2708
2709 /* read servers state from local file */
2710 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
2711 /* servers are only in backends */
2712 if (!(curproxy->cap & PR_CAP_BE))
2713 continue;
2714 fileopenerr = 0;
2715 filepath = NULL;
2716
2717 /* search server state file path and name */
2718 switch (curproxy->load_server_state_from_file) {
2719 /* read servers state from global file */
2720 case PR_SRV_STATE_FILE_GLOBAL:
2721 /* there was an error while generating global server state file path */
2722 if (globalfilepathlen == 0)
2723 continue;
2724 filepath = globalfilepath;
2725 fileopenerr = 1;
2726 break;
2727 /* this backend has its own file */
2728 case PR_SRV_STATE_FILE_LOCAL:
2729 localfilepathlen = 0;
2730 localfilepath[0] = '\0';
2731 len = 0;
2732 /* create the localfilepath variable */
2733 /* absolute path or no base directory provided */
2734 if ((curproxy->server_state_file_name[0] == '/') || (!global.server_state_base)) {
2735 len = strlen(curproxy->server_state_file_name);
2736 if (len > MAXPATHLEN) {
2737 localfilepathlen = 0;
2738 goto localfileerror;
2739 }
2740 memcpy(localfilepath, curproxy->server_state_file_name, len);
2741 localfilepath[len] = '\0';
2742 localfilepathlen = len;
2743 }
2744 else if (global.server_state_base) {
2745 len = strlen(global.server_state_base);
2746 localfilepathlen += len;
2747
2748 if (localfilepathlen > MAXPATHLEN) {
2749 localfilepathlen = 0;
2750 goto localfileerror;
2751 }
2752 strncpy(localfilepath, global.server_state_base, len);
2753 localfilepath[localfilepathlen] = 0;
2754
2755 /* append a slash if needed */
2756 if (!localfilepathlen || localfilepath[localfilepathlen - 1] != '/') {
2757 if (localfilepathlen + 1 > MAXPATHLEN) {
2758 localfilepathlen = 0;
2759 goto localfileerror;
2760 }
2761 localfilepath[localfilepathlen++] = '/';
2762 }
2763
2764 len = strlen(curproxy->server_state_file_name);
2765 if (localfilepathlen + len > MAXPATHLEN) {
2766 localfilepathlen = 0;
2767 goto localfileerror;
2768 }
2769 memcpy(localfilepath + localfilepathlen, curproxy->server_state_file_name, len);
2770 localfilepathlen += len;
2771 localfilepath[localfilepathlen++] = 0;
2772 }
2773 filepath = localfilepath;
2774 localfileerror:
2775 if (localfilepathlen == 0)
2776 localfilepath[0] = '\0';
2777
2778 break;
2779 case PR_SRV_STATE_FILE_NONE:
2780 default:
2781 continue;
2782 }
2783
2784 /* preload global state file */
2785 errno = 0;
2786 f = fopen(filepath, "r");
2787 if (errno && fileopenerr)
2788 Warning("Can't open server state file '%s': %s\n", filepath, strerror(errno));
2789 if (!f)
2790 continue;
2791
2792 mybuf[0] = '\0';
2793 mybuflen = 0;
2794 version = 0;
2795
2796 /* first character of first line of the file must contain the version of the export */
Dragan Dosencf4fb032015-11-04 23:03:26 +01002797 if (fgets(mybuf, SRV_STATE_LINE_MAXLEN, f) == NULL) {
2798 Warning("Can't read first line of the server state file '%s'\n", filepath);
2799 goto fileclose;
2800 }
2801
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002802 cur = mybuf;
2803 version = atoi(cur);
2804 if ((version < SRV_STATE_FILE_VERSION_MIN) ||
2805 (version > SRV_STATE_FILE_VERSION_MAX))
Dragan Dosencf4fb032015-11-04 23:03:26 +01002806 goto fileclose;
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002807
2808 while (fgets(mybuf, SRV_STATE_LINE_MAXLEN, f)) {
2809 int bk_f_forced_id = 0;
2810 int check_id = 0;
2811 int check_name = 0;
2812
2813 mybuflen = strlen(mybuf);
2814 cur = mybuf;
2815 end = cur + mybuflen;
2816
2817 bk = NULL;
2818 srv = NULL;
2819
2820 /* we need at least one character */
2821 if (mybuflen == 0)
2822 continue;
2823
2824 /* ignore blank characters at the beginning of the line */
2825 while (isspace(*cur))
2826 ++cur;
2827
2828 if (cur == end)
2829 continue;
2830
2831 /* ignore comment line */
2832 if (*cur == '#')
2833 continue;
2834
2835 /* we're now ready to move the line into *srv_params[] */
2836 params[0] = cur;
2837 arg = 1;
2838 srv_arg = 0;
2839 while (*cur && arg < SRV_STATE_FILE_MAX_FIELDS) {
2840 if (isspace(*cur)) {
2841 *cur = '\0';
2842 ++cur;
2843 while (isspace(*cur))
2844 ++cur;
2845 switch (version) {
2846 case 1:
2847 /*
2848 * srv_addr: params[4] => srv_params[0]
2849 * srv_op_state: params[5] => srv_params[1]
2850 * srv_admin_state: params[6] => srv_params[2]
2851 * srv_uweight: params[7] => srv_params[3]
2852 * srv_iweight: params[8] => srv_params[4]
2853 * srv_last_time_change: params[9] => srv_params[5]
2854 * srv_check_status: params[10] => srv_params[6]
2855 * srv_check_result: params[11] => srv_params[7]
2856 * srv_check_health: params[12] => srv_params[8]
2857 * srv_check_state: params[13] => srv_params[9]
2858 * srv_agent_state: params[14] => srv_params[10]
2859 * bk_f_forced_id: params[15] => srv_params[11]
2860 * srv_f_forced_id: params[16] => srv_params[12]
2861 */
2862 if (arg >= 4) {
2863 srv_params[srv_arg] = cur;
2864 ++srv_arg;
2865 }
2866 break;
2867 }
2868
2869 params[arg] = cur;
2870 ++arg;
2871 }
2872 else {
2873 ++cur;
2874 }
2875 }
2876
2877 /* if line is incomplete line, then ignore it.
2878 * otherwise, update useful flags */
2879 switch (version) {
2880 case 1:
2881 if (arg < SRV_STATE_FILE_NB_FIELDS_VERSION_1)
2882 continue;
2883 bk_f_forced_id = (atoi(params[15]) & PR_O_FORCED_ID);
2884 check_id = (atoi(params[0]) == curproxy->uuid);
2885 check_name = (strcmp(curproxy->id, params[1]) == 0);
2886 break;
2887 }
2888
2889 diff = 0;
2890 bk = curproxy;
2891
2892 /* if backend can't be found, let's continue */
2893 if (!check_id && !check_name)
2894 continue;
2895 else if (!check_id && check_name) {
2896 Warning("backend ID mismatch: from server state file: '%s', from running config '%d'\n", params[0], bk->uuid);
2897 send_log(bk, LOG_NOTICE, "backend ID mismatch: from server state file: '%s', from running config '%d'\n", params[0], bk->uuid);
2898 }
2899 else if (check_id && !check_name) {
2900 Warning("backend name mismatch: from server state file: '%s', from running config '%s'\n", params[1], bk->id);
2901 send_log(bk, LOG_NOTICE, "backend name mismatch: from server state file: '%s', from running config '%s'\n", params[1], bk->id);
2902 /* if name doesn't match, we still want to update curproxy if the backend id
2903 * was forced in previous the previous configuration */
2904 if (!bk_f_forced_id)
2905 continue;
2906 }
2907
2908 /* look for the server by its id: param[2] */
2909 /* else look for the server by its name: param[3] */
2910 diff = 0;
2911 srv = server_find_best_match(bk, params[3], atoi(params[2]), &diff);
2912
2913 if (!srv) {
2914 /* if no server found, then warning and continue with next line */
2915 Warning("can't find server '%s' with id '%s' in backend with id '%s' or name '%s'\n",
2916 params[3], params[2], params[0], params[1]);
2917 send_log(bk, LOG_NOTICE, "can't find server '%s' with id '%s' in backend with id '%s' or name '%s'\n",
2918 params[3], params[2], params[0], params[1]);
2919 continue;
2920 }
2921 else if (diff & PR_FBM_MISMATCH_ID) {
2922 Warning("In backend '%s' (id: '%d'): server ID mismatch: from server state file: '%s', from running config %d\n", bk->id, bk->uuid, params[2], srv->puid);
2923 send_log(bk, LOG_NOTICE, "In backend '%s' (id: %d): server ID mismatch: from server state file: '%s', from running config %d\n", bk->id, bk->uuid, params[2], srv->puid);
2924 }
2925 else if (diff & PR_FBM_MISMATCH_NAME) {
2926 Warning("In backend '%s' (id: %d): server name mismatch: from server state file: '%s', from running config '%s'\n", bk->id, bk->uuid, params[3], srv->id);
2927 send_log(bk, LOG_NOTICE, "In backend '%s' (id: %d): server name mismatch: from server state file: '%s', from running config '%s'\n", bk->id, bk->uuid, params[3], srv->id);
2928 }
2929
2930 /* now we can proceed with server's state update */
2931 srv_update_state(srv, version, srv_params);
2932 }
Dragan Dosencf4fb032015-11-04 23:03:26 +01002933fileclose:
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002934 fclose(f);
2935 }
2936}
2937
Simon Horman7d09b9a2013-02-12 10:45:51 +09002938/*
Baptiste Assmann14e40142015-04-14 01:13:07 +02002939 * update a server's current IP address.
2940 * ip is a pointer to the new IP address, whose address family is ip_sin_family.
2941 * ip is in network format.
2942 * updater is a string which contains an information about the requester of the update.
2943 * updater is used if not NULL.
2944 *
2945 * A log line and a stderr warning message is generated based on server's backend options.
2946 */
Thierry Fournierd35b7a62016-02-24 08:23:22 +01002947int update_server_addr(struct server *s, void *ip, int ip_sin_family, const char *updater)
Baptiste Assmann14e40142015-04-14 01:13:07 +02002948{
2949 /* generates a log line and a warning on stderr */
2950 if (1) {
2951 /* book enough space for both IPv4 and IPv6 */
2952 char oldip[INET6_ADDRSTRLEN];
2953 char newip[INET6_ADDRSTRLEN];
2954
2955 memset(oldip, '\0', INET6_ADDRSTRLEN);
2956 memset(newip, '\0', INET6_ADDRSTRLEN);
2957
2958 /* copy old IP address in a string */
2959 switch (s->addr.ss_family) {
2960 case AF_INET:
2961 inet_ntop(s->addr.ss_family, &((struct sockaddr_in *)&s->addr)->sin_addr, oldip, INET_ADDRSTRLEN);
2962 break;
2963 case AF_INET6:
2964 inet_ntop(s->addr.ss_family, &((struct sockaddr_in6 *)&s->addr)->sin6_addr, oldip, INET6_ADDRSTRLEN);
2965 break;
2966 };
2967
2968 /* copy new IP address in a string */
2969 switch (ip_sin_family) {
2970 case AF_INET:
2971 inet_ntop(ip_sin_family, ip, newip, INET_ADDRSTRLEN);
2972 break;
2973 case AF_INET6:
2974 inet_ntop(ip_sin_family, ip, newip, INET6_ADDRSTRLEN);
2975 break;
2976 };
2977
2978 /* save log line into a buffer */
2979 chunk_printf(&trash, "%s/%s changed its IP from %s to %s by %s",
2980 s->proxy->id, s->id, oldip, newip, updater);
2981
2982 /* write the buffer on stderr */
2983 Warning("%s.\n", trash.str);
2984
2985 /* send a log */
2986 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
2987 }
2988
2989 /* save the new IP family */
2990 s->addr.ss_family = ip_sin_family;
2991 /* save the new IP address */
2992 switch (ip_sin_family) {
2993 case AF_INET:
Willy Tarreaueec1d382016-07-13 11:59:39 +02002994 memcpy(&((struct sockaddr_in *)&s->addr)->sin_addr.s_addr, ip, 4);
Baptiste Assmann14e40142015-04-14 01:13:07 +02002995 break;
2996 case AF_INET6:
2997 memcpy(((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr, ip, 16);
2998 break;
2999 };
Olivier Houchard4e694042017-03-14 20:01:29 +01003000 srv_set_dyncookie(s);
Baptiste Assmann14e40142015-04-14 01:13:07 +02003001
3002 return 0;
3003}
3004
3005/*
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003006 * This function update a server's addr and port only for AF_INET and AF_INET6 families.
3007 *
3008 * Caller can pass its name through <updater> to get it integrated in the response message
3009 * returned by the function.
3010 *
3011 * The function first does the following, in that order:
3012 * - validates the new addr and/or port
3013 * - checks if an update is required (new IP or port is different than current ones)
3014 * - checks the update is allowed:
3015 * - don't switch from/to a family other than AF_INET4 and AF_INET6
3016 * - allow all changes if no CHECKS are configured
3017 * - if CHECK is configured:
3018 * - if switch to port map (SRV_F_MAPPORTS), ensure health check have their own ports
3019 * - applies required changes to both ADDR and PORT if both 'required' and 'allowed'
3020 * conditions are met
3021 */
3022const char *update_server_addr_port(struct server *s, const char *addr, const char *port, char *updater)
3023{
3024 struct sockaddr_storage sa;
3025 int ret, port_change_required;
3026 char current_addr[INET6_ADDRSTRLEN];
David Carlier327298c2016-11-20 10:42:38 +00003027 uint16_t current_port, new_port;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003028 struct chunk *msg;
Olivier Houchard4e694042017-03-14 20:01:29 +01003029 int changed = 0;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003030
3031 msg = get_trash_chunk();
3032 chunk_reset(msg);
3033
3034 if (addr) {
3035 memset(&sa, 0, sizeof(struct sockaddr_storage));
3036 if (str2ip2(addr, &sa, 0) == NULL) {
3037 chunk_printf(msg, "Invalid addr '%s'", addr);
3038 goto out;
3039 }
3040
3041 /* changes are allowed on AF_INET* families only */
3042 if ((sa.ss_family != AF_INET) && (sa.ss_family != AF_INET6)) {
3043 chunk_printf(msg, "Update to families other than AF_INET and AF_INET6 supported only through configuration file");
3044 goto out;
3045 }
3046
3047 /* collecting data currently setup */
3048 memset(current_addr, '\0', sizeof(current_addr));
3049 ret = addr_to_str(&s->addr, current_addr, sizeof(current_addr));
3050 /* changes are allowed on AF_INET* families only */
3051 if ((ret != AF_INET) && (ret != AF_INET6)) {
3052 chunk_printf(msg, "Update for the current server address family is only supported through configuration file");
3053 goto out;
3054 }
3055
3056 /* applying ADDR changes if required and allowed
3057 * ipcmp returns 0 when both ADDR are the same
3058 */
3059 if (ipcmp(&s->addr, &sa) == 0) {
3060 chunk_appendf(msg, "no need to change the addr");
3061 goto port;
3062 }
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003063 ipcpy(&sa, &s->addr);
Olivier Houchard4e694042017-03-14 20:01:29 +01003064 changed = 1;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003065
3066 /* we also need to update check's ADDR only if it uses the server's one */
3067 if ((s->check.state & CHK_ST_CONFIGURED) && (s->flags & SRV_F_CHECKADDR)) {
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003068 ipcpy(&sa, &s->check.addr);
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003069 }
3070
3071 /* we also need to update agent ADDR only if it use the server's one */
3072 if ((s->agent.state & CHK_ST_CONFIGURED) && (s->flags & SRV_F_AGENTADDR)) {
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003073 ipcpy(&sa, &s->agent.addr);
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003074 }
3075
3076 /* update report for caller */
3077 chunk_printf(msg, "IP changed from '%s' to '%s'", current_addr, addr);
3078 }
3079
3080 port:
3081 if (port) {
3082 char sign = '\0';
3083 char *endptr;
3084
3085 if (addr)
3086 chunk_appendf(msg, ", ");
3087
3088 /* collecting data currently setup */
Willy Tarreau04276f32017-01-06 17:41:29 +01003089 current_port = s->svc_port;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003090
3091 /* check if PORT change is required */
3092 port_change_required = 0;
3093
3094 sign = *port;
Ryabin Sergey77ee7522017-01-11 19:39:55 +04003095 errno = 0;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003096 new_port = strtol(port, &endptr, 10);
3097 if ((errno != 0) || (port == endptr)) {
3098 chunk_appendf(msg, "problem converting port '%s' to an int", port);
3099 goto out;
3100 }
3101
3102 /* check if caller triggers a port mapped or offset */
3103 if (sign == '-' || (sign == '+')) {
3104 /* check if server currently uses port map */
3105 if (!(s->flags & SRV_F_MAPPORTS)) {
3106 /* switch from fixed port to port map mandatorily triggers
3107 * a port change */
3108 port_change_required = 1;
3109 /* check is configured
3110 * we're switching from a fixed port to a SRV_F_MAPPORTS (mapped) port
3111 * prevent PORT change if check doesn't have it's dedicated port while switching
3112 * to port mapping */
3113 if ((s->check.state & CHK_ST_CONFIGURED) && !(s->flags & SRV_F_CHECKPORT)) {
3114 chunk_appendf(msg, "can't change <port> to port map because it is incompatible with current health check port configuration (use 'port' statement from the 'server' directive.");
3115 goto out;
3116 }
3117 }
3118 /* we're already using port maps */
3119 else {
3120 port_change_required = current_port != new_port;
3121 }
3122 }
3123 /* fixed port */
3124 else {
3125 port_change_required = current_port != new_port;
3126 }
3127
3128 /* applying PORT changes if required and update response message */
3129 if (port_change_required) {
3130 /* apply new port */
Willy Tarreau04276f32017-01-06 17:41:29 +01003131 s->svc_port = new_port;
Olivier Houchard4e694042017-03-14 20:01:29 +01003132 changed = 1;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003133
3134 /* prepare message */
3135 chunk_appendf(msg, "port changed from '");
3136 if (s->flags & SRV_F_MAPPORTS)
3137 chunk_appendf(msg, "+");
3138 chunk_appendf(msg, "%d' to '", current_port);
3139
3140 if (sign == '-') {
3141 s->flags |= SRV_F_MAPPORTS;
3142 chunk_appendf(msg, "%c", sign);
3143 /* just use for result output */
3144 new_port = -new_port;
3145 }
3146 else if (sign == '+') {
3147 s->flags |= SRV_F_MAPPORTS;
3148 chunk_appendf(msg, "%c", sign);
3149 }
3150 else {
3151 s->flags &= ~SRV_F_MAPPORTS;
3152 }
3153
3154 chunk_appendf(msg, "%d'", new_port);
3155
3156 /* we also need to update health checks port only if it uses server's realport */
3157 if ((s->check.state & CHK_ST_CONFIGURED) && !(s->flags & SRV_F_CHECKPORT)) {
3158 s->check.port = new_port;
3159 }
3160 }
3161 else {
3162 chunk_appendf(msg, "no need to change the port");
3163 }
3164 }
3165
3166out:
Olivier Houchard4e694042017-03-14 20:01:29 +01003167 if (changed)
3168 srv_set_dyncookie(s);
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003169 if (updater)
3170 chunk_appendf(msg, " by '%s'", updater);
3171 chunk_appendf(msg, "\n");
3172 return msg->str;
3173}
3174
3175
3176/*
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003177 * update server status based on result of name resolution
3178 * returns:
3179 * 0 if server status is updated
3180 * 1 if server status has not changed
3181 */
3182int snr_update_srv_status(struct server *s)
3183{
3184 struct dns_resolution *resolution = s->resolution;
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003185 struct dns_resolvers *resolvers;
3186
3187 resolvers = resolution->resolvers;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003188
3189 switch (resolution->status) {
3190 case RSLV_STATUS_NONE:
3191 /* status when HAProxy has just (re)started */
3192 trigger_resolution(s);
3193 break;
3194
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003195 case RSLV_STATUS_VALID:
3196 /*
3197 * resume health checks
3198 * server will be turned back on if health check is safe
3199 */
3200 if (!(s->admin & SRV_ADMF_RMAINT))
3201 return 1;
3202 srv_clr_admin_flag(s, SRV_ADMF_RMAINT);
3203 chunk_printf(&trash, "Server %s/%s administratively READY thanks to valid DNS answer",
3204 s->proxy->id, s->id);
3205
3206 Warning("%s.\n", trash.str);
3207 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
3208 return 0;
3209
3210 case RSLV_STATUS_NX:
3211 /* stop server if resolution is NX for a long enough period */
3212 if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.nx), now_ms)) {
3213 if (s->admin & SRV_ADMF_RMAINT)
3214 return 1;
3215 srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS NX status");
3216 return 0;
3217 }
3218 break;
3219
3220 case RSLV_STATUS_TIMEOUT:
3221 /* stop server if resolution is TIMEOUT for a long enough period */
3222 if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.timeout), now_ms)) {
3223 if (s->admin & SRV_ADMF_RMAINT)
3224 return 1;
3225 srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS timeout status");
3226 return 0;
3227 }
3228 break;
3229
3230 case RSLV_STATUS_REFUSED:
3231 /* stop server if resolution is REFUSED for a long enough period */
3232 if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.refused), now_ms)) {
3233 if (s->admin & SRV_ADMF_RMAINT)
3234 return 1;
3235 srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS refused status");
3236 return 0;
3237 }
3238 break;
3239
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003240 default:
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003241 /* stop server if resolution is in unmatched error for a long enough period */
3242 if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.other), now_ms)) {
3243 if (s->admin & SRV_ADMF_RMAINT)
3244 return 1;
3245 srv_set_admin_flag(s, SRV_ADMF_RMAINT, "unspecified DNS error");
3246 return 0;
3247 }
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003248 break;
3249 }
3250
3251 return 1;
3252}
3253
3254/*
3255 * Server Name Resolution valid response callback
3256 * It expects:
3257 * - <nameserver>: the name server which answered the valid response
3258 * - <response>: buffer containing a valid DNS response
3259 * - <response_len>: size of <response>
3260 * It performs the following actions:
3261 * - ignore response if current ip found and server family not met
3262 * - update with first new ip found if family is met and current IP is not found
3263 * returns:
3264 * 0 on error
3265 * 1 when no error or safe ignore
3266 */
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02003267int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *nameserver, struct dns_response_packet *dns_p)
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003268{
3269 struct server *s;
3270 void *serverip, *firstip;
3271 short server_sin_family, firstip_sin_family;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003272 int ret;
3273 struct chunk *chk = get_trash_chunk();
3274
3275 /* initializing variables */
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003276 firstip = NULL; /* pointer to the first valid response found */
3277 /* it will be used as the new IP if a change is required */
3278 firstip_sin_family = AF_UNSPEC;
3279 serverip = NULL; /* current server IP address */
3280
3281 /* shortcut to the server whose name is being resolved */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003282 s = resolution->requester;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003283
3284 /* initializing server IP pointer */
3285 server_sin_family = s->addr.ss_family;
3286 switch (server_sin_family) {
3287 case AF_INET:
3288 serverip = &((struct sockaddr_in *)&s->addr)->sin_addr.s_addr;
3289 break;
3290
3291 case AF_INET6:
3292 serverip = &((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr;
3293 break;
3294
Willy Tarreau3acfcd12017-01-06 19:18:32 +01003295 case AF_UNSPEC:
3296 break;
3297
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003298 default:
3299 goto invalid;
3300 }
3301
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02003302 ret = dns_get_ip_from_response(dns_p, resolution,
Thierry Fournierada34842016-02-17 21:25:09 +01003303 serverip, server_sin_family, &firstip,
3304 &firstip_sin_family);
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003305
3306 switch (ret) {
3307 case DNS_UPD_NO:
3308 if (resolution->status != RSLV_STATUS_VALID) {
3309 resolution->status = RSLV_STATUS_VALID;
3310 resolution->last_status_change = now_ms;
3311 }
3312 goto stop_resolution;
3313
3314 case DNS_UPD_SRVIP_NOT_FOUND:
3315 goto save_ip;
3316
3317 case DNS_UPD_CNAME:
3318 if (resolution->status != RSLV_STATUS_VALID) {
3319 resolution->status = RSLV_STATUS_VALID;
3320 resolution->last_status_change = now_ms;
3321 }
3322 goto invalid;
3323
Baptiste Assmann0453a1d2015-09-09 00:51:08 +02003324 case DNS_UPD_NO_IP_FOUND:
3325 if (resolution->status != RSLV_STATUS_OTHER) {
3326 resolution->status = RSLV_STATUS_OTHER;
3327 resolution->last_status_change = now_ms;
3328 }
3329 goto stop_resolution;
3330
Baptiste Assmannfad03182015-10-28 02:03:32 +01003331 case DNS_UPD_NAME_ERROR:
3332 /* if this is not the last expected response, we ignore it */
3333 if (resolution->nb_responses < nameserver->resolvers->count_nameservers)
3334 return 0;
3335 /* update resolution status to OTHER error type */
3336 if (resolution->status != RSLV_STATUS_OTHER) {
3337 resolution->status = RSLV_STATUS_OTHER;
3338 resolution->last_status_change = now_ms;
3339 }
3340 goto stop_resolution;
3341
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003342 default:
3343 goto invalid;
3344
3345 }
3346
3347 save_ip:
3348 nameserver->counters.update += 1;
3349 if (resolution->status != RSLV_STATUS_VALID) {
3350 resolution->status = RSLV_STATUS_VALID;
3351 resolution->last_status_change = now_ms;
3352 }
3353
3354 /* save the first ip we found */
3355 chunk_printf(chk, "%s/%s", nameserver->resolvers->id, nameserver->id);
3356 update_server_addr(s, firstip, firstip_sin_family, (char *)chk->str);
3357
3358 stop_resolution:
3359 /* update last resolution date and time */
3360 resolution->last_resolution = now_ms;
3361 /* reset current status flag */
3362 resolution->step = RSLV_STEP_NONE;
3363 /* reset values */
3364 dns_reset_resolution(resolution);
3365
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003366 dns_update_resolvers_timeout(nameserver->resolvers);
3367
3368 snr_update_srv_status(s);
3369 return 0;
3370
3371 invalid:
3372 nameserver->counters.invalid += 1;
3373 if (resolution->nb_responses >= nameserver->resolvers->count_nameservers)
3374 goto stop_resolution;
3375
3376 snr_update_srv_status(s);
3377 return 0;
3378}
3379
3380/*
3381 * Server Name Resolution error management callback
3382 * returns:
3383 * 0 on error
3384 * 1 when no error or safe ignore
3385 */
3386int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code)
3387{
3388 struct server *s;
3389 struct dns_resolvers *resolvers;
Andrew Hayworthe6a4a322015-10-19 22:29:51 +00003390 int res_preferred_afinet, res_preferred_afinet6;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003391
3392 /* shortcut to the server whose name is being resolved */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003393 s = resolution->requester;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003394 resolvers = resolution->resolvers;
3395
3396 /* can be ignored if this is not the last response */
3397 if ((error_code != DNS_RESP_TIMEOUT) && (resolution->nb_responses < resolvers->count_nameservers)) {
3398 return 1;
3399 }
3400
3401 switch (error_code) {
3402 case DNS_RESP_INVALID:
3403 case DNS_RESP_WRONG_NAME:
3404 if (resolution->status != RSLV_STATUS_INVALID) {
3405 resolution->status = RSLV_STATUS_INVALID;
3406 resolution->last_status_change = now_ms;
3407 }
3408 break;
3409
3410 case DNS_RESP_ANCOUNT_ZERO:
Baptiste Assmann0df5d962015-09-02 21:58:32 +02003411 case DNS_RESP_TRUNCATED:
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003412 case DNS_RESP_ERROR:
Baptiste Assmann96972bc2015-09-09 00:46:58 +02003413 case DNS_RESP_NO_EXPECTED_RECORD:
Baptiste Assmann65ce3f52016-09-05 08:38:57 +02003414 case DNS_RESP_CNAME_ERROR:
Thierry Fournierada34842016-02-17 21:25:09 +01003415 res_preferred_afinet = resolution->opts->family_prio == AF_INET && resolution->query_type == DNS_RTYPE_A;
3416 res_preferred_afinet6 = resolution->opts->family_prio == AF_INET6 && resolution->query_type == DNS_RTYPE_AAAA;
Baptiste Assmann90447582015-09-02 22:20:56 +02003417
Andrew Hayworthe6a4a322015-10-19 22:29:51 +00003418 if ((res_preferred_afinet || res_preferred_afinet6)
Baptiste Assmannf778bb42015-09-09 00:54:38 +02003419 || (resolution->try > 0)) {
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003420 /* let's change the query type */
Andrew Hayworthe6a4a322015-10-19 22:29:51 +00003421 if (res_preferred_afinet6) {
Baptiste Assmann90447582015-09-02 22:20:56 +02003422 /* fallback from AAAA to A */
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003423 resolution->query_type = DNS_RTYPE_A;
Baptiste Assmann90447582015-09-02 22:20:56 +02003424 }
3425 else if (res_preferred_afinet) {
3426 /* fallback from A to AAAA */
3427 resolution->query_type = DNS_RTYPE_AAAA;
3428 }
Baptiste Assmannf778bb42015-09-09 00:54:38 +02003429 else {
3430 resolution->try -= 1;
Thierry Fournierada34842016-02-17 21:25:09 +01003431 if (resolution->opts->family_prio == AF_INET) {
Andrew Hayworthe6a4a322015-10-19 22:29:51 +00003432 resolution->query_type = DNS_RTYPE_A;
3433 } else {
3434 resolution->query_type = DNS_RTYPE_AAAA;
3435 }
Baptiste Assmannf778bb42015-09-09 00:54:38 +02003436 }
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003437
3438 dns_send_query(resolution);
3439
3440 /*
3441 * move the resolution to the last element of the FIFO queue
3442 * and update timeout wakeup based on the new first entry
3443 */
3444 if (dns_check_resolution_queue(resolvers) > 1) {
3445 /* second resolution becomes first one */
Baptiste Assmann11c4e4e2015-09-02 22:15:58 +02003446 LIST_DEL(&resolution->list);
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003447 /* ex first resolution goes to the end of the queue */
3448 LIST_ADDQ(&resolvers->curr_resolution, &resolution->list);
3449 }
3450 dns_update_resolvers_timeout(resolvers);
3451 goto leave;
3452 }
3453 else {
3454 if (resolution->status != RSLV_STATUS_OTHER) {
3455 resolution->status = RSLV_STATUS_OTHER;
3456 resolution->last_status_change = now_ms;
3457 }
3458 }
3459 break;
3460
3461 case DNS_RESP_NX_DOMAIN:
3462 if (resolution->status != RSLV_STATUS_NX) {
3463 resolution->status = RSLV_STATUS_NX;
3464 resolution->last_status_change = now_ms;
3465 }
3466 break;
3467
3468 case DNS_RESP_REFUSED:
3469 if (resolution->status != RSLV_STATUS_REFUSED) {
3470 resolution->status = RSLV_STATUS_REFUSED;
3471 resolution->last_status_change = now_ms;
3472 }
3473 break;
3474
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003475 case DNS_RESP_TIMEOUT:
3476 if (resolution->status != RSLV_STATUS_TIMEOUT) {
3477 resolution->status = RSLV_STATUS_TIMEOUT;
3478 resolution->last_status_change = now_ms;
3479 }
3480 break;
3481 }
3482
3483 /* update last resolution date and time */
3484 resolution->last_resolution = now_ms;
3485 /* reset current status flag */
3486 resolution->step = RSLV_STEP_NONE;
3487 /* reset values */
3488 dns_reset_resolution(resolution);
3489
3490 LIST_DEL(&resolution->list);
3491 dns_update_resolvers_timeout(resolvers);
3492
3493 leave:
3494 snr_update_srv_status(s);
3495 return 1;
3496}
3497
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003498/* Sets the server's address (srv->addr) from srv->hostname using the libc's
3499 * resolver. This is suited for initial address configuration. Returns 0 on
3500 * success otherwise a non-zero error code. In case of error, *err_code, if
3501 * not NULL, is filled up.
3502 */
3503int srv_set_addr_via_libc(struct server *srv, int *err_code)
3504{
3505 if (str2ip2(srv->hostname, &srv->addr, 1) == NULL) {
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003506 if (err_code)
Willy Tarreau465b6e52016-11-07 19:19:22 +01003507 *err_code |= ERR_WARN;
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003508 return 1;
3509 }
3510 return 0;
3511}
3512
3513/* Sets the server's address (srv->addr) from srv->lastaddr which was filled
3514 * from the state file. This is suited for initial address configuration.
3515 * Returns 0 on success otherwise a non-zero error code. In case of error,
3516 * *err_code, if not NULL, is filled up.
3517 */
3518static int srv_apply_lastaddr(struct server *srv, int *err_code)
3519{
3520 if (!str2ip2(srv->lastaddr, &srv->addr, 0)) {
3521 if (err_code)
3522 *err_code |= ERR_WARN;
3523 return 1;
3524 }
3525 return 0;
3526}
3527
Willy Tarreau25e51522016-11-04 15:10:17 +01003528/* returns 0 if no error, otherwise a combination of ERR_* flags */
3529static int srv_iterate_initaddr(struct server *srv)
3530{
3531 int return_code = 0;
3532 int err_code;
3533 unsigned int methods;
3534
3535 methods = srv->init_addr_methods;
3536 if (!methods) { // default to "last,libc"
3537 srv_append_initaddr(&methods, SRV_IADDR_LAST);
3538 srv_append_initaddr(&methods, SRV_IADDR_LIBC);
3539 }
3540
Willy Tarreau3eed10e2016-11-07 21:03:16 +01003541 /* "-dr" : always append "none" so that server addresses resolution
3542 * failures are silently ignored, this is convenient to validate some
3543 * configs out of their environment.
3544 */
3545 if (global.tune.options & GTUNE_RESOLVE_DONTFAIL)
3546 srv_append_initaddr(&methods, SRV_IADDR_NONE);
3547
Willy Tarreau25e51522016-11-04 15:10:17 +01003548 while (methods) {
3549 err_code = 0;
3550 switch (srv_get_next_initaddr(&methods)) {
3551 case SRV_IADDR_LAST:
3552 if (!srv->lastaddr)
3553 continue;
3554 if (srv_apply_lastaddr(srv, &err_code) == 0)
Olivier Houchard4e694042017-03-14 20:01:29 +01003555 goto out;
Willy Tarreau25e51522016-11-04 15:10:17 +01003556 return_code |= err_code;
3557 break;
3558
3559 case SRV_IADDR_LIBC:
3560 if (!srv->hostname)
3561 continue;
3562 if (srv_set_addr_via_libc(srv, &err_code) == 0)
Olivier Houchard4e694042017-03-14 20:01:29 +01003563 goto out;
Willy Tarreau25e51522016-11-04 15:10:17 +01003564 return_code |= err_code;
3565 break;
3566
Willy Tarreau37ebe122016-11-04 15:17:58 +01003567 case SRV_IADDR_NONE:
3568 srv_set_admin_flag(srv, SRV_ADMF_RMAINT, NULL);
Willy Tarreau465b6e52016-11-07 19:19:22 +01003569 if (return_code) {
3570 Warning("parsing [%s:%d] : 'server %s' : could not resolve address '%s', disabling server.\n",
3571 srv->conf.file, srv->conf.line, srv->id, srv->hostname);
3572 }
Willy Tarreau37ebe122016-11-04 15:17:58 +01003573 return return_code;
3574
Willy Tarreau4310d362016-11-02 15:05:56 +01003575 case SRV_IADDR_IP:
3576 ipcpy(&srv->init_addr, &srv->addr);
3577 if (return_code) {
3578 Warning("parsing [%s:%d] : 'server %s' : could not resolve address '%s', falling back to configured address.\n",
3579 srv->conf.file, srv->conf.line, srv->id, srv->hostname);
3580 }
Olivier Houchard4e694042017-03-14 20:01:29 +01003581 goto out;
Willy Tarreau4310d362016-11-02 15:05:56 +01003582
Willy Tarreau25e51522016-11-04 15:10:17 +01003583 default: /* unhandled method */
3584 break;
3585 }
3586 }
3587
3588 if (!return_code) {
3589 Alert("parsing [%s:%d] : 'server %s' : no method found to resolve address '%s'\n",
3590 srv->conf.file, srv->conf.line, srv->id, srv->hostname);
3591 }
Willy Tarreau465b6e52016-11-07 19:19:22 +01003592 else {
3593 Alert("parsing [%s:%d] : 'server %s' : could not resolve address '%s'.\n",
3594 srv->conf.file, srv->conf.line, srv->id, srv->hostname);
3595 }
Willy Tarreau25e51522016-11-04 15:10:17 +01003596
3597 return_code |= ERR_ALERT | ERR_FATAL;
3598 return return_code;
Olivier Houchard4e694042017-03-14 20:01:29 +01003599out:
3600 srv_set_dyncookie(srv);
3601 return return_code;
Willy Tarreau25e51522016-11-04 15:10:17 +01003602}
3603
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003604/*
3605 * This function parses all backends and all servers within each backend
3606 * and performs servers' addr resolution based on information provided by:
3607 * - configuration file
3608 * - server-state file (states provided by an 'old' haproxy process)
3609 *
3610 * Returns 0 if no error, otherwise, a combination of ERR_ flags.
3611 */
3612int srv_init_addr(void)
3613{
3614 struct proxy *curproxy;
3615 int return_code = 0;
3616
3617 curproxy = proxy;
3618 while (curproxy) {
3619 struct server *srv;
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003620
3621 /* servers are in backend only */
3622 if (!(curproxy->cap & PR_CAP_BE))
3623 goto srv_init_addr_next;
3624
Willy Tarreau25e51522016-11-04 15:10:17 +01003625 for (srv = curproxy->srv; srv; srv = srv->next)
3626 if (srv->hostname)
3627 return_code |= srv_iterate_initaddr(srv);
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003628
3629 srv_init_addr_next:
3630 curproxy = curproxy->next;
3631 }
3632
3633 return return_code;
3634}
3635
Willy Tarreau21b069d2016-11-23 17:15:08 +01003636/* Expects to find a backend and a server in <arg> under the form <backend>/<server>,
3637 * and returns the pointer to the server. Otherwise, display adequate error messages
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003638 * on the CLI, sets the CLI's state to CLI_ST_PRINT and returns NULL. This is only
Willy Tarreau21b069d2016-11-23 17:15:08 +01003639 * used for CLI commands requiring a server name.
3640 * Important: the <arg> is modified to remove the '/'.
3641 */
3642struct server *cli_find_server(struct appctx *appctx, char *arg)
3643{
3644 struct proxy *px;
3645 struct server *sv;
3646 char *line;
3647
3648 /* split "backend/server" and make <line> point to server */
3649 for (line = arg; *line; line++)
3650 if (*line == '/') {
3651 *line++ = '\0';
3652 break;
3653 }
3654
3655 if (!*line || !*arg) {
3656 appctx->ctx.cli.msg = "Require 'backend/server'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003657 appctx->st0 = CLI_ST_PRINT;
Willy Tarreau21b069d2016-11-23 17:15:08 +01003658 return NULL;
3659 }
3660
3661 if (!get_backend_server(arg, line, &px, &sv)) {
3662 appctx->ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003663 appctx->st0 = CLI_ST_PRINT;
Willy Tarreau21b069d2016-11-23 17:15:08 +01003664 return NULL;
3665 }
3666
3667 if (px->state == PR_STSTOPPED) {
3668 appctx->ctx.cli.msg = "Proxy is disabled.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003669 appctx->st0 = CLI_ST_PRINT;
Willy Tarreau21b069d2016-11-23 17:15:08 +01003670 return NULL;
3671 }
3672
3673 return sv;
3674}
3675
William Lallemand222baf22016-11-19 02:00:33 +01003676
3677static int cli_parse_set_server(char **args, struct appctx *appctx, void *private)
3678{
3679 struct server *sv;
3680 const char *warning;
3681
3682 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3683 return 1;
3684
3685 sv = cli_find_server(appctx, args[2]);
3686 if (!sv)
3687 return 1;
3688
3689 if (strcmp(args[3], "weight") == 0) {
3690 warning = server_parse_weight_change_request(sv, args[4]);
3691 if (warning) {
3692 appctx->ctx.cli.msg = warning;
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003693 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003694 }
3695 }
3696 else if (strcmp(args[3], "state") == 0) {
3697 if (strcmp(args[4], "ready") == 0)
3698 srv_adm_set_ready(sv);
3699 else if (strcmp(args[4], "drain") == 0)
3700 srv_adm_set_drain(sv);
3701 else if (strcmp(args[4], "maint") == 0)
3702 srv_adm_set_maint(sv);
3703 else {
3704 appctx->ctx.cli.msg = "'set server <srv> state' expects 'ready', 'drain' and 'maint'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003705 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003706 }
3707 }
3708 else if (strcmp(args[3], "health") == 0) {
3709 if (sv->track) {
3710 appctx->ctx.cli.msg = "cannot change health on a tracking server.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003711 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003712 }
3713 else if (strcmp(args[4], "up") == 0) {
3714 sv->check.health = sv->check.rise + sv->check.fall - 1;
3715 srv_set_running(sv, "changed from CLI");
3716 }
3717 else if (strcmp(args[4], "stopping") == 0) {
3718 sv->check.health = sv->check.rise + sv->check.fall - 1;
3719 srv_set_stopping(sv, "changed from CLI");
3720 }
3721 else if (strcmp(args[4], "down") == 0) {
3722 sv->check.health = 0;
3723 srv_set_stopped(sv, "changed from CLI");
3724 }
3725 else {
3726 appctx->ctx.cli.msg = "'set server <srv> health' expects 'up', 'stopping', or 'down'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003727 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003728 }
3729 }
3730 else if (strcmp(args[3], "agent") == 0) {
3731 if (!(sv->agent.state & CHK_ST_ENABLED)) {
3732 appctx->ctx.cli.msg = "agent checks are not enabled on this server.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003733 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003734 }
3735 else if (strcmp(args[4], "up") == 0) {
3736 sv->agent.health = sv->agent.rise + sv->agent.fall - 1;
3737 srv_set_running(sv, "changed from CLI");
3738 }
3739 else if (strcmp(args[4], "down") == 0) {
3740 sv->agent.health = 0;
3741 srv_set_stopped(sv, "changed from CLI");
3742 }
3743 else {
3744 appctx->ctx.cli.msg = "'set server <srv> agent' expects 'up' or 'down'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003745 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003746 }
3747 }
Misiek2da082d2017-01-09 09:40:42 +01003748 else if (strcmp(args[3], "agent-addr") == 0) {
3749 if (!(sv->agent.state & CHK_ST_ENABLED)) {
3750 appctx->ctx.cli.msg = "agent checks are not enabled on this server.\n";
3751 appctx->st0 = CLI_ST_PRINT;
3752 } else {
3753 if (str2ip(args[4], &sv->agent.addr) == NULL) {
3754 appctx->ctx.cli.msg = "incorrect addr address given for agent.\n";
3755 appctx->st0 = CLI_ST_PRINT;
3756 }
3757 }
3758 }
3759 else if (strcmp(args[3], "agent-send") == 0) {
3760 if (!(sv->agent.state & CHK_ST_ENABLED)) {
3761 appctx->ctx.cli.msg = "agent checks are not enabled on this server.\n";
3762 appctx->st0 = CLI_ST_PRINT;
3763 } else {
3764 char *nss = strdup(args[4]);
3765 if (!nss) {
3766 appctx->ctx.cli.msg = "cannot allocate memory for new string.\n";
3767 appctx->st0 = CLI_ST_PRINT;
3768 } else {
3769 free(sv->agent.send_string);
3770 sv->agent.send_string = nss;
3771 sv->agent.send_string_len = strlen(args[4]);
3772 }
3773 }
3774 }
William Lallemand222baf22016-11-19 02:00:33 +01003775 else if (strcmp(args[3], "check-port") == 0) {
3776 int i = 0;
3777 if (strl2irc(args[4], strlen(args[4]), &i) != 0) {
3778 appctx->ctx.cli.msg = "'set server <srv> check-port' expects an integer as argument.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003779 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003780 }
3781 if ((i < 0) || (i > 65535)) {
3782 appctx->ctx.cli.msg = "provided port is not valid.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003783 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003784 }
3785 /* prevent the update of port to 0 if MAPPORTS are in use */
3786 if ((sv->flags & SRV_F_MAPPORTS) && (i == 0)) {
3787 appctx->ctx.cli.msg = "can't unset 'port' since MAPPORTS is in use.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003788 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003789 return 1;
3790 }
3791 sv->check.port = i;
3792 appctx->ctx.cli.msg = "health check port updated.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003793 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003794 }
3795 else if (strcmp(args[3], "addr") == 0) {
3796 char *addr = NULL;
3797 char *port = NULL;
3798 if (strlen(args[4]) == 0) {
3799 appctx->ctx.cli.msg = "set server <b>/<s> addr requires an address and optionally a port.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003800 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003801 return 1;
3802 }
3803 else {
3804 addr = args[4];
3805 }
3806 if (strcmp(args[5], "port") == 0) {
3807 port = args[6];
3808 }
3809 warning = update_server_addr_port(sv, addr, port, "stats socket command");
3810 if (warning) {
3811 appctx->ctx.cli.msg = warning;
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003812 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003813 }
3814 srv_clr_admin_flag(sv, SRV_ADMF_RMAINT);
3815 }
3816 else {
3817 appctx->ctx.cli.msg = "'set server <srv>' only supports 'agent', 'health', 'state', 'weight', 'addr' and 'check-port'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003818 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003819 }
3820 return 1;
3821}
3822
William Lallemand6b160942016-11-22 12:34:35 +01003823static int cli_parse_get_weight(char **args, struct appctx *appctx, void *private)
3824{
3825 struct stream_interface *si = appctx->owner;
3826 struct proxy *px;
3827 struct server *sv;
3828 char *line;
3829
3830
3831 /* split "backend/server" and make <line> point to server */
3832 for (line = args[2]; *line; line++)
3833 if (*line == '/') {
3834 *line++ = '\0';
3835 break;
3836 }
3837
3838 if (!*line) {
3839 appctx->ctx.cli.msg = "Require 'backend/server'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003840 appctx->st0 = CLI_ST_PRINT;
William Lallemand6b160942016-11-22 12:34:35 +01003841 return 1;
3842 }
3843
3844 if (!get_backend_server(args[2], line, &px, &sv)) {
3845 appctx->ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003846 appctx->st0 = CLI_ST_PRINT;
William Lallemand6b160942016-11-22 12:34:35 +01003847 return 1;
3848 }
3849
3850 /* return server's effective weight at the moment */
3851 snprintf(trash.str, trash.size, "%d (initial %d)\n", sv->uweight, sv->iweight);
Christopher Faulet90b5abe2016-12-05 14:25:08 +01003852 if (bi_putstr(si_ic(si), trash.str) == -1) {
William Lallemand6b160942016-11-22 12:34:35 +01003853 si_applet_cant_put(si);
Christopher Faulet90b5abe2016-12-05 14:25:08 +01003854 return 0;
3855 }
William Lallemand6b160942016-11-22 12:34:35 +01003856 return 1;
3857}
3858
3859static int cli_parse_set_weight(char **args, struct appctx *appctx, void *private)
3860{
3861 struct server *sv;
3862 const char *warning;
3863
3864 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3865 return 1;
3866
3867 sv = cli_find_server(appctx, args[2]);
3868 if (!sv)
3869 return 1;
3870
3871 warning = server_parse_weight_change_request(sv, args[3]);
3872 if (warning) {
3873 appctx->ctx.cli.msg = warning;
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003874 appctx->st0 = CLI_ST_PRINT;
William Lallemand6b160942016-11-22 12:34:35 +01003875 }
3876 return 1;
3877}
3878
Willy Tarreaub8026272016-11-23 11:26:56 +01003879/* parse a "set maxconn server" command. It always returns 1. */
3880static int cli_parse_set_maxconn_server(char **args, struct appctx *appctx, void *private)
3881{
3882 struct server *sv;
3883 const char *warning;
3884
3885 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3886 return 1;
3887
3888 sv = cli_find_server(appctx, args[3]);
3889 if (!sv)
3890 return 1;
3891
3892 warning = server_parse_maxconn_change_request(sv, args[4]);
3893 if (warning) {
3894 appctx->ctx.cli.msg = warning;
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003895 appctx->st0 = CLI_ST_PRINT;
Willy Tarreaub8026272016-11-23 11:26:56 +01003896 }
3897 return 1;
3898}
William Lallemand6b160942016-11-22 12:34:35 +01003899
Willy Tarreau58d9cb72016-11-24 12:56:01 +01003900/* parse a "disable agent" command. It always returns 1. */
3901static int cli_parse_disable_agent(char **args, struct appctx *appctx, void *private)
3902{
3903 struct server *sv;
3904
3905 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3906 return 1;
3907
3908 sv = cli_find_server(appctx, args[2]);
3909 if (!sv)
3910 return 1;
3911
3912 sv->agent.state &= ~CHK_ST_ENABLED;
3913 return 1;
3914}
3915
Willy Tarreau2c04eda2016-11-24 12:51:04 +01003916/* parse a "disable health" command. It always returns 1. */
3917static int cli_parse_disable_health(char **args, struct appctx *appctx, void *private)
3918{
3919 struct server *sv;
3920
3921 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3922 return 1;
3923
3924 sv = cli_find_server(appctx, args[2]);
3925 if (!sv)
3926 return 1;
3927
3928 sv->check.state &= ~CHK_ST_ENABLED;
3929 return 1;
3930}
3931
Willy Tarreauffb4d582016-11-24 12:47:00 +01003932/* parse a "disable server" command. It always returns 1. */
3933static int cli_parse_disable_server(char **args, struct appctx *appctx, void *private)
3934{
3935 struct server *sv;
3936
3937 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3938 return 1;
3939
3940 sv = cli_find_server(appctx, args[2]);
3941 if (!sv)
3942 return 1;
3943
3944 srv_adm_set_maint(sv);
3945 return 1;
3946}
3947
Willy Tarreau58d9cb72016-11-24 12:56:01 +01003948/* parse a "enable agent" command. It always returns 1. */
3949static int cli_parse_enable_agent(char **args, struct appctx *appctx, void *private)
3950{
3951 struct server *sv;
3952
3953 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3954 return 1;
3955
3956 sv = cli_find_server(appctx, args[2]);
3957 if (!sv)
3958 return 1;
3959
3960 if (!(sv->agent.state & CHK_ST_CONFIGURED)) {
3961 appctx->ctx.cli.msg = "Agent was not configured on this server, cannot enable.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003962 appctx->st0 = CLI_ST_PRINT;
Willy Tarreau58d9cb72016-11-24 12:56:01 +01003963 return 1;
3964 }
3965
3966 sv->agent.state |= CHK_ST_ENABLED;
3967 return 1;
3968}
3969
Willy Tarreau2c04eda2016-11-24 12:51:04 +01003970/* parse a "enable health" command. It always returns 1. */
3971static int cli_parse_enable_health(char **args, struct appctx *appctx, void *private)
3972{
3973 struct server *sv;
3974
3975 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3976 return 1;
3977
3978 sv = cli_find_server(appctx, args[2]);
3979 if (!sv)
3980 return 1;
3981
3982 sv->check.state |= CHK_ST_ENABLED;
3983 return 1;
3984}
3985
Willy Tarreauffb4d582016-11-24 12:47:00 +01003986/* parse a "enable server" command. It always returns 1. */
3987static int cli_parse_enable_server(char **args, struct appctx *appctx, void *private)
3988{
3989 struct server *sv;
3990
3991 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3992 return 1;
3993
3994 sv = cli_find_server(appctx, args[2]);
3995 if (!sv)
3996 return 1;
3997
3998 srv_adm_set_ready(sv);
3999 return 1;
4000}
4001
William Lallemand222baf22016-11-19 02:00:33 +01004002/* register cli keywords */
4003static struct cli_kw_list cli_kws = {{ },{
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004004 { { "disable", "agent", NULL }, "disable agent : disable agent checks (use 'set server' instead)", cli_parse_disable_agent, NULL },
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004005 { { "disable", "health", NULL }, "disable health : disable health checks (use 'set server' instead)", cli_parse_disable_health, NULL },
Willy Tarreauffb4d582016-11-24 12:47:00 +01004006 { { "disable", "server", NULL }, "disable server : disable a server for maintenance (use 'set server' instead)", cli_parse_disable_server, NULL },
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004007 { { "enable", "agent", NULL }, "enable agent : enable agent checks (use 'set server' instead)", cli_parse_enable_agent, NULL },
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004008 { { "enable", "health", NULL }, "enable health : enable health checks (use 'set server' instead)", cli_parse_enable_health, NULL },
Willy Tarreauffb4d582016-11-24 12:47:00 +01004009 { { "enable", "server", NULL }, "enable server : enable a disabled server (use 'set server' instead)", cli_parse_enable_server, NULL },
Willy Tarreaub8026272016-11-23 11:26:56 +01004010 { { "set", "maxconn", "server", NULL }, "set maxconn server : change a server's maxconn setting", cli_parse_set_maxconn_server, NULL },
William Lallemand222baf22016-11-19 02:00:33 +01004011 { { "set", "server", NULL }, "set server : change a server's state, weight or address", cli_parse_set_server },
William Lallemand6b160942016-11-22 12:34:35 +01004012 { { "get", "weight", NULL }, "get weight : report a server's current weight", cli_parse_get_weight },
4013 { { "set", "weight", NULL }, "set weight : change a server's weight (deprecated)", cli_parse_set_weight },
4014
William Lallemand222baf22016-11-19 02:00:33 +01004015 {{},}
4016}};
4017
4018__attribute__((constructor))
4019static void __server_init(void)
4020{
4021 cli_register_kw(&cli_kws);
4022}
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01004023
Baptiste Assmanna68ca962015-04-14 01:15:08 +02004024/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02004025 * Local variables:
4026 * c-indent-level: 8
4027 * c-basic-offset: 8
4028 * End:
4029 */