source file: /home/buildslave/tahoe/edgy/build/src/allmydata/web/check_results.py
file stats: 488 lines, 417 executed: 85.5% covered
coverage versus previous test: 0 lines added, 0 lines removed
1.
2. import time
3. import simplejson
4. from nevow import rend, inevow, tags as T
5. from twisted.web import http, html
6. from allmydata.web.common import getxmlfile, get_arg, get_root, WebError
7. from allmydata.web.operations import ReloadMixin
8. from allmydata.interfaces import ICheckAndRepairResults, ICheckResults
9. from allmydata.util import base32, idlib
10.
11. def json_check_counts(d):
12. r = {}
13. r["count-shares-good"] = d["count-shares-good"]
14. r["count-shares-needed"] = d["count-shares-needed"]
15. r["count-shares-expected"] = d["count-shares-expected"]
16. r["count-good-share-hosts"] = d["count-good-share-hosts"]
17. r["count-corrupt-shares"] = d["count-corrupt-shares"]
18. r["list-corrupt-shares"] = [ (idlib.nodeid_b2a(serverid),
19. base32.b2a(si), shnum)
20. for (serverid, si, shnum)
21. in d["list-corrupt-shares"] ]
22. r["servers-responding"] = [idlib.nodeid_b2a(serverid)
23. for serverid in d["servers-responding"]]
24. sharemap = {}
25. for (shareid, serverids) in d["sharemap"].items():
26. sharemap[shareid] = [idlib.nodeid_b2a(serverid)
27. for serverid in serverids]
28. r["sharemap"] = sharemap
29.
30. r["count-wrong-shares"] = d["count-wrong-shares"]
31. r["count-recoverable-versions"] = d["count-recoverable-versions"]
32. r["count-unrecoverable-versions"] = d["count-unrecoverable-versions"]
33.
34. return r
35.
36. def json_check_results(r):
37. if r is None:
38. # LIT file
39. data = {"storage-index": "",
40. "results": {"healthy": True},
41. }
42. return data
43. data = {}
44. data["storage-index"] = r.get_storage_index_string()
45. data["summary"] = r.get_summary()
46. data["results"] = json_check_counts(r.get_data())
47. data["results"]["needs-rebalancing"] = r.needs_rebalancing()
48. data["results"]["healthy"] = r.is_healthy()
49. data["results"]["recoverable"] = r.is_recoverable()
50. return data
51.
52. def json_check_and_repair_results(r):
53. if r is None:
54. # LIT file
55. data = {"storage-index": "",
56. "repair-attempted": False,
57. }
58. return data
59. data = {}
60. data["storage-index"] = r.get_storage_index_string()
61. data["repair-attempted"] = r.get_repair_attempted()
62. data["repair-successful"] = r.get_repair_successful()
63. pre = r.get_pre_repair_results()
64. data["pre-repair-results"] = json_check_results(pre)
65. post = r.get_post_repair_results()
66. data["post-repair-results"] = json_check_results(post)
67. return data
68.
69. class ResultsBase:
70. # self.client must point to the Client, so we can get nicknames and
71. # determine the permuted peer order
72.
73. def _join_pathstring(self, path):
74. if path:
75. pathstring = "/".join(self._html(path))
76. else:
77. pathstring = "<root>"
78. return pathstring
79.
80. def _render_results(self, ctx, cr):
81. assert ICheckResults(cr)
82. c = self.client
83. sb = c.get_storage_broker()
84. data = cr.get_data()
85. r = []
86. def add(name, value):
87. r.append(T.li[name + ": ", value])
88.
89. add("Report", T.pre["\n".join(self._html(cr.get_report()))])
90. add("Share Counts",
91. "need %d-of-%d, have %d" % (data["count-shares-needed"],
92. data["count-shares-expected"],
93. data["count-shares-good"]))
94. add("Hosts with good shares", data["count-good-share-hosts"])
95.
96. if data["list-corrupt-shares"]:
97. badsharemap = []
98. for (serverid, si, shnum) in data["list-corrupt-shares"]:
99. nickname = sb.get_nickname_for_serverid(serverid)
100. badsharemap.append(T.tr[T.td["sh#%d" % shnum],
101. T.td[T.div(class_="nickname")[nickname],
102. T.div(class_="nodeid")[T.tt[base32.b2a(serverid)]]],
103. ])
104. add("Corrupt shares", T.table()[
105. T.tr[T.th["Share ID"],
106. T.th(class_="nickname-and-peerid")[T.div["Nickname"], T.div(class_="nodeid")["Node ID"]]],
107. badsharemap])
108. else:
109. add("Corrupt shares", "none")
110.
111. add("Wrong Shares", data["count-wrong-shares"])
112.
113. sharemap = []
114. servers = {}
115.
116. # FIXME: The two tables below contain nickname-and-nodeid table column markup which is duplicated with each other, introducer.xhtml, and deep-check-results.xhtml. All of these (and any other presentations of nickname-and-nodeid) should be combined.
117.
118. for shareid in sorted(data["sharemap"].keys()):
119. serverids = data["sharemap"][shareid]
120. for i,serverid in enumerate(serverids):
121. if serverid not in servers:
122. servers[serverid] = []
123. servers[serverid].append(shareid)
124. shareid_s = ""
125. if i == 0:
126. shareid_s = shareid
127. nickname = sb.get_nickname_for_serverid(serverid)
128. sharemap.append(T.tr[T.td[shareid_s],
129. T.td[T.div(class_="nickname")[nickname],
130. T.div(class_="nodeid")[T.tt[base32.b2a(serverid)]]]
131. ])
132. add("Good Shares (sorted in share order)",
133. T.table()[T.tr[T.th["Share ID"], T.th(class_="nickname-and-peerid")[T.div["Nickname"], T.div(class_="nodeid")["Node ID"]]],
134. sharemap])
135.
136.
137. add("Recoverable Versions", data["count-recoverable-versions"])
138. add("Unrecoverable Versions", data["count-unrecoverable-versions"])
139.
140. # this table is sorted by permuted order
141. sb = c.get_storage_broker()
142. permuted_peer_ids = [peerid
143. for (peerid, rref)
144. in sb.get_servers_for_index(cr.get_storage_index())]
145.
146. num_shares_left = sum([len(shares) for shares in servers.values()])
147. servermap = []
148. for serverid in permuted_peer_ids:
149. nickname = sb.get_nickname_for_serverid(serverid)
150. shareids = servers.get(serverid, [])
151. shareids.reverse()
152. shareids_s = [ T.tt[shareid, " "] for shareid in sorted(shareids) ]
153. servermap.append(T.tr[T.td[T.div(class_="nickname")[nickname],
154. T.div(class_="nodeid")[T.tt[base32.b2a(serverid)]]],
155. T.td[shareids_s],
156. ])
157. num_shares_left -= len(shareids)
158. if not num_shares_left:
159. break
160. add("Share Balancing (servers in permuted order)",
161. T.table()[T.tr[T.th(class_="nickname-and-peerid")[T.div["Nickname"], T.div(class_="nodeid")["Node ID"]], T.th["Share IDs"]],
162. servermap])
163.
164. return T.ul[r]
165.
166. def _html(self, s):
167. if isinstance(s, (str, unicode)):
168. return html.escape(s)
169. assert isinstance(s, (list, tuple))
170. return [html.escape(w) for w in s]
171.
172. def want_json(self, ctx):
173. output = get_arg(inevow.IRequest(ctx), "output", "").lower()
174. if output.lower() == "json":
175. return True
176. return False
177.
178. def _render_si_link(self, ctx, storage_index):
179. si_s = base32.b2a(storage_index)
180. root = get_root(ctx)
181. req = inevow.IRequest(ctx)
182. ophandle = req.prepath[-1]
183. target = "%s/operations/%s/%s" % (get_root(ctx), ophandle, si_s)
184. output = get_arg(ctx, "output")
185. if output:
186. target = target + "?output=%s" % output
187. return T.a(href=target)[si_s]
188.
189. class LiteralCheckResults(rend.Page, ResultsBase):
190. docFactory = getxmlfile("literal-check-results.xhtml")
191.
192. def __init__(self, client):
193. self.client = client
194. rend.Page.__init__(self, client)
195.
196. def renderHTTP(self, ctx):
197. if self.want_json(ctx):
198. return self.json(ctx)
199. return rend.Page.renderHTTP(self, ctx)
200.
201. def json(self, ctx):
202. inevow.IRequest(ctx).setHeader("content-type", "text/plain")
203. data = json_check_results(None)
204. return simplejson.dumps(data, indent=1) + "\n"
205.
206. def render_return(self, ctx, data):
207. req = inevow.IRequest(ctx)
208. return_to = get_arg(req, "return_to", None)
209. if return_to:
210. return T.div[T.a(href=return_to)["Return to file."]]
211. return ""
212.
213. class CheckerBase:
214.
215. def renderHTTP(self, ctx):
216. if self.want_json(ctx):
217. return self.json(ctx)
218. return rend.Page.renderHTTP(self, ctx)
219.
220. def render_storage_index(self, ctx, data):
221. return self.r.get_storage_index_string()
222.
223. def render_return(self, ctx, data):
224. req = inevow.IRequest(ctx)
225. return_to = get_arg(req, "return_to", None)
226. if return_to:
227. return T.div[T.a(href=return_to)["Return to file/directory."]]
228. return ""
229.
230. class CheckResults(CheckerBase, rend.Page, ResultsBase):
231. docFactory = getxmlfile("check-results.xhtml")
232.
233. def __init__(self, client, results):
234. self.client = client
235. self.r = ICheckResults(results)
236. rend.Page.__init__(self, results)
237.
238. def json(self, ctx):
239. inevow.IRequest(ctx).setHeader("content-type", "text/plain")
240. data = json_check_results(self.r)
241. return simplejson.dumps(data, indent=1) + "\n"
242.
243. def render_summary(self, ctx, data):
244. results = []
245. if data.is_healthy():
246. results.append("Healthy")
247. elif data.is_recoverable():
248. results.append("Not Healthy!")
249. else:
250. results.append("Not Recoverable!")
251. results.append(" : ")
252. results.append(self._html(data.get_summary()))
253. return ctx.tag[results]
254.
255. def render_repair(self, ctx, data):
256. if data.is_healthy():
257. return ""
258. repair = T.form(action=".", method="post",
259. enctype="multipart/form-data")[
260. T.fieldset[
261. T.input(type="hidden", name="t", value="check"),
262. T.input(type="hidden", name="repair", value="true"),
263. T.input(type="submit", value="Repair"),
264. ]]
265. return "" # repair button disabled until we make it work correctly,
266. # see #622 for details
267. return ctx.tag[repair]
268.
269. def render_results(self, ctx, data):
270. cr = self._render_results(ctx, data)
271. return ctx.tag[cr]
272.
273. class CheckAndRepairResults(CheckerBase, rend.Page, ResultsBase):
274. docFactory = getxmlfile("check-and-repair-results.xhtml")
275.
276. def __init__(self, client, results):
277. self.client = client
278. self.r = None
279. if results:
280. self.r = ICheckAndRepairResults(results)
281. rend.Page.__init__(self, results)
282.
283. def json(self, ctx):
284. inevow.IRequest(ctx).setHeader("content-type", "text/plain")
285. data = json_check_and_repair_results(self.r)
286. return simplejson.dumps(data, indent=1) + "\n"
287.
288. def render_summary(self, ctx, data):
289. cr = data.get_post_repair_results()
290. results = []
291. if cr.is_healthy():
292. results.append("Healthy")
293. elif cr.is_recoverable():
294. results.append("Not Healthy!")
295. else:
296. results.append("Not Recoverable!")
297. results.append(" : ")
298. results.append(self._html(cr.get_summary()))
299. return ctx.tag[results]
300.
301. def render_repair_results(self, ctx, data):
302. if data.get_repair_attempted():
303. if data.get_repair_successful():
304. return ctx.tag["Repair successful"]
305. else:
306. return ctx.tag["Repair unsuccessful"]
307. return ctx.tag["No repair necessary"]
308.
309. def render_post_repair_results(self, ctx, data):
310. cr = self._render_results(ctx, data.get_post_repair_results())
311. return ctx.tag[T.div["Post-Repair Checker Results:"], cr]
312.
313. def render_maybe_pre_repair_results(self, ctx, data):
314. if data.get_repair_attempted():
315. cr = self._render_results(ctx, data.get_pre_repair_results())
316. return ctx.tag[T.div["Pre-Repair Checker Results:"], cr]
317. return ""
318.
319.
320. class DeepCheckResults(rend.Page, ResultsBase, ReloadMixin):
321. docFactory = getxmlfile("deep-check-results.xhtml")
322.
323. def __init__(self, client, monitor):
324. self.client = client
325. self.monitor = monitor
326.
327. def childFactory(self, ctx, name):
328. if not name:
329. return self
330. # /operation/$OPHANDLE/$STORAGEINDEX provides detailed information
331. # about a specific file or directory that was checked
332. si = base32.a2b(name)
333. r = self.monitor.get_status()
334. try:
335. return CheckResults(self.client,
336. r.get_results_for_storage_index(si))
337. except KeyError:
338. raise WebError("No detailed results for SI %s" % html.escape(name),
339. http.NOT_FOUND)
340.
341. def renderHTTP(self, ctx):
342. if self.want_json(ctx):
343. return self.json(ctx)
344. return rend.Page.renderHTTP(self, ctx)
345.
346. def json(self, ctx):
347. inevow.IRequest(ctx).setHeader("content-type", "text/plain")
348. data = {}
349. data["finished"] = self.monitor.is_finished()
350. res = self.monitor.get_status()
351. data["root-storage-index"] = res.get_root_storage_index_string()
352. c = res.get_counters()
353. data["count-objects-checked"] = c["count-objects-checked"]
354. data["count-objects-healthy"] = c["count-objects-healthy"]
355. data["count-objects-unhealthy"] = c["count-objects-unhealthy"]
356. data["count-corrupt-shares"] = c["count-corrupt-shares"]
357. data["list-corrupt-shares"] = [ (idlib.nodeid_b2a(serverid),
358. base32.b2a(storage_index),
359. shnum)
360. for (serverid, storage_index, shnum)
361. in res.get_corrupt_shares() ]
362. data["list-unhealthy-files"] = [ (path_t, json_check_results(r))
363. for (path_t, r)
364. in res.get_all_results().items()
365. if not r.is_healthy() ]
366. data["stats"] = res.get_stats()
367. return simplejson.dumps(data, indent=1) + "\n"
368.
369. def render_root_storage_index(self, ctx, data):
370. return self.monitor.get_status().get_root_storage_index_string()
371.
372. def data_objects_checked(self, ctx, data):
373. return self.monitor.get_status().get_counters()["count-objects-checked"]
374. def data_objects_healthy(self, ctx, data):
375. return self.monitor.get_status().get_counters()["count-objects-healthy"]
376. def data_objects_unhealthy(self, ctx, data):
377. return self.monitor.get_status().get_counters()["count-objects-unhealthy"]
378. def data_objects_unrecoverable(self, ctx, data):
379. return self.monitor.get_status().get_counters()["count-objects-unrecoverable"]
380.
381. def data_count_corrupt_shares(self, ctx, data):
382. return self.monitor.get_status().get_counters()["count-corrupt-shares"]
383.
384. def render_problems_p(self, ctx, data):
385. c = self.monitor.get_status().get_counters()
386. if c["count-objects-unhealthy"]:
387. return ctx.tag
388. return ""
389.
390. def data_problems(self, ctx, data):
391. all_objects = self.monitor.get_status().get_all_results()
392. for path in sorted(all_objects.keys()):
393. cr = all_objects[path]
394. assert ICheckResults.providedBy(cr)
395. if not cr.is_healthy():
396. yield path, cr
397.
398. def render_problem(self, ctx, data):
399. path, cr = data
400. summary_text = ""
401. summary = cr.get_summary()
402. if summary:
403. summary_text = ": " + summary
404. summary_text += " [SI: %s]" % cr.get_storage_index_string()
405. return ctx.tag[self._join_pathstring(path), self._html(summary_text)]
406.
407.
408. def render_servers_with_corrupt_shares_p(self, ctx, data):
409. if self.monitor.get_status().get_counters()["count-corrupt-shares"]:
410. return ctx.tag
411. return ""
412.
413. def data_servers_with_corrupt_shares(self, ctx, data):
414. servers = [serverid
415. for (serverid, storage_index, sharenum)
416. in self.monitor.get_status().get_corrupt_shares()]
417. servers.sort()
418. return servers
419.
420. def render_server_problem(self, ctx, data):
421. serverid = data
422. data = [idlib.shortnodeid_b2a(serverid)]
423. sb = self.client.get_storage_broker()
424. nickname = sb.get_nickname_for_serverid(serverid)
425. if nickname:
426. data.append(" (%s)" % self._html(nickname))
427. return ctx.tag[data]
428.
429.
430. def render_corrupt_shares_p(self, ctx, data):
431. if self.monitor.get_status().get_counters()["count-corrupt-shares"]:
432. return ctx.tag
433. return ""
434. def data_corrupt_shares(self, ctx, data):
435. return self.monitor.get_status().get_corrupt_shares()
436. def render_share_problem(self, ctx, data):
437. serverid, storage_index, sharenum = data
438. sb = self.client.get_storage_broker()
439. nickname = sb.get_nickname_for_serverid(serverid)
440. ctx.fillSlots("serverid", idlib.shortnodeid_b2a(serverid))
441. if nickname:
442. ctx.fillSlots("nickname", self._html(nickname))
443. ctx.fillSlots("si", self._render_si_link(ctx, storage_index))
444. ctx.fillSlots("shnum", str(sharenum))
445. return ctx.tag
446.
447. def render_return(self, ctx, data):
448. req = inevow.IRequest(ctx)
449. return_to = get_arg(req, "return_to", None)
450. if return_to:
451. return T.div[T.a(href=return_to)["Return to file/directory."]]
452. return ""
453.
454. def data_all_objects(self, ctx, data):
455. r = self.monitor.get_status().get_all_results()
456. for path in sorted(r.keys()):
457. yield (path, r[path])
458.
459. def render_object(self, ctx, data):
460. path, r = data
461. ctx.fillSlots("path", self._join_pathstring(path))
462. ctx.fillSlots("healthy", str(r.is_healthy()))
463. ctx.fillSlots("recoverable", str(r.is_recoverable()))
464. storage_index = r.get_storage_index()
465. ctx.fillSlots("storage_index", self._render_si_link(ctx, storage_index))
466. ctx.fillSlots("summary", self._html(r.get_summary()))
467. return ctx.tag
468.
469. def render_runtime(self, ctx, data):
470. req = inevow.IRequest(ctx)
471. runtime = time.time() - req.processing_started_timestamp
472. return ctx.tag["runtime: %s seconds" % runtime]
473.
474. class DeepCheckAndRepairResults(rend.Page, ResultsBase, ReloadMixin):
475. docFactory = getxmlfile("deep-check-and-repair-results.xhtml")
476.
477. def __init__(self, client, monitor):
478. self.client = client
479. self.monitor = monitor
480.
481. def childFactory(self, ctx, name):
482. if not name:
483. return self
484. # /operation/$OPHANDLE/$STORAGEINDEX provides detailed information
485. # about a specific file or directory that was checked
486. si = base32.a2b(name)
487. r = self.monitor.get_status()
488. try:
489. return CheckAndRepairResults(self.client,
490. r.get_results_for_storage_index(si))
491. except KeyError:
492. raise WebError("No detailed results for SI %s" % html.escape(name),
493. http.NOT_FOUND)
494.
495. def renderHTTP(self, ctx):
496. if self.want_json(ctx):
497. return self.json(ctx)
498. return rend.Page.renderHTTP(self, ctx)
499.
500. def json(self, ctx):
501. inevow.IRequest(ctx).setHeader("content-type", "text/plain")
502. res = self.monitor.get_status()
503. data = {}
504. data["finished"] = self.monitor.is_finished()
505. data["root-storage-index"] = res.get_root_storage_index_string()
506. c = res.get_counters()
507. data["count-objects-checked"] = c["count-objects-checked"]
508.
509. data["count-objects-healthy-pre-repair"] = c["count-objects-healthy-pre-repair"]
510. data["count-objects-unhealthy-pre-repair"] = c["count-objects-unhealthy-pre-repair"]
511. data["count-objects-healthy-post-repair"] = c["count-objects-healthy-post-repair"]
512. data["count-objects-unhealthy-post-repair"] = c["count-objects-unhealthy-post-repair"]
513.
514. data["count-repairs-attempted"] = c["count-repairs-attempted"]
515. data["count-repairs-successful"] = c["count-repairs-successful"]
516. data["count-repairs-unsuccessful"] = c["count-repairs-unsuccessful"]
517.
518. data["count-corrupt-shares-pre-repair"] = c["count-corrupt-shares-pre-repair"]
519. data["count-corrupt-shares-post-repair"] = c["count-corrupt-shares-pre-repair"]
520.
521. data["list-corrupt-shares"] = [ (idlib.nodeid_b2a(serverid),
522. base32.b2a(storage_index),
523. shnum)
524. for (serverid, storage_index, shnum)
525. in res.get_corrupt_shares() ]
526.
527. remaining_corrupt = [ (idlib.nodeid_b2a(serverid),
528. base32.b2a(storage_index),
529. shnum)
530. for (serverid, storage_index, shnum)
531. in res.get_remaining_corrupt_shares() ]
532. data["list-remaining-corrupt-shares"] = remaining_corrupt
533.
534. unhealthy = [ (path_t,
535. json_check_results(crr.get_pre_repair_results()))
536. for (path_t, crr)
537. in res.get_all_results().items()
538. if not crr.get_pre_repair_results().is_healthy() ]
539. data["list-unhealthy-files"] = unhealthy
540. data["stats"] = res.get_stats()
541. return simplejson.dumps(data, indent=1) + "\n"
542.
543. def render_root_storage_index(self, ctx, data):
544. return self.monitor.get_status().get_root_storage_index_string()
545.
546. def data_objects_checked(self, ctx, data):
547. return self.monitor.get_status().get_counters()["count-objects-checked"]
548.
549. def data_objects_healthy(self, ctx, data):
550. return self.monitor.get_status().get_counters()["count-objects-healthy-pre-repair"]
551. def data_objects_unhealthy(self, ctx, data):
552. return self.monitor.get_status().get_counters()["count-objects-unhealthy-pre-repair"]
553. def data_corrupt_shares(self, ctx, data):
554. return self.monitor.get_status().get_counters()["count-corrupt-shares-pre-repair"]
555.
556. def data_repairs_attempted(self, ctx, data):
557. return self.monitor.get_status().get_counters()["count-repairs-attempted"]
558. def data_repairs_successful(self, ctx, data):
559. return self.monitor.get_status().get_counters()["count-repairs-successful"]
560. def data_repairs_unsuccessful(self, ctx, data):
561. return self.monitor.get_status().get_counters()["count-repairs-unsuccessful"]
562.
563. def data_objects_healthy_post(self, ctx, data):
564. return self.monitor.get_status().get_counters()["count-objects-healthy-post-repair"]
565. def data_objects_unhealthy_post(self, ctx, data):
566. return self.monitor.get_status().get_counters()["count-objects-unhealthy-post-repair"]
567. def data_corrupt_shares_post(self, ctx, data):
568. return self.monitor.get_status().get_counters()["count-corrupt-shares-post-repair"]
569.
570. def render_pre_repair_problems_p(self, ctx, data):
571. c = self.monitor.get_status().get_counters()
572. if c["count-objects-unhealthy-pre-repair"]:
573. return ctx.tag
574. return ""
575.
576. def data_pre_repair_problems(self, ctx, data):
577. all_objects = self.monitor.get_status().get_all_results()
578. for path in sorted(all_objects.keys()):
579. r = all_objects[path]
580. assert ICheckAndRepairResults.providedBy(r)
581. cr = r.get_pre_repair_results()
582. if not cr.is_healthy():
583. yield path, cr
584.
585. def render_problem(self, ctx, data):
586. path, cr = data
587. return ctx.tag[self._join_pathstring(path), ": ",
588. self._html(cr.get_summary())]
589.
590. def render_post_repair_problems_p(self, ctx, data):
591. c = self.monitor.get_status().get_counters()
592. if (c["count-objects-unhealthy-post-repair"]
593. or c["count-corrupt-shares-post-repair"]):
594. return ctx.tag
595. return ""
596.
597. def data_post_repair_problems(self, ctx, data):
598. all_objects = self.monitor.get_status().get_all_results()
599. for path in sorted(all_objects.keys()):
600. r = all_objects[path]
601. assert ICheckAndRepairResults.providedBy(r)
602. cr = r.get_post_repair_results()
603. if not cr.is_healthy():
604. yield path, cr
605.
606. def render_servers_with_corrupt_shares_p(self, ctx, data):
607. if self.monitor.get_status().get_counters()["count-corrupt-shares-pre-repair"]:
608. return ctx.tag
609. return ""
610. def data_servers_with_corrupt_shares(self, ctx, data):
611. return [] # TODO
612. def render_server_problem(self, ctx, data):
613. pass
614.
615.
616. def render_remaining_corrupt_shares_p(self, ctx, data):
617. if self.monitor.get_status().get_counters()["count-corrupt-shares-post-repair"]:
618. return ctx.tag
619. return ""
620. def data_post_repair_corrupt_shares(self, ctx, data):
621. return [] # TODO
622.
623. def render_share_problem(self, ctx, data):
624. pass
625.
626.
627. def render_return(self, ctx, data):
628. req = inevow.IRequest(ctx)
629. return_to = get_arg(req, "return_to", None)
630. if return_to:
631. return T.div[T.a(href=return_to)["Return to file/directory."]]
632. return ""
633.
634. def data_all_objects(self, ctx, data):
635. r = self.monitor.get_status().get_all_results()
636. for path in sorted(r.keys()):
637. yield (path, r[path])
638.
639. def render_object(self, ctx, data):
640. path, r = data
641. ctx.fillSlots("path", self._join_pathstring(path))
642. ctx.fillSlots("healthy_pre_repair",
643. str(r.get_pre_repair_results().is_healthy()))
644. ctx.fillSlots("recoverable_pre_repair",
645. str(r.get_pre_repair_results().is_recoverable()))
646. ctx.fillSlots("healthy_post_repair",
647. str(r.get_post_repair_results().is_healthy()))
648. storage_index = r.get_storage_index()
649. ctx.fillSlots("storage_index",
650. self._render_si_link(ctx, storage_index))
651. ctx.fillSlots("summary",
652. self._html(r.get_pre_repair_results().get_summary()))
653. return ctx.tag
654.
655. def render_runtime(self, ctx, data):
656. req = inevow.IRequest(ctx)
657. runtime = time.time() - req.processing_started_timestamp
658. return ctx.tag["runtime: %s seconds" % runtime]