mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-08 22:37:27 +00: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);
|
||||
|
||||
/*
|
||||
* 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 everything is fine, NULL is returned.
|
||||
*/
|
||||
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
|
||||
* 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 */
|
||||
struct eb32_node id; /* place in the tree of used IDs */
|
||||
} 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
|
||||
|
@ -2859,7 +2859,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
||||
curproxy->conf.args.line = linenum;
|
||||
|
||||
/* 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);
|
||||
if (err_code & ERR_FATAL)
|
||||
goto out;
|
||||
|
107
src/server.c
107
src/server.c
@ -1969,18 +1969,53 @@ static int server_finalize_init(const char *file, int linenum, char **args, int
|
||||
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)
|
||||
{
|
||||
struct server *newsrv = NULL;
|
||||
const char *err;
|
||||
const char *err = NULL;
|
||||
char *errmsg = NULL;
|
||||
int err_code = 0;
|
||||
unsigned val;
|
||||
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 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) {
|
||||
Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
|
||||
@ -1990,19 +2025,47 @@ 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))
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
|
||||
if (!defsrv && !*args[2]) {
|
||||
Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
|
||||
file, linenum, args[0]);
|
||||
/* 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",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = invalid_char(args[1]);
|
||||
}
|
||||
else if (srv_tmpl) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
err = invalid_char(args[1]);
|
||||
if (err && !defsrv) {
|
||||
Alert("parsing [%s:%d] : character '%c' is not permitted in server name '%s'.\n",
|
||||
file, linenum, *err, 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) {
|
||||
@ -2018,12 +2081,24 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
|
||||
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 */
|
||||
newsrv->next = curproxy->srv;
|
||||
curproxy->srv = newsrv;
|
||||
newsrv->conf.file = strdup(file);
|
||||
newsrv->conf.line = linenum;
|
||||
newsrv->id = strdup(args[1]);
|
||||
/* 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]);
|
||||
else
|
||||
newsrv->tmpl_info.prefix = strdup(args[1]);
|
||||
|
||||
/* several ways to check the port component :
|
||||
* - 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
|
||||
*/
|
||||
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) {
|
||||
Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], errmsg);
|
||||
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;
|
||||
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",
|
||||
file, linenum, args[2]);
|
||||
file, linenum, args[cur_arg]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
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)) {
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Copy default server settings to new server settings. */
|
||||
srv_settings_cpy(newsrv, &curproxy->defsrv);
|
||||
cur_arg = 3;
|
||||
cur_arg++;
|
||||
} else {
|
||||
newsrv = &curproxy->defsrv;
|
||||
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 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)
|
||||
return name;
|
||||
|
||||
while (*name) {
|
||||
if (!isalnum((int)(unsigned char)*name) && *name != '.' &&
|
||||
if (!f((int)(unsigned char)*name) && *name != '.' &&
|
||||
*name != '_' && *name != '-')
|
||||
return name;
|
||||
|
||||
@ -612,6 +613,24 @@ const char *invalid_domainchar(const char *name) {
|
||||
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
|
||||
* caller must have zeroed <sa> first, and may have set sa->ss_family to force
|
||||
|
Loading…
Reference in New Issue
Block a user