4 from twisted.protocols.basic import LineOnlyReceiver
5 from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \
7 from allmydata.scripts.common_http import do_http
13 stdout = options.stdout
14 stderr = options.stderr
15 nodeurl = options['node-url']
16 if not nodeurl.endswith("/"):
20 rootcap, path = get_alias(options.aliases, where, DEFAULT_ALIAS)
21 except UnknownAliasError, e:
22 print >>stderr, "error: %s" % e.args[0]
26 url = nodeurl + "uri/%s" % urllib.quote(rootcap)
28 url += "/" + escape_path(path)
29 # todo: should it end with a slash?
30 url += "?t=check&output=JSON"
35 if options["add-lease"]:
36 url += "&add-lease=true"
38 resp = do_http("POST", url)
39 if resp.status != 200:
40 print >>stderr, "ERROR", resp.status, resp.reason, resp.read()
43 if options.get("raw"):
47 data = simplejson.loads(jdata)
51 if data["pre-repair-results"]["results"]["healthy"]:
54 summary = "not healthy"
55 stdout.write("Summary: %s\n" % summary)
56 cr = data["pre-repair-results"]["results"]
57 stdout.write(" storage index: %s\n" % data["storage-index"])
58 stdout.write(" good-shares: %d (encoding is %d-of-%d)\n"
59 % (cr["count-shares-good"],
60 cr["count-shares-needed"],
61 cr["count-shares-expected"]))
62 stdout.write(" wrong-shares: %d\n" % cr["count-wrong-shares"])
63 corrupt = cr["list-corrupt-shares"]
65 stdout.write(" corrupt shares:\n")
66 for (serverid, storage_index, sharenum) in corrupt:
67 stdout.write(" server %s, SI %s, shnum %d\n" %
68 (serverid, storage_index, sharenum))
69 if data["repair-attempted"]:
70 if data["repair-successful"]:
71 stdout.write(" repair successful\n")
73 stdout.write(" repair failed\n")
75 stdout.write("Summary: %s\n" % data["summary"])
77 stdout.write(" storage index: %s\n" % data["storage-index"])
78 stdout.write(" good-shares: %d (encoding is %d-of-%d)\n"
79 % (cr["count-shares-good"],
80 cr["count-shares-needed"],
81 cr["count-shares-expected"]))
82 stdout.write(" wrong-shares: %d\n" % cr["count-wrong-shares"])
83 corrupt = cr["list-corrupt-shares"]
85 stdout.write(" corrupt shares:\n")
86 for (serverid, storage_index, sharenum) in corrupt:
87 stdout.write(" server %s, SI %s, shnum %d\n" %
88 (serverid, storage_index, sharenum))
95 class DeepCheckOutput(LineOnlyReceiver):
97 def __init__(self, streamer, options):
98 self.streamer = streamer
99 self.transport = FakeTransport()
101 self.verbose = bool(options["verbose"])
102 self.stdout = options.stdout
103 self.stderr = options.stderr
105 self.files_healthy = 0
106 self.files_unhealthy = 0
107 self.in_error = False
109 def lineReceived(self, line):
111 print >>self.stderr, line
113 if line.startswith("ERROR:"):
116 print >>self.stderr, line
119 d = simplejson.loads(line)
121 if d["type"] not in ("file", "directory"):
123 self.num_objects += 1
124 # non-verbose means print a progress marker every 100 files
125 if self.num_objects % 100 == 0:
126 print >>stdout, "%d objects checked.." % self.num_objects
127 cr = d["check-results"]
128 if cr["results"]["healthy"]:
129 self.files_healthy += 1
131 self.files_unhealthy += 1
133 # verbose means also print one line per file
137 summary = cr.get("summary", "Healthy (LIT)")
139 print >>stdout, "%s: %s" % ("/".join(path), summary)
140 except UnicodeEncodeError:
141 print >>stdout, "%s: %s" % ("/".join([p.encode("utf-8")
144 # always print out corrupt shares
145 for shareloc in cr["results"].get("list-corrupt-shares", []):
146 (serverid, storage_index, sharenum) = shareloc
147 print >>stdout, " corrupt: server %s, SI %s, shnum %d" % \
148 (serverid, storage_index, sharenum)
154 print >>stdout, "done: %d objects checked, %d healthy, %d unhealthy" \
155 % (self.num_objects, self.files_healthy, self.files_unhealthy)
157 class DeepCheckAndRepairOutput(LineOnlyReceiver):
159 def __init__(self, streamer, options):
160 self.streamer = streamer
161 self.transport = FakeTransport()
163 self.verbose = bool(options["verbose"])
164 self.stdout = options.stdout
165 self.stderr = options.stderr
167 self.pre_repair_files_healthy = 0
168 self.pre_repair_files_unhealthy = 0
169 self.repairs_attempted = 0
170 self.repairs_successful = 0
171 self.post_repair_files_healthy = 0
172 self.post_repair_files_unhealthy = 0
173 self.in_error = False
175 def lineReceived(self, line):
177 print >>self.stderr, line
179 if line.startswith("ERROR:"):
182 print >>self.stderr, line
185 d = simplejson.loads(line)
187 if d["type"] not in ("file", "directory"):
189 self.num_objects += 1
190 # non-verbose means print a progress marker every 100 files
191 if self.num_objects % 100 == 0:
192 print >>stdout, "%d objects checked.." % self.num_objects
193 crr = d["check-and-repair-results"]
194 if d["storage-index"]:
195 if crr["pre-repair-results"]["results"]["healthy"]:
197 self.pre_repair_files_healthy += 1
200 self.pre_repair_files_unhealthy += 1
201 if crr["post-repair-results"]["results"]["healthy"]:
202 self.post_repair_files_healthy += 1
204 self.post_repair_files_unhealthy += 1
208 self.pre_repair_files_healthy += 1
209 self.post_repair_files_healthy += 1
210 if crr["repair-attempted"]:
211 self.repairs_attempted += 1
212 if crr["repair-successful"]:
213 self.repairs_successful += 1
215 # verbose means also print one line per file
219 # we don't seem to have a summary available, so build one
223 summary = "not healthy"
225 print >>stdout, "%s: %s" % ("/".join(path), summary)
226 except UnicodeEncodeError:
227 print >>stdout, "%s: %s" % ("/".join([p.encode("utf-8")
230 # always print out corrupt shares
231 prr = crr.get("pre-repair-results", {})
232 for shareloc in prr.get("results", {}).get("list-corrupt-shares", []):
233 (serverid, storage_index, sharenum) = shareloc
234 print >>stdout, " corrupt: server %s, SI %s, shnum %d" % \
235 (serverid, storage_index, sharenum)
237 # always print out repairs
238 if crr["repair-attempted"]:
239 if crr["repair-successful"]:
240 print >>stdout, " repair successful"
242 print >>stdout, " repair failed"
248 print >>stdout, "done: %d objects checked" % self.num_objects
249 print >>stdout, " pre-repair: %d healthy, %d unhealthy" \
250 % (self.pre_repair_files_healthy,
251 self.pre_repair_files_unhealthy)
252 print >>stdout, " %d repairs attempted, %d successful, %d failed" \
253 % (self.repairs_attempted,
254 self.repairs_successful,
255 (self.repairs_attempted - self.repairs_successful))
256 print >>stdout, " post-repair: %d healthy, %d unhealthy" \
257 % (self.post_repair_files_healthy,
258 self.post_repair_files_unhealthy)
260 class DeepCheckStreamer(LineOnlyReceiver):
262 def run(self, options):
263 stdout = options.stdout
264 stderr = options.stderr
266 self.options = options
267 nodeurl = options['node-url']
268 if not nodeurl.endswith("/"):
270 self.nodeurl = nodeurl
271 where = options.where
273 rootcap, path = get_alias(options.aliases, where, DEFAULT_ALIAS)
274 except UnknownAliasError, e:
275 print >>stderr, "error: %s" % e.args[0]
279 url = nodeurl + "uri/%s" % urllib.quote(rootcap)
281 url += "/" + escape_path(path)
282 # todo: should it end with a slash?
283 url += "?t=stream-deep-check"
284 if options["verify"]:
285 url += "&verify=true"
286 if options["repair"]:
287 url += "&repair=true"
288 output = DeepCheckAndRepairOutput(self, options)
290 output = DeepCheckOutput(self, options)
291 if options["add-lease"]:
292 url += "&add-lease=true"
293 resp = do_http("POST", url)
294 if resp.status not in (200, 302):
295 print >>stderr, "ERROR", resp.status, resp.reason, resp.read()
298 # use Twisted to split this into lines
300 chunk = resp.read(100)
303 if self.options["raw"]:
306 output.dataReceived(chunk)
307 if not self.options["raw"]:
311 def deepcheck(options):
312 return DeepCheckStreamer().run(options)