blob: 721de33bc55b39879bae3263d7db179fcb43005b [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>
Willy Tarreau272adea2014-03-31 10:39:59 +020016
Olivier Houchard4e694042017-03-14 20:01:29 +010017#include <import/xxhash.h>
18
Willy Tarreau272adea2014-03-31 10:39:59 +020019#include <common/cfgparse.h>
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020020#include <common/config.h>
Willy Tarreaudff55432012-10-10 17:51:05 +020021#include <common/errors.h>
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +010022#include <common/namespace.h>
Krzysztof Oledzki85130942007-10-22 16:21:10 +020023#include <common/time.h>
24
William Lallemand222baf22016-11-19 02:00:33 +010025#include <types/applet.h>
26#include <types/cli.h>
Willy Tarreau272adea2014-03-31 10:39:59 +020027#include <types/global.h>
Willy Tarreau21b069d2016-11-23 17:15:08 +010028#include <types/cli.h>
Baptiste Assmanna68ca962015-04-14 01:15:08 +020029#include <types/dns.h>
William Lallemand222baf22016-11-19 02:00:33 +010030#include <types/stats.h>
Willy Tarreau272adea2014-03-31 10:39:59 +020031
William Lallemand222baf22016-11-19 02:00:33 +010032#include <proto/applet.h>
33#include <proto/cli.h>
Simon Hormanb1900d52015-01-30 11:22:54 +090034#include <proto/checks.h>
Willy Tarreau272adea2014-03-31 10:39:59 +020035#include <proto/port_range.h>
36#include <proto/protocol.h>
Willy Tarreau4aac7db2014-05-16 11:48:10 +020037#include <proto/queue.h>
Frédéric Lécaille9a146de2017-03-20 14:54:41 +010038#include <proto/sample.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>
David Carlier6f182082017-04-03 21:58:04 +010045#include <netinet/tcp.h>
Willy Tarreau4aac7db2014-05-16 11:48:10 +020046
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +020047static void srv_update_state(struct server *srv, int version, char **params);
Baptiste Assmann83cbaa52016-11-02 15:34:05 +010048static int srv_apply_lastaddr(struct server *srv, int *err_code);
Willy Tarreaubaaee002006-06-26 02:48:02 +020049
Michal Idzikowski266b1a82017-03-27 14:45:49 +020050const char *server_propagate_weight_change_request(struct server *sv,
51 const char *weight_str);
52
Willy Tarreau21faa912012-10-10 08:27:36 +020053/* List head of all known server keywords */
54static struct srv_kw_list srv_keywords = {
55 .list = LIST_HEAD_INIT(srv_keywords.list)
56};
Krzysztof Oledzki85130942007-10-22 16:21:10 +020057
Simon Hormana3608442013-11-01 16:46:15 +090058int srv_downtime(const struct server *s)
Willy Tarreau21faa912012-10-10 08:27:36 +020059{
Willy Tarreau892337c2014-05-13 23:41:20 +020060 if ((s->state != SRV_ST_STOPPED) && s->last_change < now.tv_sec) // ignore negative time
Krzysztof Oledzki85130942007-10-22 16:21:10 +020061 return s->down_time;
62
63 return now.tv_sec - s->last_change + s->down_time;
64}
Willy Tarreaubaaee002006-06-26 02:48:02 +020065
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -050066int srv_lastsession(const struct server *s)
67{
68 if (s->counters.last_sess)
69 return now.tv_sec - s->counters.last_sess;
70
71 return -1;
72}
73
Simon Horman4a741432013-02-23 15:35:38 +090074int srv_getinter(const struct check *check)
Willy Tarreau21faa912012-10-10 08:27:36 +020075{
Simon Horman4a741432013-02-23 15:35:38 +090076 const struct server *s = check->server;
77
Willy Tarreauff5ae352013-12-11 20:36:34 +010078 if ((check->state & CHK_ST_CONFIGURED) && (check->health == check->rise + check->fall - 1))
Simon Horman4a741432013-02-23 15:35:38 +090079 return check->inter;
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +010080
Willy Tarreau892337c2014-05-13 23:41:20 +020081 if ((s->state == SRV_ST_STOPPED) && check->health == 0)
Simon Horman4a741432013-02-23 15:35:38 +090082 return (check->downinter)?(check->downinter):(check->inter);
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +010083
Simon Horman4a741432013-02-23 15:35:38 +090084 return (check->fastinter)?(check->fastinter):(check->inter);
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +010085}
86
Olivier Houchard4e694042017-03-14 20:01:29 +010087void srv_set_dyncookie(struct server *s)
88{
89 struct proxy *p = s->proxy;
90 struct server *tmpserv;
91 char *tmpbuf;
92 unsigned long long hash_value;
Olivier Houchard2cb49eb2017-03-15 15:11:06 +010093 size_t key_len;
Olivier Houchard4e694042017-03-14 20:01:29 +010094 size_t buffer_len;
95 int addr_len;
96 int port;
97
98 if ((s->flags & SRV_F_COOKIESET) ||
99 !(s->proxy->ck_opts & PR_CK_DYNAMIC) ||
100 s->proxy->dyncookie_key == NULL)
101 return;
Olivier Houchard2cb49eb2017-03-15 15:11:06 +0100102 key_len = strlen(p->dyncookie_key);
Olivier Houchard4e694042017-03-14 20:01:29 +0100103
104 if (s->addr.ss_family != AF_INET &&
105 s->addr.ss_family != AF_INET6)
106 return;
107 /*
108 * Buffer to calculate the cookie value.
109 * The buffer contains the secret key + the server IP address
110 * + the TCP port.
111 */
112 addr_len = (s->addr.ss_family == AF_INET) ? 4 : 16;
113 /*
114 * The TCP port should use only 2 bytes, but is stored in
115 * an unsigned int in struct server, so let's use 4, to be
116 * on the safe side.
117 */
118 buffer_len = key_len + addr_len + 4;
119 tmpbuf = trash.str;
120 memcpy(tmpbuf, p->dyncookie_key, key_len);
121 memcpy(&(tmpbuf[key_len]),
122 s->addr.ss_family == AF_INET ?
123 (void *)&((struct sockaddr_in *)&s->addr)->sin_addr.s_addr :
124 (void *)&(((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr),
125 addr_len);
126 /*
127 * Make sure it's the same across all the load balancers,
128 * no matter their endianness.
129 */
130 port = htonl(s->svc_port);
131 memcpy(&tmpbuf[key_len + addr_len], &port, 4);
132 hash_value = XXH64(tmpbuf, buffer_len, 0);
133 memprintf(&s->cookie, "%016llx", hash_value);
134 if (!s->cookie)
135 return;
136 s->cklen = 16;
137 /*
138 * Check that we did not get a hash collision.
139 * Unlikely, but it can happen.
140 */
Olivier Houchardb4a2d5e2017-04-04 22:10:36 +0200141 for (tmpserv = p->srv; tmpserv != NULL;
142 tmpserv = tmpserv->next) {
143 if (tmpserv == s)
144 continue;
145 if (tmpserv->cookie &&
146 strcmp(tmpserv->cookie, s->cookie) == 0) {
147 Warning("We generated two equal cookies for two different servers.\n"
148 "Please change the secret key for '%s'.\n",
149 s->proxy->id);
Olivier Houchard4e694042017-03-14 20:01:29 +0100150 }
Olivier Houchardb4a2d5e2017-04-04 22:10:36 +0200151 }
Olivier Houchard4e694042017-03-14 20:01:29 +0100152}
153
Willy Tarreau21faa912012-10-10 08:27:36 +0200154/*
155 * Registers the server keyword list <kwl> as a list of valid keywords for next
156 * parsing sessions.
157 */
158void srv_register_keywords(struct srv_kw_list *kwl)
159{
160 LIST_ADDQ(&srv_keywords.list, &kwl->list);
161}
162
163/* Return a pointer to the server keyword <kw>, or NULL if not found. If the
164 * keyword is found with a NULL ->parse() function, then an attempt is made to
165 * find one with a valid ->parse() function. This way it is possible to declare
166 * platform-dependant, known keywords as NULL, then only declare them as valid
167 * if some options are met. Note that if the requested keyword contains an
168 * opening parenthesis, everything from this point is ignored.
169 */
170struct srv_kw *srv_find_kw(const char *kw)
171{
172 int index;
173 const char *kwend;
174 struct srv_kw_list *kwl;
175 struct srv_kw *ret = NULL;
176
177 kwend = strchr(kw, '(');
178 if (!kwend)
179 kwend = kw + strlen(kw);
180
181 list_for_each_entry(kwl, &srv_keywords.list, list) {
182 for (index = 0; kwl->kw[index].kw != NULL; index++) {
183 if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
184 kwl->kw[index].kw[kwend-kw] == 0) {
185 if (kwl->kw[index].parse)
186 return &kwl->kw[index]; /* found it !*/
187 else
188 ret = &kwl->kw[index]; /* may be OK */
189 }
190 }
191 }
192 return ret;
193}
194
195/* Dumps all registered "server" keywords to the <out> string pointer. The
196 * unsupported keywords are only dumped if their supported form was not
197 * found.
198 */
199void srv_dump_kws(char **out)
200{
201 struct srv_kw_list *kwl;
202 int index;
203
204 *out = NULL;
205 list_for_each_entry(kwl, &srv_keywords.list, list) {
206 for (index = 0; kwl->kw[index].kw != NULL; index++) {
207 if (kwl->kw[index].parse ||
208 srv_find_kw(kwl->kw[index].kw) == &kwl->kw[index]) {
209 memprintf(out, "%s[%4s] %s%s%s%s\n", *out ? *out : "",
210 kwl->scope,
211 kwl->kw[index].kw,
212 kwl->kw[index].skip ? " <arg>" : "",
213 kwl->kw[index].default_ok ? " [dflt_ok]" : "",
214 kwl->kw[index].parse ? "" : " (not supported)");
215 }
216 }
217 }
218}
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100219
Frédéric Lécaille6e5e0d82017-03-20 16:30:18 +0100220/* Parse the "addr" server keyword */
221static int srv_parse_addr(char **args, int *cur_arg,
222 struct proxy *curproxy, struct server *newsrv, char **err)
223{
224 char *errmsg, *arg;
225 struct sockaddr_storage *sk;
226 int port1, port2;
227 struct protocol *proto;
228
229 errmsg = NULL;
230 arg = args[*cur_arg + 1];
231
232 if (!*arg) {
233 memprintf(err, "'%s' expects <ipv4|ipv6> as argument.\n", args[*cur_arg]);
234 goto err;
235 }
236
237 sk = str2sa_range(arg, NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
238 if (!sk) {
239 memprintf(err, "'%s' : %s", args[*cur_arg], errmsg);
240 goto err;
241 }
242
243 proto = protocol_by_family(sk->ss_family);
244 if (!proto || !proto->connect) {
245 memprintf(err, "'%s %s' : connect() not supported for this address family.\n",
246 args[*cur_arg], arg);
247 goto err;
248 }
249
250 if (port1 != port2) {
251 memprintf(err, "'%s' : port ranges and offsets are not allowed in '%s'\n",
252 args[*cur_arg], arg);
253 goto err;
254 }
255
256 newsrv->check.addr = newsrv->agent.addr = *sk;
257 newsrv->flags |= SRV_F_CHECKADDR;
258 newsrv->flags |= SRV_F_AGENTADDR;
259
260 return 0;
261
262 err:
263 free(errmsg);
264 return ERR_ALERT | ERR_FATAL;
265}
266
Frédéric Lécaille6e0843c2017-03-21 16:39:15 +0100267/* Parse the "agent-check" server keyword */
268static int srv_parse_agent_check(char **args, int *cur_arg,
269 struct proxy *curproxy, struct server *newsrv, char **err)
270{
271 newsrv->do_agent = 1;
272 return 0;
273}
274
Frédéric Lécaillef5bf9032017-03-10 11:51:05 +0100275/* Parse the "backup" server keyword */
276static int srv_parse_backup(char **args, int *cur_arg,
277 struct proxy *curproxy, struct server *newsrv, char **err)
278{
279 newsrv->flags |= SRV_F_BACKUP;
280 return 0;
281}
282
Frédéric Lécaille65aa3562017-03-14 11:20:13 +0100283/* Parse the "check" server keyword */
284static int srv_parse_check(char **args, int *cur_arg,
285 struct proxy *curproxy, struct server *newsrv, char **err)
286{
287 newsrv->do_check = 1;
288 return 0;
289}
290
Frédéric Lécaille25df8902017-03-10 14:04:31 +0100291/* Parse the "check-send-proxy" server keyword */
292static int srv_parse_check_send_proxy(char **args, int *cur_arg,
293 struct proxy *curproxy, struct server *newsrv, char **err)
294{
295 newsrv->check.send_proxy = 1;
296 return 0;
297}
298
Frédéric Lécaille9d1b95b2017-03-15 09:13:33 +0100299/* Parse the "cookie" server keyword */
300static int srv_parse_cookie(char **args, int *cur_arg,
301 struct proxy *curproxy, struct server *newsrv, char **err)
302{
303 char *arg;
304
305 arg = args[*cur_arg + 1];
306 if (!*arg) {
307 memprintf(err, "'%s' expects <value> as argument.\n", args[*cur_arg]);
308 return ERR_ALERT | ERR_FATAL;
309 }
310
311 free(newsrv->cookie);
312 newsrv->cookie = strdup(arg);
313 newsrv->cklen = strlen(arg);
314 newsrv->flags |= SRV_F_COOKIESET;
315 return 0;
316}
317
Frédéric Lécaille2a0d0612017-03-21 11:53:54 +0100318/* Parse the "disabled" server keyword */
319static int srv_parse_disabled(char **args, int *cur_arg,
320 struct proxy *curproxy, struct server *newsrv, char **err)
321{
322 newsrv->admin |= SRV_ADMF_CMAINT | SRV_ADMF_FMAINT;
323 newsrv->state = SRV_ST_STOPPED;
324 newsrv->check.state |= CHK_ST_PAUSED;
325 newsrv->check.health = 0;
326 return 0;
327}
328
329/* Parse the "enabled" server keyword */
330static int srv_parse_enabled(char **args, int *cur_arg,
331 struct proxy *curproxy, struct server *newsrv, char **err)
332{
333 newsrv->admin &= ~SRV_ADMF_CMAINT & ~SRV_ADMF_FMAINT;
334 newsrv->state = SRV_ST_RUNNING;
335 newsrv->check.state &= ~CHK_ST_PAUSED;
336 newsrv->check.health = newsrv->check.rise;
337 return 0;
338}
339
Willy Tarreaudff55432012-10-10 17:51:05 +0200340/* parse the "id" server keyword */
341static int srv_parse_id(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
342{
343 struct eb32_node *node;
344
345 if (!*args[*cur_arg + 1]) {
346 memprintf(err, "'%s' : expects an integer argument", args[*cur_arg]);
347 return ERR_ALERT | ERR_FATAL;
348 }
349
350 newsrv->puid = atol(args[*cur_arg + 1]);
351 newsrv->conf.id.key = newsrv->puid;
352
353 if (newsrv->puid <= 0) {
354 memprintf(err, "'%s' : custom id has to be > 0", args[*cur_arg]);
355 return ERR_ALERT | ERR_FATAL;
356 }
357
358 node = eb32_lookup(&curproxy->conf.used_server_id, newsrv->puid);
359 if (node) {
360 struct server *target = container_of(node, struct server, conf.id);
361 memprintf(err, "'%s' : custom id %d already used at %s:%d ('server %s')",
362 args[*cur_arg], newsrv->puid, target->conf.file, target->conf.line,
363 target->id);
364 return ERR_ALERT | ERR_FATAL;
365 }
366
367 eb32_insert(&curproxy->conf.used_server_id, &newsrv->conf.id);
Baptiste Assmann7cc419a2015-07-07 22:02:20 +0200368 newsrv->flags |= SRV_F_FORCED_ID;
Willy Tarreaudff55432012-10-10 17:51:05 +0200369 return 0;
370}
371
Frédéric Lécaille22f41a22017-03-16 17:17:36 +0100372/* Parse the "namespace" server keyword */
373static int srv_parse_namespace(char **args, int *cur_arg,
374 struct proxy *curproxy, struct server *newsrv, char **err)
375{
376#ifdef CONFIG_HAP_NS
377 char *arg;
378
379 arg = args[*cur_arg + 1];
380 if (!*arg) {
381 memprintf(err, "'%s' : expects <name> as argument", args[*cur_arg]);
382 return ERR_ALERT | ERR_FATAL;
383 }
384
385 if (!strcmp(arg, "*")) {
386 /* Use the namespace associated with the connection (if present). */
387 newsrv->flags |= SRV_F_USE_NS_FROM_PP;
388 return 0;
389 }
390
391 /*
392 * As this parser may be called several times for the same 'default-server'
393 * object, or for a new 'server' instance deriving from a 'default-server'
394 * one with SRV_F_USE_NS_FROM_PP flag enabled, let's reset it.
395 */
396 newsrv->flags &= ~SRV_F_USE_NS_FROM_PP;
397
398 newsrv->netns = netns_store_lookup(arg, strlen(arg));
399 if (!newsrv->netns)
400 newsrv->netns = netns_store_insert(arg);
401
402 if (!newsrv->netns) {
403 memprintf(err, "Cannot open namespace '%s'", arg);
404 return ERR_ALERT | ERR_FATAL;
405 }
406
407 return 0;
408#else
409 memprintf(err, "'%s': '%s' option not implemented", args[0], args[*cur_arg]);
410 return ERR_ALERT | ERR_FATAL;
411#endif
412}
413
Frédéric Lécaille6e0843c2017-03-21 16:39:15 +0100414/* Parse the "no-agent-check" server keyword */
415static int srv_parse_no_agent_check(char **args, int *cur_arg,
416 struct proxy *curproxy, struct server *newsrv, char **err)
417{
418 free_check(&newsrv->agent);
419 newsrv->agent.inter = 0;
420 newsrv->agent.port = 0;
421 newsrv->agent.state &= ~CHK_ST_CONFIGURED & ~CHK_ST_ENABLED & ~CHK_ST_AGENT;
422 newsrv->do_agent = 0;
423 return 0;
424}
425
Frédéric Lécaillef5bf9032017-03-10 11:51:05 +0100426/* Parse the "no-backup" server keyword */
427static int srv_parse_no_backup(char **args, int *cur_arg,
428 struct proxy *curproxy, struct server *newsrv, char **err)
429{
430 newsrv->flags &= ~SRV_F_BACKUP;
431 return 0;
432}
433
Frédéric Lécaille65aa3562017-03-14 11:20:13 +0100434/* Parse the "no-check" server keyword */
435static int srv_parse_no_check(char **args, int *cur_arg,
436 struct proxy *curproxy, struct server *newsrv, char **err)
437{
438 free_check(&newsrv->check);
439 newsrv->check.state &= ~CHK_ST_CONFIGURED & ~CHK_ST_ENABLED;
440 newsrv->do_check = 0;
441 return 0;
442}
443
Frédéric Lécaille25df8902017-03-10 14:04:31 +0100444/* Parse the "no-check-send-proxy" server keyword */
445static int srv_parse_no_check_send_proxy(char **args, int *cur_arg,
446 struct proxy *curproxy, struct server *newsrv, char **err)
447{
448 newsrv->check.send_proxy = 0;
449 return 0;
450}
451
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100452/* Disable server PROXY protocol flags. */
453static int inline srv_disable_pp_flags(struct server *srv, unsigned int flags)
454{
455 srv->pp_opts &= ~flags;
456 return 0;
457}
458
459/* Parse the "no-send-proxy" server keyword */
460static int srv_parse_no_send_proxy(char **args, int *cur_arg,
461 struct proxy *curproxy, struct server *newsrv, char **err)
462{
463 return srv_disable_pp_flags(newsrv, SRV_PP_V1);
464}
465
466/* Parse the "no-send-proxy-v2" server keyword */
467static int srv_parse_no_send_proxy_v2(char **args, int *cur_arg,
468 struct proxy *curproxy, struct server *newsrv, char **err)
469{
470 return srv_disable_pp_flags(newsrv, SRV_PP_V2);
471}
472
Frédéric Lécaillef9bc1d62017-03-10 15:50:49 +0100473/* Parse the "non-stick" server keyword */
474static int srv_parse_non_stick(char **args, int *cur_arg,
475 struct proxy *curproxy, struct server *newsrv, char **err)
476{
477 newsrv->flags |= SRV_F_NON_STICK;
478 return 0;
479}
480
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100481/* Enable server PROXY protocol flags. */
482static int inline srv_enable_pp_flags(struct server *srv, unsigned int flags)
483{
484 srv->pp_opts |= flags;
485 return 0;
486}
487
Frédéric Lécaille547356e2017-03-15 08:55:39 +0100488/* Parse the "observe" server keyword */
489static int srv_parse_observe(char **args, int *cur_arg,
490 struct proxy *curproxy, struct server *newsrv, char **err)
491{
492 char *arg;
493
494 arg = args[*cur_arg + 1];
495 if (!*arg) {
496 memprintf(err, "'%s' expects <mode> as argument.\n", args[*cur_arg]);
497 return ERR_ALERT | ERR_FATAL;
498 }
499
500 if (!strcmp(arg, "none")) {
501 newsrv->observe = HANA_OBS_NONE;
502 }
503 else if (!strcmp(arg, "layer4")) {
504 newsrv->observe = HANA_OBS_LAYER4;
505 }
506 else if (!strcmp(arg, "layer7")) {
507 if (curproxy->mode != PR_MODE_HTTP) {
508 memprintf(err, "'%s' can only be used in http proxies.\n", arg);
509 return ERR_ALERT;
510 }
511 newsrv->observe = HANA_OBS_LAYER7;
512 }
513 else {
514 memprintf(err, "'%s' expects one of 'none', 'layer4', 'layer7' "
515 "but got '%s'\n", args[*cur_arg], arg);
516 return ERR_ALERT | ERR_FATAL;
517 }
518
519 return 0;
520}
521
Frédéric Lécaille16186232017-03-14 16:42:49 +0100522/* Parse the "redir" server keyword */
523static int srv_parse_redir(char **args, int *cur_arg,
524 struct proxy *curproxy, struct server *newsrv, char **err)
525{
526 char *arg;
527
528 arg = args[*cur_arg + 1];
529 if (!*arg) {
530 memprintf(err, "'%s' expects <prefix> as argument.\n", args[*cur_arg]);
531 return ERR_ALERT | ERR_FATAL;
532 }
533
534 free(newsrv->rdr_pfx);
535 newsrv->rdr_pfx = strdup(arg);
536 newsrv->rdr_len = strlen(arg);
537
538 return 0;
539}
540
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100541/* Parse the "send-proxy" server keyword */
542static int srv_parse_send_proxy(char **args, int *cur_arg,
543 struct proxy *curproxy, struct server *newsrv, char **err)
544{
545 return srv_enable_pp_flags(newsrv, SRV_PP_V1);
546}
547
548/* Parse the "send-proxy-v2" server keyword */
549static int srv_parse_send_proxy_v2(char **args, int *cur_arg,
550 struct proxy *curproxy, struct server *newsrv, char **err)
551{
552 return srv_enable_pp_flags(newsrv, SRV_PP_V2);
553}
554
Frédéric Lécailledba97072017-03-17 15:33:50 +0100555
556/* Parse the "source" server keyword */
557static int srv_parse_source(char **args, int *cur_arg,
558 struct proxy *curproxy, struct server *newsrv, char **err)
559{
560 char *errmsg;
561 int port_low, port_high;
562 struct sockaddr_storage *sk;
563 struct protocol *proto;
564
565 errmsg = NULL;
566
567 if (!*args[*cur_arg + 1]) {
568 memprintf(err, "'%s' expects <addr>[:<port>[-<port>]], and optionally '%s' <addr>, "
569 "and '%s' <name> as argument.\n", args[*cur_arg], "usesrc", "interface");
570 goto err;
571 }
572
573 /* 'sk' is statically allocated (no need to be freed). */
574 sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, &errmsg, NULL, NULL, 1);
575 if (!sk) {
576 memprintf(err, "'%s %s' : %s\n", args[*cur_arg], args[*cur_arg + 1], errmsg);
577 goto err;
578 }
579
580 proto = protocol_by_family(sk->ss_family);
581 if (!proto || !proto->connect) {
582 Alert("'%s %s' : connect() not supported for this address family.\n",
583 args[*cur_arg], args[*cur_arg + 1]);
584 goto err;
585 }
586
587 newsrv->conn_src.opts |= CO_SRC_BIND;
588 newsrv->conn_src.source_addr = *sk;
589
590 if (port_low != port_high) {
591 int i;
592
593 if (!port_low || !port_high) {
594 Alert("'%s' does not support port offsets (found '%s').\n",
595 args[*cur_arg], args[*cur_arg + 1]);
596 goto err;
597 }
598
599 if (port_low <= 0 || port_low > 65535 ||
600 port_high <= 0 || port_high > 65535 ||
601 port_low > port_high) {
602 Alert("'%s': invalid source port range %d-%d.\n", args[*cur_arg], port_low, port_high);
603 goto err;
604 }
605 newsrv->conn_src.sport_range = port_range_alloc_range(port_high - port_low + 1);
606 for (i = 0; i < newsrv->conn_src.sport_range->size; i++)
607 newsrv->conn_src.sport_range->ports[i] = port_low + i;
608 }
609
610 *cur_arg += 2;
611 while (*(args[*cur_arg])) {
612 if (!strcmp(args[*cur_arg], "usesrc")) { /* address to use outside */
613#if defined(CONFIG_HAP_TRANSPARENT)
614 if (!*args[*cur_arg + 1]) {
615 Alert("'usesrc' expects <addr>[:<port>], 'client', 'clientip', "
616 "or 'hdr_ip(name,#)' as argument.\n");
617 goto err;
618 }
619 if (!strcmp(args[*cur_arg + 1], "client")) {
620 newsrv->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
621 newsrv->conn_src.opts |= CO_SRC_TPROXY_CLI;
622 }
623 else if (!strcmp(args[*cur_arg + 1], "clientip")) {
624 newsrv->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
625 newsrv->conn_src.opts |= CO_SRC_TPROXY_CIP;
626 }
627 else if (!strncmp(args[*cur_arg + 1], "hdr_ip(", 7)) {
628 char *name, *end;
629
630 name = args[*cur_arg + 1] + 7;
631 while (isspace(*name))
632 name++;
633
634 end = name;
635 while (*end && !isspace(*end) && *end != ',' && *end != ')')
636 end++;
637
638 newsrv->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
639 newsrv->conn_src.opts |= CO_SRC_TPROXY_DYN;
640 free(newsrv->conn_src.bind_hdr_name);
641 newsrv->conn_src.bind_hdr_name = calloc(1, end - name + 1);
642 newsrv->conn_src.bind_hdr_len = end - name;
643 memcpy(newsrv->conn_src.bind_hdr_name, name, end - name);
644 newsrv->conn_src.bind_hdr_name[end - name] = '\0';
645 newsrv->conn_src.bind_hdr_occ = -1;
646
647 /* now look for an occurrence number */
648 while (isspace(*end))
649 end++;
650 if (*end == ',') {
651 end++;
652 name = end;
653 if (*end == '-')
654 end++;
655 while (isdigit((int)*end))
656 end++;
657 newsrv->conn_src.bind_hdr_occ = strl2ic(name, end - name);
658 }
659
660 if (newsrv->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
661 Alert("usesrc hdr_ip(name,num) does not support negative"
662 " occurrences values smaller than %d.\n", MAX_HDR_HISTORY);
663 goto err;
664 }
665 }
666 else {
667 struct sockaddr_storage *sk;
668 int port1, port2;
669
670 /* 'sk' is statically allocated (no need to be freed). */
671 sk = str2sa_range(args[*cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
672 if (!sk) {
673 Alert("'%s %s' : %s\n", args[*cur_arg], args[*cur_arg + 1], errmsg);
674 goto err;
675 }
676
677 proto = protocol_by_family(sk->ss_family);
678 if (!proto || !proto->connect) {
679 Alert("'%s %s' : connect() not supported for this address family.\n",
680 args[*cur_arg], args[*cur_arg + 1]);
681 goto err;
682 }
683
684 if (port1 != port2) {
685 Alert("'%s' : port ranges and offsets are not allowed in '%s'\n",
686 args[*cur_arg], args[*cur_arg + 1]);
687 goto err;
688 }
689 newsrv->conn_src.tproxy_addr = *sk;
690 newsrv->conn_src.opts |= CO_SRC_TPROXY_ADDR;
691 }
692 global.last_checks |= LSTCHK_NETADM;
693 *cur_arg += 2;
694 continue;
695#else /* no TPROXY support */
696 Alert("'usesrc' not allowed here because support for TPROXY was not compiled in.\n");
697 goto err;
698#endif /* defined(CONFIG_HAP_TRANSPARENT) */
699 } /* "usesrc" */
700
701 if (!strcmp(args[*cur_arg], "interface")) { /* specifically bind to this interface */
702#ifdef SO_BINDTODEVICE
703 if (!*args[*cur_arg + 1]) {
704 Alert("'%s' : missing interface name.\n", args[0]);
705 goto err;
706 }
707 free(newsrv->conn_src.iface_name);
708 newsrv->conn_src.iface_name = strdup(args[*cur_arg + 1]);
709 newsrv->conn_src.iface_len = strlen(newsrv->conn_src.iface_name);
710 global.last_checks |= LSTCHK_NETADM;
711#else
712 Alert("'%s' : '%s' option not implemented.\n", args[0], args[*cur_arg]);
713 goto err;
714#endif
715 *cur_arg += 2;
716 continue;
717 }
718 /* this keyword in not an option of "source" */
719 break;
720 } /* while */
721
722 return 0;
723
724 err:
725 free(errmsg);
726 return ERR_ALERT | ERR_FATAL;
727}
728
Frédéric Lécaillef9bc1d62017-03-10 15:50:49 +0100729/* Parse the "stick" server keyword */
730static int srv_parse_stick(char **args, int *cur_arg,
731 struct proxy *curproxy, struct server *newsrv, char **err)
732{
733 newsrv->flags &= ~SRV_F_NON_STICK;
734 return 0;
735}
736
Frédéric Lécaille67e0e612017-03-14 15:21:31 +0100737/* Parse the "track" server keyword */
738static int srv_parse_track(char **args, int *cur_arg,
739 struct proxy *curproxy, struct server *newsrv, char **err)
740{
741 char *arg;
742
743 arg = args[*cur_arg + 1];
744 if (!*arg) {
745 memprintf(err, "'track' expects [<proxy>/]<server> as argument.\n");
746 return ERR_ALERT | ERR_FATAL;
747 }
748
749 free(newsrv->trackit);
750 newsrv->trackit = strdup(arg);
751
752 return 0;
753}
754
Frédéric Lécailledba97072017-03-17 15:33:50 +0100755
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200756/* Shutdown all connections of a server. The caller must pass a termination
Willy Tarreaue7dff022015-04-03 01:14:29 +0200757 * code in <why>, which must be one of SF_ERR_* indicating the reason for the
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200758 * shutdown.
759 */
Willy Tarreau87b09662015-04-03 00:22:06 +0200760void srv_shutdown_streams(struct server *srv, int why)
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200761{
Willy Tarreau87b09662015-04-03 00:22:06 +0200762 struct stream *stream, *stream_bck;
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200763
Willy Tarreau87b09662015-04-03 00:22:06 +0200764 list_for_each_entry_safe(stream, stream_bck, &srv->actconns, by_srv)
765 if (stream->srv_conn == srv)
766 stream_shutdown(stream, why);
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200767}
768
769/* Shutdown all connections of all backup servers of a proxy. The caller must
Willy Tarreaue7dff022015-04-03 01:14:29 +0200770 * pass a termination code in <why>, which must be one of SF_ERR_* indicating
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200771 * the reason for the shutdown.
772 */
Willy Tarreau87b09662015-04-03 00:22:06 +0200773void srv_shutdown_backup_streams(struct proxy *px, int why)
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200774{
775 struct server *srv;
776
777 for (srv = px->srv; srv != NULL; srv = srv->next)
778 if (srv->flags & SRV_F_BACKUP)
Willy Tarreau87b09662015-04-03 00:22:06 +0200779 srv_shutdown_streams(srv, why);
Willy Tarreau4aac7db2014-05-16 11:48:10 +0200780}
781
Willy Tarreaubda92272014-05-20 21:55:30 +0200782/* Appends some information to a message string related to a server going UP or
783 * DOWN. If both <forced> and <reason> are null and the server tracks another
784 * one, a "via" information will be provided to know where the status came from.
785 * If <reason> is non-null, the entire string will be appended after a comma and
786 * a space (eg: to report some information from the check that changed the state).
Willy Tarreau87b09662015-04-03 00:22:06 +0200787 * If <xferred> is non-negative, some information about requeued streams are
Willy Tarreaubda92272014-05-20 21:55:30 +0200788 * provided.
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200789 */
Willy Tarreaubda92272014-05-20 21:55:30 +0200790void srv_append_status(struct chunk *msg, struct server *s, const char *reason, int xferred, int forced)
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200791{
Willy Tarreaubda92272014-05-20 21:55:30 +0200792 if (reason)
793 chunk_appendf(msg, ", %s", reason);
794 else if (!forced && s->track)
795 chunk_appendf(msg, " via %s/%s", s->track->proxy->id, s->track->id);
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200796
797 if (xferred >= 0) {
798 if (s->state == SRV_ST_STOPPED)
799 chunk_appendf(msg, ". %d active and %d backup servers left.%s"
800 " %d sessions active, %d requeued, %d remaining in queue",
801 s->proxy->srv_act, s->proxy->srv_bck,
802 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
803 s->cur_sess, xferred, s->nbpend);
804 else
805 chunk_appendf(msg, ". %d active and %d backup servers online.%s"
806 " %d sessions requeued, %d total in queue",
807 s->proxy->srv_act, s->proxy->srv_bck,
808 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
809 xferred, s->nbpend);
810 }
811}
812
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200813/* Marks server <s> down, regardless of its checks' statuses, notifies by all
814 * available means, recounts the remaining servers on the proxy and transfers
Willy Tarreau87b09662015-04-03 00:22:06 +0200815 * queued streams whenever possible to other servers. It automatically
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200816 * recomputes the number of servers, but not the map. Maintenance servers are
817 * ignored. It reports <reason> if non-null as the reason for going down. Note
818 * that it makes use of the trash to build the log strings, so <reason> must
819 * not be placed there.
820 */
821void srv_set_stopped(struct server *s, const char *reason)
822{
823 struct server *srv;
824 int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
825 int srv_was_stopping = (s->state == SRV_ST_STOPPING);
Simon Horman64e34162015-02-06 11:11:57 +0900826 int log_level;
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200827 int xferred;
828
829 if ((s->admin & SRV_ADMF_MAINT) || s->state == SRV_ST_STOPPED)
830 return;
831
832 s->last_change = now.tv_sec;
833 s->state = SRV_ST_STOPPED;
834 if (s->proxy->lbprm.set_server_status_down)
835 s->proxy->lbprm.set_server_status_down(s);
836
837 if (s->onmarkeddown & HANA_ONMARKEDDOWN_SHUTDOWNSESSIONS)
Willy Tarreaue7dff022015-04-03 01:14:29 +0200838 srv_shutdown_streams(s, SF_ERR_DOWN);
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200839
Willy Tarreau87b09662015-04-03 00:22:06 +0200840 /* we might have streams queued on this server and waiting for
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200841 * a connection. Those which are redispatchable will be queued
842 * to another server or to the proxy itself.
843 */
844 xferred = pendconn_redistribute(s);
845
846 chunk_printf(&trash,
847 "%sServer %s/%s is DOWN", s->flags & SRV_F_BACKUP ? "Backup " : "",
848 s->proxy->id, s->id);
849
850 srv_append_status(&trash, s, reason, xferred, 0);
851 Warning("%s.\n", trash.str);
852
853 /* we don't send an alert if the server was previously paused */
Simon Horman64e34162015-02-06 11:11:57 +0900854 log_level = srv_was_stopping ? LOG_NOTICE : LOG_ALERT;
855 send_log(s->proxy, log_level, "%s.\n", trash.str);
856 send_email_alert(s, log_level, "%s", trash.str);
Willy Tarreaue7d1ef12014-05-20 22:25:12 +0200857
858 if (prev_srv_count && s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
859 set_backend_down(s->proxy);
860
861 s->counters.down_trans++;
862
863 for (srv = s->trackers; srv; srv = srv->tracknext)
864 srv_set_stopped(srv, NULL);
865}
866
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200867/* Marks server <s> up regardless of its checks' statuses and provided it isn't
868 * in maintenance. Notifies by all available means, recounts the remaining
869 * servers on the proxy and tries to grab requests from the proxy. It
870 * automatically recomputes the number of servers, but not the map. Maintenance
871 * servers are ignored. It reports <reason> if non-null as the reason for going
872 * up. Note that it makes use of the trash to build the log strings, so <reason>
873 * must not be placed there.
874 */
875void srv_set_running(struct server *s, const char *reason)
876{
877 struct server *srv;
878 int xferred;
879
880 if (s->admin & SRV_ADMF_MAINT)
881 return;
882
883 if (s->state == SRV_ST_STARTING || s->state == SRV_ST_RUNNING)
884 return;
885
886 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
887 if (s->proxy->last_change < now.tv_sec) // ignore negative times
888 s->proxy->down_time += now.tv_sec - s->proxy->last_change;
889 s->proxy->last_change = now.tv_sec;
890 }
891
892 if (s->state == SRV_ST_STOPPED && s->last_change < now.tv_sec) // ignore negative times
893 s->down_time += now.tv_sec - s->last_change;
894
895 s->last_change = now.tv_sec;
896
897 s->state = SRV_ST_STARTING;
898 if (s->slowstart > 0)
899 task_schedule(s->warmup, tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20))));
900 else
901 s->state = SRV_ST_RUNNING;
902
903 server_recalc_eweight(s);
904
905 /* If the server is set with "on-marked-up shutdown-backup-sessions",
906 * and it's not a backup server and its effective weight is > 0,
Willy Tarreau87b09662015-04-03 00:22:06 +0200907 * then it can accept new connections, so we shut down all streams
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200908 * on all backup servers.
909 */
910 if ((s->onmarkedup & HANA_ONMARKEDUP_SHUTDOWNBACKUPSESSIONS) &&
911 !(s->flags & SRV_F_BACKUP) && s->eweight)
Willy Tarreaue7dff022015-04-03 01:14:29 +0200912 srv_shutdown_backup_streams(s->proxy, SF_ERR_UP);
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200913
914 /* check if we can handle some connections queued at the proxy. We
915 * will take as many as we can handle.
916 */
917 xferred = pendconn_grab_from_px(s);
918
919 chunk_printf(&trash,
920 "%sServer %s/%s is UP", s->flags & SRV_F_BACKUP ? "Backup " : "",
921 s->proxy->id, s->id);
922
923 srv_append_status(&trash, s, reason, xferred, 0);
924 Warning("%s.\n", trash.str);
925 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
Simon Horman4cd477f2015-04-30 13:10:34 +0900926 send_email_alert(s, LOG_NOTICE, "%s", trash.str);
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200927
928 for (srv = s->trackers; srv; srv = srv->tracknext)
929 srv_set_running(srv, NULL);
930}
931
Willy Tarreau8eb77842014-05-21 13:54:57 +0200932/* Marks server <s> stopping regardless of its checks' statuses and provided it
933 * isn't in maintenance. Notifies by all available means, recounts the remaining
934 * servers on the proxy and tries to grab requests from the proxy. It
935 * automatically recomputes the number of servers, but not the map. Maintenance
936 * servers are ignored. It reports <reason> if non-null as the reason for going
937 * up. Note that it makes use of the trash to build the log strings, so <reason>
938 * must not be placed there.
939 */
940void srv_set_stopping(struct server *s, const char *reason)
941{
942 struct server *srv;
943 int xferred;
944
945 if (s->admin & SRV_ADMF_MAINT)
946 return;
947
948 if (s->state == SRV_ST_STOPPING)
949 return;
950
951 s->last_change = now.tv_sec;
952 s->state = SRV_ST_STOPPING;
953 if (s->proxy->lbprm.set_server_status_down)
954 s->proxy->lbprm.set_server_status_down(s);
955
Willy Tarreau87b09662015-04-03 00:22:06 +0200956 /* we might have streams queued on this server and waiting for
Willy Tarreau8eb77842014-05-21 13:54:57 +0200957 * a connection. Those which are redispatchable will be queued
958 * to another server or to the proxy itself.
959 */
960 xferred = pendconn_redistribute(s);
961
962 chunk_printf(&trash,
963 "%sServer %s/%s is stopping", s->flags & SRV_F_BACKUP ? "Backup " : "",
964 s->proxy->id, s->id);
965
966 srv_append_status(&trash, s, reason, xferred, 0);
967
968 Warning("%s.\n", trash.str);
969 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
970
971 if (!s->proxy->srv_bck && !s->proxy->srv_act)
972 set_backend_down(s->proxy);
973
974 for (srv = s->trackers; srv; srv = srv->tracknext)
975 srv_set_stopping(srv, NULL);
976}
Willy Tarreaudbd5e782014-05-20 22:46:35 +0200977
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +0200978/* Enables admin flag <mode> (among SRV_ADMF_*) on server <s>. This is used to
979 * enforce either maint mode or drain mode. It is not allowed to set more than
980 * one flag at once. The equivalent "inherited" flag is propagated to all
981 * tracking servers. Maintenance mode disables health checks (but not agent
982 * checks). When either the flag is already set or no flag is passed, nothing
Willy Tarreau8b428482016-11-07 15:53:43 +0100983 * is done. If <cause> is non-null, it will be displayed at the end of the log
984 * lines to justify the state change.
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200985 */
Willy Tarreau8b428482016-11-07 15:53:43 +0100986void srv_set_admin_flag(struct server *s, enum srv_admin mode, const char *cause)
Willy Tarreaua0066dd2014-05-16 11:25:16 +0200987{
988 struct check *check = &s->check;
989 struct server *srv;
990 int xferred;
991
992 if (!mode)
993 return;
994
995 /* stop going down as soon as we meet a server already in the same state */
996 if (s->admin & mode)
997 return;
998
999 s->admin |= mode;
1000
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001001 /* stop going down if the equivalent flag was already present (forced or inherited) */
1002 if (((mode & SRV_ADMF_MAINT) && (s->admin & ~mode & SRV_ADMF_MAINT)) ||
1003 ((mode & SRV_ADMF_DRAIN) && (s->admin & ~mode & SRV_ADMF_DRAIN)))
1004 return;
1005
1006 /* Maintenance must also disable health checks */
1007 if (mode & SRV_ADMF_MAINT) {
1008 if (s->check.state & CHK_ST_ENABLED) {
1009 s->check.state |= CHK_ST_PAUSED;
1010 check->health = 0;
1011 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001012
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001013 if (s->state == SRV_ST_STOPPED) { /* server was already down */
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001014 chunk_printf(&trash,
Willy Tarreau8b428482016-11-07 15:53:43 +01001015 "%sServer %s/%s was DOWN and now enters maintenance%s%s%s",
1016 s->flags & SRV_F_BACKUP ? "Backup " : "", s->proxy->id, s->id,
1017 cause ? " (" : "", cause ? cause : "", cause ? ")" : "");
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001018
Willy Tarreaubda92272014-05-20 21:55:30 +02001019 srv_append_status(&trash, s, NULL, -1, (mode & SRV_ADMF_FMAINT));
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001020
Willy Tarreau6fb8dc12016-11-03 19:42:36 +01001021 if (!(global.mode & MODE_STARTING)) {
1022 Warning("%s.\n", trash.str);
1023 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
1024 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001025 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001026 else { /* server was still running */
1027 int srv_was_stopping = (s->state == SRV_ST_STOPPING) || (s->admin & SRV_ADMF_DRAIN);
1028 int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
1029
1030 check->health = 0; /* failure */
1031 s->last_change = now.tv_sec;
1032 s->state = SRV_ST_STOPPED;
1033 if (s->proxy->lbprm.set_server_status_down)
1034 s->proxy->lbprm.set_server_status_down(s);
1035
1036 if (s->onmarkeddown & HANA_ONMARKEDDOWN_SHUTDOWNSESSIONS)
Willy Tarreaue7dff022015-04-03 01:14:29 +02001037 srv_shutdown_streams(s, SF_ERR_DOWN);
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001038
Willy Tarreau87b09662015-04-03 00:22:06 +02001039 /* we might have streams queued on this server and waiting for
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001040 * a connection. Those which are redispatchable will be queued
1041 * to another server or to the proxy itself.
1042 */
1043 xferred = pendconn_redistribute(s);
1044
1045 chunk_printf(&trash,
Willy Tarreau8b428482016-11-07 15:53:43 +01001046 "%sServer %s/%s is going DOWN for maintenance%s%s%s",
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001047 s->flags & SRV_F_BACKUP ? "Backup " : "",
Willy Tarreau8b428482016-11-07 15:53:43 +01001048 s->proxy->id, s->id,
1049 cause ? " (" : "", cause ? cause : "", cause ? ")" : "");
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001050
1051 srv_append_status(&trash, s, NULL, xferred, (mode & SRV_ADMF_FMAINT));
1052
Willy Tarreau6fb8dc12016-11-03 19:42:36 +01001053 if (!(global.mode & MODE_STARTING)) {
1054 Warning("%s.\n", trash.str);
1055 send_log(s->proxy, srv_was_stopping ? LOG_NOTICE : LOG_ALERT, "%s.\n", trash.str);
1056 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001057
1058 if (prev_srv_count && s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
1059 set_backend_down(s->proxy);
1060
1061 s->counters.down_trans++;
1062 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001063 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001064
1065 /* drain state is applied only if not yet in maint */
1066 if ((mode & SRV_ADMF_DRAIN) && !(s->admin & SRV_ADMF_MAINT)) {
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001067 int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
1068
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001069 s->last_change = now.tv_sec;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001070 if (s->proxy->lbprm.set_server_status_down)
1071 s->proxy->lbprm.set_server_status_down(s);
1072
Willy Tarreau87b09662015-04-03 00:22:06 +02001073 /* we might have streams queued on this server and waiting for
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001074 * a connection. Those which are redispatchable will be queued
1075 * to another server or to the proxy itself.
1076 */
1077 xferred = pendconn_redistribute(s);
1078
Willy Tarreau8b428482016-11-07 15:53:43 +01001079 chunk_printf(&trash, "%sServer %s/%s enters drain state%s%s%s",
1080 s->flags & SRV_F_BACKUP ? "Backup " : "", s->proxy->id, s->id,
1081 cause ? " (" : "", cause ? cause : "", cause ? ")" : "");
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001082
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001083 srv_append_status(&trash, s, NULL, xferred, (mode & SRV_ADMF_FDRAIN));
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001084
Willy Tarreau6fb8dc12016-11-03 19:42:36 +01001085 if (!(global.mode & MODE_STARTING)) {
1086 Warning("%s.\n", trash.str);
1087 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
1088 send_email_alert(s, LOG_NOTICE, "%s", trash.str);
1089 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001090 if (prev_srv_count && s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
1091 set_backend_down(s->proxy);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001092 }
1093
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001094 /* compute the inherited flag to propagate */
1095 if (mode & SRV_ADMF_MAINT)
1096 mode = SRV_ADMF_IMAINT;
1097 else if (mode & SRV_ADMF_DRAIN)
1098 mode = SRV_ADMF_IDRAIN;
1099
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001100 for (srv = s->trackers; srv; srv = srv->tracknext)
Willy Tarreau8b428482016-11-07 15:53:43 +01001101 srv_set_admin_flag(srv, mode, cause);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001102}
1103
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001104/* Disables admin flag <mode> (among SRV_ADMF_*) on server <s>. This is used to
1105 * stop enforcing either maint mode or drain mode. It is not allowed to set more
1106 * than one flag at once. The equivalent "inherited" flag is propagated to all
1107 * tracking servers. Leaving maintenance mode re-enables health checks. When
1108 * either the flag is already cleared or no flag is passed, nothing is done.
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001109 */
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001110void srv_clr_admin_flag(struct server *s, enum srv_admin mode)
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001111{
1112 struct check *check = &s->check;
1113 struct server *srv;
1114 int xferred = -1;
1115
1116 if (!mode)
1117 return;
1118
1119 /* stop going down as soon as we see the flag is not there anymore */
1120 if (!(s->admin & mode))
1121 return;
1122
1123 s->admin &= ~mode;
1124
1125 if (s->admin & SRV_ADMF_MAINT) {
1126 /* remaining in maintenance mode, let's inform precisely about the
1127 * situation.
1128 */
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001129 if (mode & SRV_ADMF_FMAINT) {
1130 chunk_printf(&trash,
1131 "%sServer %s/%s is leaving forced maintenance but remains in maintenance",
1132 s->flags & SRV_F_BACKUP ? "Backup " : "",
1133 s->proxy->id, s->id);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001134
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001135 if (s->track) /* normally it's mandatory here */
1136 chunk_appendf(&trash, " via %s/%s",
1137 s->track->proxy->id, s->track->id);
1138 Warning("%s.\n", trash.str);
1139 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
1140 }
Willy Tarreaue6599732016-11-07 15:42:33 +01001141 if (mode & SRV_ADMF_RMAINT) {
1142 chunk_printf(&trash,
1143 "%sServer %s/%s ('%s') resolves again but remains in maintenance",
1144 s->flags & SRV_F_BACKUP ? "Backup " : "",
1145 s->proxy->id, s->id, s->hostname);
1146
1147 if (s->track) /* normally it's mandatory here */
1148 chunk_appendf(&trash, " via %s/%s",
1149 s->track->proxy->id, s->track->id);
1150 Warning("%s.\n", trash.str);
1151 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
1152 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001153 else if (mode & SRV_ADMF_IMAINT) {
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001154 chunk_printf(&trash,
1155 "%sServer %s/%s remains in forced maintenance",
1156 s->flags & SRV_F_BACKUP ? "Backup " : "",
1157 s->proxy->id, s->id);
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001158 Warning("%s.\n", trash.str);
1159 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
1160 }
1161 /* don't report anything when leaving drain mode and remaining in maintenance */
1162 }
1163 else if (mode & SRV_ADMF_MAINT) {
1164 /* OK here we're leaving maintenance, we have many things to check,
1165 * because the server might possibly be coming back up depending on
1166 * its state. In practice, leaving maintenance means that we should
1167 * immediately turn to UP (more or less the slowstart) under the
1168 * following conditions :
1169 * - server is neither checked nor tracked
1170 * - server tracks another server which is not checked
1171 * - server tracks another server which is already up
1172 * Which sums up as something simpler :
1173 * "either the tracking server is up or the server's checks are disabled
1174 * or up". Otherwise we only re-enable health checks. There's a special
1175 * case associated to the stopping state which can be inherited. Note
1176 * that the server might still be in drain mode, which is naturally dealt
1177 * with by the lower level functions.
1178 */
1179
1180 if (s->check.state & CHK_ST_ENABLED) {
1181 s->check.state &= ~CHK_ST_PAUSED;
1182 check->health = check->rise; /* start OK but check immediately */
1183 }
1184
1185 if ((!s->track || s->track->state != SRV_ST_STOPPED) &&
1186 (!(s->agent.state & CHK_ST_ENABLED) || (s->agent.health >= s->agent.rise)) &&
1187 (!(s->check.state & CHK_ST_ENABLED) || (s->check.health >= s->check.rise))) {
1188 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
1189 if (s->proxy->last_change < now.tv_sec) // ignore negative times
1190 s->proxy->down_time += now.tv_sec - s->proxy->last_change;
1191 s->proxy->last_change = now.tv_sec;
1192 }
1193
1194 if (s->last_change < now.tv_sec) // ignore negative times
1195 s->down_time += now.tv_sec - s->last_change;
1196 s->last_change = now.tv_sec;
1197
1198 if (s->track && s->track->state == SRV_ST_STOPPING)
1199 s->state = SRV_ST_STOPPING;
1200 else {
1201 s->state = SRV_ST_STARTING;
1202 if (s->slowstart > 0)
1203 task_schedule(s->warmup, tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20))));
1204 else
1205 s->state = SRV_ST_RUNNING;
1206 }
1207
1208 server_recalc_eweight(s);
1209
1210 /* If the server is set with "on-marked-up shutdown-backup-sessions",
1211 * and it's not a backup server and its effective weight is > 0,
Willy Tarreau87b09662015-04-03 00:22:06 +02001212 * then it can accept new connections, so we shut down all streams
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001213 * on all backup servers.
1214 */
1215 if ((s->onmarkedup & HANA_ONMARKEDUP_SHUTDOWNBACKUPSESSIONS) &&
1216 !(s->flags & SRV_F_BACKUP) && s->eweight)
Willy Tarreaue7dff022015-04-03 01:14:29 +02001217 srv_shutdown_backup_streams(s->proxy, SF_ERR_UP);
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001218
1219 /* check if we can handle some connections queued at the proxy. We
1220 * will take as many as we can handle.
1221 */
1222 xferred = pendconn_grab_from_px(s);
1223 }
1224
1225 if (mode & SRV_ADMF_FMAINT) {
1226 chunk_printf(&trash,
1227 "%sServer %s/%s is %s/%s (leaving forced maintenance)",
1228 s->flags & SRV_F_BACKUP ? "Backup " : "",
1229 s->proxy->id, s->id,
1230 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP",
1231 (s->admin & SRV_ADMF_DRAIN) ? "DRAIN" : "READY");
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001232 }
Willy Tarreaue6599732016-11-07 15:42:33 +01001233 else if (mode & SRV_ADMF_RMAINT) {
1234 chunk_printf(&trash,
1235 "%sServer %s/%s ('%s') is %s/%s (resolves again)",
1236 s->flags & SRV_F_BACKUP ? "Backup " : "",
1237 s->proxy->id, s->id, s->hostname,
1238 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP",
1239 (s->admin & SRV_ADMF_DRAIN) ? "DRAIN" : "READY");
1240 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001241 else {
1242 chunk_printf(&trash,
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001243 "%sServer %s/%s is %s/%s (leaving maintenance)",
1244 s->flags & SRV_F_BACKUP ? "Backup " : "",
1245 s->proxy->id, s->id,
1246 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP",
1247 (s->admin & SRV_ADMF_DRAIN) ? "DRAIN" : "READY");
1248 srv_append_status(&trash, s, NULL, xferred, 0);
1249 }
1250 Warning("%s.\n", trash.str);
1251 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
1252 }
1253 else if ((mode & SRV_ADMF_DRAIN) && (s->admin & SRV_ADMF_DRAIN)) {
1254 /* remaining in drain mode after removing one of its flags */
1255
1256 if (mode & SRV_ADMF_FDRAIN) {
1257 chunk_printf(&trash,
1258 "%sServer %s/%s is leaving forced drain but remains in drain mode",
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001259 s->flags & SRV_F_BACKUP ? "Backup " : "",
1260 s->proxy->id, s->id);
1261
1262 if (s->track) /* normally it's mandatory here */
1263 chunk_appendf(&trash, " via %s/%s",
1264 s->track->proxy->id, s->track->id);
1265 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001266 else {
1267 chunk_printf(&trash,
1268 "%sServer %s/%s remains in forced drain mode",
1269 s->flags & SRV_F_BACKUP ? "Backup " : "",
1270 s->proxy->id, s->id);
1271 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001272 Warning("%s.\n", trash.str);
1273 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001274 }
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001275 else if (mode & SRV_ADMF_DRAIN) {
1276 /* OK completely leaving drain mode */
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001277 if (s->proxy->srv_bck == 0 && s->proxy->srv_act == 0) {
1278 if (s->proxy->last_change < now.tv_sec) // ignore negative times
1279 s->proxy->down_time += now.tv_sec - s->proxy->last_change;
1280 s->proxy->last_change = now.tv_sec;
1281 }
1282
1283 if (s->last_change < now.tv_sec) // ignore negative times
1284 s->down_time += now.tv_sec - s->last_change;
1285 s->last_change = now.tv_sec;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001286 server_recalc_eweight(s);
1287
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001288 if (mode & SRV_ADMF_FDRAIN) {
1289 chunk_printf(&trash,
1290 "%sServer %s/%s is %s (leaving forced drain)",
1291 s->flags & SRV_F_BACKUP ? "Backup " : "",
1292 s->proxy->id, s->id,
1293 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP");
1294 }
1295 else {
1296 chunk_printf(&trash,
1297 "%sServer %s/%s is %s (leaving drain)",
1298 s->flags & SRV_F_BACKUP ? "Backup " : "",
1299 s->proxy->id, s->id,
1300 (s->state == SRV_ST_STOPPED) ? "DOWN" : "UP");
1301 if (s->track) /* normally it's mandatory here */
1302 chunk_appendf(&trash, " via %s/%s",
1303 s->track->proxy->id, s->track->id);
1304 }
1305 Warning("%s.\n", trash.str);
1306 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001307 }
1308
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001309 /* stop going down if the equivalent flag is still present (forced or inherited) */
1310 if (((mode & SRV_ADMF_MAINT) && (s->admin & SRV_ADMF_MAINT)) ||
1311 ((mode & SRV_ADMF_DRAIN) && (s->admin & SRV_ADMF_DRAIN)))
1312 return;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001313
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001314 if (mode & SRV_ADMF_MAINT)
1315 mode = SRV_ADMF_IMAINT;
1316 else if (mode & SRV_ADMF_DRAIN)
1317 mode = SRV_ADMF_IDRAIN;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001318
1319 for (srv = s->trackers; srv; srv = srv->tracknext)
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001320 srv_clr_admin_flag(srv, mode);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001321}
1322
Willy Tarreau757478e2016-11-03 19:22:19 +01001323/* principle: propagate maint and drain to tracking servers. This is useful
1324 * upon startup so that inherited states are correct.
1325 */
1326static void srv_propagate_admin_state(struct server *srv)
1327{
1328 struct server *srv2;
1329
1330 if (!srv->trackers)
1331 return;
1332
1333 for (srv2 = srv->trackers; srv2; srv2 = srv2->tracknext) {
1334 if (srv->admin & (SRV_ADMF_MAINT | SRV_ADMF_CMAINT))
Willy Tarreau8b428482016-11-07 15:53:43 +01001335 srv_set_admin_flag(srv2, SRV_ADMF_IMAINT, NULL);
Willy Tarreau757478e2016-11-03 19:22:19 +01001336
1337 if (srv->admin & SRV_ADMF_DRAIN)
Willy Tarreau8b428482016-11-07 15:53:43 +01001338 srv_set_admin_flag(srv2, SRV_ADMF_IDRAIN, NULL);
Willy Tarreau757478e2016-11-03 19:22:19 +01001339 }
1340}
1341
1342/* Compute and propagate the admin states for all servers in proxy <px>.
1343 * Only servers *not* tracking another one are considered, because other
1344 * ones will be handled when the server they track is visited.
1345 */
1346void srv_compute_all_admin_states(struct proxy *px)
1347{
1348 struct server *srv;
1349
1350 for (srv = px->srv; srv; srv = srv->next) {
1351 if (srv->track)
1352 continue;
1353 srv_propagate_admin_state(srv);
1354 }
1355}
1356
Willy Tarreaudff55432012-10-10 17:51:05 +02001357/* Note: must not be declared <const> as its list will be overwritten.
1358 * Please take care of keeping this list alphabetically sorted, doing so helps
1359 * all code contributors.
1360 * Optional keywords are also declared with a NULL ->parse() function so that
1361 * the config parser can report an appropriate error when a known keyword was
1362 * not enabled.
1363 */
1364static struct srv_kw_list srv_kws = { "ALL", { }, {
Frédéric Lécaille6e5e0d82017-03-20 16:30:18 +01001365 { "addr", srv_parse_addr, 1, 1 }, /* IP address to send health to or to probe from agent-check */
Frédéric Lécaille6e0843c2017-03-21 16:39:15 +01001366 { "agent-check", srv_parse_agent_check, 0, 1 }, /* Enable an auxiliary agent check */
Frédéric Lécaille1502cfd2017-03-10 15:36:14 +01001367 { "backup", srv_parse_backup, 0, 1 }, /* Flag as backup server */
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01001368 { "check", srv_parse_check, 0, 1 }, /* enable health checks */
Frédéric Lécaille25df8902017-03-10 14:04:31 +01001369 { "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 +01001370 { "cookie", srv_parse_cookie, 1, 1 }, /* Assign a cookie to the server */
Frédéric Lécaille2a0d0612017-03-21 11:53:54 +01001371 { "disabled", srv_parse_disabled, 0, 1 }, /* Start the server in 'disabled' state */
1372 { "enabled", srv_parse_enabled, 0, 1 }, /* Start the server in 'enabled' state */
Frédéric Lécaille1502cfd2017-03-10 15:36:14 +01001373 { "id", srv_parse_id, 1, 0 }, /* set id# of server */
Frédéric Lécaille22f41a22017-03-16 17:17:36 +01001374 { "namespace", srv_parse_namespace, 1, 1 }, /* Namespace the server socket belongs to (if supported) */
Frédéric Lécaille6e0843c2017-03-21 16:39:15 +01001375 { "no-agent-check", srv_parse_no_agent_check, 0, 1 }, /* Do not enable any auxiliary agent check */
Frédéric Lécaille1502cfd2017-03-10 15:36:14 +01001376 { "no-backup", srv_parse_no_backup, 0, 1 }, /* Flag as non-backup server */
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01001377 { "no-check", srv_parse_no_check, 0, 1 }, /* disable health checks */
Frédéric Lécaille25df8902017-03-10 14:04:31 +01001378 { "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 +01001379 { "no-send-proxy", srv_parse_no_send_proxy, 0, 1 }, /* Disable use of PROXY V1 protocol */
1380 { "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 +01001381 { "non-stick", srv_parse_non_stick, 0, 1 }, /* Disable stick-table persistence */
Frédéric Lécaille547356e2017-03-15 08:55:39 +01001382 { "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 +01001383 { "redir", srv_parse_redir, 1, 1 }, /* Enable redirection mode */
Frédéric Lécaille31045e42017-03-10 16:40:00 +01001384 { "send-proxy", srv_parse_send_proxy, 0, 1 }, /* Enforce use of PROXY V1 protocol */
1385 { "send-proxy-v2", srv_parse_send_proxy_v2, 0, 1 }, /* Enforce use of PROXY V2 protocol */
Frédéric Lécailledba97072017-03-17 15:33:50 +01001386 /*
1387 * Note: the following 'skip' field value is 0.
1388 * Here this does not mean that "source" setting does not need any argument.
1389 * This means that the number of argument is variable.
1390 */
1391 { "source", srv_parse_source, 0, 1 }, /* Set the source address to be used to connect to the server */
Frédéric Lécaillef9bc1d62017-03-10 15:50:49 +01001392 { "stick", srv_parse_stick, 0, 1 }, /* Enable stick-table persistence */
Frédéric Lécaille67e0e612017-03-14 15:21:31 +01001393 { "track", srv_parse_track, 1, 1 }, /* Set the current state of the server, tracking another one */
Willy Tarreaudff55432012-10-10 17:51:05 +02001394 { NULL, NULL, 0 },
1395}};
1396
1397__attribute__((constructor))
1398static void __listener_init(void)
1399{
1400 srv_register_keywords(&srv_kws);
1401}
1402
Willy Tarreau004e0452013-11-21 11:22:01 +01001403/* Recomputes the server's eweight based on its state, uweight, the current time,
1404 * and the proxy's algorihtm. To be used after updating sv->uweight. The warmup
1405 * state is automatically disabled if the time is elapsed.
1406 */
1407void server_recalc_eweight(struct server *sv)
1408{
1409 struct proxy *px = sv->proxy;
1410 unsigned w;
1411
1412 if (now.tv_sec < sv->last_change || now.tv_sec >= sv->last_change + sv->slowstart) {
1413 /* go to full throttle if the slowstart interval is reached */
Willy Tarreau892337c2014-05-13 23:41:20 +02001414 if (sv->state == SRV_ST_STARTING)
1415 sv->state = SRV_ST_RUNNING;
Willy Tarreau004e0452013-11-21 11:22:01 +01001416 }
1417
1418 /* We must take care of not pushing the server to full throttle during slow starts.
1419 * It must also start immediately, at least at the minimal step when leaving maintenance.
1420 */
Willy Tarreau892337c2014-05-13 23:41:20 +02001421 if ((sv->state == SRV_ST_STARTING) && (px->lbprm.algo & BE_LB_PROP_DYN))
Willy Tarreau004e0452013-11-21 11:22:01 +01001422 w = (px->lbprm.wdiv * (now.tv_sec - sv->last_change) + sv->slowstart) / sv->slowstart;
1423 else
1424 w = px->lbprm.wdiv;
1425
1426 sv->eweight = (sv->uweight * w + px->lbprm.wmult - 1) / px->lbprm.wmult;
1427
1428 /* now propagate the status change to any LB algorithms */
1429 if (px->lbprm.update_server_eweight)
1430 px->lbprm.update_server_eweight(sv);
Willy Tarreau9943d312014-05-22 16:20:59 +02001431 else if (srv_is_usable(sv)) {
Willy Tarreau004e0452013-11-21 11:22:01 +01001432 if (px->lbprm.set_server_status_up)
1433 px->lbprm.set_server_status_up(sv);
1434 }
1435 else {
1436 if (px->lbprm.set_server_status_down)
1437 px->lbprm.set_server_status_down(sv);
1438 }
1439}
1440
Willy Tarreaubaaee002006-06-26 02:48:02 +02001441/*
Simon Horman7d09b9a2013-02-12 10:45:51 +09001442 * Parses weight_str and configures sv accordingly.
1443 * Returns NULL on success, error message string otherwise.
1444 */
1445const char *server_parse_weight_change_request(struct server *sv,
1446 const char *weight_str)
1447{
1448 struct proxy *px;
Simon Hormanb796afa2013-02-12 10:45:53 +09001449 long int w;
1450 char *end;
Michal Idzikowski266b1a82017-03-27 14:45:49 +02001451 const char *msg;
1452 int relative = 0;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001453
1454 px = sv->proxy;
1455
1456 /* if the weight is terminated with '%', it is set relative to
1457 * the initial weight, otherwise it is absolute.
1458 */
1459 if (!*weight_str)
1460 return "Require <weight> or <weight%>.\n";
1461
Simon Hormanb796afa2013-02-12 10:45:53 +09001462 w = strtol(weight_str, &end, 10);
1463 if (end == weight_str)
1464 return "Empty weight string empty or preceded by garbage";
1465 else if (end[0] == '%' && end[1] == '\0') {
Simon Horman58b5d292013-02-12 10:45:52 +09001466 if (w < 0)
Simon Horman7d09b9a2013-02-12 10:45:51 +09001467 return "Relative weight must be positive.\n";
Simon Horman58b5d292013-02-12 10:45:52 +09001468 /* Avoid integer overflow */
1469 if (w > 25600)
1470 w = 25600;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001471 w = sv->iweight * w / 100;
Simon Horman58b5d292013-02-12 10:45:52 +09001472 if (w > 256)
1473 w = 256;
Michal Idzikowski266b1a82017-03-27 14:45:49 +02001474
1475 relative = 1;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001476 }
1477 else if (w < 0 || w > 256)
1478 return "Absolute weight can only be between 0 and 256 inclusive.\n";
Simon Hormanb796afa2013-02-12 10:45:53 +09001479 else if (end[0] != '\0')
1480 return "Trailing garbage in weight string";
Simon Horman7d09b9a2013-02-12 10:45:51 +09001481
1482 if (w && w != sv->iweight && !(px->lbprm.algo & BE_LB_PROP_DYN))
1483 return "Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.\n";
1484
1485 sv->uweight = w;
Willy Tarreau004e0452013-11-21 11:22:01 +01001486 server_recalc_eweight(sv);
Simon Horman7d09b9a2013-02-12 10:45:51 +09001487
Michal Idzikowski266b1a82017-03-27 14:45:49 +02001488 if (relative) {
1489 msg = server_propagate_weight_change_request(sv, weight_str);
1490 if (msg != NULL) {
1491 return msg;
1492 }
1493 }
1494
1495 return NULL;
1496}
1497
1498const char *server_propagate_weight_change_request(struct server *sv,
1499 const char *weight_str)
1500{
1501 struct server *tracker;
1502 const char *msg;
1503
1504 for (tracker = sv->trackers; tracker; tracker = tracker->tracknext) {
1505 msg = server_parse_weight_change_request(tracker, weight_str);
1506 if (msg)
1507 return msg;
1508 }
1509
Simon Horman7d09b9a2013-02-12 10:45:51 +09001510 return NULL;
1511}
1512
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001513/*
Thierry Fournier09a91782016-02-24 08:25:39 +01001514 * Parses <addr_str> and configures <sv> accordingly. <from> precise
1515 * the source of the change in the associated message log.
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001516 * Returns:
1517 * - error string on error
1518 * - NULL on success
1519 */
1520const char *server_parse_addr_change_request(struct server *sv,
Thierry Fournier09a91782016-02-24 08:25:39 +01001521 const char *addr_str, const char *updater)
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001522{
1523 unsigned char ip[INET6_ADDRSTRLEN];
1524
1525 if (inet_pton(AF_INET6, addr_str, ip)) {
Thierry Fournier09a91782016-02-24 08:25:39 +01001526 update_server_addr(sv, ip, AF_INET6, updater);
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001527 return NULL;
1528 }
1529 if (inet_pton(AF_INET, addr_str, ip)) {
Thierry Fournier09a91782016-02-24 08:25:39 +01001530 update_server_addr(sv, ip, AF_INET, updater);
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001531 return NULL;
1532 }
1533
1534 return "Could not understand IP address format.\n";
1535}
1536
Nenad Merdanovic174dd372016-04-24 23:10:06 +02001537const char *server_parse_maxconn_change_request(struct server *sv,
1538 const char *maxconn_str)
1539{
1540 long int v;
1541 char *end;
1542
1543 if (!*maxconn_str)
1544 return "Require <maxconn>.\n";
1545
1546 v = strtol(maxconn_str, &end, 10);
1547 if (end == maxconn_str)
1548 return "maxconn string empty or preceded by garbage";
1549 else if (end[0] != '\0')
1550 return "Trailing garbage in maxconn string";
1551
1552 if (sv->maxconn == sv->minconn) { // static maxconn
1553 sv->maxconn = sv->minconn = v;
1554 } else { // dynamic maxconn
1555 sv->maxconn = v;
1556 }
1557
1558 if (may_dequeue_tasks(sv, sv->proxy))
1559 process_srv_queue(sv);
1560
1561 return NULL;
1562}
1563
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01001564#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1565static int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char **err)
1566{
1567 int idx;
1568 struct sample_expr *expr;
1569 const char *args[] = {
1570 newsrv->sni_expr,
1571 NULL,
1572 };
1573
1574 idx = 0;
1575 proxy->conf.args.ctx = ARGC_SRV;
1576
1577 expr = sample_parse_expr((char **)args, &idx, px->conf.file, px->conf.line,
1578 err, &proxy->conf.args);
1579 if (!expr) {
1580 memprintf(err, "error detected while parsing sni expression : %s", *err);
1581 return ERR_ALERT | ERR_FATAL;
1582 }
1583
1584 if (!(expr->fetch->val & SMP_VAL_BE_SRV_CON)) {
1585 memprintf(err, "error detected while parsing sni expression : "
1586 " fetch method '%s' extracts information from '%s', "
1587 "none of which is available here.\n",
1588 args[0], sample_src_names(expr->fetch->use));
1589 return ERR_ALERT | ERR_FATAL;
1590 }
1591
1592 px->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
1593 release_sample_expr(newsrv->ssl_ctx.sni);
1594 newsrv->ssl_ctx.sni = expr;
1595
1596 return 0;
1597}
1598#endif
1599
1600static void display_parser_err(const char *file, int linenum, char **args, int cur_arg, char **err)
1601{
1602 if (err && *err) {
1603 indent_msg(err, 2);
1604 Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], *err);
1605 }
1606 else
1607 Alert("parsing [%s:%d] : '%s %s' : error encountered while processing '%s'.\n",
1608 file, linenum, args[0], args[1], args[cur_arg]);
1609}
1610
Willy Tarreau272adea2014-03-31 10:39:59 +02001611int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
1612{
1613 struct server *newsrv = NULL;
1614 const char *err;
1615 char *errmsg = NULL;
1616 int err_code = 0;
1617 unsigned val;
Willy Tarreau07101d52015-09-08 16:16:35 +02001618 char *fqdn = NULL;
Willy Tarreau272adea2014-03-31 10:39:59 +02001619
1620 if (!strcmp(args[0], "server") || !strcmp(args[0], "default-server")) { /* server address */
1621 int cur_arg;
Frédéric Lécaille6e0843c2017-03-21 16:39:15 +01001622 int defsrv = (*args[0] == 'd');
Willy Tarreau272adea2014-03-31 10:39:59 +02001623
1624 if (!defsrv && curproxy == defproxy) {
1625 Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
1626 err_code |= ERR_ALERT | ERR_FATAL;
1627 goto out;
1628 }
1629 else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
1630 err_code |= ERR_ALERT | ERR_FATAL;
1631
Frédéric Lécaille8065b6d2017-03-09 14:01:02 +01001632 if (!defsrv && !*args[2]) {
Willy Tarreau272adea2014-03-31 10:39:59 +02001633 Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
1634 file, linenum, args[0]);
1635 err_code |= ERR_ALERT | ERR_FATAL;
1636 goto out;
1637 }
1638
1639 err = invalid_char(args[1]);
1640 if (err && !defsrv) {
1641 Alert("parsing [%s:%d] : character '%c' is not permitted in server name '%s'.\n",
1642 file, linenum, *err, args[1]);
1643 err_code |= ERR_ALERT | ERR_FATAL;
1644 goto out;
1645 }
1646
1647 if (!defsrv) {
1648 struct sockaddr_storage *sk;
Willy Tarreau6ecb10a2017-01-06 18:36:06 +01001649 int port1, port2, port;
Willy Tarreau272adea2014-03-31 10:39:59 +02001650 struct protocol *proto;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001651 struct dns_resolution *curr_resolution;
Willy Tarreau272adea2014-03-31 10:39:59 +02001652
Vincent Bernat02779b62016-04-03 13:48:43 +02001653 if ((newsrv = calloc(1, sizeof(*newsrv))) == NULL) {
Willy Tarreau272adea2014-03-31 10:39:59 +02001654 Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
1655 err_code |= ERR_ALERT | ERR_ABORT;
1656 goto out;
1657 }
1658
1659 /* the servers are linked backwards first */
1660 newsrv->next = curproxy->srv;
1661 curproxy->srv = newsrv;
1662 newsrv->proxy = curproxy;
1663 newsrv->conf.file = strdup(file);
1664 newsrv->conf.line = linenum;
1665
1666 newsrv->obj_type = OBJ_TYPE_SERVER;
1667 LIST_INIT(&newsrv->actconns);
1668 LIST_INIT(&newsrv->pendconns);
Willy Tarreau600802a2015-08-04 17:19:06 +02001669 LIST_INIT(&newsrv->priv_conns);
Willy Tarreau173a1c62015-08-05 10:31:57 +02001670 LIST_INIT(&newsrv->idle_conns);
Willy Tarreau7017cb02015-08-05 16:35:23 +02001671 LIST_INIT(&newsrv->safe_conns);
Willy Tarreauc93cd162014-05-13 15:54:22 +02001672 newsrv->flags = 0;
Willy Tarreau20125212014-05-13 19:44:56 +02001673 newsrv->admin = 0;
Willy Tarreau892337c2014-05-13 23:41:20 +02001674 newsrv->state = SRV_ST_RUNNING; /* early server setup */
Willy Tarreau272adea2014-03-31 10:39:59 +02001675 newsrv->last_change = now.tv_sec;
1676 newsrv->id = strdup(args[1]);
1677
1678 /* several ways to check the port component :
1679 * - IP => port=+0, relative (IPv4 only)
1680 * - IP: => port=+0, relative
1681 * - IP:N => port=N, absolute
1682 * - IP:+N => port=+N, relative
1683 * - IP:-N => port=-N, relative
1684 */
Willy Tarreau6ecb10a2017-01-06 18:36:06 +01001685 sk = str2sa_range(args[2], &port, &port1, &port2, &errmsg, NULL, &fqdn, 0);
Willy Tarreau272adea2014-03-31 10:39:59 +02001686 if (!sk) {
1687 Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
1688 err_code |= ERR_ALERT | ERR_FATAL;
1689 goto out;
1690 }
1691
1692 proto = protocol_by_family(sk->ss_family);
Willy Tarreau9698f4b2017-01-06 18:42:57 +01001693 if (!fqdn && (!proto || !proto->connect)) {
Willy Tarreau272adea2014-03-31 10:39:59 +02001694 Alert("parsing [%s:%d] : '%s %s' : connect() not supported for this address family.\n",
1695 file, linenum, args[0], args[1]);
1696 err_code |= ERR_ALERT | ERR_FATAL;
1697 goto out;
1698 }
1699
1700 if (!port1 || !port2) {
1701 /* no port specified, +offset, -offset */
Willy Tarreauc93cd162014-05-13 15:54:22 +02001702 newsrv->flags |= SRV_F_MAPPORTS;
Willy Tarreau272adea2014-03-31 10:39:59 +02001703 }
1704 else if (port1 != port2) {
1705 /* port range */
1706 Alert("parsing [%s:%d] : '%s %s' : port ranges are not allowed in '%s'\n",
1707 file, linenum, args[0], args[1], args[2]);
1708 err_code |= ERR_ALERT | ERR_FATAL;
1709 goto out;
1710 }
Willy Tarreau272adea2014-03-31 10:39:59 +02001711
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001712 /* save hostname and create associated name resolution */
Willy Tarreau07101d52015-09-08 16:16:35 +02001713 newsrv->hostname = fqdn;
1714 if (!fqdn)
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001715 goto skip_name_resolution;
1716
Willy Tarreau07101d52015-09-08 16:16:35 +02001717 fqdn = NULL;
Vincent Bernat02779b62016-04-03 13:48:43 +02001718 if ((curr_resolution = calloc(1, sizeof(*curr_resolution))) == NULL)
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001719 goto skip_name_resolution;
1720
1721 curr_resolution->hostname_dn_len = dns_str_to_dn_label_len(newsrv->hostname);
1722 if ((curr_resolution->hostname_dn = calloc(curr_resolution->hostname_dn_len + 1, sizeof(char))) == NULL)
1723 goto skip_name_resolution;
1724 if ((dns_str_to_dn_label(newsrv->hostname, curr_resolution->hostname_dn, curr_resolution->hostname_dn_len + 1)) == NULL) {
1725 Alert("parsing [%s:%d] : Invalid hostname '%s'\n",
1726 file, linenum, args[2]);
1727 err_code |= ERR_ALERT | ERR_FATAL;
1728 goto out;
1729 }
1730
1731 curr_resolution->requester = newsrv;
1732 curr_resolution->requester_cb = snr_resolution_cb;
1733 curr_resolution->requester_error_cb = snr_resolution_error_cb;
1734 curr_resolution->status = RSLV_STATUS_NONE;
1735 curr_resolution->step = RSLV_STEP_NONE;
1736 /* a first resolution has been done by the configuration parser */
Baptiste Assmannf046f112015-08-27 22:12:46 +02001737 curr_resolution->last_resolution = 0;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001738 newsrv->resolution = curr_resolution;
1739
1740 skip_name_resolution:
Willy Tarreau272adea2014-03-31 10:39:59 +02001741 newsrv->addr = *sk;
Willy Tarreau6ecb10a2017-01-06 18:36:06 +01001742 newsrv->svc_port = port;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01001743 newsrv->xprt = newsrv->check.xprt = newsrv->agent.xprt = xprt_get(XPRT_RAW);
Willy Tarreau272adea2014-03-31 10:39:59 +02001744
Willy Tarreau9698f4b2017-01-06 18:42:57 +01001745 if (!newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) {
Willy Tarreau272adea2014-03-31 10:39:59 +02001746 Alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n",
1747 file, linenum, newsrv->addr.ss_family, args[2]);
1748 err_code |= ERR_ALERT | ERR_FATAL;
1749 goto out;
1750 }
1751
Frédéric Lécailledba97072017-03-17 15:33:50 +01001752 /*
1753 * In this section we copy default-server connection source settings to
1754 * the new server object connection source
1755 * (newsrv->conn_src <- curproxy->defsrv.conn_src).
1756 */
1757 newsrv->conn_src.opts = curproxy->defsrv.conn_src.opts;
1758 newsrv->conn_src.source_addr = curproxy->defsrv.conn_src.source_addr;
1759 if (curproxy->defsrv.conn_src.sport_range != NULL) {
1760 int i, def_sport_range_sz;
1761 struct server *default_srv;
1762
1763 default_srv = &curproxy->defsrv;
1764 def_sport_range_sz = default_srv->conn_src.sport_range->size;
1765 if (def_sport_range_sz > 0) {
1766 newsrv->conn_src.sport_range = port_range_alloc_range(def_sport_range_sz);
1767 if (newsrv->conn_src.sport_range) {
1768 for (i = 0; i < def_sport_range_sz; i++)
1769 newsrv->conn_src.sport_range->ports[i] = default_srv->conn_src.sport_range->ports[i];
1770 }
1771 }
1772 }
David Carlier3a471932017-04-07 20:48:00 +01001773#ifdef CONFIG_HAP_TRANSPARENT
Frédéric Lécailledba97072017-03-17 15:33:50 +01001774 if (curproxy->defsrv.conn_src.bind_hdr_name != NULL) {
1775 newsrv->conn_src.bind_hdr_name = strdup(curproxy->defsrv.conn_src.bind_hdr_name);
1776 newsrv->conn_src.bind_hdr_len = strlen(curproxy->defsrv.conn_src.bind_hdr_name);
1777 }
1778 newsrv->conn_src.bind_hdr_occ = curproxy->defsrv.conn_src.bind_hdr_occ;
1779 newsrv->conn_src.tproxy_addr = curproxy->defsrv.conn_src.tproxy_addr;
David Carlier3a471932017-04-07 20:48:00 +01001780#endif
Frédéric Lécailledba97072017-03-17 15:33:50 +01001781 if (curproxy->defsrv.conn_src.iface_name != NULL)
1782 newsrv->conn_src.iface_name = strdup(curproxy->defsrv.conn_src.iface_name);
1783
Frédéric Lécaille31045e42017-03-10 16:40:00 +01001784 newsrv->pp_opts = curproxy->defsrv.pp_opts;
Frédéric Lécaille16186232017-03-14 16:42:49 +01001785 if (curproxy->defsrv.rdr_pfx != NULL) {
1786 newsrv->rdr_pfx = strdup(curproxy->defsrv.rdr_pfx);
1787 newsrv->rdr_len = curproxy->defsrv.rdr_len;
1788 }
Frédéric Lécaille9d1b95b2017-03-15 09:13:33 +01001789 if (curproxy->defsrv.cookie != NULL) {
1790 newsrv->cookie = strdup(curproxy->defsrv.cookie);
1791 newsrv->cklen = curproxy->defsrv.cklen;
1792 }
Willy Tarreau141ad852016-12-22 18:38:00 +01001793 newsrv->use_ssl = curproxy->defsrv.use_ssl;
Frédéric Lécaille6e5e0d82017-03-20 16:30:18 +01001794 newsrv->check.addr = newsrv->agent.addr = curproxy->defsrv.check.addr;
Willy Tarreau272adea2014-03-31 10:39:59 +02001795 newsrv->check.use_ssl = curproxy->defsrv.check.use_ssl;
1796 newsrv->check.port = curproxy->defsrv.check.port;
Frédéric Lécaillef5bf9032017-03-10 11:51:05 +01001797 /* Note: 'flags' field has potentially been already initialized. */
1798 newsrv->flags |= curproxy->defsrv.flags;
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01001799 newsrv->do_check = curproxy->defsrv.do_check;
Frédéric Lécaille6e0843c2017-03-21 16:39:15 +01001800 newsrv->do_agent = curproxy->defsrv.do_agent;
Baptiste Assmann6b453f12016-08-11 23:12:18 +02001801 if (newsrv->check.port)
1802 newsrv->flags |= SRV_F_CHECKPORT;
Willy Tarreau272adea2014-03-31 10:39:59 +02001803 newsrv->check.inter = curproxy->defsrv.check.inter;
1804 newsrv->check.fastinter = curproxy->defsrv.check.fastinter;
1805 newsrv->check.downinter = curproxy->defsrv.check.downinter;
1806 newsrv->agent.use_ssl = curproxy->defsrv.agent.use_ssl;
1807 newsrv->agent.port = curproxy->defsrv.agent.port;
James Brown55f9ff12015-10-21 18:19:05 -07001808 if (curproxy->defsrv.agent.send_string != NULL)
1809 newsrv->agent.send_string = strdup(curproxy->defsrv.agent.send_string);
1810 newsrv->agent.send_string_len = curproxy->defsrv.agent.send_string_len;
Willy Tarreau272adea2014-03-31 10:39:59 +02001811 newsrv->agent.inter = curproxy->defsrv.agent.inter;
1812 newsrv->agent.fastinter = curproxy->defsrv.agent.fastinter;
1813 newsrv->agent.downinter = curproxy->defsrv.agent.downinter;
1814 newsrv->maxqueue = curproxy->defsrv.maxqueue;
1815 newsrv->minconn = curproxy->defsrv.minconn;
1816 newsrv->maxconn = curproxy->defsrv.maxconn;
1817 newsrv->slowstart = curproxy->defsrv.slowstart;
Frédéric Lécaille547356e2017-03-15 08:55:39 +01001818 newsrv->observe = curproxy->defsrv.observe;
Willy Tarreau272adea2014-03-31 10:39:59 +02001819 newsrv->onerror = curproxy->defsrv.onerror;
1820 newsrv->onmarkeddown = curproxy->defsrv.onmarkeddown;
1821 newsrv->onmarkedup = curproxy->defsrv.onmarkedup;
Frédéric Lécaille67e0e612017-03-14 15:21:31 +01001822 if (curproxy->defsrv.trackit != NULL)
1823 newsrv->trackit = strdup(curproxy->defsrv.trackit);
Willy Tarreau272adea2014-03-31 10:39:59 +02001824 newsrv->consecutive_errors_limit
1825 = curproxy->defsrv.consecutive_errors_limit;
Willy Tarreau272adea2014-03-31 10:39:59 +02001826 newsrv->uweight = newsrv->iweight
1827 = curproxy->defsrv.iweight;
1828
1829 newsrv->check.status = HCHK_STATUS_INI;
Frédéric Lécaille25df8902017-03-10 14:04:31 +01001830 newsrv->check.send_proxy = curproxy->defsrv.check.send_proxy;
Willy Tarreau272adea2014-03-31 10:39:59 +02001831 newsrv->check.rise = curproxy->defsrv.check.rise;
1832 newsrv->check.fall = curproxy->defsrv.check.fall;
1833 newsrv->check.health = newsrv->check.rise; /* up, but will fall down at first failure */
Frédéric Lécaille2a0d0612017-03-21 11:53:54 +01001834 /* Here we check if 'disabled' is the default server state */
1835 if (curproxy->defsrv.admin & (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT)) {
1836 newsrv->admin |= SRV_ADMF_CMAINT | SRV_ADMF_FMAINT;
1837 newsrv->state = SRV_ST_STOPPED;
1838 newsrv->check.state |= CHK_ST_PAUSED;
1839 newsrv->check.health = 0;
1840 }
Willy Tarreau272adea2014-03-31 10:39:59 +02001841 newsrv->check.server = newsrv;
Simon Hormane16c1b32015-01-30 11:22:57 +09001842 newsrv->check.tcpcheck_rules = &curproxy->tcpcheck_rules;
Willy Tarreau272adea2014-03-31 10:39:59 +02001843
1844 newsrv->agent.status = HCHK_STATUS_INI;
1845 newsrv->agent.rise = curproxy->defsrv.agent.rise;
1846 newsrv->agent.fall = curproxy->defsrv.agent.fall;
1847 newsrv->agent.health = newsrv->agent.rise; /* up, but will fall down at first failure */
1848 newsrv->agent.server = newsrv;
Thierry Fournierada34842016-02-17 21:25:09 +01001849 newsrv->dns_opts.family_prio = curproxy->defsrv.dns_opts.family_prio;
1850 if (newsrv->dns_opts.family_prio == AF_UNSPEC)
1851 newsrv->dns_opts.family_prio = AF_INET6;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001852 memcpy(newsrv->dns_opts.pref_net,
1853 curproxy->defsrv.dns_opts.pref_net,
1854 sizeof(newsrv->dns_opts.pref_net));
1855 newsrv->dns_opts.pref_net_nb = curproxy->defsrv.dns_opts.pref_net_nb;
Baptiste Assmann25938272016-09-21 20:26:16 +02001856 newsrv->init_addr_methods = curproxy->defsrv.init_addr_methods;
1857 newsrv->init_addr = curproxy->defsrv.init_addr;
Frédéric Lécaille7c8cd582017-03-13 13:41:16 +01001858#if defined(USE_OPENSSL)
1859 /* SSL config. */
Frédéric Lécaille5e576432017-03-14 15:52:04 +01001860 if (curproxy->defsrv.ssl_ctx.ca_file != NULL)
1861 newsrv->ssl_ctx.ca_file = strdup(curproxy->defsrv.ssl_ctx.ca_file);
1862 if (curproxy->defsrv.ssl_ctx.crl_file != NULL)
1863 newsrv->ssl_ctx.crl_file = strdup(curproxy->defsrv.ssl_ctx.crl_file);
1864 if (curproxy->defsrv.ssl_ctx.client_crt != NULL)
Frédéric Lécailleacd48272017-03-29 14:58:09 +02001865 newsrv->ssl_ctx.client_crt = strdup(curproxy->defsrv.ssl_ctx.client_crt);
Frédéric Lécaille7c8cd582017-03-13 13:41:16 +01001866 newsrv->ssl_ctx.verify = curproxy->defsrv.ssl_ctx.verify;
Frédéric Lécaille273f3212017-03-13 15:52:01 +01001867 if (curproxy->defsrv.ssl_ctx.verify_host != NULL)
1868 newsrv->ssl_ctx.verify_host = strdup(curproxy->defsrv.ssl_ctx.verify_host);
Frédéric Lécaillebcaf1d72017-03-15 16:20:02 +01001869 if (curproxy->defsrv.ssl_ctx.ciphers != NULL)
1870 newsrv->ssl_ctx.ciphers = strdup(curproxy->defsrv.ssl_ctx.ciphers);
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01001871 if (curproxy->defsrv.sni_expr != NULL)
1872 newsrv->sni_expr = strdup(curproxy->defsrv.sni_expr);
Frédéric Lécaille7c8cd582017-03-13 13:41:16 +01001873#endif
Willy Tarreau272adea2014-03-31 10:39:59 +02001874
Frédéric Lécaille5c3cd972017-03-15 16:36:09 +01001875#ifdef TCP_USER_TIMEOUT
1876 newsrv->tcp_ut = curproxy->defsrv.tcp_ut;
1877#endif
1878
Willy Tarreau272adea2014-03-31 10:39:59 +02001879 cur_arg = 3;
1880 } else {
1881 newsrv = &curproxy->defsrv;
1882 cur_arg = 1;
Thierry Fournierada34842016-02-17 21:25:09 +01001883 newsrv->dns_opts.family_prio = AF_INET6;
Willy Tarreau272adea2014-03-31 10:39:59 +02001884 }
1885
1886 while (*args[cur_arg]) {
Frédéric Lécaille6e0843c2017-03-21 16:39:15 +01001887 if (!strcmp(args[cur_arg], "agent-inter")) {
Willy Tarreau272adea2014-03-31 10:39:59 +02001888 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
1889 if (err) {
1890 Alert("parsing [%s:%d] : unexpected character '%c' in 'agent-inter' argument of server %s.\n",
1891 file, linenum, *err, newsrv->id);
1892 err_code |= ERR_ALERT | ERR_FATAL;
1893 goto out;
1894 }
1895 if (val <= 0) {
1896 Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n",
1897 file, linenum, val, args[cur_arg], newsrv->id);
1898 err_code |= ERR_ALERT | ERR_FATAL;
1899 goto out;
1900 }
1901 newsrv->agent.inter = val;
1902 cur_arg += 2;
1903 }
Misiekea849332017-01-09 09:39:51 +01001904 else if (!strcmp(args[cur_arg], "agent-addr")) {
1905 if(str2ip(args[cur_arg + 1], &newsrv->agent.addr) == NULL) {
1906 Alert("parsing agent-addr failed. Check if %s is correct address.\n", args[cur_arg + 1]);
1907 goto out;
1908 }
1909
1910 cur_arg += 2;
1911 }
Willy Tarreau272adea2014-03-31 10:39:59 +02001912 else if (!strcmp(args[cur_arg], "agent-port")) {
1913 global.maxsock++;
1914 newsrv->agent.port = atol(args[cur_arg + 1]);
1915 cur_arg += 2;
1916 }
James Brown55f9ff12015-10-21 18:19:05 -07001917 else if (!strcmp(args[cur_arg], "agent-send")) {
1918 global.maxsock++;
1919 free(newsrv->agent.send_string);
1920 newsrv->agent.send_string_len = strlen(args[cur_arg + 1]);
1921 newsrv->agent.send_string = calloc(1, newsrv->agent.send_string_len + 1);
1922 memcpy(newsrv->agent.send_string, args[cur_arg + 1], newsrv->agent.send_string_len);
1923 cur_arg += 2;
1924 }
Baptiste Assmann25938272016-09-21 20:26:16 +02001925 else if (!strcmp(args[cur_arg], "init-addr")) {
1926 char *p, *end;
1927 int done;
Willy Tarreau4310d362016-11-02 15:05:56 +01001928 struct sockaddr_storage sa;
Baptiste Assmann25938272016-09-21 20:26:16 +02001929
1930 newsrv->init_addr_methods = 0;
1931 memset(&newsrv->init_addr, 0, sizeof(newsrv->init_addr));
1932
1933 for (p = args[cur_arg + 1]; *p; p = end) {
1934 /* cut on next comma */
1935 for (end = p; *end && *end != ','; end++);
1936 if (*end)
1937 *(end++) = 0;
1938
Willy Tarreau4310d362016-11-02 15:05:56 +01001939 memset(&sa, 0, sizeof(sa));
Baptiste Assmann25938272016-09-21 20:26:16 +02001940 if (!strcmp(p, "libc")) {
1941 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_LIBC);
1942 }
1943 else if (!strcmp(p, "last")) {
1944 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_LAST);
1945 }
Willy Tarreau37ebe122016-11-04 15:17:58 +01001946 else if (!strcmp(p, "none")) {
1947 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_NONE);
1948 }
Willy Tarreau4310d362016-11-02 15:05:56 +01001949 else if (str2ip2(p, &sa, 0)) {
1950 if (is_addr(&newsrv->init_addr)) {
1951 Alert("parsing [%s:%d]: '%s' : initial address already specified, cannot add '%s'.\n",
1952 file, linenum, args[cur_arg], p);
1953 err_code |= ERR_ALERT | ERR_FATAL;
1954 goto out;
1955 }
1956 newsrv->init_addr = sa;
1957 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_IP);
1958 }
Baptiste Assmann25938272016-09-21 20:26:16 +02001959 else {
Willy Tarreau37ebe122016-11-04 15:17:58 +01001960 Alert("parsing [%s:%d]: '%s' : unknown init-addr method '%s', supported methods are 'libc', 'last', 'none'.\n",
Baptiste Assmann25938272016-09-21 20:26:16 +02001961 file, linenum, args[cur_arg], p);
1962 err_code |= ERR_ALERT | ERR_FATAL;
1963 goto out;
1964 }
1965 if (!done) {
1966 Alert("parsing [%s:%d]: '%s' : too many init-addr methods when trying to add '%s'\n",
1967 file, linenum, args[cur_arg], p);
1968 err_code |= ERR_ALERT | ERR_FATAL;
1969 goto out;
1970 }
1971 }
1972 cur_arg += 2;
1973 }
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001974 else if (!strcmp(args[cur_arg], "resolvers")) {
1975 newsrv->resolvers_id = strdup(args[cur_arg + 1]);
1976 cur_arg += 2;
1977 }
1978 else if (!strcmp(args[cur_arg], "resolve-prefer")) {
1979 if (!strcmp(args[cur_arg + 1], "ipv4"))
Thierry Fournierada34842016-02-17 21:25:09 +01001980 newsrv->dns_opts.family_prio = AF_INET;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001981 else if (!strcmp(args[cur_arg + 1], "ipv6"))
Thierry Fournierada34842016-02-17 21:25:09 +01001982 newsrv->dns_opts.family_prio = AF_INET6;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02001983 else {
1984 Alert("parsing [%s:%d]: '%s' expects either ipv4 or ipv6 as argument.\n",
1985 file, linenum, args[cur_arg]);
1986 err_code |= ERR_ALERT | ERR_FATAL;
1987 goto out;
1988 }
1989 cur_arg += 2;
1990 }
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001991 else if (!strcmp(args[cur_arg], "resolve-net")) {
1992 char *p, *e;
1993 unsigned char mask;
1994 struct dns_options *opt;
1995
1996 if (!args[cur_arg + 1] || args[cur_arg + 1][0] == '\0') {
1997 Alert("parsing [%s:%d]: '%s' expects a list of networks.\n",
1998 file, linenum, args[cur_arg]);
1999 err_code |= ERR_ALERT | ERR_FATAL;
2000 goto out;
2001 }
2002
2003 opt = &newsrv->dns_opts;
2004
2005 /* Split arguments by comma, and convert it from ipv4 or ipv6
2006 * string network in in_addr or in6_addr.
2007 */
2008 p = args[cur_arg + 1];
2009 e = p;
2010 while (*p != '\0') {
2011 /* If no room avalaible, return error. */
David Carlierd10025c2016-04-08 10:26:44 +01002012 if (opt->pref_net_nb >= SRV_MAX_PREF_NET) {
Thierry Fournierac88cfe2016-02-17 22:05:30 +01002013 Alert("parsing [%s:%d]: '%s' exceed %d networks.\n",
2014 file, linenum, args[cur_arg], SRV_MAX_PREF_NET);
2015 err_code |= ERR_ALERT | ERR_FATAL;
2016 goto out;
2017 }
2018 /* look for end or comma. */
2019 while (*e != ',' && *e != '\0')
2020 e++;
2021 if (*e == ',') {
2022 *e = '\0';
2023 e++;
2024 }
2025 if (str2net(p, 0, &opt->pref_net[opt->pref_net_nb].addr.in4,
2026 &opt->pref_net[opt->pref_net_nb].mask.in4)) {
2027 /* Try to convert input string from ipv4 or ipv6 network. */
2028 opt->pref_net[opt->pref_net_nb].family = AF_INET;
2029 } else if (str62net(p, &opt->pref_net[opt->pref_net_nb].addr.in6,
2030 &mask)) {
2031 /* Try to convert input string from ipv6 network. */
2032 len2mask6(mask, &opt->pref_net[opt->pref_net_nb].mask.in6);
2033 opt->pref_net[opt->pref_net_nb].family = AF_INET6;
2034 } else {
2035 /* All network conversions fail, retrun error. */
2036 Alert("parsing [%s:%d]: '%s': invalid network '%s'.\n",
2037 file, linenum, args[cur_arg], p);
2038 err_code |= ERR_ALERT | ERR_FATAL;
2039 goto out;
2040 }
2041 opt->pref_net_nb++;
2042 p = e;
2043 }
2044
2045 cur_arg += 2;
2046 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002047 else if (!strcmp(args[cur_arg], "rise")) {
2048 if (!*args[cur_arg + 1]) {
2049 Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
2050 file, linenum, args[cur_arg]);
2051 err_code |= ERR_ALERT | ERR_FATAL;
2052 goto out;
2053 }
2054
2055 newsrv->check.rise = atol(args[cur_arg + 1]);
2056 if (newsrv->check.rise <= 0) {
2057 Alert("parsing [%s:%d]: '%s' has to be > 0.\n",
2058 file, linenum, args[cur_arg]);
2059 err_code |= ERR_ALERT | ERR_FATAL;
2060 goto out;
2061 }
2062
2063 if (newsrv->check.health)
2064 newsrv->check.health = newsrv->check.rise;
2065 cur_arg += 2;
2066 }
2067 else if (!strcmp(args[cur_arg], "fall")) {
2068 newsrv->check.fall = atol(args[cur_arg + 1]);
2069
2070 if (!*args[cur_arg + 1]) {
2071 Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
2072 file, linenum, args[cur_arg]);
2073 err_code |= ERR_ALERT | ERR_FATAL;
2074 goto out;
2075 }
2076
2077 if (newsrv->check.fall <= 0) {
2078 Alert("parsing [%s:%d]: '%s' has to be > 0.\n",
2079 file, linenum, args[cur_arg]);
2080 err_code |= ERR_ALERT | ERR_FATAL;
2081 goto out;
2082 }
2083
2084 cur_arg += 2;
2085 }
2086 else if (!strcmp(args[cur_arg], "inter")) {
2087 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
2088 if (err) {
2089 Alert("parsing [%s:%d] : unexpected character '%c' in 'inter' argument of server %s.\n",
2090 file, linenum, *err, newsrv->id);
2091 err_code |= ERR_ALERT | ERR_FATAL;
2092 goto out;
2093 }
2094 if (val <= 0) {
2095 Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n",
2096 file, linenum, val, args[cur_arg], newsrv->id);
2097 err_code |= ERR_ALERT | ERR_FATAL;
2098 goto out;
2099 }
2100 newsrv->check.inter = val;
2101 cur_arg += 2;
2102 }
2103 else if (!strcmp(args[cur_arg], "fastinter")) {
2104 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
2105 if (err) {
2106 Alert("parsing [%s:%d]: unexpected character '%c' in 'fastinter' argument of server %s.\n",
2107 file, linenum, *err, newsrv->id);
2108 err_code |= ERR_ALERT | ERR_FATAL;
2109 goto out;
2110 }
2111 if (val <= 0) {
2112 Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n",
2113 file, linenum, val, args[cur_arg], newsrv->id);
2114 err_code |= ERR_ALERT | ERR_FATAL;
2115 goto out;
2116 }
2117 newsrv->check.fastinter = val;
2118 cur_arg += 2;
2119 }
2120 else if (!strcmp(args[cur_arg], "downinter")) {
2121 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
2122 if (err) {
2123 Alert("parsing [%s:%d]: unexpected character '%c' in 'downinter' argument of server %s.\n",
2124 file, linenum, *err, newsrv->id);
2125 err_code |= ERR_ALERT | ERR_FATAL;
2126 goto out;
2127 }
2128 if (val <= 0) {
2129 Alert("parsing [%s:%d]: invalid value %d for argument '%s' of server %s.\n",
2130 file, linenum, val, args[cur_arg], newsrv->id);
2131 err_code |= ERR_ALERT | ERR_FATAL;
2132 goto out;
2133 }
2134 newsrv->check.downinter = val;
2135 cur_arg += 2;
2136 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002137 else if (!strcmp(args[cur_arg], "port")) {
2138 newsrv->check.port = atol(args[cur_arg + 1]);
Baptiste Assmann6b453f12016-08-11 23:12:18 +02002139 newsrv->flags |= SRV_F_CHECKPORT;
Willy Tarreau272adea2014-03-31 10:39:59 +02002140 cur_arg += 2;
2141 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002142 else if (!strcmp(args[cur_arg], "weight")) {
2143 int w;
2144 w = atol(args[cur_arg + 1]);
2145 if (w < 0 || w > SRV_UWGHT_MAX) {
2146 Alert("parsing [%s:%d] : weight of server %s is not within 0 and %d (%d).\n",
2147 file, linenum, newsrv->id, SRV_UWGHT_MAX, w);
2148 err_code |= ERR_ALERT | ERR_FATAL;
2149 goto out;
2150 }
2151 newsrv->uweight = newsrv->iweight = w;
2152 cur_arg += 2;
2153 }
2154 else if (!strcmp(args[cur_arg], "minconn")) {
2155 newsrv->minconn = atol(args[cur_arg + 1]);
2156 cur_arg += 2;
2157 }
2158 else if (!strcmp(args[cur_arg], "maxconn")) {
2159 newsrv->maxconn = atol(args[cur_arg + 1]);
2160 cur_arg += 2;
2161 }
2162 else if (!strcmp(args[cur_arg], "maxqueue")) {
2163 newsrv->maxqueue = atol(args[cur_arg + 1]);
2164 cur_arg += 2;
2165 }
2166 else if (!strcmp(args[cur_arg], "slowstart")) {
2167 /* slowstart is stored in seconds */
2168 const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
2169 if (err) {
2170 Alert("parsing [%s:%d] : unexpected character '%c' in 'slowstart' argument of server %s.\n",
2171 file, linenum, *err, newsrv->id);
2172 err_code |= ERR_ALERT | ERR_FATAL;
2173 goto out;
2174 }
2175 newsrv->slowstart = (val + 999) / 1000;
2176 cur_arg += 2;
2177 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002178 else if (!strcmp(args[cur_arg], "on-error")) {
2179 if (!strcmp(args[cur_arg + 1], "fastinter"))
2180 newsrv->onerror = HANA_ONERR_FASTINTER;
2181 else if (!strcmp(args[cur_arg + 1], "fail-check"))
2182 newsrv->onerror = HANA_ONERR_FAILCHK;
2183 else if (!strcmp(args[cur_arg + 1], "sudden-death"))
2184 newsrv->onerror = HANA_ONERR_SUDDTH;
2185 else if (!strcmp(args[cur_arg + 1], "mark-down"))
2186 newsrv->onerror = HANA_ONERR_MARKDWN;
2187 else {
2188 Alert("parsing [%s:%d]: '%s' expects one of 'fastinter', "
2189 "'fail-check', 'sudden-death' or 'mark-down' but got '%s'\n",
2190 file, linenum, args[cur_arg], args[cur_arg + 1]);
2191 err_code |= ERR_ALERT | ERR_FATAL;
2192 goto out;
2193 }
2194
2195 cur_arg += 2;
2196 }
2197 else if (!strcmp(args[cur_arg], "on-marked-down")) {
2198 if (!strcmp(args[cur_arg + 1], "shutdown-sessions"))
2199 newsrv->onmarkeddown = HANA_ONMARKEDDOWN_SHUTDOWNSESSIONS;
2200 else {
2201 Alert("parsing [%s:%d]: '%s' expects 'shutdown-sessions' but got '%s'\n",
2202 file, linenum, args[cur_arg], args[cur_arg + 1]);
2203 err_code |= ERR_ALERT | ERR_FATAL;
2204 goto out;
2205 }
2206
2207 cur_arg += 2;
2208 }
2209 else if (!strcmp(args[cur_arg], "on-marked-up")) {
2210 if (!strcmp(args[cur_arg + 1], "shutdown-backup-sessions"))
2211 newsrv->onmarkedup = HANA_ONMARKEDUP_SHUTDOWNBACKUPSESSIONS;
2212 else {
2213 Alert("parsing [%s:%d]: '%s' expects 'shutdown-backup-sessions' but got '%s'\n",
2214 file, linenum, args[cur_arg], args[cur_arg + 1]);
2215 err_code |= ERR_ALERT | ERR_FATAL;
2216 goto out;
2217 }
2218
2219 cur_arg += 2;
2220 }
2221 else if (!strcmp(args[cur_arg], "error-limit")) {
2222 if (!*args[cur_arg + 1]) {
2223 Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
2224 file, linenum, args[cur_arg]);
2225 err_code |= ERR_ALERT | ERR_FATAL;
2226 goto out;
2227 }
2228
2229 newsrv->consecutive_errors_limit = atoi(args[cur_arg + 1]);
2230
2231 if (newsrv->consecutive_errors_limit <= 0) {
2232 Alert("parsing [%s:%d]: %s has to be > 0.\n",
2233 file, linenum, args[cur_arg]);
2234 err_code |= ERR_ALERT | ERR_FATAL;
2235 goto out;
2236 }
2237 cur_arg += 2;
2238 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002239 else if (!defsrv && !strcmp(args[cur_arg], "usesrc")) { /* address to use outside: needs "source" first */
2240 Alert("parsing [%s:%d] : '%s' only allowed after a '%s' statement.\n",
2241 file, linenum, "usesrc", "source");
2242 err_code |= ERR_ALERT | ERR_FATAL;
2243 goto out;
KOVACS Krisztianb3e54fe2014-11-17 15:11:45 +01002244 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002245 else {
2246 static int srv_dumped;
2247 struct srv_kw *kw;
2248 char *err;
2249
2250 kw = srv_find_kw(args[cur_arg]);
2251 if (kw) {
2252 char *err = NULL;
2253 int code;
2254
2255 if (!kw->parse) {
2256 Alert("parsing [%s:%d] : '%s %s' : '%s' option is not implemented in this version (check build options).\n",
2257 file, linenum, args[0], args[1], args[cur_arg]);
2258 cur_arg += 1 + kw->skip ;
2259 err_code |= ERR_ALERT | ERR_FATAL;
2260 goto out;
2261 }
2262
2263 if (defsrv && !kw->default_ok) {
2264 Alert("parsing [%s:%d] : '%s %s' : '%s' option is not accepted in default-server sections.\n",
2265 file, linenum, args[0], args[1], args[cur_arg]);
2266 cur_arg += 1 + kw->skip ;
2267 err_code |= ERR_ALERT;
2268 continue;
2269 }
2270
2271 code = kw->parse(args, &cur_arg, curproxy, newsrv, &err);
2272 err_code |= code;
2273
2274 if (code) {
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002275 display_parser_err(file, linenum, args, cur_arg, &err);
Willy Tarreau272adea2014-03-31 10:39:59 +02002276 if (code & ERR_FATAL) {
2277 free(err);
2278 cur_arg += 1 + kw->skip;
2279 goto out;
2280 }
2281 }
2282 free(err);
2283 cur_arg += 1 + kw->skip;
2284 continue;
2285 }
2286
2287 err = NULL;
2288 if (!srv_dumped) {
2289 srv_dump_kws(&err);
2290 indent_msg(&err, 4);
2291 srv_dumped = 1;
2292 }
2293
2294 Alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'.%s%s\n",
2295 file, linenum, args[0], args[1], args[cur_arg],
2296 err ? " Registered keywords :" : "", err ? err : "");
2297 free(err);
2298
2299 err_code |= ERR_ALERT | ERR_FATAL;
2300 goto out;
2301 }
2302 }
2303
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01002304 /* This check is done only for 'server' instances. */
2305 if (!defsrv && newsrv->do_check) {
Simon Hormanb1900d52015-01-30 11:22:54 +09002306 const char *ret;
Willy Tarreau272adea2014-03-31 10:39:59 +02002307
2308 if (newsrv->trackit) {
2309 Alert("parsing [%s:%d]: unable to enable checks and tracking at the same time!\n",
2310 file, linenum);
2311 err_code |= ERR_ALERT | ERR_FATAL;
2312 goto out;
2313 }
2314
Willy Tarreau272adea2014-03-31 10:39:59 +02002315 /*
2316 * We need at least a service port, a check port or the first tcp-check rule must
Willy Tarreau5cf0b522014-05-09 23:59:19 +02002317 * be a 'connect' one when checking an IPv4/IPv6 server.
Willy Tarreau272adea2014-03-31 10:39:59 +02002318 */
Baptiste Assmann95db2bc2016-06-13 14:15:41 +02002319 if ((srv_check_healthcheck_port(&newsrv->check) == 0) &&
Simon Horman41f58762015-01-30 11:22:56 +09002320 (is_inet_addr(&newsrv->check.addr) ||
2321 (!is_addr(&newsrv->check.addr) && is_inet_addr(&newsrv->addr)))) {
Willy Tarreau1a786d72016-03-08 15:20:25 +01002322 struct tcpcheck_rule *r = NULL;
Willy Tarreau272adea2014-03-31 10:39:59 +02002323 struct list *l;
2324
2325 r = (struct tcpcheck_rule *)newsrv->proxy->tcpcheck_rules.n;
2326 if (!r) {
2327 Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
2328 file, linenum, newsrv->id);
2329 err_code |= ERR_ALERT | ERR_FATAL;
2330 goto out;
2331 }
Baptiste Assmannbaf97942015-12-04 06:49:31 +01002332 /* search the first action (connect / send / expect) in the list */
2333 l = &newsrv->proxy->tcpcheck_rules;
Willy Tarreau1a786d72016-03-08 15:20:25 +01002334 list_for_each_entry(r, l, list) {
Baptiste Assmannbaf97942015-12-04 06:49:31 +01002335 if (r->action != TCPCHK_ACT_COMMENT)
2336 break;
2337 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002338 if ((r->action != TCPCHK_ACT_CONNECT) || !r->port) {
2339 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",
2340 file, linenum, newsrv->id);
2341 err_code |= ERR_ALERT | ERR_FATAL;
2342 goto out;
2343 }
2344 else {
2345 /* scan the tcp-check ruleset to ensure a port has been configured */
2346 l = &newsrv->proxy->tcpcheck_rules;
Willy Tarreau1a786d72016-03-08 15:20:25 +01002347 list_for_each_entry(r, l, list) {
Willy Tarreau272adea2014-03-31 10:39:59 +02002348 if ((r->action == TCPCHK_ACT_CONNECT) && (!r->port)) {
2349 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",
2350 file, linenum, newsrv->id);
2351 err_code |= ERR_ALERT | ERR_FATAL;
2352 goto out;
2353 }
2354 }
2355 }
2356 }
2357
2358 /* note: check type will be set during the config review phase */
Simon Hormanb1900d52015-01-30 11:22:54 +09002359 ret = init_check(&newsrv->check, 0);
Willy Tarreau272adea2014-03-31 10:39:59 +02002360 if (ret) {
Simon Hormanb1900d52015-01-30 11:22:54 +09002361 Alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
2362 err_code |= ERR_ALERT | ERR_ABORT;
Willy Tarreau272adea2014-03-31 10:39:59 +02002363 goto out;
2364 }
2365
Baptiste Assmanna68ca962015-04-14 01:15:08 +02002366 if (newsrv->resolution)
Thierry Fournierada34842016-02-17 21:25:09 +01002367 newsrv->resolution->opts = &newsrv->dns_opts;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02002368
Willy Tarreau272adea2014-03-31 10:39:59 +02002369 newsrv->check.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED;
Frédéric Lécaille65aa3562017-03-14 11:20:13 +01002370 global.maxsock++;
Willy Tarreau272adea2014-03-31 10:39:59 +02002371 }
2372
Frédéric Lécaille6e0843c2017-03-21 16:39:15 +01002373 if (!defsrv && newsrv->do_agent) {
Simon Hormanb1900d52015-01-30 11:22:54 +09002374 const char *ret;
Willy Tarreau272adea2014-03-31 10:39:59 +02002375
2376 if (!newsrv->agent.port) {
2377 Alert("parsing [%s:%d] : server %s does not have agent port. Agent check has been disabled.\n",
2378 file, linenum, newsrv->id);
2379 err_code |= ERR_ALERT | ERR_FATAL;
2380 goto out;
2381 }
2382
2383 if (!newsrv->agent.inter)
2384 newsrv->agent.inter = newsrv->check.inter;
2385
Simon Hormanb1900d52015-01-30 11:22:54 +09002386 ret = init_check(&newsrv->agent, PR_O2_LB_AGENT_CHK);
Willy Tarreau272adea2014-03-31 10:39:59 +02002387 if (ret) {
Simon Hormanb1900d52015-01-30 11:22:54 +09002388 Alert("parsing [%s:%d] : %s.\n", file, linenum, ret);
2389 err_code |= ERR_ALERT | ERR_ABORT;
Willy Tarreau272adea2014-03-31 10:39:59 +02002390 goto out;
2391 }
2392
2393 newsrv->agent.state |= CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_AGENT;
Frédéric Lécaille6e0843c2017-03-21 16:39:15 +01002394 global.maxsock++;
Willy Tarreau272adea2014-03-31 10:39:59 +02002395 }
2396
2397 if (!defsrv) {
Willy Tarreauc93cd162014-05-13 15:54:22 +02002398 if (newsrv->flags & SRV_F_BACKUP)
Willy Tarreau272adea2014-03-31 10:39:59 +02002399 curproxy->srv_bck++;
2400 else
2401 curproxy->srv_act++;
2402
Willy Tarreauc5150da2014-05-13 19:27:31 +02002403 srv_lb_commit_status(newsrv);
Willy Tarreau272adea2014-03-31 10:39:59 +02002404 }
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002405#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2406 if (!defsrv && newsrv->sni_expr) {
2407 int code;
2408 char *err;
2409
2410 err = NULL;
2411
2412 code = server_parse_sni_expr(newsrv, curproxy, &err);
2413 err_code |= code;
2414 if (code) {
2415 display_parser_err(file, linenum, args, cur_arg, &err);
2416 free(err);
2417 if (code & ERR_FATAL)
2418 goto out;
2419 }
2420 }
2421#endif
Willy Tarreau272adea2014-03-31 10:39:59 +02002422 }
Willy Tarreau07101d52015-09-08 16:16:35 +02002423 free(fqdn);
Willy Tarreau272adea2014-03-31 10:39:59 +02002424 return 0;
2425
2426 out:
Willy Tarreau07101d52015-09-08 16:16:35 +02002427 free(fqdn);
Willy Tarreau272adea2014-03-31 10:39:59 +02002428 free(errmsg);
2429 return err_code;
2430}
2431
Baptiste Assmann19a106d2015-07-08 22:03:56 +02002432/* Returns a pointer to the first server matching either id <id>.
2433 * NULL is returned if no match is found.
2434 * the lookup is performed in the backend <bk>
2435 */
2436struct server *server_find_by_id(struct proxy *bk, int id)
2437{
2438 struct eb32_node *eb32;
2439 struct server *curserver;
2440
2441 if (!bk || (id ==0))
2442 return NULL;
2443
2444 /* <bk> has no backend capabilities, so it can't have a server */
2445 if (!(bk->cap & PR_CAP_BE))
2446 return NULL;
2447
2448 curserver = NULL;
2449
2450 eb32 = eb32_lookup(&bk->conf.used_server_id, id);
2451 if (eb32)
2452 curserver = container_of(eb32, struct server, conf.id);
2453
2454 return curserver;
2455}
2456
2457/* Returns a pointer to the first server matching either name <name>, or id
2458 * if <name> starts with a '#'. NULL is returned if no match is found.
2459 * the lookup is performed in the backend <bk>
2460 */
2461struct server *server_find_by_name(struct proxy *bk, const char *name)
2462{
2463 struct server *curserver;
2464
2465 if (!bk || !name)
2466 return NULL;
2467
2468 /* <bk> has no backend capabilities, so it can't have a server */
2469 if (!(bk->cap & PR_CAP_BE))
2470 return NULL;
2471
2472 curserver = NULL;
2473 if (*name == '#') {
2474 curserver = server_find_by_id(bk, atoi(name + 1));
2475 if (curserver)
2476 return curserver;
2477 }
2478 else {
2479 curserver = bk->srv;
2480
2481 while (curserver && (strcmp(curserver->id, name) != 0))
2482 curserver = curserver->next;
2483
2484 if (curserver)
2485 return curserver;
2486 }
2487
2488 return NULL;
2489}
2490
2491struct server *server_find_best_match(struct proxy *bk, char *name, int id, int *diff)
2492{
2493 struct server *byname;
2494 struct server *byid;
2495
2496 if (!name && !id)
2497 return NULL;
2498
2499 if (diff)
2500 *diff = 0;
2501
2502 byname = byid = NULL;
2503
2504 if (name) {
2505 byname = server_find_by_name(bk, name);
2506 if (byname && (!id || byname->puid == id))
2507 return byname;
2508 }
2509
2510 /* remaining possibilities :
2511 * - name not set
2512 * - name set but not found
2513 * - name found but ID doesn't match
2514 */
2515 if (id) {
2516 byid = server_find_by_id(bk, id);
2517 if (byid) {
2518 if (byname) {
2519 /* use id only if forced by configuration */
2520 if (byid->flags & SRV_F_FORCED_ID) {
2521 if (diff)
2522 *diff |= 2;
2523 return byid;
2524 }
2525 else {
2526 if (diff)
2527 *diff |= 1;
2528 return byname;
2529 }
2530 }
2531
2532 /* remaining possibilities:
2533 * - name not set
2534 * - name set but not found
2535 */
2536 if (name && diff)
2537 *diff |= 2;
2538 return byid;
2539 }
2540
2541 /* id bot found */
2542 if (byname) {
2543 if (diff)
2544 *diff |= 1;
2545 return byname;
2546 }
2547 }
2548
2549 return NULL;
2550}
2551
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002552/* Update a server state using the parameters available in the params list */
2553static void srv_update_state(struct server *srv, int version, char **params)
2554{
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002555 char *p;
Willy Tarreau31138fa2015-09-29 18:38:47 +02002556 struct chunk *msg;
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002557
2558 /* fields since version 1
2559 * and common to all other upcoming versions
2560 */
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002561 enum srv_state srv_op_state;
2562 enum srv_admin srv_admin_state;
2563 unsigned srv_uweight, srv_iweight;
2564 unsigned long srv_last_time_change;
2565 short srv_check_status;
2566 enum chk_result srv_check_result;
2567 int srv_check_health;
2568 int srv_check_state, srv_agent_state;
2569 int bk_f_forced_id;
2570 int srv_f_forced_id;
2571
Willy Tarreau31138fa2015-09-29 18:38:47 +02002572 msg = get_trash_chunk();
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002573 switch (version) {
2574 case 1:
2575 /*
2576 * now we can proceed with server's state update:
2577 * srv_addr: params[0]
2578 * srv_op_state: params[1]
2579 * srv_admin_state: params[2]
2580 * srv_uweight: params[3]
2581 * srv_iweight: params[4]
2582 * srv_last_time_change: params[5]
2583 * srv_check_status: params[6]
2584 * srv_check_result: params[7]
2585 * srv_check_health: params[8]
2586 * srv_check_state: params[9]
2587 * srv_agent_state: params[10]
2588 * bk_f_forced_id: params[11]
2589 * srv_f_forced_id: params[12]
2590 */
2591
2592 /* validating srv_op_state */
2593 p = NULL;
2594 errno = 0;
2595 srv_op_state = strtol(params[1], &p, 10);
2596 if ((p == params[1]) || errno == EINVAL || errno == ERANGE ||
2597 (srv_op_state != SRV_ST_STOPPED &&
2598 srv_op_state != SRV_ST_STARTING &&
2599 srv_op_state != SRV_ST_RUNNING &&
2600 srv_op_state != SRV_ST_STOPPING)) {
2601 chunk_appendf(msg, ", invalid srv_op_state value '%s'", params[1]);
2602 }
2603
2604 /* validating srv_admin_state */
2605 p = NULL;
2606 errno = 0;
2607 srv_admin_state = strtol(params[2], &p, 10);
Willy Tarreau757478e2016-11-03 19:22:19 +01002608
2609 /* inherited statuses will be recomputed later */
2610 srv_admin_state &= ~SRV_ADMF_IDRAIN & ~SRV_ADMF_IMAINT;
2611
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002612 if ((p == params[2]) || errno == EINVAL || errno == ERANGE ||
2613 (srv_admin_state != 0 &&
2614 srv_admin_state != SRV_ADMF_FMAINT &&
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002615 srv_admin_state != SRV_ADMF_CMAINT &&
2616 srv_admin_state != (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT) &&
Willy Tarreaue1bde142016-11-03 18:33:25 +01002617 srv_admin_state != (SRV_ADMF_CMAINT | SRV_ADMF_FDRAIN) &&
Willy Tarreau757478e2016-11-03 19:22:19 +01002618 srv_admin_state != SRV_ADMF_FDRAIN)) {
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002619 chunk_appendf(msg, ", invalid srv_admin_state value '%s'", params[2]);
2620 }
2621
2622 /* validating srv_uweight */
2623 p = NULL;
2624 errno = 0;
2625 srv_uweight = strtol(params[3], &p, 10);
Willy Tarreaue1aebb22015-09-29 18:32:57 +02002626 if ((p == params[3]) || errno == EINVAL || errno == ERANGE || (srv_uweight > SRV_UWGHT_MAX))
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002627 chunk_appendf(msg, ", invalid srv_uweight value '%s'", params[3]);
2628
2629 /* validating srv_iweight */
2630 p = NULL;
2631 errno = 0;
2632 srv_iweight = strtol(params[4], &p, 10);
Willy Tarreaue1aebb22015-09-29 18:32:57 +02002633 if ((p == params[4]) || errno == EINVAL || errno == ERANGE || (srv_iweight > SRV_UWGHT_MAX))
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002634 chunk_appendf(msg, ", invalid srv_iweight value '%s'", params[4]);
2635
2636 /* validating srv_last_time_change */
2637 p = NULL;
2638 errno = 0;
2639 srv_last_time_change = strtol(params[5], &p, 10);
2640 if ((p == params[5]) || errno == EINVAL || errno == ERANGE)
2641 chunk_appendf(msg, ", invalid srv_last_time_change value '%s'", params[5]);
2642
2643 /* validating srv_check_status */
2644 p = NULL;
2645 errno = 0;
2646 srv_check_status = strtol(params[6], &p, 10);
2647 if (p == params[6] || errno == EINVAL || errno == ERANGE ||
2648 (srv_check_status >= HCHK_STATUS_SIZE))
2649 chunk_appendf(msg, ", invalid srv_check_status value '%s'", params[6]);
2650
2651 /* validating srv_check_result */
2652 p = NULL;
2653 errno = 0;
2654 srv_check_result = strtol(params[7], &p, 10);
2655 if ((p == params[7]) || errno == EINVAL || errno == ERANGE ||
2656 (srv_check_result != CHK_RES_UNKNOWN &&
2657 srv_check_result != CHK_RES_NEUTRAL &&
2658 srv_check_result != CHK_RES_FAILED &&
2659 srv_check_result != CHK_RES_PASSED &&
2660 srv_check_result != CHK_RES_CONDPASS)) {
2661 chunk_appendf(msg, ", invalid srv_check_result value '%s'", params[7]);
2662 }
2663
2664 /* validating srv_check_health */
2665 p = NULL;
2666 errno = 0;
2667 srv_check_health = strtol(params[8], &p, 10);
2668 if (p == params[8] || errno == EINVAL || errno == ERANGE)
2669 chunk_appendf(msg, ", invalid srv_check_health value '%s'", params[8]);
2670
2671 /* validating srv_check_state */
2672 p = NULL;
2673 errno = 0;
2674 srv_check_state = strtol(params[9], &p, 10);
2675 if (p == params[9] || errno == EINVAL || errno == ERANGE ||
2676 (srv_check_state & ~(CHK_ST_INPROGRESS | CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_PAUSED | CHK_ST_AGENT)))
2677 chunk_appendf(msg, ", invalid srv_check_state value '%s'", params[9]);
2678
2679 /* validating srv_agent_state */
2680 p = NULL;
2681 errno = 0;
2682 srv_agent_state = strtol(params[10], &p, 10);
2683 if (p == params[10] || errno == EINVAL || errno == ERANGE ||
2684 (srv_agent_state & ~(CHK_ST_INPROGRESS | CHK_ST_CONFIGURED | CHK_ST_ENABLED | CHK_ST_PAUSED | CHK_ST_AGENT)))
2685 chunk_appendf(msg, ", invalid srv_agent_state value '%s'", params[10]);
2686
2687 /* validating bk_f_forced_id */
2688 p = NULL;
2689 errno = 0;
2690 bk_f_forced_id = strtol(params[11], &p, 10);
2691 if (p == params[11] || errno == EINVAL || errno == ERANGE || !((bk_f_forced_id == 0) || (bk_f_forced_id == 1)))
2692 chunk_appendf(msg, ", invalid bk_f_forced_id value '%s'", params[11]);
2693
2694 /* validating srv_f_forced_id */
2695 p = NULL;
2696 errno = 0;
2697 srv_f_forced_id = strtol(params[12], &p, 10);
2698 if (p == params[12] || errno == EINVAL || errno == ERANGE || !((srv_f_forced_id == 0) || (srv_f_forced_id == 1)))
2699 chunk_appendf(msg, ", invalid srv_f_forced_id value '%s'", params[12]);
2700
2701
2702 /* don't apply anything if one error has been detected */
Willy Tarreau31138fa2015-09-29 18:38:47 +02002703 if (msg->len)
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002704 goto out;
2705
2706 /* recover operational state and apply it to this server
2707 * and all servers tracking this one */
2708 switch (srv_op_state) {
2709 case SRV_ST_STOPPED:
2710 srv->check.health = 0;
2711 srv_set_stopped(srv, "changed from server-state after a reload");
2712 break;
2713 case SRV_ST_STARTING:
2714 srv->state = srv_op_state;
2715 break;
2716 case SRV_ST_STOPPING:
2717 srv->check.health = srv->check.rise + srv->check.fall - 1;
2718 srv_set_stopping(srv, "changed from server-state after a reload");
2719 break;
2720 case SRV_ST_RUNNING:
2721 srv->check.health = srv->check.rise + srv->check.fall - 1;
2722 srv_set_running(srv, "");
2723 break;
2724 }
2725
2726 /* When applying server state, the following rules apply:
2727 * - in case of a configuration change, we apply the setting from the new
2728 * configuration, regardless of old running state
2729 * - if no configuration change, we apply old running state only if old running
2730 * state is different from new configuration state
2731 */
2732 /* configuration has changed */
2733 if ((srv_admin_state & SRV_ADMF_CMAINT) != (srv->admin & SRV_ADMF_CMAINT)) {
2734 if (srv->admin & SRV_ADMF_CMAINT)
2735 srv_adm_set_maint(srv);
2736 else
2737 srv_adm_set_ready(srv);
2738 }
2739 /* configuration is the same, let's compate old running state and new conf state */
2740 else {
2741 if (srv_admin_state & SRV_ADMF_FMAINT && !(srv->admin & SRV_ADMF_CMAINT))
2742 srv_adm_set_maint(srv);
2743 else if (!(srv_admin_state & SRV_ADMF_FMAINT) && (srv->admin & SRV_ADMF_CMAINT))
2744 srv_adm_set_ready(srv);
2745 }
2746 /* apply drain mode if server is currently enabled */
2747 if (!(srv->admin & SRV_ADMF_FMAINT) && (srv_admin_state & SRV_ADMF_FDRAIN)) {
2748 /* The SRV_ADMF_FDRAIN flag is inherited when srv->iweight is 0
Willy Tarreau22cace22016-11-03 18:19:49 +01002749 * (srv->iweight is the weight set up in configuration).
2750 * There are two possible reasons for FDRAIN to have been present :
2751 * - previous config weight was zero
2752 * - "set server b/s drain" was sent to the CLI
2753 *
2754 * In the first case, we simply want to drop this drain state
2755 * if the new weight is not zero anymore, meaning the administrator
2756 * has intentionally turned the weight back to a positive value to
2757 * enable the server again after an operation. In the second case,
2758 * the drain state was forced on the CLI regardless of the config's
2759 * weight so we don't want a change to the config weight to lose this
2760 * status. What this means is :
2761 * - if previous weight was 0 and new one is >0, drop the DRAIN state.
2762 * - if the previous weight was >0, keep it.
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002763 */
Willy Tarreau22cace22016-11-03 18:19:49 +01002764 if (srv_iweight > 0 || srv->iweight == 0)
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002765 srv_adm_set_drain(srv);
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002766 }
2767
2768 srv->last_change = date.tv_sec - srv_last_time_change;
2769 srv->check.status = srv_check_status;
2770 srv->check.result = srv_check_result;
2771 srv->check.health = srv_check_health;
2772
2773 /* Only case we want to apply is removing ENABLED flag which could have been
2774 * done by the "disable health" command over the stats socket
2775 */
2776 if ((srv->check.state & CHK_ST_CONFIGURED) &&
2777 (srv_check_state & CHK_ST_CONFIGURED) &&
2778 !(srv_check_state & CHK_ST_ENABLED))
2779 srv->check.state &= ~CHK_ST_ENABLED;
2780
2781 /* Only case we want to apply is removing ENABLED flag which could have been
2782 * done by the "disable agent" command over the stats socket
2783 */
2784 if ((srv->agent.state & CHK_ST_CONFIGURED) &&
2785 (srv_agent_state & CHK_ST_CONFIGURED) &&
2786 !(srv_agent_state & CHK_ST_ENABLED))
2787 srv->agent.state &= ~CHK_ST_ENABLED;
2788
Baptiste Assmann6076d1c2015-09-17 22:53:59 +02002789 /* We want to apply the previous 'running' weight (srv_uweight) only if there
2790 * was no change in the configuration: both previous and new iweight are equals
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002791 *
Baptiste Assmann6076d1c2015-09-17 22:53:59 +02002792 * It means that a configuration file change has precedence over a unix socket change
2793 * for server's weight
2794 *
2795 * by default, HAProxy applies the following weight when parsing the configuration
2796 * srv->uweight = srv->iweight
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002797 */
Baptiste Assmann6076d1c2015-09-17 22:53:59 +02002798 if (srv_iweight == srv->iweight) {
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002799 srv->uweight = srv_uweight;
2800 }
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002801 server_recalc_eweight(srv);
2802
Willy Tarreaue5a60682016-11-09 14:54:53 +01002803 /* load server IP address */
2804 srv->lastaddr = strdup(params[0]);
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002805 break;
2806 default:
2807 chunk_appendf(msg, ", version '%d' not supported", version);
2808 }
2809
2810 out:
Baptiste Assmann0821bb92016-01-21 00:20:50 +01002811 if (msg->len) {
2812 chunk_appendf(msg, "\n");
Willy Tarreau31138fa2015-09-29 18:38:47 +02002813 Warning("server-state application failed for server '%s/%s'%s",
2814 srv->proxy->id, srv->id, msg->str);
Baptiste Assmann0821bb92016-01-21 00:20:50 +01002815 }
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002816}
2817
2818/* This function parses all the proxies and only take care of the backends (since we're looking for server)
2819 * For each proxy, it does the following:
2820 * - opens its server state file (either one or local one)
2821 * - read whole file, line by line
2822 * - analyse each line to check if it matches our current backend:
2823 * - backend name matches
2824 * - backend id matches if id is forced and name doesn't match
2825 * - if the server pointed by the line is found, then state is applied
2826 *
2827 * If the running backend uuid or id differs from the state file, then HAProxy reports
2828 * a warning.
2829 */
2830void apply_server_state(void)
2831{
2832 char *cur, *end;
2833 char mybuf[SRV_STATE_LINE_MAXLEN];
2834 int mybuflen;
2835 char *params[SRV_STATE_FILE_MAX_FIELDS];
2836 char *srv_params[SRV_STATE_FILE_MAX_FIELDS];
2837 int arg, srv_arg, version, diff;
2838 FILE *f;
2839 char *filepath;
2840 char globalfilepath[MAXPATHLEN + 1];
2841 char localfilepath[MAXPATHLEN + 1];
2842 int len, fileopenerr, globalfilepathlen, localfilepathlen;
2843 extern struct proxy *proxy;
2844 struct proxy *curproxy, *bk;
2845 struct server *srv;
2846
2847 globalfilepathlen = 0;
2848 /* create the globalfilepath variable */
2849 if (global.server_state_file) {
2850 /* absolute path or no base directory provided */
2851 if ((global.server_state_file[0] == '/') || (!global.server_state_base)) {
2852 len = strlen(global.server_state_file);
2853 if (len > MAXPATHLEN) {
2854 globalfilepathlen = 0;
2855 goto globalfileerror;
2856 }
2857 memcpy(globalfilepath, global.server_state_file, len);
2858 globalfilepath[len] = '\0';
2859 globalfilepathlen = len;
2860 }
2861 else if (global.server_state_base) {
2862 len = strlen(global.server_state_base);
2863 globalfilepathlen += len;
2864
2865 if (globalfilepathlen > MAXPATHLEN) {
2866 globalfilepathlen = 0;
2867 goto globalfileerror;
2868 }
2869 strncpy(globalfilepath, global.server_state_base, len);
2870 globalfilepath[globalfilepathlen] = 0;
2871
2872 /* append a slash if needed */
2873 if (!globalfilepathlen || globalfilepath[globalfilepathlen - 1] != '/') {
2874 if (globalfilepathlen + 1 > MAXPATHLEN) {
2875 globalfilepathlen = 0;
2876 goto globalfileerror;
2877 }
2878 globalfilepath[globalfilepathlen++] = '/';
2879 }
2880
2881 len = strlen(global.server_state_file);
2882 if (globalfilepathlen + len > MAXPATHLEN) {
2883 globalfilepathlen = 0;
2884 goto globalfileerror;
2885 }
2886 memcpy(globalfilepath + globalfilepathlen, global.server_state_file, len);
2887 globalfilepathlen += len;
2888 globalfilepath[globalfilepathlen++] = 0;
2889 }
2890 }
2891 globalfileerror:
2892 if (globalfilepathlen == 0)
2893 globalfilepath[0] = '\0';
2894
2895 /* read servers state from local file */
2896 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
2897 /* servers are only in backends */
2898 if (!(curproxy->cap & PR_CAP_BE))
2899 continue;
2900 fileopenerr = 0;
2901 filepath = NULL;
2902
2903 /* search server state file path and name */
2904 switch (curproxy->load_server_state_from_file) {
2905 /* read servers state from global file */
2906 case PR_SRV_STATE_FILE_GLOBAL:
2907 /* there was an error while generating global server state file path */
2908 if (globalfilepathlen == 0)
2909 continue;
2910 filepath = globalfilepath;
2911 fileopenerr = 1;
2912 break;
2913 /* this backend has its own file */
2914 case PR_SRV_STATE_FILE_LOCAL:
2915 localfilepathlen = 0;
2916 localfilepath[0] = '\0';
2917 len = 0;
2918 /* create the localfilepath variable */
2919 /* absolute path or no base directory provided */
2920 if ((curproxy->server_state_file_name[0] == '/') || (!global.server_state_base)) {
2921 len = strlen(curproxy->server_state_file_name);
2922 if (len > MAXPATHLEN) {
2923 localfilepathlen = 0;
2924 goto localfileerror;
2925 }
2926 memcpy(localfilepath, curproxy->server_state_file_name, len);
2927 localfilepath[len] = '\0';
2928 localfilepathlen = len;
2929 }
2930 else if (global.server_state_base) {
2931 len = strlen(global.server_state_base);
2932 localfilepathlen += len;
2933
2934 if (localfilepathlen > MAXPATHLEN) {
2935 localfilepathlen = 0;
2936 goto localfileerror;
2937 }
2938 strncpy(localfilepath, global.server_state_base, len);
2939 localfilepath[localfilepathlen] = 0;
2940
2941 /* append a slash if needed */
2942 if (!localfilepathlen || localfilepath[localfilepathlen - 1] != '/') {
2943 if (localfilepathlen + 1 > MAXPATHLEN) {
2944 localfilepathlen = 0;
2945 goto localfileerror;
2946 }
2947 localfilepath[localfilepathlen++] = '/';
2948 }
2949
2950 len = strlen(curproxy->server_state_file_name);
2951 if (localfilepathlen + len > MAXPATHLEN) {
2952 localfilepathlen = 0;
2953 goto localfileerror;
2954 }
2955 memcpy(localfilepath + localfilepathlen, curproxy->server_state_file_name, len);
2956 localfilepathlen += len;
2957 localfilepath[localfilepathlen++] = 0;
2958 }
2959 filepath = localfilepath;
2960 localfileerror:
2961 if (localfilepathlen == 0)
2962 localfilepath[0] = '\0';
2963
2964 break;
2965 case PR_SRV_STATE_FILE_NONE:
2966 default:
2967 continue;
2968 }
2969
2970 /* preload global state file */
2971 errno = 0;
2972 f = fopen(filepath, "r");
2973 if (errno && fileopenerr)
2974 Warning("Can't open server state file '%s': %s\n", filepath, strerror(errno));
2975 if (!f)
2976 continue;
2977
2978 mybuf[0] = '\0';
2979 mybuflen = 0;
2980 version = 0;
2981
2982 /* first character of first line of the file must contain the version of the export */
Dragan Dosencf4fb032015-11-04 23:03:26 +01002983 if (fgets(mybuf, SRV_STATE_LINE_MAXLEN, f) == NULL) {
2984 Warning("Can't read first line of the server state file '%s'\n", filepath);
2985 goto fileclose;
2986 }
2987
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002988 cur = mybuf;
2989 version = atoi(cur);
2990 if ((version < SRV_STATE_FILE_VERSION_MIN) ||
2991 (version > SRV_STATE_FILE_VERSION_MAX))
Dragan Dosencf4fb032015-11-04 23:03:26 +01002992 goto fileclose;
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02002993
2994 while (fgets(mybuf, SRV_STATE_LINE_MAXLEN, f)) {
2995 int bk_f_forced_id = 0;
2996 int check_id = 0;
2997 int check_name = 0;
2998
2999 mybuflen = strlen(mybuf);
3000 cur = mybuf;
3001 end = cur + mybuflen;
3002
3003 bk = NULL;
3004 srv = NULL;
3005
3006 /* we need at least one character */
3007 if (mybuflen == 0)
3008 continue;
3009
3010 /* ignore blank characters at the beginning of the line */
3011 while (isspace(*cur))
3012 ++cur;
3013
3014 if (cur == end)
3015 continue;
3016
3017 /* ignore comment line */
3018 if (*cur == '#')
3019 continue;
3020
3021 /* we're now ready to move the line into *srv_params[] */
3022 params[0] = cur;
3023 arg = 1;
3024 srv_arg = 0;
3025 while (*cur && arg < SRV_STATE_FILE_MAX_FIELDS) {
3026 if (isspace(*cur)) {
3027 *cur = '\0';
3028 ++cur;
3029 while (isspace(*cur))
3030 ++cur;
3031 switch (version) {
3032 case 1:
3033 /*
3034 * srv_addr: params[4] => srv_params[0]
3035 * srv_op_state: params[5] => srv_params[1]
3036 * srv_admin_state: params[6] => srv_params[2]
3037 * srv_uweight: params[7] => srv_params[3]
3038 * srv_iweight: params[8] => srv_params[4]
3039 * srv_last_time_change: params[9] => srv_params[5]
3040 * srv_check_status: params[10] => srv_params[6]
3041 * srv_check_result: params[11] => srv_params[7]
3042 * srv_check_health: params[12] => srv_params[8]
3043 * srv_check_state: params[13] => srv_params[9]
3044 * srv_agent_state: params[14] => srv_params[10]
3045 * bk_f_forced_id: params[15] => srv_params[11]
3046 * srv_f_forced_id: params[16] => srv_params[12]
3047 */
3048 if (arg >= 4) {
3049 srv_params[srv_arg] = cur;
3050 ++srv_arg;
3051 }
3052 break;
3053 }
3054
3055 params[arg] = cur;
3056 ++arg;
3057 }
3058 else {
3059 ++cur;
3060 }
3061 }
3062
3063 /* if line is incomplete line, then ignore it.
3064 * otherwise, update useful flags */
3065 switch (version) {
3066 case 1:
3067 if (arg < SRV_STATE_FILE_NB_FIELDS_VERSION_1)
3068 continue;
3069 bk_f_forced_id = (atoi(params[15]) & PR_O_FORCED_ID);
3070 check_id = (atoi(params[0]) == curproxy->uuid);
3071 check_name = (strcmp(curproxy->id, params[1]) == 0);
3072 break;
3073 }
3074
3075 diff = 0;
3076 bk = curproxy;
3077
3078 /* if backend can't be found, let's continue */
3079 if (!check_id && !check_name)
3080 continue;
3081 else if (!check_id && check_name) {
3082 Warning("backend ID mismatch: from server state file: '%s', from running config '%d'\n", params[0], bk->uuid);
3083 send_log(bk, LOG_NOTICE, "backend ID mismatch: from server state file: '%s', from running config '%d'\n", params[0], bk->uuid);
3084 }
3085 else if (check_id && !check_name) {
3086 Warning("backend name mismatch: from server state file: '%s', from running config '%s'\n", params[1], bk->id);
3087 send_log(bk, LOG_NOTICE, "backend name mismatch: from server state file: '%s', from running config '%s'\n", params[1], bk->id);
3088 /* if name doesn't match, we still want to update curproxy if the backend id
3089 * was forced in previous the previous configuration */
3090 if (!bk_f_forced_id)
3091 continue;
3092 }
3093
3094 /* look for the server by its id: param[2] */
3095 /* else look for the server by its name: param[3] */
3096 diff = 0;
3097 srv = server_find_best_match(bk, params[3], atoi(params[2]), &diff);
3098
3099 if (!srv) {
3100 /* if no server found, then warning and continue with next line */
3101 Warning("can't find server '%s' with id '%s' in backend with id '%s' or name '%s'\n",
3102 params[3], params[2], params[0], params[1]);
3103 send_log(bk, LOG_NOTICE, "can't find server '%s' with id '%s' in backend with id '%s' or name '%s'\n",
3104 params[3], params[2], params[0], params[1]);
3105 continue;
3106 }
3107 else if (diff & PR_FBM_MISMATCH_ID) {
3108 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);
3109 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);
3110 }
3111 else if (diff & PR_FBM_MISMATCH_NAME) {
3112 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);
3113 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);
3114 }
3115
3116 /* now we can proceed with server's state update */
3117 srv_update_state(srv, version, srv_params);
3118 }
Dragan Dosencf4fb032015-11-04 23:03:26 +01003119fileclose:
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +02003120 fclose(f);
3121 }
3122}
3123
Simon Horman7d09b9a2013-02-12 10:45:51 +09003124/*
Baptiste Assmann14e40142015-04-14 01:13:07 +02003125 * update a server's current IP address.
3126 * ip is a pointer to the new IP address, whose address family is ip_sin_family.
3127 * ip is in network format.
3128 * updater is a string which contains an information about the requester of the update.
3129 * updater is used if not NULL.
3130 *
3131 * A log line and a stderr warning message is generated based on server's backend options.
3132 */
Thierry Fournierd35b7a62016-02-24 08:23:22 +01003133int update_server_addr(struct server *s, void *ip, int ip_sin_family, const char *updater)
Baptiste Assmann14e40142015-04-14 01:13:07 +02003134{
3135 /* generates a log line and a warning on stderr */
3136 if (1) {
3137 /* book enough space for both IPv4 and IPv6 */
3138 char oldip[INET6_ADDRSTRLEN];
3139 char newip[INET6_ADDRSTRLEN];
3140
3141 memset(oldip, '\0', INET6_ADDRSTRLEN);
3142 memset(newip, '\0', INET6_ADDRSTRLEN);
3143
3144 /* copy old IP address in a string */
3145 switch (s->addr.ss_family) {
3146 case AF_INET:
3147 inet_ntop(s->addr.ss_family, &((struct sockaddr_in *)&s->addr)->sin_addr, oldip, INET_ADDRSTRLEN);
3148 break;
3149 case AF_INET6:
3150 inet_ntop(s->addr.ss_family, &((struct sockaddr_in6 *)&s->addr)->sin6_addr, oldip, INET6_ADDRSTRLEN);
3151 break;
3152 };
3153
3154 /* copy new IP address in a string */
3155 switch (ip_sin_family) {
3156 case AF_INET:
3157 inet_ntop(ip_sin_family, ip, newip, INET_ADDRSTRLEN);
3158 break;
3159 case AF_INET6:
3160 inet_ntop(ip_sin_family, ip, newip, INET6_ADDRSTRLEN);
3161 break;
3162 };
3163
3164 /* save log line into a buffer */
3165 chunk_printf(&trash, "%s/%s changed its IP from %s to %s by %s",
3166 s->proxy->id, s->id, oldip, newip, updater);
3167
3168 /* write the buffer on stderr */
3169 Warning("%s.\n", trash.str);
3170
3171 /* send a log */
3172 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
3173 }
3174
3175 /* save the new IP family */
3176 s->addr.ss_family = ip_sin_family;
3177 /* save the new IP address */
3178 switch (ip_sin_family) {
3179 case AF_INET:
Willy Tarreaueec1d382016-07-13 11:59:39 +02003180 memcpy(&((struct sockaddr_in *)&s->addr)->sin_addr.s_addr, ip, 4);
Baptiste Assmann14e40142015-04-14 01:13:07 +02003181 break;
3182 case AF_INET6:
3183 memcpy(((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr, ip, 16);
3184 break;
3185 };
Olivier Houchard4e694042017-03-14 20:01:29 +01003186 srv_set_dyncookie(s);
Baptiste Assmann14e40142015-04-14 01:13:07 +02003187
3188 return 0;
3189}
3190
3191/*
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003192 * This function update a server's addr and port only for AF_INET and AF_INET6 families.
3193 *
3194 * Caller can pass its name through <updater> to get it integrated in the response message
3195 * returned by the function.
3196 *
3197 * The function first does the following, in that order:
3198 * - validates the new addr and/or port
3199 * - checks if an update is required (new IP or port is different than current ones)
3200 * - checks the update is allowed:
3201 * - don't switch from/to a family other than AF_INET4 and AF_INET6
3202 * - allow all changes if no CHECKS are configured
3203 * - if CHECK is configured:
3204 * - if switch to port map (SRV_F_MAPPORTS), ensure health check have their own ports
3205 * - applies required changes to both ADDR and PORT if both 'required' and 'allowed'
3206 * conditions are met
3207 */
3208const char *update_server_addr_port(struct server *s, const char *addr, const char *port, char *updater)
3209{
3210 struct sockaddr_storage sa;
3211 int ret, port_change_required;
3212 char current_addr[INET6_ADDRSTRLEN];
David Carlier327298c2016-11-20 10:42:38 +00003213 uint16_t current_port, new_port;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003214 struct chunk *msg;
Olivier Houchard4e694042017-03-14 20:01:29 +01003215 int changed = 0;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003216
3217 msg = get_trash_chunk();
3218 chunk_reset(msg);
3219
3220 if (addr) {
3221 memset(&sa, 0, sizeof(struct sockaddr_storage));
3222 if (str2ip2(addr, &sa, 0) == NULL) {
3223 chunk_printf(msg, "Invalid addr '%s'", addr);
3224 goto out;
3225 }
3226
3227 /* changes are allowed on AF_INET* families only */
3228 if ((sa.ss_family != AF_INET) && (sa.ss_family != AF_INET6)) {
3229 chunk_printf(msg, "Update to families other than AF_INET and AF_INET6 supported only through configuration file");
3230 goto out;
3231 }
3232
3233 /* collecting data currently setup */
3234 memset(current_addr, '\0', sizeof(current_addr));
3235 ret = addr_to_str(&s->addr, current_addr, sizeof(current_addr));
3236 /* changes are allowed on AF_INET* families only */
3237 if ((ret != AF_INET) && (ret != AF_INET6)) {
3238 chunk_printf(msg, "Update for the current server address family is only supported through configuration file");
3239 goto out;
3240 }
3241
3242 /* applying ADDR changes if required and allowed
3243 * ipcmp returns 0 when both ADDR are the same
3244 */
3245 if (ipcmp(&s->addr, &sa) == 0) {
3246 chunk_appendf(msg, "no need to change the addr");
3247 goto port;
3248 }
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003249 ipcpy(&sa, &s->addr);
Olivier Houchard4e694042017-03-14 20:01:29 +01003250 changed = 1;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003251
3252 /* we also need to update check's ADDR only if it uses the server's one */
3253 if ((s->check.state & CHK_ST_CONFIGURED) && (s->flags & SRV_F_CHECKADDR)) {
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003254 ipcpy(&sa, &s->check.addr);
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003255 }
3256
3257 /* we also need to update agent ADDR only if it use the server's one */
3258 if ((s->agent.state & CHK_ST_CONFIGURED) && (s->flags & SRV_F_AGENTADDR)) {
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003259 ipcpy(&sa, &s->agent.addr);
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003260 }
3261
3262 /* update report for caller */
3263 chunk_printf(msg, "IP changed from '%s' to '%s'", current_addr, addr);
3264 }
3265
3266 port:
3267 if (port) {
3268 char sign = '\0';
3269 char *endptr;
3270
3271 if (addr)
3272 chunk_appendf(msg, ", ");
3273
3274 /* collecting data currently setup */
Willy Tarreau04276f32017-01-06 17:41:29 +01003275 current_port = s->svc_port;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003276
3277 /* check if PORT change is required */
3278 port_change_required = 0;
3279
3280 sign = *port;
Ryabin Sergey77ee7522017-01-11 19:39:55 +04003281 errno = 0;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003282 new_port = strtol(port, &endptr, 10);
3283 if ((errno != 0) || (port == endptr)) {
3284 chunk_appendf(msg, "problem converting port '%s' to an int", port);
3285 goto out;
3286 }
3287
3288 /* check if caller triggers a port mapped or offset */
3289 if (sign == '-' || (sign == '+')) {
3290 /* check if server currently uses port map */
3291 if (!(s->flags & SRV_F_MAPPORTS)) {
3292 /* switch from fixed port to port map mandatorily triggers
3293 * a port change */
3294 port_change_required = 1;
3295 /* check is configured
3296 * we're switching from a fixed port to a SRV_F_MAPPORTS (mapped) port
3297 * prevent PORT change if check doesn't have it's dedicated port while switching
3298 * to port mapping */
3299 if ((s->check.state & CHK_ST_CONFIGURED) && !(s->flags & SRV_F_CHECKPORT)) {
3300 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.");
3301 goto out;
3302 }
3303 }
3304 /* we're already using port maps */
3305 else {
3306 port_change_required = current_port != new_port;
3307 }
3308 }
3309 /* fixed port */
3310 else {
3311 port_change_required = current_port != new_port;
3312 }
3313
3314 /* applying PORT changes if required and update response message */
3315 if (port_change_required) {
3316 /* apply new port */
Willy Tarreau04276f32017-01-06 17:41:29 +01003317 s->svc_port = new_port;
Olivier Houchard4e694042017-03-14 20:01:29 +01003318 changed = 1;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003319
3320 /* prepare message */
3321 chunk_appendf(msg, "port changed from '");
3322 if (s->flags & SRV_F_MAPPORTS)
3323 chunk_appendf(msg, "+");
3324 chunk_appendf(msg, "%d' to '", current_port);
3325
3326 if (sign == '-') {
3327 s->flags |= SRV_F_MAPPORTS;
3328 chunk_appendf(msg, "%c", sign);
3329 /* just use for result output */
3330 new_port = -new_port;
3331 }
3332 else if (sign == '+') {
3333 s->flags |= SRV_F_MAPPORTS;
3334 chunk_appendf(msg, "%c", sign);
3335 }
3336 else {
3337 s->flags &= ~SRV_F_MAPPORTS;
3338 }
3339
3340 chunk_appendf(msg, "%d'", new_port);
3341
3342 /* we also need to update health checks port only if it uses server's realport */
3343 if ((s->check.state & CHK_ST_CONFIGURED) && !(s->flags & SRV_F_CHECKPORT)) {
3344 s->check.port = new_port;
3345 }
3346 }
3347 else {
3348 chunk_appendf(msg, "no need to change the port");
3349 }
3350 }
3351
3352out:
Olivier Houchard4e694042017-03-14 20:01:29 +01003353 if (changed)
3354 srv_set_dyncookie(s);
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003355 if (updater)
3356 chunk_appendf(msg, " by '%s'", updater);
3357 chunk_appendf(msg, "\n");
3358 return msg->str;
3359}
3360
3361
3362/*
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003363 * update server status based on result of name resolution
3364 * returns:
3365 * 0 if server status is updated
3366 * 1 if server status has not changed
3367 */
3368int snr_update_srv_status(struct server *s)
3369{
3370 struct dns_resolution *resolution = s->resolution;
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003371 struct dns_resolvers *resolvers;
3372
3373 resolvers = resolution->resolvers;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003374
3375 switch (resolution->status) {
3376 case RSLV_STATUS_NONE:
3377 /* status when HAProxy has just (re)started */
3378 trigger_resolution(s);
3379 break;
3380
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003381 case RSLV_STATUS_VALID:
3382 /*
3383 * resume health checks
3384 * server will be turned back on if health check is safe
3385 */
3386 if (!(s->admin & SRV_ADMF_RMAINT))
3387 return 1;
3388 srv_clr_admin_flag(s, SRV_ADMF_RMAINT);
3389 chunk_printf(&trash, "Server %s/%s administratively READY thanks to valid DNS answer",
3390 s->proxy->id, s->id);
3391
3392 Warning("%s.\n", trash.str);
3393 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str);
3394 return 0;
3395
3396 case RSLV_STATUS_NX:
3397 /* stop server if resolution is NX for a long enough period */
3398 if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.nx), now_ms)) {
3399 if (s->admin & SRV_ADMF_RMAINT)
3400 return 1;
3401 srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS NX status");
3402 return 0;
3403 }
3404 break;
3405
3406 case RSLV_STATUS_TIMEOUT:
3407 /* stop server if resolution is TIMEOUT for a long enough period */
3408 if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.timeout), now_ms)) {
3409 if (s->admin & SRV_ADMF_RMAINT)
3410 return 1;
3411 srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS timeout status");
3412 return 0;
3413 }
3414 break;
3415
3416 case RSLV_STATUS_REFUSED:
3417 /* stop server if resolution is REFUSED for a long enough period */
3418 if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.refused), now_ms)) {
3419 if (s->admin & SRV_ADMF_RMAINT)
3420 return 1;
3421 srv_set_admin_flag(s, SRV_ADMF_RMAINT, "DNS refused status");
3422 return 0;
3423 }
3424 break;
3425
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003426 default:
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003427 /* stop server if resolution is in unmatched error for a long enough period */
3428 if (tick_is_expired(tick_add(resolution->last_status_change, resolvers->hold.other), now_ms)) {
3429 if (s->admin & SRV_ADMF_RMAINT)
3430 return 1;
3431 srv_set_admin_flag(s, SRV_ADMF_RMAINT, "unspecified DNS error");
3432 return 0;
3433 }
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003434 break;
3435 }
3436
3437 return 1;
3438}
3439
3440/*
3441 * Server Name Resolution valid response callback
3442 * It expects:
3443 * - <nameserver>: the name server which answered the valid response
3444 * - <response>: buffer containing a valid DNS response
3445 * - <response_len>: size of <response>
3446 * It performs the following actions:
3447 * - ignore response if current ip found and server family not met
3448 * - update with first new ip found if family is met and current IP is not found
3449 * returns:
3450 * 0 on error
3451 * 1 when no error or safe ignore
3452 */
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02003453int snr_resolution_cb(struct dns_resolution *resolution, struct dns_nameserver *nameserver, struct dns_response_packet *dns_p)
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003454{
3455 struct server *s;
3456 void *serverip, *firstip;
3457 short server_sin_family, firstip_sin_family;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003458 int ret;
3459 struct chunk *chk = get_trash_chunk();
3460
3461 /* initializing variables */
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003462 firstip = NULL; /* pointer to the first valid response found */
3463 /* it will be used as the new IP if a change is required */
3464 firstip_sin_family = AF_UNSPEC;
3465 serverip = NULL; /* current server IP address */
3466
3467 /* shortcut to the server whose name is being resolved */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003468 s = resolution->requester;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003469
3470 /* initializing server IP pointer */
3471 server_sin_family = s->addr.ss_family;
3472 switch (server_sin_family) {
3473 case AF_INET:
3474 serverip = &((struct sockaddr_in *)&s->addr)->sin_addr.s_addr;
3475 break;
3476
3477 case AF_INET6:
3478 serverip = &((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr;
3479 break;
3480
Willy Tarreau3acfcd12017-01-06 19:18:32 +01003481 case AF_UNSPEC:
3482 break;
3483
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003484 default:
3485 goto invalid;
3486 }
3487
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02003488 ret = dns_get_ip_from_response(dns_p, resolution,
Thierry Fournierada34842016-02-17 21:25:09 +01003489 serverip, server_sin_family, &firstip,
3490 &firstip_sin_family);
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003491
3492 switch (ret) {
3493 case DNS_UPD_NO:
3494 if (resolution->status != RSLV_STATUS_VALID) {
3495 resolution->status = RSLV_STATUS_VALID;
3496 resolution->last_status_change = now_ms;
3497 }
3498 goto stop_resolution;
3499
3500 case DNS_UPD_SRVIP_NOT_FOUND:
3501 goto save_ip;
3502
3503 case DNS_UPD_CNAME:
3504 if (resolution->status != RSLV_STATUS_VALID) {
3505 resolution->status = RSLV_STATUS_VALID;
3506 resolution->last_status_change = now_ms;
3507 }
3508 goto invalid;
3509
Baptiste Assmann0453a1d2015-09-09 00:51:08 +02003510 case DNS_UPD_NO_IP_FOUND:
3511 if (resolution->status != RSLV_STATUS_OTHER) {
3512 resolution->status = RSLV_STATUS_OTHER;
3513 resolution->last_status_change = now_ms;
3514 }
3515 goto stop_resolution;
3516
Baptiste Assmannfad03182015-10-28 02:03:32 +01003517 case DNS_UPD_NAME_ERROR:
3518 /* if this is not the last expected response, we ignore it */
3519 if (resolution->nb_responses < nameserver->resolvers->count_nameservers)
3520 return 0;
3521 /* update resolution status to OTHER error type */
3522 if (resolution->status != RSLV_STATUS_OTHER) {
3523 resolution->status = RSLV_STATUS_OTHER;
3524 resolution->last_status_change = now_ms;
3525 }
3526 goto stop_resolution;
3527
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003528 default:
3529 goto invalid;
3530
3531 }
3532
3533 save_ip:
3534 nameserver->counters.update += 1;
3535 if (resolution->status != RSLV_STATUS_VALID) {
3536 resolution->status = RSLV_STATUS_VALID;
3537 resolution->last_status_change = now_ms;
3538 }
3539
3540 /* save the first ip we found */
3541 chunk_printf(chk, "%s/%s", nameserver->resolvers->id, nameserver->id);
3542 update_server_addr(s, firstip, firstip_sin_family, (char *)chk->str);
3543
3544 stop_resolution:
3545 /* update last resolution date and time */
3546 resolution->last_resolution = now_ms;
3547 /* reset current status flag */
3548 resolution->step = RSLV_STEP_NONE;
3549 /* reset values */
3550 dns_reset_resolution(resolution);
3551
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003552 dns_update_resolvers_timeout(nameserver->resolvers);
3553
3554 snr_update_srv_status(s);
3555 return 0;
3556
3557 invalid:
3558 nameserver->counters.invalid += 1;
3559 if (resolution->nb_responses >= nameserver->resolvers->count_nameservers)
3560 goto stop_resolution;
3561
3562 snr_update_srv_status(s);
3563 return 0;
3564}
3565
3566/*
3567 * Server Name Resolution error management callback
3568 * returns:
3569 * 0 on error
3570 * 1 when no error or safe ignore
3571 */
3572int snr_resolution_error_cb(struct dns_resolution *resolution, int error_code)
3573{
3574 struct server *s;
3575 struct dns_resolvers *resolvers;
Andrew Hayworthe6a4a322015-10-19 22:29:51 +00003576 int res_preferred_afinet, res_preferred_afinet6;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003577
3578 /* shortcut to the server whose name is being resolved */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003579 s = resolution->requester;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003580 resolvers = resolution->resolvers;
3581
3582 /* can be ignored if this is not the last response */
3583 if ((error_code != DNS_RESP_TIMEOUT) && (resolution->nb_responses < resolvers->count_nameservers)) {
3584 return 1;
3585 }
3586
3587 switch (error_code) {
3588 case DNS_RESP_INVALID:
3589 case DNS_RESP_WRONG_NAME:
3590 if (resolution->status != RSLV_STATUS_INVALID) {
3591 resolution->status = RSLV_STATUS_INVALID;
3592 resolution->last_status_change = now_ms;
3593 }
3594 break;
3595
3596 case DNS_RESP_ANCOUNT_ZERO:
Baptiste Assmann0df5d962015-09-02 21:58:32 +02003597 case DNS_RESP_TRUNCATED:
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003598 case DNS_RESP_ERROR:
Baptiste Assmann96972bc2015-09-09 00:46:58 +02003599 case DNS_RESP_NO_EXPECTED_RECORD:
Baptiste Assmann65ce3f52016-09-05 08:38:57 +02003600 case DNS_RESP_CNAME_ERROR:
Thierry Fournierada34842016-02-17 21:25:09 +01003601 res_preferred_afinet = resolution->opts->family_prio == AF_INET && resolution->query_type == DNS_RTYPE_A;
3602 res_preferred_afinet6 = resolution->opts->family_prio == AF_INET6 && resolution->query_type == DNS_RTYPE_AAAA;
Baptiste Assmann90447582015-09-02 22:20:56 +02003603
Andrew Hayworthe6a4a322015-10-19 22:29:51 +00003604 if ((res_preferred_afinet || res_preferred_afinet6)
Baptiste Assmannf778bb42015-09-09 00:54:38 +02003605 || (resolution->try > 0)) {
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003606 /* let's change the query type */
Andrew Hayworthe6a4a322015-10-19 22:29:51 +00003607 if (res_preferred_afinet6) {
Baptiste Assmann90447582015-09-02 22:20:56 +02003608 /* fallback from AAAA to A */
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003609 resolution->query_type = DNS_RTYPE_A;
Baptiste Assmann90447582015-09-02 22:20:56 +02003610 }
3611 else if (res_preferred_afinet) {
3612 /* fallback from A to AAAA */
3613 resolution->query_type = DNS_RTYPE_AAAA;
3614 }
Baptiste Assmannf778bb42015-09-09 00:54:38 +02003615 else {
3616 resolution->try -= 1;
Thierry Fournierada34842016-02-17 21:25:09 +01003617 if (resolution->opts->family_prio == AF_INET) {
Andrew Hayworthe6a4a322015-10-19 22:29:51 +00003618 resolution->query_type = DNS_RTYPE_A;
3619 } else {
3620 resolution->query_type = DNS_RTYPE_AAAA;
3621 }
Baptiste Assmannf778bb42015-09-09 00:54:38 +02003622 }
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003623
3624 dns_send_query(resolution);
3625
3626 /*
3627 * move the resolution to the last element of the FIFO queue
3628 * and update timeout wakeup based on the new first entry
3629 */
3630 if (dns_check_resolution_queue(resolvers) > 1) {
3631 /* second resolution becomes first one */
Baptiste Assmann11c4e4e2015-09-02 22:15:58 +02003632 LIST_DEL(&resolution->list);
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003633 /* ex first resolution goes to the end of the queue */
3634 LIST_ADDQ(&resolvers->curr_resolution, &resolution->list);
3635 }
3636 dns_update_resolvers_timeout(resolvers);
3637 goto leave;
3638 }
3639 else {
3640 if (resolution->status != RSLV_STATUS_OTHER) {
3641 resolution->status = RSLV_STATUS_OTHER;
3642 resolution->last_status_change = now_ms;
3643 }
3644 }
3645 break;
3646
3647 case DNS_RESP_NX_DOMAIN:
3648 if (resolution->status != RSLV_STATUS_NX) {
3649 resolution->status = RSLV_STATUS_NX;
3650 resolution->last_status_change = now_ms;
3651 }
3652 break;
3653
3654 case DNS_RESP_REFUSED:
3655 if (resolution->status != RSLV_STATUS_REFUSED) {
3656 resolution->status = RSLV_STATUS_REFUSED;
3657 resolution->last_status_change = now_ms;
3658 }
3659 break;
3660
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003661 case DNS_RESP_TIMEOUT:
3662 if (resolution->status != RSLV_STATUS_TIMEOUT) {
3663 resolution->status = RSLV_STATUS_TIMEOUT;
3664 resolution->last_status_change = now_ms;
3665 }
3666 break;
3667 }
3668
3669 /* update last resolution date and time */
3670 resolution->last_resolution = now_ms;
3671 /* reset current status flag */
3672 resolution->step = RSLV_STEP_NONE;
3673 /* reset values */
3674 dns_reset_resolution(resolution);
3675
3676 LIST_DEL(&resolution->list);
3677 dns_update_resolvers_timeout(resolvers);
3678
3679 leave:
3680 snr_update_srv_status(s);
3681 return 1;
3682}
3683
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003684/* Sets the server's address (srv->addr) from srv->hostname using the libc's
3685 * resolver. This is suited for initial address configuration. Returns 0 on
3686 * success otherwise a non-zero error code. In case of error, *err_code, if
3687 * not NULL, is filled up.
3688 */
3689int srv_set_addr_via_libc(struct server *srv, int *err_code)
3690{
3691 if (str2ip2(srv->hostname, &srv->addr, 1) == NULL) {
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003692 if (err_code)
Willy Tarreau465b6e52016-11-07 19:19:22 +01003693 *err_code |= ERR_WARN;
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003694 return 1;
3695 }
3696 return 0;
3697}
3698
3699/* Sets the server's address (srv->addr) from srv->lastaddr which was filled
3700 * from the state file. This is suited for initial address configuration.
3701 * Returns 0 on success otherwise a non-zero error code. In case of error,
3702 * *err_code, if not NULL, is filled up.
3703 */
3704static int srv_apply_lastaddr(struct server *srv, int *err_code)
3705{
3706 if (!str2ip2(srv->lastaddr, &srv->addr, 0)) {
3707 if (err_code)
3708 *err_code |= ERR_WARN;
3709 return 1;
3710 }
3711 return 0;
3712}
3713
Willy Tarreau25e51522016-11-04 15:10:17 +01003714/* returns 0 if no error, otherwise a combination of ERR_* flags */
3715static int srv_iterate_initaddr(struct server *srv)
3716{
3717 int return_code = 0;
3718 int err_code;
3719 unsigned int methods;
3720
3721 methods = srv->init_addr_methods;
3722 if (!methods) { // default to "last,libc"
3723 srv_append_initaddr(&methods, SRV_IADDR_LAST);
3724 srv_append_initaddr(&methods, SRV_IADDR_LIBC);
3725 }
3726
Willy Tarreau3eed10e2016-11-07 21:03:16 +01003727 /* "-dr" : always append "none" so that server addresses resolution
3728 * failures are silently ignored, this is convenient to validate some
3729 * configs out of their environment.
3730 */
3731 if (global.tune.options & GTUNE_RESOLVE_DONTFAIL)
3732 srv_append_initaddr(&methods, SRV_IADDR_NONE);
3733
Willy Tarreau25e51522016-11-04 15:10:17 +01003734 while (methods) {
3735 err_code = 0;
3736 switch (srv_get_next_initaddr(&methods)) {
3737 case SRV_IADDR_LAST:
3738 if (!srv->lastaddr)
3739 continue;
3740 if (srv_apply_lastaddr(srv, &err_code) == 0)
Olivier Houchard4e694042017-03-14 20:01:29 +01003741 goto out;
Willy Tarreau25e51522016-11-04 15:10:17 +01003742 return_code |= err_code;
3743 break;
3744
3745 case SRV_IADDR_LIBC:
3746 if (!srv->hostname)
3747 continue;
3748 if (srv_set_addr_via_libc(srv, &err_code) == 0)
Olivier Houchard4e694042017-03-14 20:01:29 +01003749 goto out;
Willy Tarreau25e51522016-11-04 15:10:17 +01003750 return_code |= err_code;
3751 break;
3752
Willy Tarreau37ebe122016-11-04 15:17:58 +01003753 case SRV_IADDR_NONE:
3754 srv_set_admin_flag(srv, SRV_ADMF_RMAINT, NULL);
Willy Tarreau465b6e52016-11-07 19:19:22 +01003755 if (return_code) {
3756 Warning("parsing [%s:%d] : 'server %s' : could not resolve address '%s', disabling server.\n",
3757 srv->conf.file, srv->conf.line, srv->id, srv->hostname);
3758 }
Willy Tarreau37ebe122016-11-04 15:17:58 +01003759 return return_code;
3760
Willy Tarreau4310d362016-11-02 15:05:56 +01003761 case SRV_IADDR_IP:
3762 ipcpy(&srv->init_addr, &srv->addr);
3763 if (return_code) {
3764 Warning("parsing [%s:%d] : 'server %s' : could not resolve address '%s', falling back to configured address.\n",
3765 srv->conf.file, srv->conf.line, srv->id, srv->hostname);
3766 }
Olivier Houchard4e694042017-03-14 20:01:29 +01003767 goto out;
Willy Tarreau4310d362016-11-02 15:05:56 +01003768
Willy Tarreau25e51522016-11-04 15:10:17 +01003769 default: /* unhandled method */
3770 break;
3771 }
3772 }
3773
3774 if (!return_code) {
3775 Alert("parsing [%s:%d] : 'server %s' : no method found to resolve address '%s'\n",
3776 srv->conf.file, srv->conf.line, srv->id, srv->hostname);
3777 }
Willy Tarreau465b6e52016-11-07 19:19:22 +01003778 else {
3779 Alert("parsing [%s:%d] : 'server %s' : could not resolve address '%s'.\n",
3780 srv->conf.file, srv->conf.line, srv->id, srv->hostname);
3781 }
Willy Tarreau25e51522016-11-04 15:10:17 +01003782
3783 return_code |= ERR_ALERT | ERR_FATAL;
3784 return return_code;
Olivier Houchard4e694042017-03-14 20:01:29 +01003785out:
3786 srv_set_dyncookie(srv);
3787 return return_code;
Willy Tarreau25e51522016-11-04 15:10:17 +01003788}
3789
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003790/*
3791 * This function parses all backends and all servers within each backend
3792 * and performs servers' addr resolution based on information provided by:
3793 * - configuration file
3794 * - server-state file (states provided by an 'old' haproxy process)
3795 *
3796 * Returns 0 if no error, otherwise, a combination of ERR_ flags.
3797 */
3798int srv_init_addr(void)
3799{
3800 struct proxy *curproxy;
3801 int return_code = 0;
3802
3803 curproxy = proxy;
3804 while (curproxy) {
3805 struct server *srv;
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003806
3807 /* servers are in backend only */
3808 if (!(curproxy->cap & PR_CAP_BE))
3809 goto srv_init_addr_next;
3810
Willy Tarreau25e51522016-11-04 15:10:17 +01003811 for (srv = curproxy->srv; srv; srv = srv->next)
3812 if (srv->hostname)
3813 return_code |= srv_iterate_initaddr(srv);
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003814
3815 srv_init_addr_next:
3816 curproxy = curproxy->next;
3817 }
3818
3819 return return_code;
3820}
3821
Willy Tarreau21b069d2016-11-23 17:15:08 +01003822/* Expects to find a backend and a server in <arg> under the form <backend>/<server>,
3823 * and returns the pointer to the server. Otherwise, display adequate error messages
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003824 * 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 +01003825 * used for CLI commands requiring a server name.
3826 * Important: the <arg> is modified to remove the '/'.
3827 */
3828struct server *cli_find_server(struct appctx *appctx, char *arg)
3829{
3830 struct proxy *px;
3831 struct server *sv;
3832 char *line;
3833
3834 /* split "backend/server" and make <line> point to server */
3835 for (line = arg; *line; line++)
3836 if (*line == '/') {
3837 *line++ = '\0';
3838 break;
3839 }
3840
3841 if (!*line || !*arg) {
3842 appctx->ctx.cli.msg = "Require 'backend/server'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003843 appctx->st0 = CLI_ST_PRINT;
Willy Tarreau21b069d2016-11-23 17:15:08 +01003844 return NULL;
3845 }
3846
3847 if (!get_backend_server(arg, line, &px, &sv)) {
3848 appctx->ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003849 appctx->st0 = CLI_ST_PRINT;
Willy Tarreau21b069d2016-11-23 17:15:08 +01003850 return NULL;
3851 }
3852
3853 if (px->state == PR_STSTOPPED) {
3854 appctx->ctx.cli.msg = "Proxy is disabled.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003855 appctx->st0 = CLI_ST_PRINT;
Willy Tarreau21b069d2016-11-23 17:15:08 +01003856 return NULL;
3857 }
3858
3859 return sv;
3860}
3861
William Lallemand222baf22016-11-19 02:00:33 +01003862
3863static int cli_parse_set_server(char **args, struct appctx *appctx, void *private)
3864{
3865 struct server *sv;
3866 const char *warning;
3867
3868 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
3869 return 1;
3870
3871 sv = cli_find_server(appctx, args[2]);
3872 if (!sv)
3873 return 1;
3874
3875 if (strcmp(args[3], "weight") == 0) {
3876 warning = server_parse_weight_change_request(sv, args[4]);
3877 if (warning) {
3878 appctx->ctx.cli.msg = warning;
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003879 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003880 }
3881 }
3882 else if (strcmp(args[3], "state") == 0) {
3883 if (strcmp(args[4], "ready") == 0)
3884 srv_adm_set_ready(sv);
3885 else if (strcmp(args[4], "drain") == 0)
3886 srv_adm_set_drain(sv);
3887 else if (strcmp(args[4], "maint") == 0)
3888 srv_adm_set_maint(sv);
3889 else {
3890 appctx->ctx.cli.msg = "'set server <srv> state' expects 'ready', 'drain' and 'maint'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003891 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003892 }
3893 }
3894 else if (strcmp(args[3], "health") == 0) {
3895 if (sv->track) {
3896 appctx->ctx.cli.msg = "cannot change health on a tracking server.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003897 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003898 }
3899 else if (strcmp(args[4], "up") == 0) {
3900 sv->check.health = sv->check.rise + sv->check.fall - 1;
3901 srv_set_running(sv, "changed from CLI");
3902 }
3903 else if (strcmp(args[4], "stopping") == 0) {
3904 sv->check.health = sv->check.rise + sv->check.fall - 1;
3905 srv_set_stopping(sv, "changed from CLI");
3906 }
3907 else if (strcmp(args[4], "down") == 0) {
3908 sv->check.health = 0;
3909 srv_set_stopped(sv, "changed from CLI");
3910 }
3911 else {
3912 appctx->ctx.cli.msg = "'set server <srv> health' expects 'up', 'stopping', or 'down'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003913 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003914 }
3915 }
3916 else if (strcmp(args[3], "agent") == 0) {
3917 if (!(sv->agent.state & CHK_ST_ENABLED)) {
3918 appctx->ctx.cli.msg = "agent checks are not enabled on this server.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003919 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003920 }
3921 else if (strcmp(args[4], "up") == 0) {
3922 sv->agent.health = sv->agent.rise + sv->agent.fall - 1;
3923 srv_set_running(sv, "changed from CLI");
3924 }
3925 else if (strcmp(args[4], "down") == 0) {
3926 sv->agent.health = 0;
3927 srv_set_stopped(sv, "changed from CLI");
3928 }
3929 else {
3930 appctx->ctx.cli.msg = "'set server <srv> agent' expects 'up' or 'down'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003931 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003932 }
3933 }
Misiek2da082d2017-01-09 09:40:42 +01003934 else if (strcmp(args[3], "agent-addr") == 0) {
3935 if (!(sv->agent.state & CHK_ST_ENABLED)) {
3936 appctx->ctx.cli.msg = "agent checks are not enabled on this server.\n";
3937 appctx->st0 = CLI_ST_PRINT;
3938 } else {
3939 if (str2ip(args[4], &sv->agent.addr) == NULL) {
3940 appctx->ctx.cli.msg = "incorrect addr address given for agent.\n";
3941 appctx->st0 = CLI_ST_PRINT;
3942 }
3943 }
3944 }
3945 else if (strcmp(args[3], "agent-send") == 0) {
3946 if (!(sv->agent.state & CHK_ST_ENABLED)) {
3947 appctx->ctx.cli.msg = "agent checks are not enabled on this server.\n";
3948 appctx->st0 = CLI_ST_PRINT;
3949 } else {
3950 char *nss = strdup(args[4]);
3951 if (!nss) {
3952 appctx->ctx.cli.msg = "cannot allocate memory for new string.\n";
3953 appctx->st0 = CLI_ST_PRINT;
3954 } else {
3955 free(sv->agent.send_string);
3956 sv->agent.send_string = nss;
3957 sv->agent.send_string_len = strlen(args[4]);
3958 }
3959 }
3960 }
William Lallemand222baf22016-11-19 02:00:33 +01003961 else if (strcmp(args[3], "check-port") == 0) {
3962 int i = 0;
3963 if (strl2irc(args[4], strlen(args[4]), &i) != 0) {
3964 appctx->ctx.cli.msg = "'set server <srv> check-port' expects an integer as argument.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003965 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003966 }
3967 if ((i < 0) || (i > 65535)) {
3968 appctx->ctx.cli.msg = "provided port is not valid.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003969 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003970 }
3971 /* prevent the update of port to 0 if MAPPORTS are in use */
3972 if ((sv->flags & SRV_F_MAPPORTS) && (i == 0)) {
3973 appctx->ctx.cli.msg = "can't unset 'port' since MAPPORTS is in use.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003974 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003975 return 1;
3976 }
3977 sv->check.port = i;
3978 appctx->ctx.cli.msg = "health check port updated.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003979 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003980 }
3981 else if (strcmp(args[3], "addr") == 0) {
3982 char *addr = NULL;
3983 char *port = NULL;
3984 if (strlen(args[4]) == 0) {
3985 appctx->ctx.cli.msg = "set server <b>/<s> addr requires an address and optionally a port.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003986 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003987 return 1;
3988 }
3989 else {
3990 addr = args[4];
3991 }
3992 if (strcmp(args[5], "port") == 0) {
3993 port = args[6];
3994 }
3995 warning = update_server_addr_port(sv, addr, port, "stats socket command");
3996 if (warning) {
3997 appctx->ctx.cli.msg = warning;
Willy Tarreau3b6e5472016-11-24 15:53:53 +01003998 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01003999 }
4000 srv_clr_admin_flag(sv, SRV_ADMF_RMAINT);
4001 }
4002 else {
4003 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 +01004004 appctx->st0 = CLI_ST_PRINT;
William Lallemand222baf22016-11-19 02:00:33 +01004005 }
4006 return 1;
4007}
4008
William Lallemand6b160942016-11-22 12:34:35 +01004009static int cli_parse_get_weight(char **args, struct appctx *appctx, void *private)
4010{
4011 struct stream_interface *si = appctx->owner;
4012 struct proxy *px;
4013 struct server *sv;
4014 char *line;
4015
4016
4017 /* split "backend/server" and make <line> point to server */
4018 for (line = args[2]; *line; line++)
4019 if (*line == '/') {
4020 *line++ = '\0';
4021 break;
4022 }
4023
4024 if (!*line) {
4025 appctx->ctx.cli.msg = "Require 'backend/server'.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01004026 appctx->st0 = CLI_ST_PRINT;
William Lallemand6b160942016-11-22 12:34:35 +01004027 return 1;
4028 }
4029
4030 if (!get_backend_server(args[2], line, &px, &sv)) {
4031 appctx->ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01004032 appctx->st0 = CLI_ST_PRINT;
William Lallemand6b160942016-11-22 12:34:35 +01004033 return 1;
4034 }
4035
4036 /* return server's effective weight at the moment */
4037 snprintf(trash.str, trash.size, "%d (initial %d)\n", sv->uweight, sv->iweight);
Christopher Faulet90b5abe2016-12-05 14:25:08 +01004038 if (bi_putstr(si_ic(si), trash.str) == -1) {
William Lallemand6b160942016-11-22 12:34:35 +01004039 si_applet_cant_put(si);
Christopher Faulet90b5abe2016-12-05 14:25:08 +01004040 return 0;
4041 }
William Lallemand6b160942016-11-22 12:34:35 +01004042 return 1;
4043}
4044
4045static int cli_parse_set_weight(char **args, struct appctx *appctx, void *private)
4046{
4047 struct server *sv;
4048 const char *warning;
4049
4050 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4051 return 1;
4052
4053 sv = cli_find_server(appctx, args[2]);
4054 if (!sv)
4055 return 1;
4056
4057 warning = server_parse_weight_change_request(sv, args[3]);
4058 if (warning) {
4059 appctx->ctx.cli.msg = warning;
Willy Tarreau3b6e5472016-11-24 15:53:53 +01004060 appctx->st0 = CLI_ST_PRINT;
William Lallemand6b160942016-11-22 12:34:35 +01004061 }
4062 return 1;
4063}
4064
Willy Tarreaub8026272016-11-23 11:26:56 +01004065/* parse a "set maxconn server" command. It always returns 1. */
4066static int cli_parse_set_maxconn_server(char **args, struct appctx *appctx, void *private)
4067{
4068 struct server *sv;
4069 const char *warning;
4070
4071 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4072 return 1;
4073
4074 sv = cli_find_server(appctx, args[3]);
4075 if (!sv)
4076 return 1;
4077
4078 warning = server_parse_maxconn_change_request(sv, args[4]);
4079 if (warning) {
4080 appctx->ctx.cli.msg = warning;
Willy Tarreau3b6e5472016-11-24 15:53:53 +01004081 appctx->st0 = CLI_ST_PRINT;
Willy Tarreaub8026272016-11-23 11:26:56 +01004082 }
4083 return 1;
4084}
William Lallemand6b160942016-11-22 12:34:35 +01004085
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004086/* parse a "disable agent" command. It always returns 1. */
4087static int cli_parse_disable_agent(char **args, struct appctx *appctx, void *private)
4088{
4089 struct server *sv;
4090
4091 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4092 return 1;
4093
4094 sv = cli_find_server(appctx, args[2]);
4095 if (!sv)
4096 return 1;
4097
4098 sv->agent.state &= ~CHK_ST_ENABLED;
4099 return 1;
4100}
4101
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004102/* parse a "disable health" command. It always returns 1. */
4103static int cli_parse_disable_health(char **args, struct appctx *appctx, void *private)
4104{
4105 struct server *sv;
4106
4107 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4108 return 1;
4109
4110 sv = cli_find_server(appctx, args[2]);
4111 if (!sv)
4112 return 1;
4113
4114 sv->check.state &= ~CHK_ST_ENABLED;
4115 return 1;
4116}
4117
Willy Tarreauffb4d582016-11-24 12:47:00 +01004118/* parse a "disable server" command. It always returns 1. */
4119static int cli_parse_disable_server(char **args, struct appctx *appctx, void *private)
4120{
4121 struct server *sv;
4122
4123 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4124 return 1;
4125
4126 sv = cli_find_server(appctx, args[2]);
4127 if (!sv)
4128 return 1;
4129
4130 srv_adm_set_maint(sv);
4131 return 1;
4132}
4133
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004134/* parse a "enable agent" command. It always returns 1. */
4135static int cli_parse_enable_agent(char **args, struct appctx *appctx, void *private)
4136{
4137 struct server *sv;
4138
4139 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4140 return 1;
4141
4142 sv = cli_find_server(appctx, args[2]);
4143 if (!sv)
4144 return 1;
4145
4146 if (!(sv->agent.state & CHK_ST_CONFIGURED)) {
4147 appctx->ctx.cli.msg = "Agent was not configured on this server, cannot enable.\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01004148 appctx->st0 = CLI_ST_PRINT;
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004149 return 1;
4150 }
4151
4152 sv->agent.state |= CHK_ST_ENABLED;
4153 return 1;
4154}
4155
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004156/* parse a "enable health" command. It always returns 1. */
4157static int cli_parse_enable_health(char **args, struct appctx *appctx, void *private)
4158{
4159 struct server *sv;
4160
4161 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4162 return 1;
4163
4164 sv = cli_find_server(appctx, args[2]);
4165 if (!sv)
4166 return 1;
4167
4168 sv->check.state |= CHK_ST_ENABLED;
4169 return 1;
4170}
4171
Willy Tarreauffb4d582016-11-24 12:47:00 +01004172/* parse a "enable server" command. It always returns 1. */
4173static int cli_parse_enable_server(char **args, struct appctx *appctx, void *private)
4174{
4175 struct server *sv;
4176
4177 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4178 return 1;
4179
4180 sv = cli_find_server(appctx, args[2]);
4181 if (!sv)
4182 return 1;
4183
4184 srv_adm_set_ready(sv);
4185 return 1;
4186}
4187
William Lallemand222baf22016-11-19 02:00:33 +01004188/* register cli keywords */
4189static struct cli_kw_list cli_kws = {{ },{
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004190 { { "disable", "agent", NULL }, "disable agent : disable agent checks (use 'set server' instead)", cli_parse_disable_agent, NULL },
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004191 { { "disable", "health", NULL }, "disable health : disable health checks (use 'set server' instead)", cli_parse_disable_health, NULL },
Willy Tarreauffb4d582016-11-24 12:47:00 +01004192 { { "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 +01004193 { { "enable", "agent", NULL }, "enable agent : enable agent checks (use 'set server' instead)", cli_parse_enable_agent, NULL },
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004194 { { "enable", "health", NULL }, "enable health : enable health checks (use 'set server' instead)", cli_parse_enable_health, NULL },
Willy Tarreauffb4d582016-11-24 12:47:00 +01004195 { { "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 +01004196 { { "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 +01004197 { { "set", "server", NULL }, "set server : change a server's state, weight or address", cli_parse_set_server },
William Lallemand6b160942016-11-22 12:34:35 +01004198 { { "get", "weight", NULL }, "get weight : report a server's current weight", cli_parse_get_weight },
4199 { { "set", "weight", NULL }, "set weight : change a server's weight (deprecated)", cli_parse_set_weight },
4200
William Lallemand222baf22016-11-19 02:00:33 +01004201 {{},}
4202}};
4203
4204__attribute__((constructor))
4205static void __server_init(void)
4206{
4207 cli_register_kw(&cli_kws);
4208}
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01004209
Baptiste Assmanna68ca962015-04-14 01:15:08 +02004210/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02004211 * Local variables:
4212 * c-indent-level: 8
4213 * c-basic-offset: 8
4214 * End:
4215 */