Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions addons/promex/service-prometheus.c
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,13 @@ static int promex_dump_global_metrics(struct appctx *appctx, struct htx *htx)
val = mkf_u32(FN_GAUGE, 1);
break;

#ifndef USE_ZLIB
case ST_I_INF_ZLIB_MEM_USAGE:
case ST_I_INF_MAX_ZLIB_MEM_USAGE:
/* Skip zlib metrics when built with libslz */
continue;
#endif

default:
break;
}
Expand Down
24 changes: 24 additions & 0 deletions doc/management.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1725,6 +1725,30 @@ add acl [@<ver>] <acl> <pattern>
This command cannot be used if the reference <acl> is a name also used with
a map. In this case, the "add map" command must be used instead.

add backend <name> from <defproxy> [mode <mode>] [guid <guid>] [ EXPERIMENTAL ]
Instantiate a new backend proxy with the name <name>.

Only TCP or HTTP proxies can be created. All of the settings are inherited
from <defproxy> default proxy instance. By default, it is mandatory to
specify the backend mode via the argument of the same name, unless <defproxy>
already defines it explicitely. It is also possible to use an optional GUID
argument if wanted.

Servers can be added via the command "add server". The backend is initialized
in the unpublished state. Once considered ready for traffic, use "publish
backend" to expose the newly created instance.

All named default proxies can be used, given that they validate the same
inheritance rules applied during configuration parsing. There is some
exceptions though, for example when the mode is neither TCP nor HTTP. Another
exception is that it is not yet possible to use a default proxies which
reference custom HTTP errors, for example via the errorfiles or http-rules
keywords.

This command is restricted and can only be issued on sockets configured for
level "admin". Moreover, this feature is still considered in development so it
also requires experimental mode (see "experimental-mode on").

add map [@<ver>] <map> <key> <value>
add map [@<ver>] <map> <payload>
Add an entry into the map <map> to associate the value <value> to the key
Expand Down
1 change: 1 addition & 0 deletions include/haproxy/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ int backend_parse_balance(const char **args, char **err, struct proxy *curproxy)
int tcp_persist_rdp_cookie(struct stream *s, struct channel *req, int an_bit);

int be_downtime(struct proxy *px);
int be_supports_dynamic_srv(struct proxy *px, char **msg);
void recount_servers(struct proxy *px);
void update_backend_weight(struct proxy *px);

Expand Down
2 changes: 1 addition & 1 deletion include/haproxy/proxy-t.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ enum PR_SRV_STATE_FILE {
/* Proxy flags */
#define PR_FL_DISABLED 0x01 /* The proxy was disabled in the configuration (not at runtime) */
#define PR_FL_STOPPED 0x02 /* The proxy was stopped */
#define PR_FL_READY 0x04 /* The proxy is ready to be used (initialized and configured) */
#define PR_FL_DEF_EXPLICIT_MODE 0x04 /* Proxy mode is explicitely defined - only used for defaults instance */
#define PR_FL_EXPLICIT_REF 0x08 /* The default proxy is explicitly referenced by another proxy */
#define PR_FL_IMPLICIT_REF 0x10 /* The default proxy is implicitly referenced by another proxy */
#define PR_FL_PAUSED 0x20 /* The proxy was paused at run time (reversible) */
Expand Down
7 changes: 5 additions & 2 deletions include/haproxy/proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ extern unsigned int error_snapshot_id; /* global ID assigned to each error then
extern struct ceb_root *proxy_by_name; /* tree of proxies sorted by name */
extern struct list defaults_list; /* all defaults proxies list */

extern unsigned int dynpx_next_id;

extern const struct cfg_opt cfg_opts[];
extern const struct cfg_opt cfg_opts2[];
extern const struct cfg_opt cfg_opts3[];
Expand All @@ -59,6 +61,7 @@ void deinit_proxy(struct proxy *p);
void free_proxy(struct proxy *p);
const char *proxy_cap_str(int cap);
const char *proxy_mode_str(int mode);
enum pr_mode str_to_proxy_mode(const char *mode);
const char *proxy_find_best_option(const char *word, const char **extra);
uint proxy_get_next_id(uint from);
void proxy_store_name(struct proxy *px);
Expand All @@ -74,8 +77,7 @@ void defaults_px_destroy_all_unref(void);
void defaults_px_detach(struct proxy *px);
void defaults_px_ref_all(void);
void defaults_px_unref_all(void);

void proxy_ref_defaults(struct proxy *px, struct proxy *defpx);
int proxy_ref_defaults(struct proxy *px, struct proxy *defpx, char **errmsg);
void proxy_unref_defaults(struct proxy *px);
int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char **errmsg);
struct proxy *alloc_new_proxy(const char *name, unsigned int cap,
Expand All @@ -97,6 +99,7 @@ int resolve_stick_rule(struct proxy *curproxy, struct sticking_rule *mrule);
void free_stick_rules(struct list *rules);
void free_server_rules(struct list *srules);
int proxy_init_per_thr(struct proxy *px);
int proxy_finalize(struct proxy *px, int *err_code);

/*
* This function returns a string containing the type of the proxy in a format
Expand Down
84 changes: 84 additions & 0 deletions reg-tests/proxy/cli_add_backend.vtc
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
varnishtest "Add backend via cli"

feature ignore_unknown_macro

haproxy hsrv -conf {
global
.if feature(THREAD)
thread-groups 1
.endif

defaults
mode http
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"

frontend fe
bind "fd@${fe}"
http-request return status 200
} -start

haproxy h1 -conf {
global
.if feature(THREAD)
thread-groups 1
.endif

defaults
mode http
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"

frontend fe
bind "fd@${feS}"
force-be-switch if { req.hdr("x-admin") "1" }
use_backend %[req.hdr(x-be)]

defaults def

defaults def_http
mode http
} -start

client c1 -connect ${h1_feS_sock} {
txreq -hdr "x-be: be"
rxresp
expect resp.status == 503
} -run

haproxy h1 -cli {
# non existent backend
send "experimental-mode on; add backend be from def"
expect ~ "Mode is required"

send "experimental-mode on; add backend be from def_http"
expect ~ "New backend registered."

send "add server be/srv ${hsrv_fe_addr}:${hsrv_fe_port}"
expect ~ "New server registered."
send "enable server be/srv"
expect ~ ".*"
}

client c1 -connect ${h1_feS_sock} {
txreq -hdr "x-be: be"
rxresp
expect resp.status == 503

txreq -hdr "x-be: be" -hdr "x-admin: 1"
rxresp
expect resp.status == 200
} -run

haproxy h1 -cli {
send "publish backend be"
expect ~ "Backend published."
}

client c1 -connect ${h1_feS_sock} {
txreq -hdr "x-be: be"
rxresp
expect resp.status == 200
} -run
2 changes: 1 addition & 1 deletion reg-tests/server/cli_add_server.vtc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ haproxy h1 -cli {

# invalid load-balancing algo
send "add server other/s1 ${s1_addr}:${s1_port}"
expect ~ "Backend must use a dynamic load balancing to support dynamic servers."
expect ~ "backend 'other' uses a non dynamic load balancing method"

# invalid mux proto
send "add server other2/s1 ${s1_addr}:${s1_port} proto h2"
Expand Down
22 changes: 22 additions & 0 deletions src/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#include <haproxy/task.h>
#include <haproxy/ticks.h>
#include <haproxy/time.h>
#include <haproxy/tools.h>
#include <haproxy/trace.h>

#define TRACE_SOURCE &trace_strm
Expand Down Expand Up @@ -3055,6 +3056,27 @@ int be_downtime(struct proxy *px) {
return ns_to_sec(now_ns) - px->last_change + px->down_time;
}

/* Checks if <px> backend supports the addition of servers at runtime. Either a
* backend or a defaults proxy are supported. If proxy is incompatible, <msg>
* will be allocated to contain a textual explaination.
*/
int be_supports_dynamic_srv(struct proxy *px, char **msg)
{
if (px->lbprm.algo && !(px->lbprm.algo & BE_LB_PROP_DYN)) {
memprintf(msg, "%s '%s' uses a non dynamic load balancing method",
proxy_cap_str(px->cap), px->id);
return 0;
}

if (px->mode == PR_MODE_SYSLOG) {
memprintf(msg, "%s '%s' uses mode log",
proxy_cap_str(px->cap), px->id);
return 0;
}

return 1;
}

/*
* This function returns a string containing the balancing
* mode of the proxy in a format suitable for stats.
Expand Down
103 changes: 19 additions & 84 deletions src/cfgparse-listen.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,84 +501,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
curproxy->conf.file_prev = file_prev;
curproxy->conf.line_prev = line_prev;

if (curr_defproxy && (!LIST_ISEMPTY(&curr_defproxy->http_req_rules) ||
!LIST_ISEMPTY(&curr_defproxy->http_res_rules) ||
!LIST_ISEMPTY(&curr_defproxy->http_after_res_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.inspect_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules))) {
/* If the current default proxy defines TCP/HTTP rules, the
* current proxy will keep a reference on it. But some sanity
* checks are performed first:
*
* - It cannot be used to init a defaults section
* - It cannot be used to init a listen section
* - It cannot be used to init backend and frontend sections at
* same time. It can be used to init several sections of the
* same type only.
* - It cannot define L4/L5 TCP rules if it is used to init
* backend sections.
* - It cannot define 'tcp-response content' rules if it
* is used to init frontend sections.
*
* If no error is found, refcount of the default proxy is incremented.
*/

/* Note: Add tcpcheck_rules too if unresolve args become allowed in defaults section */
if (rc & PR_CAP_DEF) {
ha_alert("parsing [%s:%d]: a defaults section cannot inherit from a defaults section defining TCP/HTTP rules (defaults section at %s:%d).\n",
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
err_code |= ERR_ALERT | ERR_ABORT;
}
else if ((rc & PR_CAP_LISTEN) == PR_CAP_LISTEN) {
ha_alert("parsing [%s:%d]: a listen section cannot inherit from a defaults section defining TCP/HTTP rules.\n",
file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
}
else {
char defcap = (curr_defproxy->cap & PR_CAP_LISTEN);

if ((defcap == PR_CAP_BE || defcap == PR_CAP_FE) && (rc & PR_CAP_LISTEN) != defcap) {
ha_alert("parsing [%s:%d]: frontends and backends cannot inherit from the same defaults section"
" if it defines TCP/HTTP rules (defaults section at %s:%d).\n",
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
err_code |= ERR_ALERT | ERR_ABORT;
}
else if (!(rc & PR_CAP_FE) && (!LIST_ISEMPTY(&curr_defproxy->tcp_req.l4_rules) ||
!LIST_ISEMPTY(&curr_defproxy->tcp_req.l5_rules))) {
ha_alert("parsing [%s:%d]: a backend section cannot inherit from a defaults section defining"
" 'tcp-request connection' or 'tcp-request session' rules (defaults section at %s:%d).\n",
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
err_code |= ERR_ALERT | ERR_ABORT;
}
else if (!(rc & PR_CAP_BE) && !LIST_ISEMPTY(&curr_defproxy->tcp_rep.inspect_rules)) {
ha_alert("parsing [%s:%d]: a frontend section cannot inherit from a defaults section defining"
" 'tcp-response content' rules (defaults section at %s:%d).\n",
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
err_code |= ERR_ALERT | ERR_ABORT;
}
else {
curr_defproxy->cap = (curr_defproxy->cap & ~PR_CAP_LISTEN) | (rc & PR_CAP_LISTEN);
proxy_ref_defaults(curproxy, curr_defproxy);
}
}
}

if (curr_defproxy && (curr_defproxy->tcpcheck_rules.flags & TCPCHK_RULES_PROTO_CHK) &&
(curproxy->cap & PR_CAP_LISTEN) == PR_CAP_BE) {
/* If the current default proxy defines tcpcheck rules, the
* current proxy will keep a reference on it. but only if the
* current proxy has the backend capability.
*/
proxy_ref_defaults(curproxy, curr_defproxy);
}

if ((rc & PR_CAP_BE) && curr_defproxy && (curr_defproxy->nb_req_cap || curr_defproxy->nb_rsp_cap)) {
ha_alert("parsing [%s:%d]: backend or defaults sections cannot inherit from a defaults section defining"
" capptures (defaults section at %s:%d).\n",
file, linenum, curr_defproxy->conf.file, curr_defproxy->conf.line);
err_code |= ERR_ALERT | ERR_ABORT;
if (curr_defproxy) {
err_code = proxy_ref_defaults(curproxy, curr_defproxy, &errmsg);
if (err_code)
ha_alert("parsing [%s:%d]: %s.\n", file, linenum, errmsg);
}

if (rc & PR_CAP_DEF) {
Expand Down Expand Up @@ -707,23 +633,32 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out;
}
else if (strcmp(args[0], "mode") == 0) { /* sets the proxy mode */
enum pr_mode mode;
if (alertif_too_many_args(1, file, linenum, args, &err_code))
goto out;

if (strcmp(args[1], "http") == 0) curproxy->mode = PR_MODE_HTTP;
else if (strcmp(args[1], "tcp") == 0) curproxy->mode = PR_MODE_TCP;
else if (strcmp(args[1], "log") == 0 && (curproxy->cap & PR_CAP_BE)) curproxy->mode = PR_MODE_SYSLOG;
else if (strcmp(args[1], "spop") == 0 && (curproxy->cap & PR_CAP_BE)) curproxy->mode = PR_MODE_SPOP;
else if (strcmp(args[1], "health") == 0) {
if (unlikely(strcmp(args[1], "health") == 0)) {
ha_alert("parsing [%s:%d] : 'mode health' doesn't exist anymore. Please use 'http-request return status 200' instead.\n", file, linenum);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
else {

mode = str_to_proxy_mode(args[1]);
if (!mode) {
ha_alert("parsing [%s:%d] : unknown proxy mode '%s'.\n", file, linenum, args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
else if ((mode == PR_MODE_SYSLOG || mode == PR_MODE_SPOP) &&
!(curproxy->cap & PR_CAP_BE)) {
ha_alert("parsing [%s:%d] : mode %s is only applicable on proxies with backend capability.\n", file, linenum, proxy_mode_str(mode));
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}

curproxy->mode = mode;
if (curproxy->cap & PR_CAP_DEF)
curproxy->flags |= PR_FL_DEF_EXPLICIT_MODE;
}
else if (strcmp(args[0], "id") == 0) {
struct proxy *conflict;
Expand Down
Loading