From: Krzysztof Piotr Oledzki Date: Fri, 2 Oct 2009 20:51:14 +0000 (+0200) Subject: [MINOR] add "description", "node" and show-node"/"show-desc", remove "node-name", v2 X-Git-Tag: v1.4-dev4~51 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=48cb2aed5aab2dec7af77055a3cd9a158727527a;p=thirdparty%2Fhaproxy.git [MINOR] add "description", "node" and show-node"/"show-desc", remove "node-name", v2 This patch implements "description" (proxy and global) and "node" (global) options, removes "node-name" and adds "show-node" & "show-desc" options for "stats". It also changes the way the header lines (with proxy name) and the statistics are displayed, so stats no longer look so clumsy with very long names. Instead of "node-name" it is possible to use show-node/show-desc with an optional parameter that overrides a default node/description. backend cust-0045 # report specific values for this customer stats show-node Europe stats show-desc Master node for Europe, Asia, Africa --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 2055a09a30..c7e582df98 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -383,6 +383,8 @@ The following keywords are supported in the "global" section : - ulimit-n - user - stats + - node + - description * Performance tuning - maxconn @@ -514,6 +516,21 @@ user Similar to "uid" but uses the UID of user name from /etc/passwd. See also "uid" and "group". +node + Only letters, digits, hyphen and underscore are allowed, like in DNS names. + + This statement is useful in HA configurations where two or more processes or + servers share the same IP address. By setting a different node-name on all + nodes, it becomes easy to immediately spot what server is handling the + traffic. + +description + Add a text that describes the instance. + + Please note that it is required to escape certain characters (# for example) + and this text is inserted into a html page so you should avoid using + "<" and ">" characters. + 3.2. Performance tuning ----------------------- @@ -696,6 +713,7 @@ clitimeout X X X - (deprecated) contimeout X - X X (deprecated) cookie X - X X default_backend - X X - +description - X X X disabled X X X X dispatch - - X X enabled X X X X @@ -3785,22 +3803,43 @@ stats enable See also : "stats auth", "stats realm", "stats uri" -stats node-name [ ] +stats show-node [ ] Enable reporting of a host name on the statistics page. May be used in sections : defaults | frontend | listen | backend yes | no | yes | yes - Arguments : - is an optional name to be reported. If unspecified, the system's - hostname is automatically used instead. + Arguments: + is an optional name to be reported. If unspecified, the + node name from global section is automatically used instead. - The node-name is read as a single word, so any spaces in it should be escaped - using a backslash ('\'). If it is left unspecified, the system's hostname is - used instead. + This statement is useful for users that offer shared services to their + customers, where node or description might be different on a stats page + provided for each customer. - This statement is useful in HA configurations where two or more processes or - servers share a same IP address. By setting a different node-name on all - nodes, it becomes easy to immediately spot what server is handling the - traffic. + Though this statement alone is enough to enable statistics reporting, it is + recommended to set all other settings in order to avoid relying on default + unobvious parameters. + + Example: + # internal monitoring access (unlimited) + backend private_monitoring + stats enable + stats show-node Europe-1 + stats uri /admin?stats + stats refresh 5s + + See also: "show-desc", "stats enable", "stats uri", and "node" in global section. + + +stats show-desc [ ] + Enable reporting of a description on the statistics page. + May be used in sections : defaults | frontend | listen | backend + yes | no | yes | yes + + is an optional description to be reported. If unspecified, the + description from global section is automatically used instead. + + This statement is useful for users that offer shared services to their + customers, where node or description should be different for each customer. Though this statement alone is enough to enable statistics reporting, it is recommended to set all other settings in order to avoid relying on default @@ -3810,11 +3849,11 @@ stats node-name [ ] # internal monitoring access (unlimited) backend private_monitoring stats enable - stats node-name master + stats show-desc Master node for Europe, Asia, Africa stats uri /admin?stats stats refresh 5s - See also : "stats enable", "stats uri" + See also: "show-node", "stats enable", "stats uri" and "description" in global section. stats realm diff --git a/include/common/uri_auth.h b/include/common/uri_auth.h index 132be218df..3a7fd9c741 100644 --- a/include/common/uri_auth.h +++ b/include/common/uri_auth.h @@ -32,13 +32,15 @@ struct stat_scope { }; #define ST_HIDEVER 0x00000001 /* do not report the version and reldate */ +#define ST_SHNODE 0x00000002 /* show node name */ +#define ST_SHDESC 0x00000004 /* show description */ /* later we may link them to support multiple URI matching */ struct uri_auth { int uri_len; /* the prefix length */ char *uri_prefix; /* the prefix we want to match */ char *auth_realm; /* the realm reported to the client */ - char *node_name; /* the node name reported to the client */ + char *node, *desc; /* node name & description reported in this stats */ int refresh; /* refresh interval for the browser (in seconds) */ int flags; /* some flags describing the statistics page */ struct user_auth *users; /* linked list of valid user:passwd couples */ @@ -75,7 +77,8 @@ struct uri_auth *stats_set_refresh(struct uri_auth **root, int interval); struct uri_auth *stats_set_flag(struct uri_auth **root, int flag); struct uri_auth *stats_add_auth(struct uri_auth **root, char *user); struct uri_auth *stats_add_scope(struct uri_auth **root, char *scope); -struct uri_auth *stats_set_node_name(struct uri_auth **root, char *name); +struct uri_auth *stats_set_node(struct uri_auth **root, char *name); +struct uri_auth *stats_set_desc(struct uri_auth **root, char *desc); #endif /* _COMMON_URI_AUTH_H */ diff --git a/include/types/global.h b/include/types/global.h index 4d349c3136..3a8faa953d 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -70,6 +70,7 @@ struct global { int spread_checks; char *chroot; char *pidfile; + char *node, *desc; /* node name & description */ int logfac1, logfac2; int loglev1, loglev2; int minlvl1, minlvl2; diff --git a/include/types/proxy.h b/include/types/proxy.h index 8c93e555bc..2cdf6895cb 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -233,7 +233,7 @@ struct proxy { int httpreq; /* maximum time for complete HTTP request */ int check; /* maximum time for complete check */ } timeout; - char *id; /* proxy id */ + char *id, *desc; /* proxy id (name) and description */ struct list pendconns; /* pending connections with no server assigned yet */ int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */ int totpend; /* total number of pending connections on this instance (for stats) */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 793865478a..3e74634531 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -603,6 +603,52 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } global.chroot = strdup(args[1]); } + else if (!strcmp(args[0], "description")) { + int i, len=0; + char *d; + + if (!*args[1]) { + Alert("parsing [%s:%d]: '%s' expects a string argument.\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + for(i=1; *args[i]; i++) + len += strlen(args[i])+1; + + if (global.desc) + free(global.desc); + + global.desc = d = (char *)calloc(1, len); + + d += sprintf(d, "%s", args[1]); + for(i=2; *args[i]; i++) + d += sprintf(d, " %s", args[i]); + } + else if (!strcmp(args[0], "node")) { + int i; + char c; + + for (i=0; args[1][i]; i++) { + c = args[1][i]; + if (!isupper(c) && !islower(c) && !isdigit(c) && c != '_' && c != '-' && c != '.') + break; + } + + if (!i || args[1][i]) { + Alert("parsing [%s:%d]: '%s' requires valid node name - non-empty string" + " with digits(0-9), letters(A-Z, a-z), dot(.), hyphen(-) or underscode(_).\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + if (global.node) + free(global.node); + + global.node = strdup(args[1]); + } else if (!strcmp(args[0], "pidfile")) { if (global.pidfile != NULL) { Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]); @@ -728,6 +774,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global"); err_code |= ERR_ALERT | ERR_FATAL; } + out: return err_code; } @@ -1179,6 +1226,27 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) goto out; } } + else if (!strcmp(args[0], "description")) { + int i, len=0; + char *d; + + if (!*args[1]) { + Alert("parsing [%s:%d]: '%s' expects a string argument.\n", + file, linenum, args[0]); + return -1; + } + + for(i=1; *args[i]; i++) + len += strlen(args[i])+1; + + d = (char *)calloc(1, len); + curproxy->desc = d; + + d += sprintf(d, "%s", args[1]); + for(i=2; *args[i]; i++) + d += sprintf(d, " %s", args[i]); + + } else if (!strcmp(args[0], "disabled")) { /* disables this proxy */ curproxy->state = PR_STSTOPPED; } @@ -1744,7 +1812,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->uri_auth = NULL; /* we must detach from the default config */ if (*(args[1]) == 0) { - Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'node-name', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]); + Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable', 'hide-version', 'show-node', 'show-desc'.\n", file, linenum, args[0]); err_code |= ERR_ALERT | ERR_FATAL; goto out; } else if (!strcmp(args[1], "uri")) { @@ -1767,12 +1835,6 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) err_code |= ERR_ALERT | ERR_ABORT; goto out; } - } else if (!strcmp(args[1], "node-name")) { - if (!stats_set_node_name(&curproxy->uri_auth, *(args[2]) ? args[2] : hostname)) { - Alert("parsing [%s:%d] : out of memory.\n", file, linenum); - err_code |= ERR_ALERT | ERR_ABORT; - goto out; - } } else if (!strcmp(args[1], "refresh")) { unsigned interval; @@ -1819,6 +1881,61 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) err_code |= ERR_ALERT | ERR_ABORT; goto out; } + } else if (!strcmp(args[1], "show-node")) { + + if (*args[2]) { + int i; + char c; + + for (i=0; args[2][i]; i++) { + c = args[2][i]; + if (!isupper(c) && !islower(c) && !isdigit(c) && c != '_' && c != '-') + break; + } + + if (!i || args[2][i]) { + Alert("parsing [%s:%d]: '%s %s' invalid node name - should be a string" + "with digits(0-9), letters(A-Z, a-z), hyphen(-) or underscode(_).\n", + file, linenum, args[0], args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } + + if (!stats_set_node(&curproxy->uri_auth, args[2])) { + Alert("parsing [%s:%d]: out of memory.\n", file, linenum); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + } else if (!strcmp(args[1], "show-desc")) { + char *desc = NULL; + + if (*args[2]) { + int i, len=0; + char *d; + + for(i=2; *args[i]; i++) + len += strlen(args[i])+1; + + desc = d = (char *)calloc(1, len); + + d += sprintf(d, "%s", args[2]); + for(i=3; *args[i]; i++) + d += sprintf(d, " %s", args[i]); + } + + if (!*args[2] && !global.desc) + Warning("parsing [%s:%d]: '%s' requires a parameter or 'desc' to be set in the global section.\n", + file, linenum, args[1]); + else { + if (!stats_set_desc(&curproxy->uri_auth, desc)) { + free(desc); + Alert("parsing [%s:%d]: out of memory.\n", file, linenum); + err_code |= ERR_ALERT | ERR_ABORT; + goto out; + } + free(desc); + } } else { Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'hide-version', 'uri', 'realm', 'auth' or 'enable').\n", file, linenum, args[0]); diff --git a/src/dumpstats.c b/src/dumpstats.c index 86ce23e86e..7199fe07e5 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -574,6 +574,8 @@ int stats_dump_raw(struct session *s, struct buffer *rep, struct uri_auth *uri) "PipesFree: %d\n" "Tasks: %d\n" "Run_queue: %d\n" + "node: %s\n" + "description: %s\n" "", global.nbproc, relative_pid, @@ -584,7 +586,8 @@ int stats_dump_raw(struct session *s, struct buffer *rep, struct uri_auth *uri) global.rlimit_nofile, global.maxsock, global.maxconn, global.maxpipes, actconn, pipes_used, pipes_free, - nb_tasks_cur, run_queue_cur + nb_tasks_cur, run_queue_cur, + global.node, global.desc?global.desc:"" ); if (buffer_write_chunk(rep, &msg) >= 0) return 0; @@ -752,8 +755,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) " border-color: black;" " border-bottom-style: solid;" "}\n" - ".pxname {background: #b00040;color: #ffff40;font-weight: bold;}\n" - ".titre {background: #20D0D0;color: #000000;font-weight: bold;}\n" + ".titre {background: #20D0D0;color: #000000; font-weight: bold;}\n" ".total {background: #20D0D0;color: #ffff80;}\n" ".frontend {background: #e8e8d0;}\n" ".backend {background: #e8e8d0;}\n" @@ -775,14 +777,16 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) "table.tbl { border-collapse: collapse; border-style: none;}\n" "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray;}\n" "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n" + "table.tbl th.pxname {background: #b00040; color: #ffff40; font-weight: bold; border-style: solid solid none solid; padding: 2px 3px;}\n" "table.tbl th.empty { border-style: none; empty-cells: hide; background: white;}\n" + "table.tbl th.desc { background: white; border-style: solid solid none solid; text-align: left; padding: 2px 3px;}\n" "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n" "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n" "table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n" "-->\n" "\n", - uri->node_name ? " on " : "", - uri->node_name ? uri->node_name : "" + (uri->flags&ST_SHNODE) ? " on " : "", + (uri->flags&ST_SHNODE) ? (uri->node ? uri->node : global.node) : "" ); } else { print_csv_header(&msg); @@ -804,16 +808,16 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) chunk_printf(&msg, "

" PRODUCT_NAME "%s

\n" - "

Statistics Report for pid %d%s%s

\n" + "

Statistics Report for pid %d%s%s%s%s

\n" "
\n" "

> General process information

\n" "
\n" "

pid = %d (process #%d, nbproc = %d)
\n" "uptime = %dd %dh%02dm%02ds
\n" - "system limits : memmax = %s%s ; ulimit-n = %d
\n" - "maxsock = %d ; maxconn = %d ; maxpipes = %d
\n" - "current conns = %d ; current pipes = %d/%d
\n" - "Running tasks : %d/%d
\n" + "system limits: memmax = %s%s; ulimit-n = %d
\n" + "maxsock = %d; maxconn = %d; maxpipes = %d
\n" + "current conns = %d; current pipes = %d/%d
\n" + "Running tasks: %d/%d
\n" "

\n" "\n" "" @@ -834,9 +838,9 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri) "Display option:
    " "", (uri->flags&ST_HIDEVER)?"":(STATS_VERSION_STRING), - pid, uri->node_name ? " on " : "", uri->node_name ? uri->node_name : "", - pid, - relative_pid, global.nbproc, + pid, (uri->flags&ST_SHNODE) ? " on " : "", (uri->flags&ST_SHNODE) ? (uri->node ? uri->node : global.node) : "", + (uri->flags&ST_SHDESC)? ": " : "", (uri->flags&ST_SHDESC) ? (uri->desc ? uri->desc : global.desc) : "", + pid, relative_pid, global.nbproc, up / 86400, (up % 86400) / 3600, (up % 3600) / 60, (up % 60), global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited", @@ -999,11 +1003,13 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) { /* print a new table */ chunk_printf(&msg, - "
 active UP
\n" + "
\n" "" - "" - "" + "" + "" "\n" + "
%s%s%s
\n" + "\n" "" "" "" @@ -1022,7 +1028,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri) "" "\n" "", - px->id); + px->id, + px->desc ? "desc" : "empty", px->desc ? px->desc : ""); if (buffer_write_chunk(rep, &msg) >= 0) return 0; diff --git a/src/haproxy.c b/src/haproxy.c index d426e67176..b5e1dc973d 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -677,6 +677,9 @@ void init(int argc, char **argv) printf("Using %s() as the polling mechanism.\n", cur_poller.name); } + if (!global.node) + global.node = strdup(hostname); + } void deinit(void) @@ -843,6 +846,8 @@ void deinit(void) free(uap->uri_prefix); free(uap->auth_realm); + free(uap->node); + free(uap->desc); while (uap->users) { user = uap->users; @@ -857,6 +862,8 @@ void deinit(void) free(global.chroot); global.chroot = NULL; free(global.pidfile); global.pidfile = NULL; + free(global.node); global.node = NULL; + free(global.desc); global.desc = NULL; free(fdtab); fdtab = NULL; free(oldpids); oldpids = NULL; diff --git a/src/uri_auth.c b/src/uri_auth.c index ba029a6ba0..3cfc445263 100644 --- a/src/uri_auth.c +++ b/src/uri_auth.c @@ -110,26 +110,71 @@ struct uri_auth *stats_set_realm(struct uri_auth **root, char *realm) } /* - * Returns a default uri_auth with set as the node name. + * Returns a default uri_auth with ST_SHNODE flag enabled and + * set as the name if it is not empty. * Uses the pointer provided if not NULL and not initialized. */ -struct uri_auth *stats_set_node_name(struct uri_auth **root, char *name) +struct uri_auth *stats_set_node(struct uri_auth **root, char *name) { struct uri_auth *u; - char *name_copy; + char *node_copy = NULL; - if ((name_copy = strdup(name)) == NULL) - goto out_realm; + if (name && *name) { + node_copy = strdup(name); + if (node_copy == NULL) + goto out_realm; + } if ((u = stats_check_init_uri_auth(root)) == NULL) goto out_u; + + if (!stats_set_flag(root, ST_SHNODE)) + goto out_u; + + if (node_copy) { + free(u->node); + u->node = node_copy; + } + + return u; + + out_u: + free(node_copy); + out_realm: + return NULL; +} + +/* + * Returns a default uri_auth with ST_SHDESC flag enabled and + * set as the desc if it is not empty. + * Uses the pointer provided if not NULL and not initialized. + */ +struct uri_auth *stats_set_desc(struct uri_auth **root, char *desc) +{ + struct uri_auth *u; + char *desc_copy = NULL; + + if (desc && *desc) { + desc_copy = strdup(desc); + if (desc_copy == NULL) + goto out_realm; + } - free(u->node_name); - u->node_name = name_copy; + if ((u = stats_check_init_uri_auth(root)) == NULL) + goto out_u; + + if (!stats_set_flag(root, ST_SHDESC)) + goto out_u; + + if (desc_copy) { + free(u->desc); + u->desc = desc_copy; + } + return u; out_u: - free(name_copy); + free(desc_copy); out_realm: return NULL; }
QueueBckChkDwnDwntmeThrtle