mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-29 17:42:54 +00:00
[MAJOR] added the 'use_backend' keyword for full content-switching
The new "use_backend" keyword permits full content switching by the use of ACLs. Its usage is simple : use_backend <backend_name> {if|unless} <acl_cond>
This commit is contained in:
parent
c11416f22f
commit
55ea7579d7
@ -85,6 +85,7 @@ struct proxy {
|
||||
} defbe;
|
||||
struct list acl; /* ACL declared on this proxy */
|
||||
struct list block_cond; /* early blocking conditions (chained) */
|
||||
struct list switching_rules; /* content switching rules (chained) */
|
||||
struct server *srv; /* known servers */
|
||||
int srv_act, srv_bck; /* # of running servers */
|
||||
int tot_wact, tot_wbck; /* total weights of active and backup servers */
|
||||
@ -150,6 +151,15 @@ struct proxy {
|
||||
struct chunk errmsg[HTTP_ERR_SIZE]; /* default or customized error messages for known errors */
|
||||
};
|
||||
|
||||
struct switching_rule {
|
||||
struct list list; /* list linked to from the proxy */
|
||||
struct acl_cond *cond; /* acl condition to meet */
|
||||
union {
|
||||
struct proxy *backend; /* target backend */
|
||||
char *name; /* target backend name during config parsing */
|
||||
} be;
|
||||
};
|
||||
|
||||
extern struct proxy *proxy;
|
||||
|
||||
#endif /* _TYPES_PROXY_H */
|
||||
|
@ -510,6 +510,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
|
||||
LIST_INIT(&curproxy->pendconns);
|
||||
LIST_INIT(&curproxy->acl);
|
||||
LIST_INIT(&curproxy->block_cond);
|
||||
LIST_INIT(&curproxy->switching_rules);
|
||||
|
||||
/* Timeouts are defined as -1, so we cannot use the zeroed area
|
||||
* as a default value.
|
||||
@ -977,6 +978,42 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
|
||||
}
|
||||
LIST_ADDQ(&curproxy->block_cond, &cond->list);
|
||||
}
|
||||
else if (!strcmp(args[0], "use_backend")) { /* early blocking based on ACLs */
|
||||
int pol = ACL_COND_NONE;
|
||||
struct acl_cond *cond;
|
||||
struct switching_rule *rule;
|
||||
|
||||
if (warnifnotcap(curproxy, PR_CAP_FE, file, linenum, args[0], NULL))
|
||||
return 0;
|
||||
|
||||
if (*(args[1]) == 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects a backend name.\n", file, linenum, args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcmp(args[2], "if"))
|
||||
pol = ACL_COND_IF;
|
||||
else if (!strcmp(args[2], "unless"))
|
||||
pol = ACL_COND_UNLESS;
|
||||
|
||||
if (pol == ACL_COND_NONE) {
|
||||
Alert("parsing [%s:%d] : '%s' requires either 'if' or 'unless' followed by a condition.\n",
|
||||
file, linenum, args[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((cond = parse_acl_cond((const char **)args + 3, &curproxy->acl, pol)) == NULL) {
|
||||
Alert("parsing [%s:%d] : error detected while parsing blocking condition.\n",
|
||||
file, linenum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rule = (struct switching_rule *)calloc(1, sizeof(*rule));
|
||||
rule->cond = cond;
|
||||
rule->be.name = strdup(args[1]);
|
||||
LIST_INIT(&rule->list);
|
||||
LIST_ADDQ(&curproxy->switching_rules, &rule->list);
|
||||
}
|
||||
else if (!strcmp(args[0], "stats")) {
|
||||
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
|
||||
return 0;
|
||||
@ -2344,6 +2381,8 @@ int readcfgfile(const char *file)
|
||||
}
|
||||
|
||||
while (curproxy != NULL) {
|
||||
struct switching_rule *rule;
|
||||
|
||||
if (curproxy->state == PR_STSTOPPED) {
|
||||
curproxy = curproxy->next;
|
||||
continue;
|
||||
@ -2479,6 +2518,38 @@ int readcfgfile(const char *file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* find the target proxy for 'use_backend' rules */
|
||||
list_for_each_entry(rule, &curproxy->switching_rules, list) {
|
||||
/* map jump target for ACT_SETBE in req_rep chain */
|
||||
struct proxy *target;
|
||||
|
||||
for (target = proxy; target != NULL; target = target->next) {
|
||||
if (strcmp(target->id, rule->be.name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (target == NULL) {
|
||||
Alert("parsing %s : backend '%s' in HTTP %s '%s' was not found !\n",
|
||||
file, rule->be.name, proxy_type_str(curproxy), curproxy->id);
|
||||
cfgerr++;
|
||||
} else if (target == curproxy) {
|
||||
Alert("parsing %s : loop detected for backend %s !\n", file, rule->be.name);
|
||||
cfgerr++;
|
||||
} else if (!(target->cap & PR_CAP_BE)) {
|
||||
Alert("parsing %s : target '%s' in HTTP %s '%s' has no backend capability !\n",
|
||||
file, rule->be.name, proxy_type_str(curproxy), curproxy->id);
|
||||
cfgerr++;
|
||||
} else if (target->mode != curproxy->mode) {
|
||||
Alert("parsing %s : backend '%s' referenced in %s '%s' is of different mode !\n",
|
||||
file, rule->be.name, proxy_type_str(curproxy), curproxy->id);
|
||||
cfgerr++;
|
||||
} else {
|
||||
free((void *)rule->be.name);
|
||||
rule->be.backend = target;
|
||||
}
|
||||
}
|
||||
|
||||
if ((curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
|
||||
(((curproxy->cap & PR_CAP_FE) && !tv_isset(&curproxy->clitimeout)) ||
|
||||
((curproxy->cap & PR_CAP_BE) && (curproxy->srv) &&
|
||||
|
@ -1888,6 +1888,29 @@ int process_cli(struct session *t)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* now check whether we have some switching rules for this request */
|
||||
if (!(t->flags & SN_BE_ASSIGNED)) {
|
||||
struct switching_rule *rule;
|
||||
|
||||
list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
|
||||
int ret;
|
||||
|
||||
ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
|
||||
if (cond->pol == ACL_COND_UNLESS)
|
||||
ret = !ret;
|
||||
|
||||
if (ret) {
|
||||
t->be = rule->be.backend;
|
||||
t->be->beconn++;
|
||||
if (t->be->beconn > t->be->beconn_max)
|
||||
t->be->beconn_max = t->be->beconn;
|
||||
t->be->cum_beconn++;
|
||||
t->flags |= SN_BE_ASSIGNED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
|
||||
/* No backend was set, but there was a default
|
||||
* backend set in the frontend, so we use it and
|
||||
|
Loading…
Reference in New Issue
Block a user