From b1db6d9ff2e78765b1a4660ca458537d7630e0c2 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Wed, 29 Oct 2008 18:09:17 -0700
Subject: [PATCH] web: add 'Repair' button to checker results when they
 indicate unhealthyness. Also add the object's uri to the CheckerResults
 instance.

---
 src/allmydata/checker_results.py        |  6 +++++-
 src/allmydata/immutable/checker.py      | 10 ++++++----
 src/allmydata/immutable/filenode.py     |  7 +++++--
 src/allmydata/interfaces.py             |  2 ++
 src/allmydata/mutable/checker.py        |  4 ++--
 src/allmydata/test/common.py            |  4 ++--
 src/allmydata/test/test_dirnode.py      |  2 +-
 src/allmydata/web/checker-results.xhtml |  2 ++
 src/allmydata/web/checker_results.py    | 12 ++++++++++++
 9 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/src/allmydata/checker_results.py b/src/allmydata/checker_results.py
index 46da9a24..803b6f82 100644
--- a/src/allmydata/checker_results.py
+++ b/src/allmydata/checker_results.py
@@ -7,7 +7,9 @@ from allmydata.util import base32
 class CheckerResults:
     implements(ICheckerResults)
 
-    def __init__(self, storage_index):
+    def __init__(self, uri, storage_index):
+        assert isinstance(uri, str)
+        self.uri = uri
         self.storage_index = storage_index
         self.problems = []
         self.data = {"count-corrupt-shares": 0,
@@ -38,6 +40,8 @@ class CheckerResults:
         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
diff --git a/src/allmydata/immutable/checker.py b/src/allmydata/immutable/checker.py
index 4c3eacaf..c5808007 100644
--- a/src/allmydata/immutable/checker.py
+++ b/src/allmydata/immutable/checker.py
@@ -17,11 +17,12 @@ class SimpleCHKFileChecker:
     """Return a list of (needed, total, found, sharemap), where sharemap maps
     share number to a list of (binary) nodeids of the shareholders."""
 
-    def __init__(self, client, storage_index, needed_shares, total_shares):
+    def __init__(self, client, uri, storage_index, needed_shares, total_shares):
         self.peer_getter = client.get_permuted_peers
         self.needed_shares = needed_shares
         self.total_shares = total_shares
         self.found_shares = set()
+        self.uri = uri
         self.storage_index = storage_index
         self.sharemap = {}
         self.responded = set()
@@ -67,7 +68,7 @@ class SimpleCHKFileChecker:
         pass
 
     def _done(self, res):
-        r = CheckerResults(self.storage_index)
+        r = CheckerResults(self.uri, self.storage_index)
         report = []
         healthy = bool(len(self.found_shares) >= self.total_shares)
         r.set_healthy(healthy)
@@ -151,9 +152,10 @@ class SimpleCHKFileVerifier(download.FileDownloader):
     # remaining shareholders, and it cannot verify the plaintext.
     check_plaintext_hash = False
 
-    def __init__(self, client, storage_index, k, N, size, ueb_hash):
+    def __init__(self, client, uri, storage_index, k, N, size, ueb_hash):
         self._client = client
 
+        self._uri = uri
         self._storage_index = storage_index
         self._uri_extension_hash = ueb_hash
         self._total_shares = N
@@ -163,7 +165,7 @@ class SimpleCHKFileVerifier(download.FileDownloader):
         self._si_s = storage.si_b2a(self._storage_index)
         self.init_logging()
 
-        self._check_results = r = CheckerResults(self._storage_index)
+        self._check_results = r = CheckerResults(self._uri, self._storage_index)
         r.set_data({"count-shares-needed": k,
                     "count-shares-expected": N,
                     })
diff --git a/src/allmydata/immutable/filenode.py b/src/allmydata/immutable/filenode.py
index 40c98a83..083eb845 100644
--- a/src/allmydata/immutable/filenode.py
+++ b/src/allmydata/immutable/filenode.py
@@ -196,9 +196,12 @@ class FileNode(_ImmutableFileNodeBase):
         ueb_hash = self.u.uri_extension_hash
         if verify:
             v = self.verifier_class(self._client,
-                                    storage_index, k, N, size, ueb_hash)
+                                    self.get_uri(), storage_index,
+                                    k, N, size, ueb_hash)
         else:
-            v = self.checker_class(self._client, storage_index, k, N)
+            v = self.checker_class(self._client,
+                                   self.get_uri(), storage_index,
+                                   k, N)
         return v.start()
 
     def check_and_repair(self, monitor, verify=False):
diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py
index c624bdfa..ce1adae0 100644
--- a/src/allmydata/interfaces.py
+++ b/src/allmydata/interfaces.py
@@ -1607,6 +1607,8 @@ class ICheckerResults(Interface):
         """Return a string with the (binary) storage index."""
     def get_storage_index_string():
         """Return a string with the (printable) abbreviated storage index."""
+    def get_uri():
+        """Return the (string) URI of the object that was checked."""
 
     def is_healthy():
         """Return a boolean, True if the file/dir is fully healthy, False if
diff --git a/src/allmydata/mutable/checker.py b/src/allmydata/mutable/checker.py
index e09050eb..8aaaedf9 100644
--- a/src/allmydata/mutable/checker.py
+++ b/src/allmydata/mutable/checker.py
@@ -16,7 +16,7 @@ class MutableChecker:
         self._monitor = monitor
         self.bad_shares = [] # list of (nodeid,shnum,failure)
         self._storage_index = self._node.get_storage_index()
-        self.results = CheckerResults(self._storage_index)
+        self.results = CheckerResults(node.get_uri(), self._storage_index)
         self.need_repair = False
         self.responded = set() # set of (binary) nodeids
 
@@ -296,7 +296,7 @@ class MutableCheckAndRepairer(MutableChecker):
         d = self._node.repair(self.results)
         def _repair_finished(repair_results):
             self.cr_results.repair_successful = True
-            r = CheckerResults(self._storage_index)
+            r = CheckerResults(self._node.get_uri(), self._storage_index)
             self.cr_results.post_repair_results = r
             self._fill_checker_results(repair_results.servermap, r)
             self.cr_results.repair_results = repair_results # TODO?
diff --git a/src/allmydata/test/common.py b/src/allmydata/test/common.py
index af86e77a..a7dbacaf 100644
--- a/src/allmydata/test/common.py
+++ b/src/allmydata/test/common.py
@@ -51,7 +51,7 @@ class FakeCHKFileNode:
         return self.storage_index
 
     def check(self, monitor, verify=False):
-        r = CheckerResults(self.storage_index)
+        r = CheckerResults(self.my_uri, self.storage_index)
         is_bad = self.bad_shares.get(self.storage_index, None)
         data = {}
         data["count-shares-needed"] = 3
@@ -183,7 +183,7 @@ class FakeMutableFileNode:
         return self.storage_index
 
     def check(self, monitor, verify=False):
-        r = CheckerResults(self.storage_index)
+        r = CheckerResults(self.my_uri.to_string(), self.storage_index)
         is_bad = self.bad_shares.get(self.storage_index, None)
         data = {}
         data["count-shares-needed"] = 3
diff --git a/src/allmydata/test/test_dirnode.py b/src/allmydata/test/test_dirnode.py
index e656bad2..42b9b26f 100644
--- a/src/allmydata/test/test_dirnode.py
+++ b/src/allmydata/test/test_dirnode.py
@@ -37,7 +37,7 @@ class Marker:
         return self.verifieruri
 
     def check(self, monitor, verify=False):
-        r = CheckerResults(None)
+        r = CheckerResults("", None)
         r.set_healthy(True)
         return defer.succeed(r)
 
diff --git a/src/allmydata/web/checker-results.xhtml b/src/allmydata/web/checker-results.xhtml
index a27df0e7..6fef7986 100644
--- a/src/allmydata/web/checker-results.xhtml
+++ b/src/allmydata/web/checker-results.xhtml
@@ -15,6 +15,8 @@
   <span n:render="rebalance" />
 </div>
 
+<div n:render="repair" />
+
 <div n:render="results" />
 
 <div n:render="return" />
diff --git a/src/allmydata/web/checker_results.py b/src/allmydata/web/checker_results.py
index d11468d7..a3eabff7 100644
--- a/src/allmydata/web/checker_results.py
+++ b/src/allmydata/web/checker_results.py
@@ -183,6 +183,18 @@ class CheckerResults(CheckerBase, rend.Page, ResultsBase):
             return ctx.tag["Healthy!"]
         return ctx.tag["Not Healthy!: ", self._html(self.r.get_summary())]
 
+    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)"]
-- 
2.45.2