From 1602c6625006a7b8f2ad439fbe1f5e1b32898f76 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 5 May 2020 17:38:08 -0400 Subject: [PATCH 01/10] Render map update status using twisted.web.template Fixes: ticket:3291 --- newsfragments/3291.minor | 0 src/allmydata/web/map-update-status.xhtml | 50 ++++---- src/allmydata/web/status.py | 136 ++++++++++++++-------- 3 files changed, 113 insertions(+), 73 deletions(-) create mode 100644 newsfragments/3291.minor diff --git a/newsfragments/3291.minor b/newsfragments/3291.minor new file mode 100644 index 000000000..e69de29bb diff --git a/src/allmydata/web/map-update-status.xhtml b/src/allmydata/web/map-update-status.xhtml index 25b6a28e0..603982623 100644 --- a/src/allmydata/web/map-update-status.xhtml +++ b/src/allmydata/web/map-update-status.xhtml @@ -1,35 +1,39 @@ - + Tahoe-LAFS - Mutable File Servermap Update Status + -

Mutable File Servermap Update Status

+

Mutable File Servermap Update Status

- + -

Update Results

- +

Update Results

-
Return to the Welcome Page
+ - + +
Return to the Welcome Page
+ + + diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index bc0d69d77..353022174 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -9,7 +9,7 @@ from twisted.web.template import ( XMLFile, renderer, renderElement, - tags + tags, ) from nevow import rend, tags as T from allmydata.util import base32, idlib @@ -868,73 +868,109 @@ class PublishStatusPage(rend.Page, RateAndTimeMixin): l[T.li["[%s]: %s" % (server.get_name(), times_s)]] return T.li["Per-Server Response Times: ", l] -class MapupdateStatusPage(rend.Page, RateAndTimeMixin): - docFactory = getxmlfile("map-update-status.xhtml") - def __init__(self, data): - rend.Page.__init__(self, data) - self.update_status = data +class MapupdateStatusPage(MultiFormatResource): - def render_started(self, ctx, data): - started_s = render_time(data.get_started()) - return started_s + def __init__(self, update_status): + super(MapupdateStatusPage, self).__init__() + self._update_status = update_status - def render_finished(self, ctx, data): - when = data.get_finished() + def render_HTML(self, req): + elem = MapupdateStatusElement(self._update_status); + return renderElement(req, elem) + + +class MapupdateStatusElement(RateAndTimeMixin, Element): + + loader = XMLFile(FilePath(__file__).sibling("map-update-status.xhtml")) + + def __init__(self, update_status): + super(MapupdateStatusElement, self).__init__() + self._update_status = update_status + + @renderer + def started(self, req, tag): + started_s = render_time(self._update_status.get_started()) + return tag(started_s) + + @renderer + def finished(self, req, tag): + when = self._update_status.get_finished() if not when: - return "not yet" - started_s = render_time(data.get_finished()) - return started_s + return tag("not yet") + started_s = render_time(self._update_status.get_finished()) + return tag(started_s) - def render_si(self, ctx, data): - si_s = base32.b2a_or_none(data.get_storage_index()) + @renderer + def si(self, req, tag): + si_s = base32.b2a_or_none(self._update_status.get_storage_index()) if si_s is None: si_s = "(None)" - return si_s + return tag(si_s) - def render_helper(self, ctx, data): - return {True: "Yes", - False: "No"}[data.using_helper()] + @renderer + def helper(self, req, tag): + return tag({True: "Yes", + False: "No"}[self._update_status.using_helper()]) - def render_progress(self, ctx, data): - progress = data.get_progress() + @renderer + def progress(self, req, tag): + progress = self._update_status.get_progress() # TODO: make an ascii-art bar - return "%.1f%%" % (100.0 * progress) + return tag("%.1f%%" % (100.0 * progress)) - def render_status(self, ctx, data): - return data.get_status() + @renderer + def status(self, req, tag): + return tag(self._update_status.get_status()) - def render_problems(self, ctx, data): - problems = data.problems + @renderer + def problems(self, req, tag): + problems = self._update_status.problems if not problems: - return "" - l = T.ul() + return tag("") + l = tags.ul() for peerid in sorted(problems.keys()): peerid_s = idlib.shortnodeid_b2a(peerid) - l[T.li["[%s]: %s" % (peerid_s, problems[peerid])]] - return ctx.tag["Server Problems:", l] + l(tags.li("[%s]: %s" % (peerid_s, problems[peerid]))) + return tag("Server Problems:", l) - def render_privkey_from(self, ctx, data): - server = data.get_privkey_from() + @renderer + def privkey_from(self, req, tag): + server = self._update_status.get_privkey_from() if server: - return ctx.tag["Got privkey from: [%s]" % server.get_name()] + return tag("Got privkey from: [%s]" % server.get_name()) else: - return "" + return tag("") - def data_time_total(self, ctx, data): - return self.update_status.timings.get("total") + # Helper to query update status timings. + # + # Querying `update_status.timings` can yield `None` or a numeric + # value, but twisted.web has trouble flattening the element tree + # when a node contains numeric values. Stringifying them helps. + def _get_update_status_timing(self, name, tag): + res = self._update_status.timings.get(name) + if not res: + return tag("") + return tag(str(res)) - def data_time_initial_queries(self, ctx, data): - return self.update_status.timings.get("initial_queries") + @renderer + def time_total(self, req, tag): + return self._get_update_status_timing("total", tag) - def data_time_cumulative_verify(self, ctx, data): - return self.update_status.timings.get("cumulative_verify") + @renderer + def time_initial_queries(self, req, tag): + return self._get_update_status_timing("initial_queries", tag) - def render_server_timings(self, ctx, data): - per_server = self.update_status.timings.get("per_server") + @renderer + def time_cumulative_verify(self, req, tag): + return self._get_update_status_timing("cumulative_verify", tag) + + @renderer + def server_timings(self, req, tag): + per_server = self._update_status.timings.get("per_server") if not per_server: - return "" - l = T.ul() + return tag("") + l = tags.ul() for server in sorted(per_server.keys(), key=lambda s: s.get_name()): times = [] for op,started,t in per_server[server]: @@ -943,14 +979,14 @@ class MapupdateStatusPage(rend.Page, RateAndTimeMixin): # self.render_time(None, started - self.update_status.get_started()), # self.render_time(None,t))) if op == "query": - times.append( self.render_time(None, t) ) + times.append(self.render_time(None, t)) elif op == "late": - times.append( "late(" + self.render_time(None, t) + ")" ) + times.append("late(" + self.render_time(None, t) + ")") else: - times.append( "privkey(" + self.render_time(None, t) + ")" ) + times.append("privkey(" + self.render_time(None, t) + ")") times_s = ", ".join(times) - l[T.li["[%s]: %s" % (server.get_name(), times_s)]] - return T.li["Per-Server Response Times: ", l] + l(tags.li("[%s]: %s" % (server.get_name(), times_s))) + return tags.li("Per-Server Response Times: ", l) def marshal_json(s): From 86871363ea61609f18061f03c3d993ec0577efa9 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 6 May 2020 08:44:31 -0400 Subject: [PATCH 02/10] Add notes to MapupdateStatusPage --- src/allmydata/web/status.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index 353022174..cd23e9ff5 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -869,9 +869,13 @@ class PublishStatusPage(rend.Page, RateAndTimeMixin): return T.li["Per-Server Response Times: ", l] +# Renders "/status/mapupdate-%d" class MapupdateStatusPage(MultiFormatResource): def __init__(self, update_status): + """ + :update_status servermap.UpdateStatus: server map stats provider. + """ super(MapupdateStatusPage, self).__init__() self._update_status = update_status From 8a71567137249d7310d436adaeece97ab0c2bc7f Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 6 May 2020 09:07:32 -0400 Subject: [PATCH 03/10] Avoid use of RateAndTimeMixin in MapupdateStatusPage --- src/allmydata/web/status.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index cd23e9ff5..e8becea98 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -884,7 +884,7 @@ class MapupdateStatusPage(MultiFormatResource): return renderElement(req, elem) -class MapupdateStatusElement(RateAndTimeMixin, Element): +class MapupdateStatusElement(Element): loader = XMLFile(FilePath(__file__).sibling("map-update-status.xhtml")) @@ -983,11 +983,11 @@ class MapupdateStatusElement(RateAndTimeMixin, Element): # self.render_time(None, started - self.update_status.get_started()), # self.render_time(None,t))) if op == "query": - times.append(self.render_time(None, t)) + times.append(abbreviate_time(t)) elif op == "late": - times.append("late(" + self.render_time(None, t) + ")") + times.append("late(" + abbreviate_time(t) + ")") else: - times.append("privkey(" + self.render_time(None, t) + ")") + times.append("privkey(" + abbreviate_time(t) + ")") times_s = ", ".join(times) l(tags.li("[%s]: %s" % (server.get_name(), times_s))) return tags.li("Per-Server Response Times: ", l) From bbbca6c0001eed27f3d5300086031184126f362b Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 6 May 2020 10:41:58 -0400 Subject: [PATCH 04/10] Drop a newline Party for consistency, partly in order to trigger a CircleCI run. --- src/allmydata/web/map-update-status.xhtml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/allmydata/web/map-update-status.xhtml b/src/allmydata/web/map-update-status.xhtml index 603982623..3bfd53dd1 100644 --- a/src/allmydata/web/map-update-status.xhtml +++ b/src/allmydata/web/map-update-status.xhtml @@ -32,7 +32,6 @@
  • -
    Return to the Welcome Page
    From 0c6889274da9fb5f1eb2538bac7565cb67366045 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 6 May 2020 13:10:31 -0400 Subject: [PATCH 05/10] Render problems only when there's a problem list --- src/allmydata/web/map-update-status.xhtml | 2 +- src/allmydata/web/status.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/allmydata/web/map-update-status.xhtml b/src/allmydata/web/map-update-status.xhtml index 3bfd53dd1..3b963b11d 100644 --- a/src/allmydata/web/map-update-status.xhtml +++ b/src/allmydata/web/map-update-status.xhtml @@ -22,7 +22,7 @@

    Update Results

      -
    • +
    • Total:
      • Initial Queries:
      • diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index e8becea98..4c79e2b25 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -931,7 +931,7 @@ class MapupdateStatusElement(Element): def problems(self, req, tag): problems = self._update_status.problems if not problems: - return tag("") + return tag l = tags.ul() for peerid in sorted(problems.keys()): peerid_s = idlib.shortnodeid_b2a(peerid) From 008812d6c8747bbda753bbf69ab24e4b273817f3 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 6 May 2020 13:11:53 -0400 Subject: [PATCH 06/10] Render abbreviated time in map update results --- src/allmydata/web/status.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index 4c79e2b25..4755ce445 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -944,7 +944,7 @@ class MapupdateStatusElement(Element): if server: return tag("Got privkey from: [%s]" % server.get_name()) else: - return tag("") + return tag # Helper to query update status timings. # @@ -954,8 +954,8 @@ class MapupdateStatusElement(Element): def _get_update_status_timing(self, name, tag): res = self._update_status.timings.get(name) if not res: - return tag("") - return tag(str(res)) + return tag("0") + return tag(abbreviate_time(res)) @renderer def time_total(self, req, tag): From 13bbda15291ea120a875b11f37055420c6913af7 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 6 May 2020 13:21:26 -0400 Subject: [PATCH 07/10] Render privkey only when there's a privkey --- src/allmydata/web/map-update-status.xhtml | 2 +- src/allmydata/web/status.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/allmydata/web/map-update-status.xhtml b/src/allmydata/web/map-update-status.xhtml index 3b963b11d..445c0b470 100644 --- a/src/allmydata/web/map-update-status.xhtml +++ b/src/allmydata/web/map-update-status.xhtml @@ -26,7 +26,7 @@
      • Total:
        • Initial Queries:
        • -
        • +
        • Cumulative Verify:
      • diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index 4755ce445..eaf0f726e 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -942,7 +942,7 @@ class MapupdateStatusElement(Element): def privkey_from(self, req, tag): server = self._update_status.get_privkey_from() if server: - return tag("Got privkey from: [%s]" % server.get_name()) + return tag(tags.li("Got privkey from: [%s]" % server.get_name())) else: return tag From c18488872ceb00ae7731d4e22bed87fdda54d2ed Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 13 May 2020 16:47:51 -0400 Subject: [PATCH 08/10] Make comment on MapupdateStatusPage a docstring --- src/allmydata/web/status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index eaf0f726e..4232a504a 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -869,8 +869,8 @@ class PublishStatusPage(rend.Page, RateAndTimeMixin): return T.li["Per-Server Response Times: ", l] -# Renders "/status/mapupdate-%d" class MapupdateStatusPage(MultiFormatResource): + """Renders "/status/mapupdate-%d.""" def __init__(self, update_status): """ From 8e17d203cf46c6f2a200b6641ed616cf17bb98aa Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 13 May 2020 16:59:52 -0400 Subject: [PATCH 09/10] Add missing "param:" to docstring --- src/allmydata/web/status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index 4232a504a..5b57aa239 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -874,7 +874,7 @@ class MapupdateStatusPage(MultiFormatResource): def __init__(self, update_status): """ - :update_status servermap.UpdateStatus: server map stats provider. + :param update_status servermap.UpdateStatus: server map stats provider. """ super(MapupdateStatusPage, self).__init__() self._update_status = update_status From 4af2e4b4df300f6d0ad7b2950e9249ae340efb14 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 13 May 2020 17:08:26 -0400 Subject: [PATCH 10/10] Drop an unbalanced quote --- src/allmydata/web/status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py index 5b57aa239..d26079345 100644 --- a/src/allmydata/web/status.py +++ b/src/allmydata/web/status.py @@ -870,7 +870,7 @@ class PublishStatusPage(rend.Page, RateAndTimeMixin): class MapupdateStatusPage(MultiFormatResource): - """Renders "/status/mapupdate-%d.""" + """Renders /status/mapupdate-%d.""" def __init__(self, update_status): """