]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
rename "checker results" to "check results", because it is more parallel to "check...
authorZooko O'Whielacronx <zooko@zooko.com>
Tue, 6 Jan 2009 20:37:03 +0000 (13:37 -0700)
committerZooko O'Whielacronx <zooko@zooko.com>
Tue, 6 Jan 2009 20:37:03 +0000 (13:37 -0700)
23 files changed:
docs/frontends/webapi.txt
src/allmydata/check_results.py [new file with mode: 0644]
src/allmydata/checker_results.py [deleted file]
src/allmydata/dirnode.py
src/allmydata/immutable/checker.py
src/allmydata/immutable/filenode.py
src/allmydata/immutable/repairer.py
src/allmydata/interfaces.py
src/allmydata/mutable/checker.py
src/allmydata/mutable/filenode.py
src/allmydata/mutable/repairer.py
src/allmydata/test/common.py
src/allmydata/test/test_dirnode.py
src/allmydata/test/test_immutable.py
src/allmydata/test/test_system.py
src/allmydata/web/check-results.xhtml [new file with mode: 0644]
src/allmydata/web/check_results.py [new file with mode: 0644]
src/allmydata/web/checker-results.xhtml [deleted file]
src/allmydata/web/checker_results.py [deleted file]
src/allmydata/web/directory.py
src/allmydata/web/filenode.py
src/allmydata/web/literal-check-results.xhtml [new file with mode: 0644]
src/allmydata/web/literal-checker-results.xhtml [deleted file]

index 426ff7be817d128c4bbd352d7e4cf530699a661e..29fae18b5c8435912c071f1e98b043551112f89d 100644 (file)
@@ -826,7 +826,7 @@ POST $URL?t=start-deep-check    (must add &ophandle=XYZ)
   will continue to run in the background, and the /operations page should be
   used to find out when the operation is done.
 
-  Detailed checker results for non-healthy files and directories will be
+  Detailed check results for non-healthy files and directories will be
   available under /operations/$HANDLE/$STORAGEINDEX, and the HTML status will
   contain links to these detailed results.
 
diff --git a/src/allmydata/check_results.py b/src/allmydata/check_results.py
new file mode 100644 (file)
index 0000000..d495115
--- /dev/null
@@ -0,0 +1,222 @@
+
+from zope.interface import implements
+from allmydata.interfaces import ICheckResults, ICheckAndRepairResults, \
+     IDeepCheckResults, IDeepCheckAndRepairResults, IURI
+from allmydata.util import base32
+
+class CheckerResults:
+    implements(ICheckResults)
+
+    def __init__(self, uri, storage_index):
+        assert IURI.providedBy(uri), uri
+        self.uri = uri
+        self.storage_index = storage_index
+        self.problems = []
+        self.data = {"count-corrupt-shares": 0,
+                     "list-corrupt-shares": [],
+                     }
+        self.summary = ""
+        self.report = []
+
+    def set_healthy(self, healthy):
+        self.healthy = bool(healthy)
+        if self.healthy:
+            assert (not hasattr(self, 'recoverable')) or self.recoverable, hasattr(self, 'recoverable') and self.recoverable
+            self.recoverable = True
+            self.summary = "healthy"
+        else:
+            self.summary = "not healthy"
+    def set_recoverable(self, recoverable):
+        self.recoverable = recoverable
+        if not self.recoverable:
+            assert (not hasattr(self, 'healthy')) or not self.healthy
+            self.healthy = False
+    def set_needs_rebalancing(self, needs_rebalancing):
+        self.needs_rebalancing_p = bool(needs_rebalancing)
+    def set_data(self, data):
+        self.data.update(data)
+    def set_summary(self, summary):
+        assert isinstance(summary, str) # should be a single string
+        self.summary = summary
+    def set_report(self, report):
+        assert not isinstance(report, str) # should be list of strings
+        self.report = report
+
+    def set_servermap(self, smap):
+        # mutable only
+        self.servermap = smap
+
+
+    def get_storage_index(self):
+        return self.storage_index
+    def get_storage_index_string(self):
+        return base32.b2a(self.storage_index)
+    def get_uri(self):
+        return self.uri
+
+    def is_healthy(self):
+        return self.healthy
+    def is_recoverable(self):
+        return self.recoverable
+
+    def needs_rebalancing(self):
+        return self.needs_rebalancing_p
+    def get_data(self):
+        return self.data
+
+    def get_summary(self):
+        return self.summary
+    def get_report(self):
+        return self.report
+    def get_servermap(self):
+        return self.servermap
+
+class CheckAndRepairResults:
+    implements(ICheckAndRepairResults)
+
+    def __init__(self, storage_index):
+        self.storage_index = storage_index
+        self.repair_attempted = False
+
+    def get_storage_index(self):
+        return self.storage_index
+    def get_storage_index_string(self):
+        return base32.b2a(self.storage_index)
+    def get_repair_attempted(self):
+        return self.repair_attempted
+    def get_repair_successful(self):
+        if not self.repair_attempted:
+            return False
+        return self.repair_successful
+    def get_pre_repair_results(self):
+        return self.pre_repair_results
+    def get_post_repair_results(self):
+        return self.post_repair_results
+
+
+class DeepResultsBase:
+
+    def __init__(self, root_storage_index):
+        self.root_storage_index = root_storage_index
+        if root_storage_index is None:
+            self.root_storage_index_s = "<none>"
+        else:
+            self.root_storage_index_s = base32.b2a(root_storage_index)
+
+        self.objects_checked = 0
+        self.objects_healthy = 0
+        self.objects_unhealthy = 0
+        self.objects_unrecoverable = 0
+        self.corrupt_shares = []
+        self.all_results = {}
+        self.all_results_by_storage_index = {}
+        self.stats = {}
+
+    def update_stats(self, new_stats):
+        self.stats.update(new_stats)
+
+    def get_root_storage_index_string(self):
+        return self.root_storage_index_s
+
+    def get_corrupt_shares(self):
+        return self.corrupt_shares
+
+    def get_all_results(self):
+        return self.all_results
+
+    def get_results_for_storage_index(self, storage_index):
+        return self.all_results_by_storage_index[storage_index]
+
+    def get_stats(self):
+        return self.stats
+
+
+class DeepCheckResults(DeepResultsBase):
+    implements(IDeepCheckResults)
+
+    def add_check(self, r, path):
+        if not r:
+            return # non-distributed object, i.e. LIT file
+        r = ICheckResults(r)
+        assert isinstance(path, (list, tuple))
+        self.objects_checked += 1
+        if r.is_healthy():
+            self.objects_healthy += 1
+        else:
+            self.objects_unhealthy += 1
+        if not r.is_recoverable():
+            self.objects_unrecoverable += 1
+        self.all_results[tuple(path)] = r
+        self.all_results_by_storage_index[r.get_storage_index()] = r
+        self.corrupt_shares.extend(r.get_data()["list-corrupt-shares"])
+
+    def get_counters(self):
+        return {"count-objects-checked": self.objects_checked,
+                "count-objects-healthy": self.objects_healthy,
+                "count-objects-unhealthy": self.objects_unhealthy,
+                "count-objects-unrecoverable": self.objects_unrecoverable,
+                "count-corrupt-shares": len(self.corrupt_shares),
+                }
+
+
+class DeepCheckAndRepairResults(DeepResultsBase):
+    implements(IDeepCheckAndRepairResults)
+
+    def __init__(self, root_storage_index):
+        DeepResultsBase.__init__(self, root_storage_index)
+        self.objects_healthy_post_repair = 0
+        self.objects_unhealthy_post_repair = 0
+        self.objects_unrecoverable_post_repair = 0
+        self.repairs_attempted = 0
+        self.repairs_successful = 0
+        self.repairs_unsuccessful = 0
+        self.corrupt_shares_post_repair = []
+
+    def add_check_and_repair(self, r, path):
+        if not r:
+            return # non-distributed object, i.e. LIT file
+        r = ICheckAndRepairResults(r)
+        assert isinstance(path, (list, tuple))
+        pre_repair = r.get_pre_repair_results()
+        post_repair = r.get_post_repair_results()
+        self.objects_checked += 1
+        if pre_repair.is_healthy():
+            self.objects_healthy += 1
+        else:
+            self.objects_unhealthy += 1
+        if not pre_repair.is_recoverable():
+            self.objects_unrecoverable += 1
+        self.corrupt_shares.extend(pre_repair.get_data()["list-corrupt-shares"])
+        if r.get_repair_attempted():
+            self.repairs_attempted += 1
+            if r.get_repair_successful():
+                self.repairs_successful += 1
+            else:
+                self.repairs_unsuccessful += 1
+        if post_repair.is_healthy():
+            self.objects_healthy_post_repair += 1
+        else:
+            self.objects_unhealthy_post_repair += 1
+        if not post_repair.is_recoverable():
+            self.objects_unrecoverable_post_repair += 1
+        self.all_results[tuple(path)] = r
+        self.all_results_by_storage_index[r.get_storage_index()] = r
+        self.corrupt_shares_post_repair.extend(post_repair.get_data()["list-corrupt-shares"])
+
+    def get_counters(self):
+        return {"count-objects-checked": self.objects_checked,
+                "count-objects-healthy-pre-repair": self.objects_healthy,
+                "count-objects-unhealthy-pre-repair": self.objects_unhealthy,
+                "count-objects-unrecoverable-pre-repair": self.objects_unrecoverable,
+                "count-objects-healthy-post-repair": self.objects_healthy_post_repair,
+                "count-objects-unhealthy-post-repair": self.objects_unhealthy_post_repair,
+                "count-objects-unrecoverable-post-repair": self.objects_unrecoverable_post_repair,
+                "count-repairs-attempted": self.repairs_attempted,
+                "count-repairs-successful": self.repairs_successful,
+                "count-repairs-unsuccessful": self.repairs_unsuccessful,
+                "count-corrupt-shares-pre-repair": len(self.corrupt_shares),
+                "count-corrupt-shares-post-repair": len(self.corrupt_shares_post_repair),
+                }
+
+    def get_remaining_corrupt_shares(self):
+        return self.corrupt_shares_post_repair
diff --git a/src/allmydata/checker_results.py b/src/allmydata/checker_results.py
deleted file mode 100644 (file)
index bfcc790..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-
-from zope.interface import implements
-from allmydata.interfaces import ICheckerResults, ICheckAndRepairResults, \
-     IDeepCheckResults, IDeepCheckAndRepairResults, IURI
-from allmydata.util import base32
-
-class CheckerResults:
-    implements(ICheckerResults)
-
-    def __init__(self, uri, storage_index):
-        assert IURI.providedBy(uri), uri
-        self.uri = uri
-        self.storage_index = storage_index
-        self.problems = []
-        self.data = {"count-corrupt-shares": 0,
-                     "list-corrupt-shares": [],
-                     }
-        self.summary = ""
-        self.report = []
-
-    def set_healthy(self, healthy):
-        self.healthy = bool(healthy)
-        if self.healthy:
-            assert (not hasattr(self, 'recoverable')) or self.recoverable, hasattr(self, 'recoverable') and self.recoverable
-            self.recoverable = True
-            self.summary = "healthy"
-        else:
-            self.summary = "not healthy"
-    def set_recoverable(self, recoverable):
-        self.recoverable = recoverable
-        if not self.recoverable:
-            assert (not hasattr(self, 'healthy')) or not self.healthy
-            self.healthy = False
-    def set_needs_rebalancing(self, needs_rebalancing):
-        self.needs_rebalancing_p = bool(needs_rebalancing)
-    def set_data(self, data):
-        self.data.update(data)
-    def set_summary(self, summary):
-        assert isinstance(summary, str) # should be a single string
-        self.summary = summary
-    def set_report(self, report):
-        assert not isinstance(report, str) # should be list of strings
-        self.report = report
-
-    def set_servermap(self, smap):
-        # mutable only
-        self.servermap = smap
-
-
-    def get_storage_index(self):
-        return self.storage_index
-    def get_storage_index_string(self):
-        return base32.b2a(self.storage_index)
-    def get_uri(self):
-        return self.uri
-
-    def is_healthy(self):
-        return self.healthy
-    def is_recoverable(self):
-        return self.recoverable
-
-    def needs_rebalancing(self):
-        return self.needs_rebalancing_p
-    def get_data(self):
-        return self.data
-
-    def get_summary(self):
-        return self.summary
-    def get_report(self):
-        return self.report
-    def get_servermap(self):
-        return self.servermap
-
-class CheckAndRepairResults:
-    implements(ICheckAndRepairResults)
-
-    def __init__(self, storage_index):
-        self.storage_index = storage_index
-        self.repair_attempted = False
-
-    def get_storage_index(self):
-        return self.storage_index
-    def get_storage_index_string(self):
-        return base32.b2a(self.storage_index)
-    def get_repair_attempted(self):
-        return self.repair_attempted
-    def get_repair_successful(self):
-        if not self.repair_attempted:
-            return False
-        return self.repair_successful
-    def get_pre_repair_results(self):
-        return self.pre_repair_results
-    def get_post_repair_results(self):
-        return self.post_repair_results
-
-
-class DeepResultsBase:
-
-    def __init__(self, root_storage_index):
-        self.root_storage_index = root_storage_index
-        if root_storage_index is None:
-            self.root_storage_index_s = "<none>"
-        else:
-            self.root_storage_index_s = base32.b2a(root_storage_index)
-
-        self.objects_checked = 0
-        self.objects_healthy = 0
-        self.objects_unhealthy = 0
-        self.objects_unrecoverable = 0
-        self.corrupt_shares = []
-        self.all_results = {}
-        self.all_results_by_storage_index = {}
-        self.stats = {}
-
-    def update_stats(self, new_stats):
-        self.stats.update(new_stats)
-
-    def get_root_storage_index_string(self):
-        return self.root_storage_index_s
-
-    def get_corrupt_shares(self):
-        return self.corrupt_shares
-
-    def get_all_results(self):
-        return self.all_results
-
-    def get_results_for_storage_index(self, storage_index):
-        return self.all_results_by_storage_index[storage_index]
-
-    def get_stats(self):
-        return self.stats
-
-
-class DeepCheckResults(DeepResultsBase):
-    implements(IDeepCheckResults)
-
-    def add_check(self, r, path):
-        if not r:
-            return # non-distributed object, i.e. LIT file
-        r = ICheckerResults(r)
-        assert isinstance(path, (list, tuple))
-        self.objects_checked += 1
-        if r.is_healthy():
-            self.objects_healthy += 1
-        else:
-            self.objects_unhealthy += 1
-        if not r.is_recoverable():
-            self.objects_unrecoverable += 1
-        self.all_results[tuple(path)] = r
-        self.all_results_by_storage_index[r.get_storage_index()] = r
-        self.corrupt_shares.extend(r.get_data()["list-corrupt-shares"])
-
-    def get_counters(self):
-        return {"count-objects-checked": self.objects_checked,
-                "count-objects-healthy": self.objects_healthy,
-                "count-objects-unhealthy": self.objects_unhealthy,
-                "count-objects-unrecoverable": self.objects_unrecoverable,
-                "count-corrupt-shares": len(self.corrupt_shares),
-                }
-
-
-class DeepCheckAndRepairResults(DeepResultsBase):
-    implements(IDeepCheckAndRepairResults)
-
-    def __init__(self, root_storage_index):
-        DeepResultsBase.__init__(self, root_storage_index)
-        self.objects_healthy_post_repair = 0
-        self.objects_unhealthy_post_repair = 0
-        self.objects_unrecoverable_post_repair = 0
-        self.repairs_attempted = 0
-        self.repairs_successful = 0
-        self.repairs_unsuccessful = 0
-        self.corrupt_shares_post_repair = []
-
-    def add_check_and_repair(self, r, path):
-        if not r:
-            return # non-distributed object, i.e. LIT file
-        r = ICheckAndRepairResults(r)
-        assert isinstance(path, (list, tuple))
-        pre_repair = r.get_pre_repair_results()
-        post_repair = r.get_post_repair_results()
-        self.objects_checked += 1
-        if pre_repair.is_healthy():
-            self.objects_healthy += 1
-        else:
-            self.objects_unhealthy += 1
-        if not pre_repair.is_recoverable():
-            self.objects_unrecoverable += 1
-        self.corrupt_shares.extend(pre_repair.get_data()["list-corrupt-shares"])
-        if r.get_repair_attempted():
-            self.repairs_attempted += 1
-            if r.get_repair_successful():
-                self.repairs_successful += 1
-            else:
-                self.repairs_unsuccessful += 1
-        if post_repair.is_healthy():
-            self.objects_healthy_post_repair += 1
-        else:
-            self.objects_unhealthy_post_repair += 1
-        if not post_repair.is_recoverable():
-            self.objects_unrecoverable_post_repair += 1
-        self.all_results[tuple(path)] = r
-        self.all_results_by_storage_index[r.get_storage_index()] = r
-        self.corrupt_shares_post_repair.extend(post_repair.get_data()["list-corrupt-shares"])
-
-    def get_counters(self):
-        return {"count-objects-checked": self.objects_checked,
-                "count-objects-healthy-pre-repair": self.objects_healthy,
-                "count-objects-unhealthy-pre-repair": self.objects_unhealthy,
-                "count-objects-unrecoverable-pre-repair": self.objects_unrecoverable,
-                "count-objects-healthy-post-repair": self.objects_healthy_post_repair,
-                "count-objects-unhealthy-post-repair": self.objects_unhealthy_post_repair,
-                "count-objects-unrecoverable-post-repair": self.objects_unrecoverable_post_repair,
-                "count-repairs-attempted": self.repairs_attempted,
-                "count-repairs-successful": self.repairs_successful,
-                "count-repairs-unsuccessful": self.repairs_unsuccessful,
-                "count-corrupt-shares-pre-repair": len(self.corrupt_shares),
-                "count-corrupt-shares-post-repair": len(self.corrupt_shares_post_repair),
-                }
-
-    def get_remaining_corrupt_shares(self):
-        return self.corrupt_shares_post_repair
index 9f2e1d250717bb43749a8db54d2697f5d3703f7b..9c38f86dddc7e6cbb3129774671497ebf457e4b4 100644 (file)
@@ -9,7 +9,7 @@ from allmydata.mutable.filenode import MutableFileNode
 from allmydata.interfaces import IMutableFileNode, IDirectoryNode,\
      IURI, IFileNode, IMutableFileURI, IFilesystemNode, \
      ExistingChildError, NoSuchChildError, ICheckable, IDeepCheckable
-from allmydata.checker_results import DeepCheckResults, \
+from allmydata.check_results import DeepCheckResults, \
      DeepCheckAndRepairResults
 from allmydata.monitor import Monitor
 from allmydata.util import hashutil, mathutil, base32, log
index bcccd8a9629f5f44e038701c0eda451c79c6d8ad..290d8cfdc582ff19a168c97af125bba3d933b6e0 100644 (file)
@@ -1,6 +1,6 @@
 from foolscap import DeadReferenceError
 from allmydata import hashtree
-from allmydata.checker_results import CheckerResults
+from allmydata.check_results import CheckerResults
 from allmydata.immutable import download
 from allmydata.uri import CHKFileVerifierURI
 from allmydata.util.assertutil import precondition
index e8e9d96be4652623dc8cebc93321e71b3a663c6e..45a4a600a9b0a0e725aa8fdbcc933fd9a0cd7c93 100644 (file)
@@ -10,7 +10,7 @@ from allmydata.interfaces import IFileNode, IFileURI, ICheckable, \
      IDownloadTarget
 from allmydata.util import log, base32
 from allmydata.immutable.checker import Checker
-from allmydata.checker_results import CheckAndRepairResults
+from allmydata.check_results import CheckAndRepairResults
 from allmydata.immutable.repairer import Repairer
 from allmydata.immutable import download
 
index 4f0e3f798e481360f6909a6b93c07a23aae3718b..9d41529d69738acf13d8dfa108da3837d97ee778 100644 (file)
@@ -1,6 +1,6 @@
 from twisted.internet import defer
 from allmydata import storage
-from allmydata.checker_results import CheckerResults, CheckAndRepairResults
+from allmydata.check_results import CheckerResults, CheckAndRepairResults
 from allmydata.immutable import download
 from allmydata.util import nummedobj
 from allmydata.util.assertutil import precondition
index a176e01c8dea4d7fbcdfad5e5bda40e250a0e16a..bfd0477ea3d1d68ce10d177540ef9e2ccf368c6b 100644 (file)
@@ -1515,7 +1515,7 @@ class ICheckable(Interface):
         """Check upon my health, optionally repairing any problems.
 
         This returns a Deferred that fires with an instance that provides
-        ICheckerResults, or None if the object is non-distributed (i.e. LIT
+        ICheckResults, or None if the object is non-distributed (i.e. LIT
         files).
 
         The monitor will be checked periodically to see if the operation has
@@ -1585,7 +1585,7 @@ class IDeepCheckable(Interface):
         IDeepCheckAndRepairResults object.
         """
 
-class ICheckerResults(Interface):
+class ICheckResults(Interface):
     """I contain the detailed results of a check/verify operation.
     """
 
@@ -1704,10 +1704,10 @@ class ICheckAndRepairResults(Interface):
         was fully healthy afterwards. False if no repair was attempted or if
         a repair attempt failed."""
     def get_pre_repair_results():
-        """Return an ICheckerResults instance that describes the state of the
+        """Return an ICheckResults instance that describes the state of the
         file/dir before any repair was attempted."""
     def get_post_repair_results():
-        """Return an ICheckerResults instance that describes the state of the
+        """Return an ICheckResults instance that describes the state of the
         file/dir after any repair was attempted. If no repair was attempted,
         the pre-repair and post-repair results will be identical."""
 
@@ -1741,11 +1741,11 @@ class IDeepCheckResults(Interface):
         """
     def get_all_results():
         """Return a dictionary mapping pathname (a tuple of strings, ready to
-        be slash-joined) to an ICheckerResults instance, one for each object
+        be slash-joined) to an ICheckResults instance, one for each object
         that was checked."""
 
     def get_results_for_storage_index(storage_index):
-        """Retrive the ICheckerResults instance for the given (binary)
+        """Retrive the ICheckResults instance for the given (binary)
         storage index. Raises KeyError if there are no results for that
         storage index."""
 
@@ -1820,15 +1820,15 @@ class IDeepCheckAndRepairResults(Interface):
 
 
 class IRepairable(Interface):
-    def repair(checker_results):
+    def repair(check_results):
         """Attempt to repair the given object. Returns a Deferred that fires
         with a IRepairResults object.
 
-        I must be called with an object that implements ICheckerResults, as
+        I must be called with an object that implements ICheckResults, as
         proof that you have actually discovered a problem with this file. I
         will use the data in the checker results to guide the repair process,
         such as which servers provided bad data and should therefore be
-        avoided. The ICheckerResults object is inside the
+        avoided. The ICheckResults object is inside the
         ICheckAndRepairResults object, which is returned by the
         ICheckable.check() method::
 
index 31e8744c4a32fde48145c21d898303a9e61e6c7f..ed9ddb3bcfa9013b11c3c217fa5e1362385d6b56 100644 (file)
@@ -4,7 +4,7 @@ from twisted.python import failure
 from allmydata import hashtree
 from allmydata.uri import from_string
 from allmydata.util import hashutil, base32, idlib, log
-from allmydata.checker_results import CheckAndRepairResults, CheckerResults
+from allmydata.check_results import CheckAndRepairResults, CheckerResults
 
 from common import MODE_CHECK, CorruptShareError
 from servermap import ServerMap, ServermapUpdater
index 8caa14547ddb269dd60d6280d53206523444ed27..1951ff1da2027e480833622f320e958129ff99b5 100644 (file)
@@ -6,7 +6,7 @@ from zope.interface import implements
 from twisted.internet import defer, reactor
 from foolscap.eventual import eventually
 from allmydata.interfaces import IMutableFileNode, IMutableFileURI, \
-     ICheckable, ICheckerResults, NotEnoughSharesError
+     ICheckable, ICheckResults, NotEnoughSharesError
 from allmydata.util import hashutil, log
 from allmydata.util.assertutil import precondition
 from allmydata.uri import WriteableSSKFileURI
@@ -253,9 +253,9 @@ class MutableFileNode:
     #################################
     # IRepairable
 
-    def repair(self, checker_results, force=False):
-        assert ICheckerResults(checker_results)
-        r = Repairer(self, checker_results)
+    def repair(self, check_results, force=False):
+        assert ICheckResults(check_results)
+        r = Repairer(self, check_results)
         d = r.start(force)
         return d
 
index f3ae1ce683843bf29546a2e2052ee6c6c14d90d5..b7d49bcde04c1b0f965254fa3bd77cbbd94f7fbc 100644 (file)
@@ -1,6 +1,6 @@
 
 from zope.interface import implements
-from allmydata.interfaces import IRepairResults, ICheckerResults
+from allmydata.interfaces import IRepairResults, ICheckResults
 
 class RepairResults:
     implements(IRepairResults)
@@ -15,10 +15,10 @@ class MustForceRepairError(Exception):
     pass
 
 class Repairer:
-    def __init__(self, node, checker_results):
+    def __init__(self, node, check_results):
         self.node = node
-        self.checker_results = ICheckerResults(checker_results)
-        assert checker_results.storage_index == self.node.get_storage_index()
+        self.check_results = ICheckResults(check_results)
+        assert check_results.storage_index == self.node.get_storage_index()
 
     def start(self, force=False):
         # download, then re-publish. If a server had a bad share, try to
@@ -47,7 +47,7 @@ class Repairer:
         #  old shares: replace old shares with the latest version
         #  bogus shares (bad sigs): replace the bad one with a good one
 
-        smap = self.checker_results.get_servermap()
+        smap = self.check_results.get_servermap()
 
         if smap.unrecoverable_newer_versions():
             if not force:
index e21cccc80098c470b06f8e862082ca880545d73b..5ed13d0b2d80d4120e287115fc855cfb5ac37a5a 100644 (file)
@@ -11,7 +11,7 @@ from allmydata import uri, dirnode, client
 from allmydata.introducer.server import IntroducerNode
 from allmydata.interfaces import IURI, IMutableFileNode, IFileNode, \
      FileTooLargeError, NotEnoughSharesError, ICheckable
-from allmydata.checker_results import CheckerResults, CheckAndRepairResults, \
+from allmydata.check_results import CheckerResults, CheckAndRepairResults, \
      DeepCheckResults, DeepCheckAndRepairResults
 from allmydata.mutable.common import CorruptShareError
 from allmydata.storage import storage_index_to_dir
index 916c9eaa3397882795b267592a49d518534935f5..52e2cfd1e0a78b503c6790d38231c63eaaf00c99 100644 (file)
@@ -15,7 +15,7 @@ from allmydata.util import hashutil, base32
 from allmydata.monitor import Monitor
 from allmydata.test.common import make_chk_file_uri, make_mutable_file_uri, \
      FakeDirectoryNode, create_chk_filenode, ErrorMixin, SystemTestMixin
-from allmydata.checker_results import CheckerResults, CheckAndRepairResults
+from allmydata.check_results import CheckerResults, CheckAndRepairResults
 import common_util as testutil
 
 # to test dirnode.py, we want to construct a tree of real DirectoryNodes that
index 34ee3a84a46eff79dc05866d1075edf18a8d1a03..7c7923dbfc84434ee8f8a77f0bb9749cc8f87b25 100644 (file)
@@ -1,5 +1,6 @@
 from allmydata.test.common import SystemTestMixin, ShareManglingMixin
 from allmydata.monitor import Monitor
+from allmydata import check_results
 from allmydata.interfaces import IURI, NotEnoughSharesError
 from allmydata.immutable import upload
 from allmydata.util import log
@@ -794,8 +795,11 @@ class Test(ShareManglingMixin, unittest.TestCase):
 
             d2 = filenode.check_and_repair(Monitor(), verify=False)
             def _after_repair(checkandrepairresults):
+                assert isinstance(checkandrepairresults, check_results.CheckAndRepairResults), checkandrepairresults
                 prerepairres = checkandrepairresults.get_pre_repair_results()
+                assert isinstance(prerepairres, check_results.CheckResults), prerepairres
                 postrepairres = checkandrepairresults.get_post_repair_results()
+                assert isinstance(postrepairres, check_results.CheckResults), postrepairres
                 after_repair_reads = self._count_reads()
                 after_repair_allocates = self._count_allocates()
 
index 0dad06fc424990604e0e45e9cf7d24f972956669..32968192257e93168c7dd7e98bf6f76b00cf2957 100644 (file)
@@ -14,7 +14,7 @@ from allmydata.util import idlib, mathutil
 from allmydata.util import log, base32
 from allmydata.scripts import runner
 from allmydata.interfaces import IDirectoryNode, IFileNode, IFileURI, \
-     ICheckerResults, ICheckAndRepairResults, IDeepCheckResults, \
+     ICheckResults, ICheckAndRepairResults, IDeepCheckResults, \
      IDeepCheckAndRepairResults, NoSuchChildError, NotEnoughSharesError
 from allmydata.monitor import Monitor, OperationCancelledError
 from allmydata.mutable.common import NotMutableError
@@ -2039,7 +2039,7 @@ class DeepCheckWebGood(DeepCheckBase, unittest.TestCase):
         return d
 
     def check_is_healthy(self, cr, n, where, incomplete=False):
-        self.failUnless(ICheckerResults.providedBy(cr), where)
+        self.failUnless(ICheckResults.providedBy(cr), where)
         self.failUnless(cr.is_healthy(), where)
         self.failUnlessEqual(cr.get_storage_index(), n.get_storage_index(),
                              where)
@@ -2622,7 +2622,7 @@ class DeepCheckWebBad(DeepCheckBase, unittest.TestCase):
 
     def check_is_healthy(self, cr, where):
         try:
-            self.failUnless(ICheckerResults.providedBy(cr), (cr, type(cr), where))
+            self.failUnless(ICheckResults.providedBy(cr), (cr, type(cr), where))
             self.failUnless(cr.is_healthy(), (cr.get_report(), cr.is_healthy(), cr.get_summary(), where))
             self.failUnless(cr.is_recoverable(), where)
             d = cr.get_data()
@@ -2634,7 +2634,7 @@ class DeepCheckWebBad(DeepCheckBase, unittest.TestCase):
             raise
 
     def check_is_missing_shares(self, cr, where):
-        self.failUnless(ICheckerResults.providedBy(cr), where)
+        self.failUnless(ICheckResults.providedBy(cr), where)
         self.failIf(cr.is_healthy(), where)
         self.failUnless(cr.is_recoverable(), where)
         d = cr.get_data()
@@ -2644,7 +2644,7 @@ class DeepCheckWebBad(DeepCheckBase, unittest.TestCase):
 
     def check_has_corrupt_shares(self, cr, where):
         # by "corrupt-shares" we mean the file is still recoverable
-        self.failUnless(ICheckerResults.providedBy(cr), where)
+        self.failUnless(ICheckResults.providedBy(cr), where)
         d = cr.get_data()
         self.failIf(cr.is_healthy(), (where, cr))
         self.failUnless(cr.is_recoverable(), where)
@@ -2655,7 +2655,7 @@ class DeepCheckWebBad(DeepCheckBase, unittest.TestCase):
         return cr
 
     def check_is_unrecoverable(self, cr, where):
-        self.failUnless(ICheckerResults.providedBy(cr), where)
+        self.failUnless(ICheckResults.providedBy(cr), where)
         d = cr.get_data()
         self.failIf(cr.is_healthy(), where)
         self.failIf(cr.is_recoverable(), where)
diff --git a/src/allmydata/web/check-results.xhtml b/src/allmydata/web/check-results.xhtml
new file mode 100644 (file)
index 0000000..0f43b9d
--- /dev/null
@@ -0,0 +1,24 @@
+<html xmlns:n="http://nevow.com/ns/nevow/0.1">
+  <head>
+    <title>AllMyData - Tahoe - Check Results</title>
+    <!-- <link href="http://www.allmydata.com/common/css/styles.css"
+          rel="stylesheet" type="text/css"/> -->
+    <link href="/webform_css" rel="stylesheet" type="text/css"/>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  </head>
+  <body>
+
+<h1>File Check Results for SI=<span n:render="storage_index" /></h1>
+
+<div>
+  <span n:render="summary" />
+</div>
+
+<div n:render="repair" />
+
+<div n:render="results" />
+
+<div n:render="return" />
+
+  </body>
+</html>
diff --git a/src/allmydata/web/check_results.py b/src/allmydata/web/check_results.py
new file mode 100644 (file)
index 0000000..529965e
--- /dev/null
@@ -0,0 +1,598 @@
+
+import time
+import simplejson
+from nevow import rend, inevow, tags as T
+from twisted.web import http, html
+from allmydata.web.common import getxmlfile, get_arg, get_root, \
+     IClient, WebError
+from allmydata.web.operations import ReloadMixin
+from allmydata.interfaces import ICheckAndRepairResults, ICheckResults
+from allmydata.util import base32, idlib
+
+class ResultsBase:
+    def _render_results(self, ctx, cr):
+        assert ICheckResults(cr)
+        c = IClient(ctx)
+        data = cr.get_data()
+        r = []
+        def add(name, value):
+            r.append(T.li[name + ": ", value])
+
+        add("Report", T.pre["\n".join(self._html(cr.get_report()))])
+        add("Share Counts",
+            "need %d-of-%d, have %d" % (data["count-shares-needed"],
+                                        data["count-shares-expected"],
+                                        data["count-shares-good"]))
+        add("Hosts with good shares", data["count-good-share-hosts"])
+
+        if data["list-corrupt-shares"]:
+            badsharemap = []
+            for (serverid, si, shnum) in data["list-corrupt-shares"]:
+                nickname = c.get_nickname_for_peerid(serverid)
+                badsharemap.append(T.tr[T.td["sh#%d" % shnum],
+                                        T.td[T.tt[base32.b2a(serverid)],
+                                             " (", nickname, ")"],
+                                        ])
+            add("Corrupt shares", T.table(border="1")[badsharemap])
+        else:
+            add("Corrupt shares", "none")
+
+        add("Wrong Shares", data["count-wrong-shares"])
+
+        sharemap = []
+        servers = {}
+
+        for shareid in sorted(data["sharemap"].keys()):
+            serverids = data["sharemap"][shareid]
+            for i,serverid in enumerate(serverids):
+                if serverid not in servers:
+                    servers[serverid] = []
+                servers[serverid].append(shareid)
+                shareid_s = ""
+                if i == 0:
+                    shareid_s = shareid
+                nickname = c.get_nickname_for_peerid(serverid)
+                sharemap.append(T.tr[T.td[shareid_s],
+                                     T.td[T.tt[base32.b2a(serverid)],
+                                          " (", nickname, ")"],
+                                     ])
+        add("Good Shares (sorted in share order)",
+            T.table(border="1")[sharemap])
+
+
+        add("Recoverable Versions", data["count-recoverable-versions"])
+        add("Unrecoverable Versions", data["count-unrecoverable-versions"])
+
+        # this table is sorted by permuted order
+        permuted_peer_ids = [peerid
+                             for (peerid, rref)
+                             in c.get_permuted_peers("storage",
+                                                     cr.get_storage_index())]
+
+        num_shares_left = sum([len(shares) for shares in servers.values()])
+        servermap = []
+        for serverid in permuted_peer_ids:
+            nickname = c.get_nickname_for_peerid(serverid)
+            shareids = servers.get(serverid, [])
+            shareids.reverse()
+            shareids_s = [ T.tt[shareid, " "] for shareid in shareids ]
+            servermap.append(T.tr[T.td[T.tt[base32.b2a(serverid)],
+                                       " (", nickname, ")"],
+                                  T.td[shareids_s] ])
+            num_shares_left -= len(shareids)
+            if not num_shares_left:
+                break
+        add("Share Balancing (servers in permuted order)",
+            T.table(border="1")[servermap])
+
+        return T.ul[r]
+
+    def _json_check_and_repair_results(self, r):
+        data = {}
+        data["storage-index"] = r.get_storage_index_string()
+        data["repair-attempted"] = r.get_repair_attempted()
+        data["repair-successful"] = r.get_repair_successful()
+        pre = r.get_pre_repair_results()
+        data["pre-repair-results"] = self._json_check_results(pre)
+        post = r.get_post_repair_results()
+        data["post-repair-results"] = self._json_check_results(post)
+        return data
+
+    def _json_check_results(self, r):
+        data = {}
+        data["storage-index"] = r.get_storage_index_string()
+        data["summary"] = r.get_summary()
+        data["results"] = self._json_check_counts(r.get_data())
+        data["results"]["needs-rebalancing"] = r.needs_rebalancing()
+        data["results"]["healthy"] = r.is_healthy()
+        data["results"]["recoverable"] = r.is_recoverable()
+        return data
+
+    def _json_check_counts(self, d):
+        r = {}
+        r["count-shares-good"] = d["count-shares-good"]
+        r["count-shares-needed"] = d["count-shares-needed"]
+        r["count-shares-expected"] = d["count-shares-expected"]
+        r["count-good-share-hosts"] = d["count-good-share-hosts"]
+        r["count-corrupt-shares"] = d["count-corrupt-shares"]
+        r["list-corrupt-shares"] = [ (idlib.nodeid_b2a(serverid),
+                                      base32.b2a(si), shnum)
+                                     for (serverid, si, shnum)
+                                     in d["list-corrupt-shares"] ]
+        r["servers-responding"] = [idlib.nodeid_b2a(serverid)
+                                   for serverid in d["servers-responding"]]
+        sharemap = {}
+        for (shareid, serverids) in d["sharemap"].items():
+            sharemap[shareid] = [idlib.nodeid_b2a(serverid)
+                                 for serverid in serverids]
+        r["sharemap"] = sharemap
+
+        r["count-wrong-shares"] = d["count-wrong-shares"]
+        r["count-recoverable-versions"] = d["count-recoverable-versions"]
+        r["count-unrecoverable-versions"] = d["count-unrecoverable-versions"]
+
+        return r
+
+    def _html(self, s):
+        if isinstance(s, (str, unicode)):
+            return html.escape(s)
+        assert isinstance(s, (list, tuple))
+        return [html.escape(w) for w in s]
+
+    def want_json(self, ctx):
+        output = get_arg(inevow.IRequest(ctx), "output", "").lower()
+        if output.lower() == "json":
+            return True
+        return False
+
+    def _render_si_link(self, ctx, storage_index):
+        si_s = base32.b2a(storage_index)
+        root = get_root(ctx)
+        req = inevow.IRequest(ctx)
+        ophandle = req.prepath[-1]
+        target = "%s/operations/%s/%s" % (get_root(ctx), ophandle, si_s)
+        output = get_arg(ctx, "output")
+        if output:
+            target = target + "?output=%s" % output
+        return T.a(href=target)[si_s]
+
+class LiteralCheckerResults(rend.Page, ResultsBase):
+    docFactory = getxmlfile("literal-check-results.xhtml")
+
+    def renderHTTP(self, ctx):
+        if self.want_json(ctx):
+            return self.json(ctx)
+        return rend.Page.renderHTTP(self, ctx)
+
+    def json(self, ctx):
+        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
+        data = {"storage-index": "",
+                "results": {"healthy": True},
+                }
+        return simplejson.dumps(data, indent=1) + "\n"
+
+class CheckerBase:
+
+    def renderHTTP(self, ctx):
+        if self.want_json(ctx):
+            return self.json(ctx)
+        return rend.Page.renderHTTP(self, ctx)
+
+    def render_storage_index(self, ctx, data):
+        return self.r.get_storage_index_string()
+
+    def render_return(self, ctx, data):
+        req = inevow.IRequest(ctx)
+        return_to = get_arg(req, "return_to", None)
+        if return_to:
+            return T.div[T.a(href=return_to)["Return to parent directory"]]
+        return ""
+
+class CheckerResults(CheckerBase, rend.Page, ResultsBase):
+    docFactory = getxmlfile("check-results.xhtml")
+
+    def __init__(self, results):
+        self.r = ICheckResults(results)
+
+    def json(self, ctx):
+        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
+        data = self._json_check_results(self.r)
+        return simplejson.dumps(data, indent=1) + "\n"
+
+    def render_summary(self, ctx, data):
+        results = []
+        if self.r.is_healthy():
+            results.append("Healthy")
+        elif self.r.is_recoverable():
+            results.append("Not Healthy!")
+        else:
+            results.append("Not Recoverable!")
+        results.append(" : ")
+        results.append(self._html(self.r.get_summary()))
+        return ctx.tag[results]
+
+    def render_repair(self, ctx, data):
+        if self.r.is_healthy():
+            return ""
+        repair = T.form(action=".", method="post",
+                        enctype="multipart/form-data")[
+            T.fieldset[
+            T.input(type="hidden", name="t", value="check"),
+            T.input(type="hidden", name="repair", value="true"),
+            T.input(type="submit", value="Repair"),
+            ]]
+        return ctx.tag[repair]
+
+    def render_rebalance(self, ctx, data):
+        if self.r.needs_rebalancing():
+            return ctx.tag["(needs rebalancing)"]
+        return ctx.tag["(does not need rebalancing)"]
+
+    def render_results(self, ctx, data):
+        cr = self._render_results(ctx, self.r)
+        return ctx.tag[cr]
+
+class CheckAndRepairResults(CheckerBase, rend.Page, ResultsBase):
+    docFactory = getxmlfile("check-and-repair-results.xhtml")
+
+    def __init__(self, results):
+        self.r = ICheckAndRepairResults(results)
+
+    def json(self, ctx):
+        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
+        data = self._json_check_and_repair_results(self.r)
+        return simplejson.dumps(data, indent=1) + "\n"
+
+    def render_summary(self, ctx, data):
+        cr = self.r.get_post_repair_results()
+        results = []
+        if cr.is_healthy():
+            results.append("Healthy")
+        elif cr.is_recoverable():
+            results.append("Not Healthy!")
+        else:
+            results.append("Not Recoverable!")
+        results.append(" : ")
+        results.append(self._html(cr.get_summary()))
+        return ctx.tag[results]
+
+    def render_repair_results(self, ctx, data):
+        if self.r.get_repair_attempted():
+            if self.r.get_repair_successful():
+                return ctx.tag["Repair successful"]
+            else:
+                return ctx.tag["Repair unsuccessful"]
+        return ctx.tag["No repair necessary"]
+
+    def render_post_repair_results(self, ctx, data):
+        cr = self._render_results(ctx, self.r.get_post_repair_results())
+        return ctx.tag[cr]
+
+    def render_maybe_pre_repair_results(self, ctx, data):
+        if self.r.get_repair_attempted():
+            cr = self._render_results(ctx, self.r.get_pre_repair_results())
+            return ctx.tag[T.div["Pre-Repair Checker Results:"], cr]
+        return ""
+
+
+class DeepCheckResults(rend.Page, ResultsBase, ReloadMixin):
+    docFactory = getxmlfile("deep-check-results.xhtml")
+
+    def __init__(self, monitor):
+        self.monitor = monitor
+
+    def childFactory(self, ctx, name):
+        if not name:
+            return self
+        # /operation/$OPHANDLE/$STORAGEINDEX provides detailed information
+        # about a specific file or directory that was checked
+        si = base32.a2b(name)
+        r = self.monitor.get_status()
+        try:
+            return CheckerResults(r.get_results_for_storage_index(si))
+        except KeyError:
+            raise WebError("No detailed results for SI %s" % html.escape(name),
+                           http.NOT_FOUND)
+
+    def renderHTTP(self, ctx):
+        if self.want_json(ctx):
+            return self.json(ctx)
+        return rend.Page.renderHTTP(self, ctx)
+
+    def json(self, ctx):
+        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
+        data = {}
+        data["finished"] = self.monitor.is_finished()
+        res = self.monitor.get_status()
+        data["root-storage-index"] = res.get_root_storage_index_string()
+        c = res.get_counters()
+        data["count-objects-checked"] = c["count-objects-checked"]
+        data["count-objects-healthy"] = c["count-objects-healthy"]
+        data["count-objects-unhealthy"] = c["count-objects-unhealthy"]
+        data["count-corrupt-shares"] = c["count-corrupt-shares"]
+        data["list-corrupt-shares"] = [ (idlib.nodeid_b2a(serverid),
+                                         base32.b2a(storage_index),
+                                         shnum)
+                                        for (serverid, storage_index, shnum)
+                                        in res.get_corrupt_shares() ]
+        data["list-unhealthy-files"] = [ (path_t, self._json_check_results(r))
+                                         for (path_t, r)
+                                         in res.get_all_results().items()
+                                         if not r.is_healthy() ]
+        data["stats"] = res.get_stats()
+        return simplejson.dumps(data, indent=1) + "\n"
+
+    def render_root_storage_index(self, ctx, data):
+        return self.monitor.get_status().get_root_storage_index_string()
+
+    def data_objects_checked(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-objects-checked"]
+    def data_objects_healthy(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-objects-healthy"]
+    def data_objects_unhealthy(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-objects-unhealthy"]
+    def data_objects_unrecoverable(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-objects-unrecoverable"]
+
+    def data_count_corrupt_shares(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-corrupt-shares"]
+
+    def render_problems_p(self, ctx, data):
+        c = self.monitor.get_status().get_counters()
+        if c["count-objects-unhealthy"]:
+            return ctx.tag
+        return ""
+
+    def data_problems(self, ctx, data):
+        all_objects = self.monitor.get_status().get_all_results()
+        for path in sorted(all_objects.keys()):
+            cr = all_objects[path]
+            assert ICheckResults.providedBy(cr)
+            if not cr.is_healthy():
+                yield path, cr
+
+    def render_problem(self, ctx, data):
+        path, cr = data
+        summary_text = ""
+        summary = cr.get_summary()
+        if summary:
+            summary_text = ": " + summary
+        summary_text += " [SI: %s]" % cr.get_storage_index_string()
+        return ctx.tag["/".join(self._html(path)), self._html(summary_text)]
+
+
+    def render_servers_with_corrupt_shares_p(self, ctx, data):
+        if self.monitor.get_status().get_counters()["count-corrupt-shares"]:
+            return ctx.tag
+        return ""
+
+    def data_servers_with_corrupt_shares(self, ctx, data):
+        servers = [serverid
+                   for (serverid, storage_index, sharenum)
+                   in self.monitor.get_status().get_corrupt_shares()]
+        servers.sort()
+        return servers
+
+    def render_server_problem(self, ctx, data):
+        serverid = data
+        data = [idlib.shortnodeid_b2a(serverid)]
+        c = IClient(ctx)
+        nickname = c.get_nickname_for_peerid(serverid)
+        if nickname:
+            data.append(" (%s)" % self._html(nickname))
+        return ctx.tag[data]
+
+
+    def render_corrupt_shares_p(self, ctx, data):
+        if self.monitor.get_status().get_counters()["count-corrupt-shares"]:
+            return ctx.tag
+        return ""
+    def data_corrupt_shares(self, ctx, data):
+        return self.monitor.get_status().get_corrupt_shares()
+    def render_share_problem(self, ctx, data):
+        serverid, storage_index, sharenum = data
+        nickname = IClient(ctx).get_nickname_for_peerid(serverid)
+        ctx.fillSlots("serverid", idlib.shortnodeid_b2a(serverid))
+        if nickname:
+            ctx.fillSlots("nickname", self._html(nickname))
+        ctx.fillSlots("si", self._render_si_link(ctx, storage_index))
+        ctx.fillSlots("shnum", str(sharenum))
+        return ctx.tag
+
+    def render_return(self, ctx, data):
+        req = inevow.IRequest(ctx)
+        return_to = get_arg(req, "return_to", None)
+        if return_to:
+            return T.div[T.a(href=return_to)["Return to parent directory"]]
+        return ""
+
+    def data_all_objects(self, ctx, data):
+        r = self.monitor.get_status().get_all_results()
+        for path in sorted(r.keys()):
+            yield (path, r[path])
+
+    def render_object(self, ctx, data):
+        path, r = data
+        if path:
+            pathstring = "/".join(self._html(path))
+        else:
+            pathstring = "<root>"
+        ctx.fillSlots("path", pathstring)
+        ctx.fillSlots("healthy", str(r.is_healthy()))
+        ctx.fillSlots("recoverable", str(r.is_recoverable()))
+        storage_index = r.get_storage_index()
+        ctx.fillSlots("storage_index", self._render_si_link(ctx, storage_index))
+        ctx.fillSlots("summary", self._html(r.get_summary()))
+        return ctx.tag
+
+    def render_runtime(self, ctx, data):
+        req = inevow.IRequest(ctx)
+        runtime = time.time() - req.processing_started_timestamp
+        return ctx.tag["runtime: %s seconds" % runtime]
+
+class DeepCheckAndRepairResults(rend.Page, ResultsBase, ReloadMixin):
+    docFactory = getxmlfile("deep-check-and-repair-results.xhtml")
+
+    def __init__(self, monitor):
+        #assert IDeepCheckAndRepairResults(results)
+        #self.r = results
+        self.monitor = monitor
+
+    def renderHTTP(self, ctx):
+        if self.want_json(ctx):
+            return self.json(ctx)
+        return rend.Page.renderHTTP(self, ctx)
+
+    def json(self, ctx):
+        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
+        res = self.monitor.get_status()
+        data = {}
+        data["finished"] = self.monitor.is_finished()
+        data["root-storage-index"] = res.get_root_storage_index_string()
+        c = res.get_counters()
+        data["count-objects-checked"] = c["count-objects-checked"]
+
+        data["count-objects-healthy-pre-repair"] = c["count-objects-healthy-pre-repair"]
+        data["count-objects-unhealthy-pre-repair"] = c["count-objects-unhealthy-pre-repair"]
+        data["count-objects-healthy-post-repair"] = c["count-objects-healthy-post-repair"]
+        data["count-objects-unhealthy-post-repair"] = c["count-objects-unhealthy-post-repair"]
+
+        data["count-repairs-attempted"] = c["count-repairs-attempted"]
+        data["count-repairs-successful"] = c["count-repairs-successful"]
+        data["count-repairs-unsuccessful"] = c["count-repairs-unsuccessful"]
+
+        data["count-corrupt-shares-pre-repair"] = c["count-corrupt-shares-pre-repair"]
+        data["count-corrupt-shares-post-repair"] = c["count-corrupt-shares-pre-repair"]
+
+        data["list-corrupt-shares"] = [ (idlib.nodeid_b2a(serverid),
+                                         base32.b2a(storage_index),
+                                         shnum)
+                                        for (serverid, storage_index, shnum)
+                                        in res.get_corrupt_shares() ]
+
+        remaining_corrupt = [ (idlib.nodeid_b2a(serverid),
+                               base32.b2a(storage_index),
+                               shnum)
+                              for (serverid, storage_index, shnum)
+                              in res.get_remaining_corrupt_shares() ]
+        data["list-remaining-corrupt-shares"] = remaining_corrupt
+
+        unhealthy = [ (path_t,
+                       self._json_check_results(crr.get_pre_repair_results()))
+                      for (path_t, crr)
+                      in res.get_all_results().items()
+                      if not crr.get_pre_repair_results().is_healthy() ]
+        data["list-unhealthy-files"] = unhealthy
+        data["stats"] = res.get_stats()
+        return simplejson.dumps(data, indent=1) + "\n"
+
+    def render_root_storage_index(self, ctx, data):
+        return self.monitor.get_status().get_root_storage_index_string()
+
+    def data_objects_checked(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-objects-checked"]
+
+    def data_objects_healthy(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-objects-healthy-pre-repair"]
+    def data_objects_unhealthy(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-objects-unhealthy-pre-repair"]
+    def data_corrupt_shares(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-corrupt-shares-pre-repair"]
+
+    def data_repairs_attempted(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-repairs-attempted"]
+    def data_repairs_successful(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-repairs-successful"]
+    def data_repairs_unsuccessful(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-repairs-unsuccessful"]
+
+    def data_objects_healthy_post(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-objects-healthy-post-repair"]
+    def data_objects_unhealthy_post(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-objects-unhealthy-post-repair"]
+    def data_corrupt_shares_post(self, ctx, data):
+        return self.monitor.get_status().get_counters()["count-corrupt-shares-post-repair"]
+
+    def render_pre_repair_problems_p(self, ctx, data):
+        c = self.monitor.get_status().get_counters()
+        if c["count-objects-unhealthy-pre-repair"]:
+            return ctx.tag
+        return ""
+
+    def data_pre_repair_problems(self, ctx, data):
+        all_objects = self.monitor.get_status().get_all_results()
+        for path in sorted(all_objects.keys()):
+            r = all_objects[path]
+            assert ICheckAndRepairResults.providedBy(r)
+            cr = r.get_pre_repair_results()
+            if not cr.is_healthy():
+                yield path, cr
+
+    def render_problem(self, ctx, data):
+        path, cr = data
+        return ["/".join(self._html(path)), ": ", self._html(cr.get_summary())]
+
+    def render_post_repair_problems_p(self, ctx, data):
+        c = self.monitor.get_status().get_counters()
+        if (c["count-objects-unhealthy-post-repair"]
+            or c["count-corrupt-shares-post-repair"]):
+            return ctx.tag
+        return ""
+
+    def data_post_repair_problems(self, ctx, data):
+        all_objects = self.monitor.get_status().get_all_results()
+        for path in sorted(all_objects.keys()):
+            r = all_objects[path]
+            assert ICheckAndRepairResults.providedBy(r)
+            cr = r.get_post_repair_results()
+            if not cr.is_healthy():
+                yield path, cr
+
+    def render_servers_with_corrupt_shares_p(self, ctx, data):
+        if self.monitor.get_status().get_counters()["count-corrupt-shares-pre-repair"]:
+            return ctx.tag
+        return ""
+    def data_servers_with_corrupt_shares(self, ctx, data):
+        return [] # TODO
+    def render_server_problem(self, ctx, data):
+        pass
+
+
+    def render_remaining_corrupt_shares_p(self, ctx, data):
+        if self.monitor.get_status().get_counters()["count-corrupt-shares-post-repair"]:
+            return ctx.tag
+        return ""
+    def data_post_repair_corrupt_shares(self, ctx, data):
+        return [] # TODO
+
+    def render_share_problem(self, ctx, data):
+        pass
+
+
+    def render_return(self, ctx, data):
+        req = inevow.IRequest(ctx)
+        return_to = get_arg(req, "return_to", None)
+        if return_to:
+            return T.div[T.a(href=return_to)["Return to parent directory"]]
+        return ""
+
+    def data_all_objects(self, ctx, data):
+        r = self.monitor.get_status().get_all_results()
+        for path in sorted(r.keys()):
+            yield (path, r[path])
+
+    def render_object(self, ctx, data):
+        path, r = data
+        ctx.fillSlots("path", "/".join(self._html(path)))
+        ctx.fillSlots("healthy_pre_repair",
+                      str(r.get_pre_repair_results().is_healthy()))
+        ctx.fillSlots("healthy_post_repair",
+                      str(r.get_post_repair_results().is_healthy()))
+        ctx.fillSlots("summary",
+                      self._html(r.get_pre_repair_results().get_summary()))
+        return ctx.tag
+
+    def render_runtime(self, ctx, data):
+        req = inevow.IRequest(ctx)
+        runtime = time.time() - req.processing_started_timestamp
+        return ctx.tag["runtime: %s seconds" % runtime]
diff --git a/src/allmydata/web/checker-results.xhtml b/src/allmydata/web/checker-results.xhtml
deleted file mode 100644 (file)
index 0f43b9d..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<html xmlns:n="http://nevow.com/ns/nevow/0.1">
-  <head>
-    <title>AllMyData - Tahoe - Check Results</title>
-    <!-- <link href="http://www.allmydata.com/common/css/styles.css"
-          rel="stylesheet" type="text/css"/> -->
-    <link href="/webform_css" rel="stylesheet" type="text/css"/>
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-  </head>
-  <body>
-
-<h1>File Check Results for SI=<span n:render="storage_index" /></h1>
-
-<div>
-  <span n:render="summary" />
-</div>
-
-<div n:render="repair" />
-
-<div n:render="results" />
-
-<div n:render="return" />
-
-  </body>
-</html>
diff --git a/src/allmydata/web/checker_results.py b/src/allmydata/web/checker_results.py
deleted file mode 100644 (file)
index 12fd955..0000000
+++ /dev/null
@@ -1,598 +0,0 @@
-
-import time
-import simplejson
-from nevow import rend, inevow, tags as T
-from twisted.web import http, html
-from allmydata.web.common import getxmlfile, get_arg, get_root, \
-     IClient, WebError
-from allmydata.web.operations import ReloadMixin
-from allmydata.interfaces import ICheckAndRepairResults, ICheckerResults
-from allmydata.util import base32, idlib
-
-class ResultsBase:
-    def _render_results(self, ctx, cr):
-        assert ICheckerResults(cr)
-        c = IClient(ctx)
-        data = cr.get_data()
-        r = []
-        def add(name, value):
-            r.append(T.li[name + ": ", value])
-
-        add("Report", T.pre["\n".join(self._html(cr.get_report()))])
-        add("Share Counts",
-            "need %d-of-%d, have %d" % (data["count-shares-needed"],
-                                        data["count-shares-expected"],
-                                        data["count-shares-good"]))
-        add("Hosts with good shares", data["count-good-share-hosts"])
-
-        if data["list-corrupt-shares"]:
-            badsharemap = []
-            for (serverid, si, shnum) in data["list-corrupt-shares"]:
-                nickname = c.get_nickname_for_peerid(serverid)
-                badsharemap.append(T.tr[T.td["sh#%d" % shnum],
-                                        T.td[T.tt[base32.b2a(serverid)],
-                                             " (", nickname, ")"],
-                                        ])
-            add("Corrupt shares", T.table(border="1")[badsharemap])
-        else:
-            add("Corrupt shares", "none")
-
-        add("Wrong Shares", data["count-wrong-shares"])
-
-        sharemap = []
-        servers = {}
-
-        for shareid in sorted(data["sharemap"].keys()):
-            serverids = data["sharemap"][shareid]
-            for i,serverid in enumerate(serverids):
-                if serverid not in servers:
-                    servers[serverid] = []
-                servers[serverid].append(shareid)
-                shareid_s = ""
-                if i == 0:
-                    shareid_s = shareid
-                nickname = c.get_nickname_for_peerid(serverid)
-                sharemap.append(T.tr[T.td[shareid_s],
-                                     T.td[T.tt[base32.b2a(serverid)],
-                                          " (", nickname, ")"],
-                                     ])
-        add("Good Shares (sorted in share order)",
-            T.table(border="1")[sharemap])
-
-
-        add("Recoverable Versions", data["count-recoverable-versions"])
-        add("Unrecoverable Versions", data["count-unrecoverable-versions"])
-
-        # this table is sorted by permuted order
-        permuted_peer_ids = [peerid
-                             for (peerid, rref)
-                             in c.get_permuted_peers("storage",
-                                                     cr.get_storage_index())]
-
-        num_shares_left = sum([len(shares) for shares in servers.values()])
-        servermap = []
-        for serverid in permuted_peer_ids:
-            nickname = c.get_nickname_for_peerid(serverid)
-            shareids = servers.get(serverid, [])
-            shareids.reverse()
-            shareids_s = [ T.tt[shareid, " "] for shareid in shareids ]
-            servermap.append(T.tr[T.td[T.tt[base32.b2a(serverid)],
-                                       " (", nickname, ")"],
-                                  T.td[shareids_s] ])
-            num_shares_left -= len(shareids)
-            if not num_shares_left:
-                break
-        add("Share Balancing (servers in permuted order)",
-            T.table(border="1")[servermap])
-
-        return T.ul[r]
-
-    def _json_check_and_repair_results(self, r):
-        data = {}
-        data["storage-index"] = r.get_storage_index_string()
-        data["repair-attempted"] = r.get_repair_attempted()
-        data["repair-successful"] = r.get_repair_successful()
-        pre = r.get_pre_repair_results()
-        data["pre-repair-results"] = self._json_check_results(pre)
-        post = r.get_post_repair_results()
-        data["post-repair-results"] = self._json_check_results(post)
-        return data
-
-    def _json_check_results(self, r):
-        data = {}
-        data["storage-index"] = r.get_storage_index_string()
-        data["summary"] = r.get_summary()
-        data["results"] = self._json_check_counts(r.get_data())
-        data["results"]["needs-rebalancing"] = r.needs_rebalancing()
-        data["results"]["healthy"] = r.is_healthy()
-        data["results"]["recoverable"] = r.is_recoverable()
-        return data
-
-    def _json_check_counts(self, d):
-        r = {}
-        r["count-shares-good"] = d["count-shares-good"]
-        r["count-shares-needed"] = d["count-shares-needed"]
-        r["count-shares-expected"] = d["count-shares-expected"]
-        r["count-good-share-hosts"] = d["count-good-share-hosts"]
-        r["count-corrupt-shares"] = d["count-corrupt-shares"]
-        r["list-corrupt-shares"] = [ (idlib.nodeid_b2a(serverid),
-                                      base32.b2a(si), shnum)
-                                     for (serverid, si, shnum)
-                                     in d["list-corrupt-shares"] ]
-        r["servers-responding"] = [idlib.nodeid_b2a(serverid)
-                                   for serverid in d["servers-responding"]]
-        sharemap = {}
-        for (shareid, serverids) in d["sharemap"].items():
-            sharemap[shareid] = [idlib.nodeid_b2a(serverid)
-                                 for serverid in serverids]
-        r["sharemap"] = sharemap
-
-        r["count-wrong-shares"] = d["count-wrong-shares"]
-        r["count-recoverable-versions"] = d["count-recoverable-versions"]
-        r["count-unrecoverable-versions"] = d["count-unrecoverable-versions"]
-
-        return r
-
-    def _html(self, s):
-        if isinstance(s, (str, unicode)):
-            return html.escape(s)
-        assert isinstance(s, (list, tuple))
-        return [html.escape(w) for w in s]
-
-    def want_json(self, ctx):
-        output = get_arg(inevow.IRequest(ctx), "output", "").lower()
-        if output.lower() == "json":
-            return True
-        return False
-
-    def _render_si_link(self, ctx, storage_index):
-        si_s = base32.b2a(storage_index)
-        root = get_root(ctx)
-        req = inevow.IRequest(ctx)
-        ophandle = req.prepath[-1]
-        target = "%s/operations/%s/%s" % (get_root(ctx), ophandle, si_s)
-        output = get_arg(ctx, "output")
-        if output:
-            target = target + "?output=%s" % output
-        return T.a(href=target)[si_s]
-
-class LiteralCheckerResults(rend.Page, ResultsBase):
-    docFactory = getxmlfile("literal-checker-results.xhtml")
-
-    def renderHTTP(self, ctx):
-        if self.want_json(ctx):
-            return self.json(ctx)
-        return rend.Page.renderHTTP(self, ctx)
-
-    def json(self, ctx):
-        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
-        data = {"storage-index": "",
-                "results": {"healthy": True},
-                }
-        return simplejson.dumps(data, indent=1) + "\n"
-
-class CheckerBase:
-
-    def renderHTTP(self, ctx):
-        if self.want_json(ctx):
-            return self.json(ctx)
-        return rend.Page.renderHTTP(self, ctx)
-
-    def render_storage_index(self, ctx, data):
-        return self.r.get_storage_index_string()
-
-    def render_return(self, ctx, data):
-        req = inevow.IRequest(ctx)
-        return_to = get_arg(req, "return_to", None)
-        if return_to:
-            return T.div[T.a(href=return_to)["Return to parent directory"]]
-        return ""
-
-class CheckerResults(CheckerBase, rend.Page, ResultsBase):
-    docFactory = getxmlfile("checker-results.xhtml")
-
-    def __init__(self, results):
-        self.r = ICheckerResults(results)
-
-    def json(self, ctx):
-        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
-        data = self._json_check_results(self.r)
-        return simplejson.dumps(data, indent=1) + "\n"
-
-    def render_summary(self, ctx, data):
-        results = []
-        if self.r.is_healthy():
-            results.append("Healthy")
-        elif self.r.is_recoverable():
-            results.append("Not Healthy!")
-        else:
-            results.append("Not Recoverable!")
-        results.append(" : ")
-        results.append(self._html(self.r.get_summary()))
-        return ctx.tag[results]
-
-    def render_repair(self, ctx, data):
-        if self.r.is_healthy():
-            return ""
-        repair = T.form(action=".", method="post",
-                        enctype="multipart/form-data")[
-            T.fieldset[
-            T.input(type="hidden", name="t", value="check"),
-            T.input(type="hidden", name="repair", value="true"),
-            T.input(type="submit", value="Repair"),
-            ]]
-        return ctx.tag[repair]
-
-    def render_rebalance(self, ctx, data):
-        if self.r.needs_rebalancing():
-            return ctx.tag["(needs rebalancing)"]
-        return ctx.tag["(does not need rebalancing)"]
-
-    def render_results(self, ctx, data):
-        cr = self._render_results(ctx, self.r)
-        return ctx.tag[cr]
-
-class CheckAndRepairResults(CheckerBase, rend.Page, ResultsBase):
-    docFactory = getxmlfile("check-and-repair-results.xhtml")
-
-    def __init__(self, results):
-        self.r = ICheckAndRepairResults(results)
-
-    def json(self, ctx):
-        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
-        data = self._json_check_and_repair_results(self.r)
-        return simplejson.dumps(data, indent=1) + "\n"
-
-    def render_summary(self, ctx, data):
-        cr = self.r.get_post_repair_results()
-        results = []
-        if cr.is_healthy():
-            results.append("Healthy")
-        elif cr.is_recoverable():
-            results.append("Not Healthy!")
-        else:
-            results.append("Not Recoverable!")
-        results.append(" : ")
-        results.append(self._html(cr.get_summary()))
-        return ctx.tag[results]
-
-    def render_repair_results(self, ctx, data):
-        if self.r.get_repair_attempted():
-            if self.r.get_repair_successful():
-                return ctx.tag["Repair successful"]
-            else:
-                return ctx.tag["Repair unsuccessful"]
-        return ctx.tag["No repair necessary"]
-
-    def render_post_repair_results(self, ctx, data):
-        cr = self._render_results(ctx, self.r.get_post_repair_results())
-        return ctx.tag[cr]
-
-    def render_maybe_pre_repair_results(self, ctx, data):
-        if self.r.get_repair_attempted():
-            cr = self._render_results(ctx, self.r.get_pre_repair_results())
-            return ctx.tag[T.div["Pre-Repair Checker Results:"], cr]
-        return ""
-
-
-class DeepCheckResults(rend.Page, ResultsBase, ReloadMixin):
-    docFactory = getxmlfile("deep-check-results.xhtml")
-
-    def __init__(self, monitor):
-        self.monitor = monitor
-
-    def childFactory(self, ctx, name):
-        if not name:
-            return self
-        # /operation/$OPHANDLE/$STORAGEINDEX provides detailed information
-        # about a specific file or directory that was checked
-        si = base32.a2b(name)
-        r = self.monitor.get_status()
-        try:
-            return CheckerResults(r.get_results_for_storage_index(si))
-        except KeyError:
-            raise WebError("No detailed results for SI %s" % html.escape(name),
-                           http.NOT_FOUND)
-
-    def renderHTTP(self, ctx):
-        if self.want_json(ctx):
-            return self.json(ctx)
-        return rend.Page.renderHTTP(self, ctx)
-
-    def json(self, ctx):
-        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
-        data = {}
-        data["finished"] = self.monitor.is_finished()
-        res = self.monitor.get_status()
-        data["root-storage-index"] = res.get_root_storage_index_string()
-        c = res.get_counters()
-        data["count-objects-checked"] = c["count-objects-checked"]
-        data["count-objects-healthy"] = c["count-objects-healthy"]
-        data["count-objects-unhealthy"] = c["count-objects-unhealthy"]
-        data["count-corrupt-shares"] = c["count-corrupt-shares"]
-        data["list-corrupt-shares"] = [ (idlib.nodeid_b2a(serverid),
-                                         base32.b2a(storage_index),
-                                         shnum)
-                                        for (serverid, storage_index, shnum)
-                                        in res.get_corrupt_shares() ]
-        data["list-unhealthy-files"] = [ (path_t, self._json_check_results(r))
-                                         for (path_t, r)
-                                         in res.get_all_results().items()
-                                         if not r.is_healthy() ]
-        data["stats"] = res.get_stats()
-        return simplejson.dumps(data, indent=1) + "\n"
-
-    def render_root_storage_index(self, ctx, data):
-        return self.monitor.get_status().get_root_storage_index_string()
-
-    def data_objects_checked(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-objects-checked"]
-    def data_objects_healthy(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-objects-healthy"]
-    def data_objects_unhealthy(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-objects-unhealthy"]
-    def data_objects_unrecoverable(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-objects-unrecoverable"]
-
-    def data_count_corrupt_shares(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-corrupt-shares"]
-
-    def render_problems_p(self, ctx, data):
-        c = self.monitor.get_status().get_counters()
-        if c["count-objects-unhealthy"]:
-            return ctx.tag
-        return ""
-
-    def data_problems(self, ctx, data):
-        all_objects = self.monitor.get_status().get_all_results()
-        for path in sorted(all_objects.keys()):
-            cr = all_objects[path]
-            assert ICheckerResults.providedBy(cr)
-            if not cr.is_healthy():
-                yield path, cr
-
-    def render_problem(self, ctx, data):
-        path, cr = data
-        summary_text = ""
-        summary = cr.get_summary()
-        if summary:
-            summary_text = ": " + summary
-        summary_text += " [SI: %s]" % cr.get_storage_index_string()
-        return ctx.tag["/".join(self._html(path)), self._html(summary_text)]
-
-
-    def render_servers_with_corrupt_shares_p(self, ctx, data):
-        if self.monitor.get_status().get_counters()["count-corrupt-shares"]:
-            return ctx.tag
-        return ""
-
-    def data_servers_with_corrupt_shares(self, ctx, data):
-        servers = [serverid
-                   for (serverid, storage_index, sharenum)
-                   in self.monitor.get_status().get_corrupt_shares()]
-        servers.sort()
-        return servers
-
-    def render_server_problem(self, ctx, data):
-        serverid = data
-        data = [idlib.shortnodeid_b2a(serverid)]
-        c = IClient(ctx)
-        nickname = c.get_nickname_for_peerid(serverid)
-        if nickname:
-            data.append(" (%s)" % self._html(nickname))
-        return ctx.tag[data]
-
-
-    def render_corrupt_shares_p(self, ctx, data):
-        if self.monitor.get_status().get_counters()["count-corrupt-shares"]:
-            return ctx.tag
-        return ""
-    def data_corrupt_shares(self, ctx, data):
-        return self.monitor.get_status().get_corrupt_shares()
-    def render_share_problem(self, ctx, data):
-        serverid, storage_index, sharenum = data
-        nickname = IClient(ctx).get_nickname_for_peerid(serverid)
-        ctx.fillSlots("serverid", idlib.shortnodeid_b2a(serverid))
-        if nickname:
-            ctx.fillSlots("nickname", self._html(nickname))
-        ctx.fillSlots("si", self._render_si_link(ctx, storage_index))
-        ctx.fillSlots("shnum", str(sharenum))
-        return ctx.tag
-
-    def render_return(self, ctx, data):
-        req = inevow.IRequest(ctx)
-        return_to = get_arg(req, "return_to", None)
-        if return_to:
-            return T.div[T.a(href=return_to)["Return to parent directory"]]
-        return ""
-
-    def data_all_objects(self, ctx, data):
-        r = self.monitor.get_status().get_all_results()
-        for path in sorted(r.keys()):
-            yield (path, r[path])
-
-    def render_object(self, ctx, data):
-        path, r = data
-        if path:
-            pathstring = "/".join(self._html(path))
-        else:
-            pathstring = "<root>"
-        ctx.fillSlots("path", pathstring)
-        ctx.fillSlots("healthy", str(r.is_healthy()))
-        ctx.fillSlots("recoverable", str(r.is_recoverable()))
-        storage_index = r.get_storage_index()
-        ctx.fillSlots("storage_index", self._render_si_link(ctx, storage_index))
-        ctx.fillSlots("summary", self._html(r.get_summary()))
-        return ctx.tag
-
-    def render_runtime(self, ctx, data):
-        req = inevow.IRequest(ctx)
-        runtime = time.time() - req.processing_started_timestamp
-        return ctx.tag["runtime: %s seconds" % runtime]
-
-class DeepCheckAndRepairResults(rend.Page, ResultsBase, ReloadMixin):
-    docFactory = getxmlfile("deep-check-and-repair-results.xhtml")
-
-    def __init__(self, monitor):
-        #assert IDeepCheckAndRepairResults(results)
-        #self.r = results
-        self.monitor = monitor
-
-    def renderHTTP(self, ctx):
-        if self.want_json(ctx):
-            return self.json(ctx)
-        return rend.Page.renderHTTP(self, ctx)
-
-    def json(self, ctx):
-        inevow.IRequest(ctx).setHeader("content-type", "text/plain")
-        res = self.monitor.get_status()
-        data = {}
-        data["finished"] = self.monitor.is_finished()
-        data["root-storage-index"] = res.get_root_storage_index_string()
-        c = res.get_counters()
-        data["count-objects-checked"] = c["count-objects-checked"]
-
-        data["count-objects-healthy-pre-repair"] = c["count-objects-healthy-pre-repair"]
-        data["count-objects-unhealthy-pre-repair"] = c["count-objects-unhealthy-pre-repair"]
-        data["count-objects-healthy-post-repair"] = c["count-objects-healthy-post-repair"]
-        data["count-objects-unhealthy-post-repair"] = c["count-objects-unhealthy-post-repair"]
-
-        data["count-repairs-attempted"] = c["count-repairs-attempted"]
-        data["count-repairs-successful"] = c["count-repairs-successful"]
-        data["count-repairs-unsuccessful"] = c["count-repairs-unsuccessful"]
-
-        data["count-corrupt-shares-pre-repair"] = c["count-corrupt-shares-pre-repair"]
-        data["count-corrupt-shares-post-repair"] = c["count-corrupt-shares-pre-repair"]
-
-        data["list-corrupt-shares"] = [ (idlib.nodeid_b2a(serverid),
-                                         base32.b2a(storage_index),
-                                         shnum)
-                                        for (serverid, storage_index, shnum)
-                                        in res.get_corrupt_shares() ]
-
-        remaining_corrupt = [ (idlib.nodeid_b2a(serverid),
-                               base32.b2a(storage_index),
-                               shnum)
-                              for (serverid, storage_index, shnum)
-                              in res.get_remaining_corrupt_shares() ]
-        data["list-remaining-corrupt-shares"] = remaining_corrupt
-
-        unhealthy = [ (path_t,
-                       self._json_check_results(crr.get_pre_repair_results()))
-                      for (path_t, crr)
-                      in res.get_all_results().items()
-                      if not crr.get_pre_repair_results().is_healthy() ]
-        data["list-unhealthy-files"] = unhealthy
-        data["stats"] = res.get_stats()
-        return simplejson.dumps(data, indent=1) + "\n"
-
-    def render_root_storage_index(self, ctx, data):
-        return self.monitor.get_status().get_root_storage_index_string()
-
-    def data_objects_checked(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-objects-checked"]
-
-    def data_objects_healthy(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-objects-healthy-pre-repair"]
-    def data_objects_unhealthy(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-objects-unhealthy-pre-repair"]
-    def data_corrupt_shares(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-corrupt-shares-pre-repair"]
-
-    def data_repairs_attempted(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-repairs-attempted"]
-    def data_repairs_successful(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-repairs-successful"]
-    def data_repairs_unsuccessful(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-repairs-unsuccessful"]
-
-    def data_objects_healthy_post(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-objects-healthy-post-repair"]
-    def data_objects_unhealthy_post(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-objects-unhealthy-post-repair"]
-    def data_corrupt_shares_post(self, ctx, data):
-        return self.monitor.get_status().get_counters()["count-corrupt-shares-post-repair"]
-
-    def render_pre_repair_problems_p(self, ctx, data):
-        c = self.monitor.get_status().get_counters()
-        if c["count-objects-unhealthy-pre-repair"]:
-            return ctx.tag
-        return ""
-
-    def data_pre_repair_problems(self, ctx, data):
-        all_objects = self.monitor.get_status().get_all_results()
-        for path in sorted(all_objects.keys()):
-            r = all_objects[path]
-            assert ICheckAndRepairResults.providedBy(r)
-            cr = r.get_pre_repair_results()
-            if not cr.is_healthy():
-                yield path, cr
-
-    def render_problem(self, ctx, data):
-        path, cr = data
-        return ["/".join(self._html(path)), ": ", self._html(cr.get_summary())]
-
-    def render_post_repair_problems_p(self, ctx, data):
-        c = self.monitor.get_status().get_counters()
-        if (c["count-objects-unhealthy-post-repair"]
-            or c["count-corrupt-shares-post-repair"]):
-            return ctx.tag
-        return ""
-
-    def data_post_repair_problems(self, ctx, data):
-        all_objects = self.monitor.get_status().get_all_results()
-        for path in sorted(all_objects.keys()):
-            r = all_objects[path]
-            assert ICheckAndRepairResults.providedBy(r)
-            cr = r.get_post_repair_results()
-            if not cr.is_healthy():
-                yield path, cr
-
-    def render_servers_with_corrupt_shares_p(self, ctx, data):
-        if self.monitor.get_status().get_counters()["count-corrupt-shares-pre-repair"]:
-            return ctx.tag
-        return ""
-    def data_servers_with_corrupt_shares(self, ctx, data):
-        return [] # TODO
-    def render_server_problem(self, ctx, data):
-        pass
-
-
-    def render_remaining_corrupt_shares_p(self, ctx, data):
-        if self.monitor.get_status().get_counters()["count-corrupt-shares-post-repair"]:
-            return ctx.tag
-        return ""
-    def data_post_repair_corrupt_shares(self, ctx, data):
-        return [] # TODO
-
-    def render_share_problem(self, ctx, data):
-        pass
-
-
-    def render_return(self, ctx, data):
-        req = inevow.IRequest(ctx)
-        return_to = get_arg(req, "return_to", None)
-        if return_to:
-            return T.div[T.a(href=return_to)["Return to parent directory"]]
-        return ""
-
-    def data_all_objects(self, ctx, data):
-        r = self.monitor.get_status().get_all_results()
-        for path in sorted(r.keys()):
-            yield (path, r[path])
-
-    def render_object(self, ctx, data):
-        path, r = data
-        ctx.fillSlots("path", "/".join(self._html(path)))
-        ctx.fillSlots("healthy_pre_repair",
-                      str(r.get_pre_repair_results().is_healthy()))
-        ctx.fillSlots("healthy_post_repair",
-                      str(r.get_post_repair_results().is_healthy()))
-        ctx.fillSlots("summary",
-                      self._html(r.get_pre_repair_results().get_summary()))
-        return ctx.tag
-
-    def render_runtime(self, ctx, data):
-        req = inevow.IRequest(ctx)
-        runtime = time.time() - req.processing_started_timestamp
-        return ctx.tag["runtime: %s seconds" % runtime]
index 233067296c09528de2ac41dc9a5b7e5ac6a1fccd..0ac24bc2468e288b49e92a80e6918e63c08c481b 100644 (file)
@@ -23,7 +23,7 @@ from allmydata.web.common import text_plain, WebError, \
      getxmlfile, RenderMixin
 from allmydata.web.filenode import ReplaceMeMixin, \
      FileNodeHandler, PlaceHolderNodeHandler
-from allmydata.web.checker_results import CheckerResults, \
+from allmydata.web.check_results import CheckerResults, \
      CheckAndRepairResults, DeepCheckResults, DeepCheckAndRepairResults
 from allmydata.web.info import MoreInfo
 from allmydata.web.operations import ReloadMixin
index e8d522290c851307dfc65b0122dfbfbd0845c626..0061805f672214958914c3b98847c651752410f8 100644 (file)
@@ -14,7 +14,7 @@ from allmydata.util import log, base32
 
 from allmydata.web.common import text_plain, WebError, IClient, RenderMixin, \
      boolean_of_arg, get_arg, should_create_intermediate_directories
-from allmydata.web.checker_results import CheckerResults, \
+from allmydata.web.check_results import CheckerResults, \
      CheckAndRepairResults, LiteralCheckerResults
 from allmydata.web.info import MoreInfo
 
diff --git a/src/allmydata/web/literal-check-results.xhtml b/src/allmydata/web/literal-check-results.xhtml
new file mode 100644 (file)
index 0000000..4e4aad6
--- /dev/null
@@ -0,0 +1,18 @@
+<html xmlns:n="http://nevow.com/ns/nevow/0.1">
+  <head>
+    <title>AllMyData - Tahoe - Check Results</title>
+    <!-- <link href="http://www.allmydata.com/common/css/styles.css"
+          rel="stylesheet" type="text/css"/> -->
+    <link href="/webform_css" rel="stylesheet" type="text/css"/>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  </head>
+  <body>
+
+<h1>File Check Results for LIT file</h1>
+
+<div>Literal files are always healthy: their data is contained in the URI</div>
+
+<div n:render="return" />
+
+  </body>
+</html>
diff --git a/src/allmydata/web/literal-checker-results.xhtml b/src/allmydata/web/literal-checker-results.xhtml
deleted file mode 100644 (file)
index 4e4aad6..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<html xmlns:n="http://nevow.com/ns/nevow/0.1">
-  <head>
-    <title>AllMyData - Tahoe - Check Results</title>
-    <!-- <link href="http://www.allmydata.com/common/css/styles.css"
-          rel="stylesheet" type="text/css"/> -->
-    <link href="/webform_css" rel="stylesheet" type="text/css"/>
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-  </head>
-  <body>
-
-<h1>File Check Results for LIT file</h1>
-
-<div>Literal files are always healthy: their data is contained in the URI</div>
-
-<div n:render="return" />
-
-  </body>
-</html>