MEDIUM: stats: Separate server state and colour in stats

There is a relationship between the state and colour of a server in
stats, however, it is not a one-to-one relationship and the current
implementation has proved fragile.

This patch attempts to address that problem by clearly separating
state and colour.

A follow-up patch will further distinguish between DRAIN states
and DRAINING colours.

Signed-off-by: Simon Horman <horms@verge.net.au>
This commit is contained in:
Simon Horman 2015-04-23 14:51:27 +09:00 committed by Willy Tarreau
parent 4d2eab61d4
commit 837bfa74db

View File

@ -2934,13 +2934,35 @@ enum srv_stats_state {
SRV_STATS_STATE_COUNT, /* Must be last */ SRV_STATS_STATE_COUNT, /* Must be last */
}; };
enum srv_stats_colour {
SRV_STATS_COLOUR_DOWN = 0,
SRV_STATS_COLOUR_GOING_UP,
SRV_STATS_COLOUR_GOING_DOWN,
SRV_STATS_COLOUR_UP,
SRV_STATS_COLOUR_NOLB,
SRV_STATS_COLOUR_DRAINING,
SRV_STATS_COLOUR_NO_CHECK,
SRV_STATS_COLOUR_COUNT, /* Must be last */
};
static const char *srv_stats_colour_st[SRV_STATS_COLOUR_COUNT] = {
[SRV_STATS_COLOUR_DOWN] = "down",
[SRV_STATS_COLOUR_GOING_UP] = "going_up",
[SRV_STATS_COLOUR_GOING_DOWN] = "going_down",
[SRV_STATS_COLOUR_UP] = "up",
[SRV_STATS_COLOUR_NOLB] = "nolb",
[SRV_STATS_COLOUR_DRAINING] = "draining",
[SRV_STATS_COLOUR_NO_CHECK] = "no_check",
};
/* Dumps a line for server <sv> and proxy <px> to the trash and uses the state /* Dumps a line for server <sv> and proxy <px> to the trash and uses the state
* from stream interface <si>, stats flags <flags>, and server state <state>. * from stream interface <si>, stats flags <flags>, and server state <state>.
* The caller is responsible for clearing the trash if needed. Returns non-zero * The caller is responsible for clearing the trash if needed. Returns non-zero
* if it emits anything, zero otherwise. * if it emits anything, zero otherwise.
*/ */
static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, int flags, struct server *sv, static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, int flags, struct server *sv,
enum srv_stats_state state) enum srv_stats_state state, enum srv_stats_colour colour)
{ {
struct appctx *appctx = __objt_appctx(si->end); struct appctx *appctx = __objt_appctx(si->end);
struct server *via, *ref; struct server *via, *ref;
@ -2974,8 +2996,8 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in
chunk_appendf(&trash, "<tr class=\"maintain\">"); chunk_appendf(&trash, "<tr class=\"maintain\">");
else else
chunk_appendf(&trash, chunk_appendf(&trash,
"<tr class=\"%s%d\">", "<tr class=\"%s_%s\">",
(sv->flags & SRV_F_BACKUP) ? "backup" : "active", state); (sv->flags & SRV_F_BACKUP) ? "backup" : "active", srv_stats_colour_st[colour]);
if ((px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN)) if ((px->cap & PR_CAP_BE) && px->srv && (appctx->ctx.stats.flags & STAT_ADMIN))
chunk_appendf(&trash, chunk_appendf(&trash,
@ -3853,6 +3875,7 @@ static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy
/* stats.sv has been initialized above */ /* stats.sv has been initialized above */
for (; appctx->ctx.stats.sv != NULL; appctx->ctx.stats.sv = sv->next) { for (; appctx->ctx.stats.sv != NULL; appctx->ctx.stats.sv = sv->next) {
enum srv_stats_state sv_state; enum srv_stats_state sv_state;
enum srv_stats_colour sv_colour;
if (buffer_almost_full(rep->buf)) { if (buffer_almost_full(rep->buf)) {
si->flags |= SI_FL_WAIT_ROOM; si->flags |= SI_FL_WAIT_ROOM;
@ -3875,37 +3898,52 @@ static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy
if (sv->state == SRV_ST_RUNNING || sv->state == SRV_ST_STARTING) { if (sv->state == SRV_ST_RUNNING || sv->state == SRV_ST_STARTING) {
if ((svs->check.state & CHK_ST_ENABLED) && if ((svs->check.state & CHK_ST_ENABLED) &&
(svs->check.health < svs->check.rise + svs->check.fall - 1)) (svs->check.health < svs->check.rise + svs->check.fall - 1)) {
sv_state = SRV_STATS_STATE_UP_GOING_DOWN; sv_state = SRV_STATS_STATE_UP_GOING_DOWN;
else sv_colour = SRV_STATS_COLOUR_GOING_DOWN;
} else {
sv_state = SRV_STATS_STATE_UP; sv_state = SRV_STATS_STATE_UP;
sv_colour = SRV_STATS_COLOUR_UP;
if (server_is_draining(sv)) {
if (sv_state == SRV_STATS_STATE_UP_GOING_DOWN)
sv_state = SRV_STATS_STATE_DRAIN_GOING_DOWN;
else
sv_state = SRV_STATS_STATE_DRAIN;
} }
if (sv_state == SRV_STATS_STATE_UP && !(svs->check.state & CHK_ST_ENABLED)) if (server_is_draining(sv)) {
if (sv_state == SRV_STATS_STATE_UP_GOING_DOWN) {
sv_state = SRV_STATS_STATE_DRAIN_GOING_DOWN;
} else {
sv_state = SRV_STATS_STATE_DRAIN;
sv_colour = SRV_STATS_COLOUR_DRAINING;
}
}
if (sv_state == SRV_STATS_STATE_UP && !(svs->check.state & CHK_ST_ENABLED)) {
sv_state = SRV_STATS_STATE_NO_CHECK; sv_state = SRV_STATS_STATE_NO_CHECK;
sv_colour = SRV_STATS_COLOUR_NO_CHECK;
}
} }
else if (sv->state == SRV_ST_STOPPING) { else if (sv->state == SRV_ST_STOPPING) {
if ((!(sv->check.state & CHK_ST_ENABLED) && !sv->track) || if ((!(sv->check.state & CHK_ST_ENABLED) && !sv->track) ||
(svs->check.health == svs->check.rise + svs->check.fall - 1)) (svs->check.health == svs->check.rise + svs->check.fall - 1)) {
sv_state = SRV_STATS_STATE_NOLB; sv_state = SRV_STATS_STATE_NOLB;
else sv_colour = SRV_STATS_COLOUR_NOLB;
} else {
sv_state = SRV_STATS_STATE_NOLB_GOING_DOWN; sv_state = SRV_STATS_STATE_NOLB_GOING_DOWN;
sv_colour = SRV_STATS_COLOUR_GOING_DOWN;
}
} }
else { /* stopped */ else { /* stopped */
if ((svs->agent.state & CHK_ST_ENABLED) && !svs->agent.health) if ((svs->agent.state & CHK_ST_ENABLED) && !svs->agent.health) {
sv_state = SRV_STATS_STATE_DOWN_AGENT; sv_state = SRV_STATS_STATE_DOWN_AGENT;
else if ((svs->check.state & CHK_ST_ENABLED) && !svs->check.health) sv_colour = SRV_STATS_COLOUR_DOWN;
} else if ((svs->check.state & CHK_ST_ENABLED) && !svs->check.health) {
sv_state = SRV_STATS_STATE_DOWN; /* DOWN */ sv_state = SRV_STATS_STATE_DOWN; /* DOWN */
else if ((svs->agent.state & CHK_ST_ENABLED) || (svs->check.state & CHK_ST_ENABLED)) sv_colour = SRV_STATS_COLOUR_DOWN;
} else if ((svs->agent.state & CHK_ST_ENABLED) || (svs->check.state & CHK_ST_ENABLED)) {
sv_state = SRV_STATS_STATE_GOING_UP; sv_state = SRV_STATS_STATE_GOING_UP;
else sv_colour = SRV_STATS_COLOUR_GOING_UP;
} else {
sv_state = SRV_STATS_STATE_DOWN; /* DOWN, unchecked */ sv_state = SRV_STATS_STATE_DOWN; /* DOWN, unchecked */
sv_colour = SRV_STATS_COLOUR_DOWN;
}
} }
if (((sv_state <= 1) || (sv->admin & SRV_ADMF_MAINT)) && (appctx->ctx.stats.flags & STAT_HIDE_DOWN)) { if (((sv_state <= 1) || (sv->admin & SRV_ADMF_MAINT)) && (appctx->ctx.stats.flags & STAT_HIDE_DOWN)) {
@ -3914,7 +3952,7 @@ static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy
continue; continue;
} }
if (stats_dump_sv_stats(si, px, uri ? uri->flags : 0, sv, sv_state)) { if (stats_dump_sv_stats(si, px, uri ? uri->flags : 0, sv, sv_state, sv_colour)) {
if (bi_putchk(rep, &trash) == -1) { if (bi_putchk(rep, &trash) == -1) {
si->flags |= SI_FL_WAIT_ROOM; si->flags |= SI_FL_WAIT_ROOM;
return 0; return 0;
@ -4015,26 +4053,20 @@ static void stats_dump_html_head(struct uri_auth *uri)
".frontend {background: #e8e8d0;}\n" ".frontend {background: #e8e8d0;}\n"
".socket {background: #d0d0d0;}\n" ".socket {background: #d0d0d0;}\n"
".backend {background: #e8e8d0;}\n" ".backend {background: #e8e8d0;}\n"
".active0 {background: #ff9090;}\n" ".active_down {background: #ff9090;}\n"
".active1 {background: #ff9090;}\n" ".active_going_up {background: #ffd020;}\n"
".active2 {background: #ffd020;}\n" ".active_going_down {background: #ffffa0;}\n"
".active3 {background: #ffffa0;}\n" ".active_up {background: #c0ffc0;}\n"
".active4 {background: #c0ffc0;}\n" ".active_nolb {background: #20a0ff;}\n"
".active5 {background: #ffffa0;}\n" /* NOLB state shows same as going down */ ".active_draining {background: #20a0FF;}\n"
".active6 {background: #20a0ff;}\n" /* NOLB state shows different to be detected */ ".active_no_check {background: #e0e0e0;}\n"
".active7 {background: #ffffa0;}\n" /* DRAIN going down = same as going down */ ".backup_down {background: #ff9090;}\n"
".active8 {background: #20a0FF;}\n" /* DRAIN must be detected (weight=0) */ ".backup_going_up {background: #ff80ff;}\n"
".active9 {background: #e0e0e0;}\n" ".backup_going_down {background: #c060ff;}\n"
".backup0 {background: #ff9090;}\n" ".backup_up {background: #b0d0ff;}\n"
".backup1 {background: #ff9090;}\n" ".backup_nolb {background: #90b0e0;}\n"
".backup2 {background: #ff80ff;}\n" ".backup_draining {background: #cc9900;}\n"
".backup3 {background: #c060ff;}\n" ".backup_no_check {background: #e0e0e0;}\n"
".backup4 {background: #b0d0ff;}\n"
".backup5 {background: #c060ff;}\n" /* NOLB state shows same as going down */
".backup6 {background: #90b0e0;}\n" /* NOLB state shows same as going down */
".backup7 {background: #c060ff;}\n"
".backup8 {background: #cc9900;}\n"
".backup9 {background: #e0e0e0;}\n"
".maintain {background: #c07820;}\n" ".maintain {background: #c07820;}\n"
".rls {letter-spacing: 0.2em; margin-right: 1px;}\n" /* right letter spacing (used for grouping digits) */ ".rls {letter-spacing: 0.2em; margin-right: 1px;}\n" /* right letter spacing (used for grouping digits) */
"\n" "\n"
@ -4110,21 +4142,21 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
"Running tasks: %d/%d; idle = %d %%<br>\n" "Running tasks: %d/%d; idle = %d %%<br>\n"
"</td><td align=\"center\" nowrap>\n" "</td><td align=\"center\" nowrap>\n"
"<table class=\"lgd\"><tr>\n" "<table class=\"lgd\"><tr>\n"
"<td class=\"active4\">&nbsp;</td><td class=\"noborder\">active UP </td>" "<td class=\"active_up\">&nbsp;</td><td class=\"noborder\">active UP </td>"
"<td class=\"backup4\">&nbsp;</td><td class=\"noborder\">backup UP </td>" "<td class=\"backup_up\">&nbsp;</td><td class=\"noborder\">backup UP </td>"
"</tr><tr>\n" "</tr><tr>\n"
"<td class=\"active3\"></td><td class=\"noborder\">active UP, going down </td>" "<td class=\"active_going_down\"></td><td class=\"noborder\">active UP, going down </td>"
"<td class=\"backup3\"></td><td class=\"noborder\">backup UP, going down </td>" "<td class=\"backup_going_down\"></td><td class=\"noborder\">backup UP, going down </td>"
"</tr><tr>\n" "</tr><tr>\n"
"<td class=\"active2\"></td><td class=\"noborder\">active DOWN, going up </td>" "<td class=\"active_going_up\"></td><td class=\"noborder\">active DOWN, going up </td>"
"<td class=\"backup2\"></td><td class=\"noborder\">backup DOWN, going up </td>" "<td class=\"backup_going_up\"></td><td class=\"noborder\">backup DOWN, going up </td>"
"</tr><tr>\n" "</tr><tr>\n"
"<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>" "<td class=\"active_down\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>"
"<td class=\"active9\"></td><td class=\"noborder\">not checked </td>" "<td class=\"active_no_check\"></td><td class=\"noborder\">not checked </td>"
"</tr><tr>\n" "</tr><tr>\n"
"<td class=\"maintain\"></td><td class=\"noborder\" colspan=\"3\">active or backup DOWN for maintenance (MAINT) &nbsp;</td>" "<td class=\"maintain\"></td><td class=\"noborder\" colspan=\"3\">active or backup DOWN for maintenance (MAINT) &nbsp;</td>"
"</tr><tr>\n" "</tr><tr>\n"
"<td class=\"active8\"></td><td class=\"noborder\" colspan=\"3\">active or backup SOFT STOPPED for maintenance &nbsp;</td>" "<td class=\"active_draining\"></td><td class=\"noborder\" colspan=\"3\">active or backup SOFT STOPPED for maintenance &nbsp;</td>"
"</tr></table>\n" "</tr></table>\n"
"Note: \"NOLB\"/\"DRAIN\" = UP with load-balancing disabled." "Note: \"NOLB\"/\"DRAIN\" = UP with load-balancing disabled."
"</td>" "</td>"
@ -4226,7 +4258,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
switch (appctx->ctx.stats.st_code) { switch (appctx->ctx.stats.st_code) {
case STAT_STATUS_DONE: case STAT_STATUS_DONE:
chunk_appendf(&trash, chunk_appendf(&trash,
"<p><div class=active4>" "<p><div class=active_up>"
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> " "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
"Action processed successfully." "Action processed successfully."
"</div>\n", uri->uri_prefix, "</div>\n", uri->uri_prefix,
@ -4236,7 +4268,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
break; break;
case STAT_STATUS_NONE: case STAT_STATUS_NONE:
chunk_appendf(&trash, chunk_appendf(&trash,
"<p><div class=active3>" "<p><div class=active_going_down>"
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> " "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
"Nothing has changed." "Nothing has changed."
"</div>\n", uri->uri_prefix, "</div>\n", uri->uri_prefix,
@ -4246,7 +4278,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
break; break;
case STAT_STATUS_PART: case STAT_STATUS_PART:
chunk_appendf(&trash, chunk_appendf(&trash,
"<p><div class=active3>" "<p><div class=active_going_down>"
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> " "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
"Action partially processed.<br>" "Action partially processed.<br>"
"Some server names are probably unknown or ambiguous (duplicated names in the backend)." "Some server names are probably unknown or ambiguous (duplicated names in the backend)."
@ -4257,7 +4289,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
break; break;
case STAT_STATUS_ERRP: case STAT_STATUS_ERRP:
chunk_appendf(&trash, chunk_appendf(&trash,
"<p><div class=active0>" "<p><div class=active_down>"
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> " "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
"Action not processed because of invalid parameters." "Action not processed because of invalid parameters."
"<ul>" "<ul>"
@ -4272,7 +4304,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
break; break;
case STAT_STATUS_EXCD: case STAT_STATUS_EXCD:
chunk_appendf(&trash, chunk_appendf(&trash,
"<p><div class=active0>" "<p><div class=active_down>"
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> " "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
"<b>Action not processed : the buffer couldn't store all the data.<br>" "<b>Action not processed : the buffer couldn't store all the data.<br>"
"You should retry with less servers at a time.</b>" "You should retry with less servers at a time.</b>"
@ -4283,7 +4315,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
break; break;
case STAT_STATUS_DENY: case STAT_STATUS_DENY:
chunk_appendf(&trash, chunk_appendf(&trash,
"<p><div class=active0>" "<p><div class=active_down>"
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> " "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
"<b>Action denied.</b>" "<b>Action denied.</b>"
"</div>\n", uri->uri_prefix, "</div>\n", uri->uri_prefix,
@ -4293,7 +4325,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
break; break;
default: default:
chunk_appendf(&trash, chunk_appendf(&trash,
"<p><div class=active9>" "<p><div class=active_no_check>"
"<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> " "<a class=lfsb href=\"%s%s%s%s\" title=\"Remove this message\">[X]</a> "
"Unexpected result." "Unexpected result."
"</div>\n", uri->uri_prefix, "</div>\n", uri->uri_prefix,