From: Brian Warner Date: Fri, 20 Feb 2009 21:29:26 +0000 (-0700) Subject: web: add Storage status page, improve tests X-Git-Tag: allmydata-tahoe-1.4.0~170 X-Git-Url: https://git.rkrishnan.org/pf/content/COPYING.TGPPL.html?a=commitdiff_plain;h=00677ff9a5877e77160fc22105898dee85d2078d;p=tahoe-lafs%2Ftahoe-lafs.git web: add Storage status page, improve tests --- diff --git a/src/allmydata/test/test_storage.py b/src/allmydata/test/test_storage.py index f2c9ac5b..d5723247 100644 --- a/src/allmydata/test/test_storage.py +++ b/src/allmydata/test/test_storage.py @@ -1,7 +1,7 @@ from twisted.trial import unittest from twisted.internet import defer -import time, os.path, stat +import time, os.path, stat, re import itertools from allmydata import interfaces from allmydata.util import fileutil, hashutil, base32 @@ -14,6 +14,8 @@ from allmydata.immutable.layout import WriteBucketProxy, WriteBucketProxy_v2, \ ReadBucketProxy from allmydata.interfaces import BadWriteEnablerError from allmydata.test.common import LoggingServiceParent +from allmydata.web.storage import StorageStatus, abbreviate_if_known, \ + remove_prefix class Marker: pass @@ -1287,3 +1289,55 @@ class Stats(unittest.TestCase): self.failUnless(abs(output["get"]["95_0_percentile"] - 5) < 1) self.failUnless(abs(output["get"]["99_0_percentile"] - 5) < 1) self.failUnless(abs(output["get"]["99_9_percentile"] - 5) < 1) + + +class WebStatus(unittest.TestCase): + + def test_no_server(self): + w = StorageStatus(None) + html = w.renderSynchronously() + self.failUnless("

No Storage Server Running

" in html, html) + + + def remove_tags(self, s): + s = re.sub(r'<[^>]*>', ' ', s) + s = re.sub(r'\s+', ' ', s) + return s + + def test_status(self): + basedir = "storage/WebStatus/status" + fileutil.make_dirs(basedir) + ss = StorageServer(basedir, "\x00" * 20) + w = StorageStatus(ss) + html = w.renderSynchronously() + self.failUnless("

Storage Server Status

" in html, html) + s = self.remove_tags(html) + self.failUnless("Accepting new shares: Yes" in s, s) + self.failUnless("Reserved space: - 0B" in s, s) + + def test_readonly(self): + basedir = "storage/WebStatus/readonly" + fileutil.make_dirs(basedir) + ss = StorageServer(basedir, "\x00" * 20, readonly_storage=True) + w = StorageStatus(ss) + html = w.renderSynchronously() + self.failUnless("

Storage Server Status

" in html, html) + s = self.remove_tags(html) + self.failUnless("Accepting new shares: No" in s, s) + + def test_reserved(self): + basedir = "storage/WebStatus/reserved" + fileutil.make_dirs(basedir) + ss = StorageServer(basedir, "\x00" * 20, reserved_space=10e6) + w = StorageStatus(ss) + html = w.renderSynchronously() + self.failUnless("

Storage Server Status

" in html, html) + s = self.remove_tags(html) + self.failUnless("Reserved space: - 10.00MB" in s, s) + + def test_util(self): + self.failUnlessEqual(abbreviate_if_known(None), "?") + self.failUnlessEqual(abbreviate_if_known(10e6), "10.00MB") + self.failUnlessEqual(remove_prefix("foo.bar", "foo."), "bar") + self.failUnlessEqual(remove_prefix("foo.bar", "baz."), None) + diff --git a/src/allmydata/web/root.py b/src/allmydata/web/root.py index e82d5758..79441c25 100644 --- a/src/allmydata/web/root.py +++ b/src/allmydata/web/root.py @@ -142,6 +142,11 @@ class Root(rend.Page): rend.Page.__init__(self, client) self.client = client self.child_operations = operations.OphandleTable() + try: + s = client.getServiceNamed("storage") + except KeyError: + s = None + self.child_storage = storage.StorageStatus(s) self.child_uri = URIHandler(client) self.child_cap = URIHandler(client) @@ -170,6 +175,7 @@ class Root(rend.Page): child_reliability = NoReliability() child_report_incident = IncidentReporter() + #child_server # let's reserve this for storage-server-over-HTTP def data_version(self, ctx, data): return get_package_versions_string() @@ -184,10 +190,15 @@ class Root(rend.Page): ul = T.ul() try: ss = self.client.getServiceNamed("storage") - allocated_s = abbreviate_size(ss.allocated_size()) - allocated = "about %s allocated" % allocated_s - reserved = "%s reserved" % abbreviate_size(ss.reserved_space) - ul[T.li["Storage Server: %s, %s" % (allocated, reserved)]] + stats = ss.get_stats() + if stats["storage_server.accepting_immutable_shares"]: + msg = "accepting new shares" + else: + msg = "not accepting new shares (read-only)" + available = stats.get("storage_server.disk_avail") + if available is not None: + msg += ", %s available" % abbreviate_size(available) + ul[T.li[T.a(href="storage")["Storage Server"], ": ", msg]] except KeyError: ul[T.li["Not running storage server"]] diff --git a/src/allmydata/web/storage.py b/src/allmydata/web/storage.py new file mode 100644 index 00000000..013cedb9 --- /dev/null +++ b/src/allmydata/web/storage.py @@ -0,0 +1,47 @@ + +from nevow import rend, tags as T +from allmydata.web.common import getxmlfile, abbreviate_size + +def abbreviate_if_known(size): + if size is None: + return "?" + return abbreviate_size(size) + +def remove_prefix(s, prefix): + if not s.startswith(prefix): + return None + return s[len(prefix):] + +class StorageStatus(rend.Page): + docFactory = getxmlfile("storage_status.xhtml") + # the default 'data' argument is the StorageServer instance + + def __init__(self, storage): + rend.Page.__init__(self, storage) + self.storage = storage + + def render_storage_running(self, ctx, storage): + if storage: + return ctx.tag + else: + return T.h1["No Storage Server Running"] + + def render_bool(self, ctx, data): + return {True: "Yes", False: "No"}[bool(data)] + + def render_space(self, ctx, data): + return abbreviate_if_known(data) + + def data_stats(self, ctx, data): + # FYI: 'data' appears to be self, rather than the StorageServer + # object in self.original that gets passed to render_* methods. I + # still don't understand Nevow. + + # all xhtml tags that are children of a tag with n:render="stats" + # will be processed with this dictionary, so something like: + # + # will use get_stats()["storage_server.disk_total"] + return dict([ (remove_prefix(k, "storage_server."), v) + for k,v in self.storage.get_stats().items() ]) diff --git a/src/allmydata/web/storage_status.xhtml b/src/allmydata/web/storage_status.xhtml new file mode 100644 index 00000000..49139446 --- /dev/null +++ b/src/allmydata/web/storage_status.xhtml @@ -0,0 +1,34 @@ + + + AllMyData - Tahoe - Storage Server Status + + + + + +
+ +

Storage Server Status

+ + + + + + + + + + + + + +
Total disk space:
Disk space used:-
Reserved space:-
+ ======
Space Available:<
+ +
+ + +