1 | |
---|
2 | import os, time |
---|
3 | from allmydata.scripts.common import get_alias, DEFAULT_ALIAS, escape_path, \ |
---|
4 | UnknownAliasError |
---|
5 | from allmydata.scripts.common_http import do_http, format_http_error |
---|
6 | from allmydata.util import base32 |
---|
7 | from allmydata.util.encodingutil import quote_output, is_printable_ascii |
---|
8 | import urllib |
---|
9 | import simplejson |
---|
10 | |
---|
11 | class SlowOperationRunner: |
---|
12 | |
---|
13 | def run(self, options): |
---|
14 | stderr = options.stderr |
---|
15 | self.options = options |
---|
16 | self.ophandle = ophandle = base32.b2a(os.urandom(16)) |
---|
17 | nodeurl = options['node-url'] |
---|
18 | if not nodeurl.endswith("/"): |
---|
19 | nodeurl += "/" |
---|
20 | self.nodeurl = nodeurl |
---|
21 | where = options.where |
---|
22 | try: |
---|
23 | rootcap, path = get_alias(options.aliases, where, DEFAULT_ALIAS) |
---|
24 | except UnknownAliasError, e: |
---|
25 | e.display(stderr) |
---|
26 | return 1 |
---|
27 | if path == '/': |
---|
28 | path = '' |
---|
29 | url = nodeurl + "uri/%s" % urllib.quote(rootcap) |
---|
30 | if path: |
---|
31 | url += "/" + escape_path(path) |
---|
32 | # todo: should it end with a slash? |
---|
33 | url = self.make_url(url, ophandle) |
---|
34 | resp = do_http("POST", url) |
---|
35 | if resp.status not in (200, 302): |
---|
36 | print >>stderr, format_http_error("ERROR", resp) |
---|
37 | return 1 |
---|
38 | # now we poll for results. We nominally poll at t=1, 5, 10, 30, 60, |
---|
39 | # 90, k*120 seconds, but if the poll takes non-zero time, that will |
---|
40 | # be slightly longer. I'm not worried about trying to make up for |
---|
41 | # that time. |
---|
42 | |
---|
43 | return self.wait_for_results() |
---|
44 | |
---|
45 | def poll_times(self): |
---|
46 | for i in (1,5,10,30,60,90): |
---|
47 | yield i |
---|
48 | i = 120 |
---|
49 | while True: |
---|
50 | yield i |
---|
51 | i += 120 |
---|
52 | |
---|
53 | def wait_for_results(self): |
---|
54 | last = 0 |
---|
55 | for next in self.poll_times(): |
---|
56 | delay = next - last |
---|
57 | time.sleep(delay) |
---|
58 | last = next |
---|
59 | if self.poll(): |
---|
60 | return 0 |
---|
61 | |
---|
62 | def poll(self): |
---|
63 | url = self.nodeurl + "operations/" + self.ophandle |
---|
64 | url += "?t=status&output=JSON&release-after-complete=true" |
---|
65 | stdout = self.options.stdout |
---|
66 | stderr = self.options.stderr |
---|
67 | resp = do_http("GET", url) |
---|
68 | if resp.status != 200: |
---|
69 | print >>stderr, format_http_error("ERROR", resp) |
---|
70 | return True |
---|
71 | jdata = resp.read() |
---|
72 | data = simplejson.loads(jdata) |
---|
73 | if not data["finished"]: |
---|
74 | return False |
---|
75 | if self.options.get("raw"): |
---|
76 | if is_printable_ascii(jdata): |
---|
77 | print >>stdout, jdata |
---|
78 | else: |
---|
79 | print >>stderr, "The JSON response contained unprintable characters:\n%s" % quote_output(jdata) |
---|
80 | return True |
---|
81 | self.write_results(data) |
---|
82 | return True |
---|
83 | |
---|