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 <ho...@verge.net.au> --- v2 * First post --- src/dumpstats.c | 134 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 51 deletions(-) diff --git a/src/dumpstats.c b/src/dumpstats.c index 402fb0ae98ad..b505d4e2e172 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -2934,13 +2934,35 @@ enum srv_stats_state { 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 * from stream interface <si>, stats flags <flags>, and server state <state>. * The caller is responsible for clearing the trash if needed. Returns non-zero * if it emits anything, zero otherwise. */ 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 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\">"); else chunk_appendf(&trash, - "<tr class=\"%s%d\">", - (sv->flags & SRV_F_BACKUP) ? "backup" : "active", state); + "<tr class=\"%s_%s\">", + (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)) 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 */ for (; appctx->ctx.stats.sv != NULL; appctx->ctx.stats.sv = sv->next) { enum srv_stats_state sv_state; + enum srv_stats_colour sv_colour; if (buffer_almost_full(rep->buf)) { 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 ((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; - else + sv_colour = SRV_STATS_COLOUR_GOING_DOWN; + } else { 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) + if (sv_state == SRV_STATS_STATE_UP_GOING_DOWN) { sv_state = SRV_STATS_STATE_DRAIN_GOING_DOWN; - else + } 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)) + if (sv_state == SRV_STATS_STATE_UP && !(svs->check.state & CHK_ST_ENABLED)) { sv_state = SRV_STATS_STATE_NO_CHECK; + sv_colour = SRV_STATS_COLOUR_NO_CHECK; + } } else if (sv->state == SRV_ST_STOPPING) { 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; - else + sv_colour = SRV_STATS_COLOUR_NOLB; + } else { sv_state = SRV_STATS_STATE_NOLB_GOING_DOWN; + sv_colour = SRV_STATS_COLOUR_GOING_DOWN; + } } 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; - 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 */ - 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; - else + sv_colour = SRV_STATS_COLOUR_GOING_UP; + } else { 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)) { @@ -3914,7 +3952,7 @@ static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy 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) { si->flags |= SI_FL_WAIT_ROOM; return 0; @@ -4015,26 +4053,20 @@ static void stats_dump_html_head(struct uri_auth *uri) ".frontend {background: #e8e8d0;}\n" ".socket {background: #d0d0d0;}\n" ".backend {background: #e8e8d0;}\n" - ".active0 {background: #ff9090;}\n" - ".active1 {background: #ff9090;}\n" - ".active2 {background: #ffd020;}\n" - ".active3 {background: #ffffa0;}\n" - ".active4 {background: #c0ffc0;}\n" - ".active5 {background: #ffffa0;}\n" /* NOLB state shows same as going down */ - ".active6 {background: #20a0ff;}\n" /* NOLB state shows different to be detected */ - ".active7 {background: #ffffa0;}\n" /* DRAIN going down = same as going down */ - ".active8 {background: #20a0FF;}\n" /* DRAIN must be detected (weight=0) */ - ".active9 {background: #e0e0e0;}\n" - ".backup0 {background: #ff9090;}\n" - ".backup1 {background: #ff9090;}\n" - ".backup2 {background: #ff80ff;}\n" - ".backup3 {background: #c060ff;}\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" + ".active_down {background: #ff9090;}\n" + ".active_going_up {background: #ffd020;}\n" + ".active_going_down {background: #ffffa0;}\n" + ".active_up {background: #c0ffc0;}\n" + ".active_nolb {background: #20a0ff;}\n" + ".active_draining {background: #20a0FF;}\n" + ".active_no_check {background: #e0e0e0;}\n" + ".backup_down {background: #ff9090;}\n" + ".backup_going_up {background: #ff80ff;}\n" + ".backup_going_down {background: #c060ff;}\n" + ".backup_up {background: #b0d0ff;}\n" + ".backup_nolb {background: #90b0e0;}\n" + ".backup_draining {background: #cc9900;}\n" + ".backup_no_check {background: #e0e0e0;}\n" ".maintain {background: #c07820;}\n" ".rls {letter-spacing: 0.2em; margin-right: 1px;}\n" /* right letter spacing (used for grouping digits) */ "\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" "</td><td align=\"center\" nowrap>\n" "<table class=\"lgd\"><tr>\n" - "<td class=\"active4\"> </td><td class=\"noborder\">active UP </td>" - "<td class=\"backup4\"> </td><td class=\"noborder\">backup UP </td>" + "<td class=\"active_up\"> </td><td class=\"noborder\">active UP </td>" + "<td class=\"backup_up\"> </td><td class=\"noborder\">backup UP </td>" "</tr><tr>\n" - "<td class=\"active3\"></td><td class=\"noborder\">active UP, going down </td>" - "<td class=\"backup3\"></td><td class=\"noborder\">backup UP, going down </td>" + "<td class=\"active_going_down\"></td><td class=\"noborder\">active UP, going down </td>" + "<td class=\"backup_going_down\"></td><td class=\"noborder\">backup UP, going down </td>" "</tr><tr>\n" - "<td class=\"active2\"></td><td class=\"noborder\">active DOWN, going up </td>" - "<td class=\"backup2\"></td><td class=\"noborder\">backup DOWN, going up </td>" + "<td class=\"active_going_up\"></td><td class=\"noborder\">active DOWN, going up </td>" + "<td class=\"backup_going_up\"></td><td class=\"noborder\">backup DOWN, going up </td>" "</tr><tr>\n" - "<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN </td>" - "<td class=\"active9\"></td><td class=\"noborder\">not checked </td>" + "<td class=\"active_down\"></td><td class=\"noborder\">active or backup DOWN </td>" + "<td class=\"active_no_check\"></td><td class=\"noborder\">not checked </td>" "</tr><tr>\n" "<td class=\"maintain\"></td><td class=\"noborder\" colspan=\"3\">active or backup DOWN for maintenance (MAINT) </td>" "</tr><tr>\n" - "<td class=\"active8\"></td><td class=\"noborder\" colspan=\"3\">active or backup SOFT STOPPED for maintenance </td>" + "<td class=\"active_draining\"></td><td class=\"noborder\" colspan=\"3\">active or backup SOFT STOPPED for maintenance </td>" "</tr></table>\n" "Note: \"NOLB\"/\"DRAIN\" = UP with load-balancing disabled." "</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) { case STAT_STATUS_DONE: 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> " "Action processed successfully." "</div>\n", uri->uri_prefix, @@ -4236,7 +4268,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u break; case STAT_STATUS_NONE: 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> " "Nothing has changed." "</div>\n", uri->uri_prefix, @@ -4246,7 +4278,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u break; case STAT_STATUS_PART: 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> " "Action partially processed.<br>" "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; case STAT_STATUS_ERRP: 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> " "Action not processed because of invalid parameters." "<ul>" @@ -4272,7 +4304,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u break; case STAT_STATUS_EXCD: 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> " "<b>Action not processed : the buffer couldn't store all the data.<br>" "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; case STAT_STATUS_DENY: 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> " "<b>Action denied.</b>" "</div>\n", uri->uri_prefix, @@ -4293,7 +4325,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u break; default: 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> " "Unexpected result." "</div>\n", uri->uri_prefix, -- 2.1.4