mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 22:31:28 +02:00
MINOR: server: Add 'server-template' new keyword supported in backend sections.
This patch makes backend sections support 'server-template' new keyword. Such 'server-template' objects are parsed similarly to a 'server' object by parse_server() function, but its first arguments are as follows: server-template <ID prefix> <nb | range> <ip | fqdn>:<port> ... The remaining arguments are the same as for 'server' lines. With such server template declarations, servers may be allocated with IDs built from <ID prefix> and <nb | range> arguments. For instance declaring: server-template foo 1-5 google.com:80 ... or server-template foo 5 google.com:80 ... would be equivalent to declare: server foo1 google.com:80 ... server foo2 google.com:80 ... server foo3 google.com:80 ... server foo4 google.com:80 ... server foo5 google.com:80 ...
This commit is contained in:
parent
759ea98db2
commit
b82f742b78
@ -259,12 +259,19 @@ unsigned int round_2dig(unsigned int i);
|
|||||||
extern const char *invalid_char(const char *name);
|
extern const char *invalid_char(const char *name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks <domainname> for invalid characters. Valid chars are [A-Za-z0-9_.-].
|
* Checks <name> for invalid characters. Valid chars are [A-Za-z0-9_.-].
|
||||||
* If an invalid character is found, a pointer to it is returned.
|
* If an invalid character is found, a pointer to it is returned.
|
||||||
* If everything is fine, NULL is returned.
|
* If everything is fine, NULL is returned.
|
||||||
*/
|
*/
|
||||||
extern const char *invalid_domainchar(const char *name);
|
extern const char *invalid_domainchar(const char *name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks <name> for invalid characters. Valid chars are [A-Za-z_.-].
|
||||||
|
* If an invalid character is found, a pointer to it is returned.
|
||||||
|
* If everything is fine, NULL is returned.
|
||||||
|
*/
|
||||||
|
extern const char *invalid_prefix_char(const char *name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* converts <str> to a locally allocated struct sockaddr_storage *, and a
|
* converts <str> to a locally allocated struct sockaddr_storage *, and a
|
||||||
* port range consisting in two integers. The low and high end are always set
|
* port range consisting in two integers. The low and high end are always set
|
||||||
|
@ -274,6 +274,15 @@ struct server {
|
|||||||
int line; /* line where the section appears */
|
int line; /* line where the section appears */
|
||||||
struct eb32_node id; /* place in the tree of used IDs */
|
struct eb32_node id; /* place in the tree of used IDs */
|
||||||
} conf; /* config information */
|
} conf; /* config information */
|
||||||
|
/* Template information used only for server objects which
|
||||||
|
* serve as template filled at parsing time and used during
|
||||||
|
* server allocations from server templates.
|
||||||
|
*/
|
||||||
|
struct {
|
||||||
|
char *prefix;
|
||||||
|
int nb_low;
|
||||||
|
int nb_high;
|
||||||
|
} tmpl_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Descriptor for a "server" keyword. The ->parse() function returns 0 in case of
|
/* Descriptor for a "server" keyword. The ->parse() function returns 0 in case of
|
||||||
|
@ -2859,7 +2859,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||||||
curproxy->conf.args.line = linenum;
|
curproxy->conf.args.line = linenum;
|
||||||
|
|
||||||
/* Now let's parse the proxy-specific keywords */
|
/* Now let's parse the proxy-specific keywords */
|
||||||
if (!strcmp(args[0], "server") || !strcmp(args[0], "default-server")) {
|
if (!strcmp(args[0], "server") ||
|
||||||
|
!strcmp(args[0], "default-server") ||
|
||||||
|
!strcmp(args[0], "server-template")) {
|
||||||
err_code |= parse_server(file, linenum, args, curproxy, &defproxy);
|
err_code |= parse_server(file, linenum, args, curproxy, &defproxy);
|
||||||
if (err_code & ERR_FATAL)
|
if (err_code & ERR_FATAL)
|
||||||
goto out;
|
goto out;
|
||||||
|
95
src/server.c
95
src/server.c
@ -1969,18 +1969,53 @@ static int server_finalize_init(const char *file, int linenum, char **args, int
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse as much as possible such a range string argument: low[-high]
|
||||||
|
* Set <nb_low> and <nb_high> values so that they may be reused by this loop
|
||||||
|
* for(int i = nb_low; i <= nb_high; i++)... with nb_low >= 1.
|
||||||
|
* Fails if 'low' < 0 or 'high' is present and not higher than 'low'.
|
||||||
|
* Returns 0 if succeeded, -1 if not.
|
||||||
|
*/
|
||||||
|
static int srv_tmpl_parse_range(struct server *srv, const char *arg, int *nb_low, int *nb_high)
|
||||||
|
{
|
||||||
|
char *nb_high_arg;
|
||||||
|
|
||||||
|
*nb_high = 0;
|
||||||
|
chunk_printf(&trash, "%s", arg);
|
||||||
|
*nb_low = atoi(trash.str);
|
||||||
|
|
||||||
|
if ((nb_high_arg = strchr(trash.str, '-'))) {
|
||||||
|
*nb_high_arg++ = '\0';
|
||||||
|
*nb_high = atoi(nb_high_arg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*nb_high += *nb_low;
|
||||||
|
*nb_low = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*nb_low < 0 || *nb_high < *nb_low)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
|
int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
|
||||||
{
|
{
|
||||||
struct server *newsrv = NULL;
|
struct server *newsrv = NULL;
|
||||||
const char *err;
|
const char *err = NULL;
|
||||||
char *errmsg = NULL;
|
char *errmsg = NULL;
|
||||||
int err_code = 0;
|
int err_code = 0;
|
||||||
unsigned val;
|
unsigned val;
|
||||||
char *fqdn = NULL;
|
char *fqdn = NULL;
|
||||||
|
|
||||||
if (!strcmp(args[0], "server") || !strcmp(args[0], "default-server")) { /* server address */
|
if (!strcmp(args[0], "server") ||
|
||||||
|
!strcmp(args[0], "default-server") ||
|
||||||
|
!strcmp(args[0], "server-template")) {
|
||||||
int cur_arg;
|
int cur_arg;
|
||||||
int defsrv = (*args[0] == 'd');
|
int defsrv = (*args[0] == 'd');
|
||||||
|
int srv = !defsrv && !strcmp(args[0], "server");
|
||||||
|
int srv_tmpl = !defsrv && !srv;
|
||||||
|
int tmpl_range_low = 0, tmpl_range_high = 0;
|
||||||
|
|
||||||
if (!defsrv && curproxy == defproxy) {
|
if (!defsrv && curproxy == defproxy) {
|
||||||
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
|
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
|
||||||
@ -1990,7 +2025,10 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
|
else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
|
||||||
if (!defsrv && !*args[2]) {
|
/* There is no mandatory first arguments for default server. */
|
||||||
|
if (srv) {
|
||||||
|
if (!*args[2]) {
|
||||||
|
/* 'server' line number of argument check. */
|
||||||
Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
|
Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
|
||||||
file, linenum, args[0]);
|
file, linenum, args[0]);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
@ -1998,13 +2036,38 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = invalid_char(args[1]);
|
err = invalid_char(args[1]);
|
||||||
if (err && !defsrv) {
|
}
|
||||||
Alert("parsing [%s:%d] : character '%c' is not permitted in server name '%s'.\n",
|
else if (srv_tmpl) {
|
||||||
file, linenum, *err, args[1]);
|
if (!*args[3]) {
|
||||||
|
/* 'server-template' line number of argument check. */
|
||||||
|
Alert("parsing [%s:%d] : '%s' expects <prefix> <nb | range> <addr>[:<port>] as arguments.\n",
|
||||||
|
file, linenum, args[0]);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = invalid_prefix_char(args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
Alert("parsing [%s:%d] : character '%c' is not permitted in %s %s '%s'.\n",
|
||||||
|
file, linenum, *err, args[0], srv ? "name" : "prefix", args[1]);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_arg = 2;
|
||||||
|
if (srv_tmpl) {
|
||||||
|
/* Parse server-template <nb | range> arg. */
|
||||||
|
if (srv_tmpl_parse_range(newsrv, args[cur_arg], &tmpl_range_low, &tmpl_range_high) < 0) {
|
||||||
|
Alert("parsing [%s:%d] : Wrong %s number or range arg '%s'.\n",
|
||||||
|
file, linenum, args[0], args[cur_arg]);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
cur_arg++;
|
||||||
|
}
|
||||||
|
|
||||||
if (!defsrv) {
|
if (!defsrv) {
|
||||||
struct sockaddr_storage *sk;
|
struct sockaddr_storage *sk;
|
||||||
int port1, port2, port;
|
int port1, port2, port;
|
||||||
@ -2018,12 +2081,24 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (srv_tmpl) {
|
||||||
|
newsrv->tmpl_info.nb_low = tmpl_range_low;
|
||||||
|
newsrv->tmpl_info.nb_high = tmpl_range_high;
|
||||||
|
}
|
||||||
|
|
||||||
/* the servers are linked backwards first */
|
/* the servers are linked backwards first */
|
||||||
newsrv->next = curproxy->srv;
|
newsrv->next = curproxy->srv;
|
||||||
curproxy->srv = newsrv;
|
curproxy->srv = newsrv;
|
||||||
newsrv->conf.file = strdup(file);
|
newsrv->conf.file = strdup(file);
|
||||||
newsrv->conf.line = linenum;
|
newsrv->conf.line = linenum;
|
||||||
|
/* Note: for a server template, its id is its prefix.
|
||||||
|
* This is a temporary id which will be used for server allocations to come
|
||||||
|
* after parsing.
|
||||||
|
*/
|
||||||
|
if (srv)
|
||||||
newsrv->id = strdup(args[1]);
|
newsrv->id = strdup(args[1]);
|
||||||
|
else
|
||||||
|
newsrv->tmpl_info.prefix = strdup(args[1]);
|
||||||
|
|
||||||
/* several ways to check the port component :
|
/* several ways to check the port component :
|
||||||
* - IP => port=+0, relative (IPv4 only)
|
* - IP => port=+0, relative (IPv4 only)
|
||||||
@ -2032,7 +2107,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
* - IP:+N => port=+N, relative
|
* - IP:+N => port=+N, relative
|
||||||
* - IP:-N => port=-N, relative
|
* - IP:-N => port=-N, relative
|
||||||
*/
|
*/
|
||||||
sk = str2sa_range(args[2], &port, &port1, &port2, &errmsg, NULL, &fqdn, 0);
|
sk = str2sa_range(args[cur_arg], &port, &port1, &port2, &errmsg, NULL, &fqdn, 0);
|
||||||
if (!sk) {
|
if (!sk) {
|
||||||
Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
|
Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
@ -2073,7 +2148,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
goto skip_name_resolution;
|
goto skip_name_resolution;
|
||||||
if ((dns_str_to_dn_label(newsrv->hostname, curr_resolution->hostname_dn, curr_resolution->hostname_dn_len + 1)) == NULL) {
|
if ((dns_str_to_dn_label(newsrv->hostname, curr_resolution->hostname_dn, curr_resolution->hostname_dn_len + 1)) == NULL) {
|
||||||
Alert("parsing [%s:%d] : Invalid hostname '%s'\n",
|
Alert("parsing [%s:%d] : Invalid hostname '%s'\n",
|
||||||
file, linenum, args[2]);
|
file, linenum, args[cur_arg]);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -2093,14 +2168,14 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
|||||||
|
|
||||||
if (!newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) {
|
if (!newsrv->hostname && !protocol_by_family(newsrv->addr.ss_family)) {
|
||||||
Alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n",
|
Alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n",
|
||||||
file, linenum, newsrv->addr.ss_family, args[2]);
|
file, linenum, newsrv->addr.ss_family, args[cur_arg]);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy default server settings to new server settings. */
|
/* Copy default server settings to new server settings. */
|
||||||
srv_settings_cpy(newsrv, &curproxy->defsrv);
|
srv_settings_cpy(newsrv, &curproxy->defsrv);
|
||||||
cur_arg = 3;
|
cur_arg++;
|
||||||
} else {
|
} else {
|
||||||
newsrv = &curproxy->defsrv;
|
newsrv = &curproxy->defsrv;
|
||||||
cur_arg = 1;
|
cur_arg = 1;
|
||||||
|
@ -592,17 +592,18 @@ const char *invalid_char(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks <domainname> for invalid characters. Valid chars are [A-Za-z0-9_.-].
|
* Checks <name> for invalid characters. Valid chars are [_.-] and those
|
||||||
|
* accepted by <f> function.
|
||||||
* If an invalid character is found, a pointer to it is returned.
|
* If an invalid character is found, a pointer to it is returned.
|
||||||
* If everything is fine, NULL is returned.
|
* If everything is fine, NULL is returned.
|
||||||
*/
|
*/
|
||||||
const char *invalid_domainchar(const char *name) {
|
static inline const char *__invalid_char(const char *name, int (*f)(int)) {
|
||||||
|
|
||||||
if (!*name)
|
if (!*name)
|
||||||
return name;
|
return name;
|
||||||
|
|
||||||
while (*name) {
|
while (*name) {
|
||||||
if (!isalnum((int)(unsigned char)*name) && *name != '.' &&
|
if (!f((int)(unsigned char)*name) && *name != '.' &&
|
||||||
*name != '_' && *name != '-')
|
*name != '_' && *name != '-')
|
||||||
return name;
|
return name;
|
||||||
|
|
||||||
@ -612,6 +613,24 @@ const char *invalid_domainchar(const char *name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks <name> for invalid characters. Valid chars are [A-Za-z0-9_.-].
|
||||||
|
* If an invalid character is found, a pointer to it is returned.
|
||||||
|
* If everything is fine, NULL is returned.
|
||||||
|
*/
|
||||||
|
const char *invalid_domainchar(const char *name) {
|
||||||
|
return __invalid_char(name, isalnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks <name> for invalid characters. Valid chars are [A-Za-z_.-].
|
||||||
|
* If an invalid character is found, a pointer to it is returned.
|
||||||
|
* If everything is fine, NULL is returned.
|
||||||
|
*/
|
||||||
|
const char *invalid_prefix_char(const char *name) {
|
||||||
|
return __invalid_char(name, isalpha);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* converts <str> to a struct sockaddr_storage* provided by the caller. The
|
* converts <str> to a struct sockaddr_storage* provided by the caller. The
|
||||||
* caller must have zeroed <sa> first, and may have set sa->ss_family to force
|
* caller must have zeroed <sa> first, and may have set sa->ss_family to force
|
||||||
|
Loading…
x
Reference in New Issue
Block a user