3 import os, subprocess, sys, signal, time
4 from twisted.python import usage
6 from twisted.python.procutils import which
10 return subprocess.call(["python", loc,], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
16 for maybetwistd in which("twistd"):
17 ret = testtwistd(maybetwistd)
23 for maybetwistd in which("twistd.py"):
24 ret = testtwistd(maybetwistd)
30 maybetwistd = os.path.join(sys.prefix, 'Scripts', 'twistd')
31 ret = testtwistd(maybetwistd)
36 maybetwistd = os.path.join(sys.prefix, 'Scripts', 'twistd.py')
37 ret = testtwistd(maybetwistd)
42 print "Can't find twistd (it comes with Twisted). Aborting."
47 ["multiple", "m", "allow multiple basedirs to be specified at once"],
50 def postOptions(self):
52 raise usage.UsageError("<basedir> parameter is required")
55 self['basedirs'] = [os.path.abspath(os.path.expanduser(b))
56 for b in self.basedirs]
58 def parseArgs(self, *args):
61 self.basedirs.append(self['basedir'])
63 self.basedirs.extend(args)
65 if len(args) == 0 and not self.basedirs:
66 self.basedirs.append(".")
68 self.basedirs.append(args[0])
70 raise usage.UsageError("I wasn't expecting so many arguments")
72 class NoDefaultBasedirMixin(BasedirMixin):
73 def parseArgs(self, *args):
74 # create-client won't default to --basedir=.
77 self.basedirs.append(self['basedir'])
79 self.basedirs.extend(args)
82 self.basedirs.append(args[0])
84 raise usage.UsageError("I wasn't expecting so many arguments")
86 raise usage.UsageError("--basedir must be provided")
88 class StartOptions(BasedirMixin, usage.Options):
90 ["basedir", "C", None, "which directory to start the node in"],
93 class StopOptions(BasedirMixin, usage.Options):
95 ["basedir", "C", None, "which directory to stop the node in"],
98 class RestartOptions(BasedirMixin, usage.Options):
100 ["basedir", "C", None, "which directory to restart the node in"],
103 class CreateClientOptions(NoDefaultBasedirMixin, usage.Options):
105 ["basedir", "C", None, "which directory to create the client in"],
108 ["quiet", "q", "operate silently"],
111 class CreateIntroducerOptions(NoDefaultBasedirMixin, usage.Options):
113 ["basedir", "C", None, "which directory to create the introducer in"],
116 ["quiet", "q", "operate silently"],
119 class DumpOptions(usage.Options):
121 ["filename", "f", None, "which file to dump"],
124 def parseArgs(self, filename=None):
126 self['filename'] = filename
128 def postOptions(self):
129 if not self['filename']:
130 raise usage.UsageError("<filename> parameter is required")
135 from allmydata import client
136 from twisted.application import service
140 application = service.Application("allmydata_client")
141 c.setServiceParent(application)
147 from allmydata import introducer_and_vdrive
148 from twisted.application import service
150 c = introducer_and_vdrive.IntroducerAndVdrive()
152 application = service.Application("allmydata_introducer")
153 c.setServiceParent(application)
156 class Options(usage.Options):
157 synopsis = "Usage: allmydata <command> [command options]"
160 ["create-client", None, CreateClientOptions, "Create a client node."],
161 ["create-introducer", None, CreateIntroducerOptions, "Create a introducer node."],
162 ["start", None, StartOptions, "Start a node (of any type)."],
163 ["stop", None, StopOptions, "Stop a node."],
164 ["restart", None, RestartOptions, "Restart a node."],
165 ["dump-uri-extension", None, DumpOptions,
166 "Unpack and display the contents of a uri_extension file."],
169 def postOptions(self):
170 if not hasattr(self, 'subOptions'):
171 raise usage.UsageError("must specify a command")
173 def runner(argv, run_by_human=True):
176 config.parseOptions(argv)
177 except usage.error, e:
180 print "%s: %s" % (sys.argv[0], e)
182 c = getattr(config, 'subOptions', config)
186 command = config.subCommand
187 so = config.subOptions
190 if command == "create-client":
191 for basedir in so.basedirs:
192 rc = create_client(basedir, so) or rc
193 elif command == "create-introducer":
194 for basedir in so.basedirs:
195 rc = create_introducer(basedir, so) or rc
196 elif command == "start":
197 for basedir in so.basedirs:
198 rc = start(basedir, so) or rc
199 elif command == "stop":
200 for basedir in so.basedirs:
201 rc = stop(basedir, so) or rc
202 elif command == "restart":
203 for basedir in so.basedirs:
204 rc = stop(basedir, so) or rc
206 print "not restarting"
208 for basedir in so.basedirs:
209 rc = start(basedir, so) or rc
210 elif command == "dump-uri-extension":
211 rc = dump_uri_extension(so)
215 rc = runner(sys.argv[1:])
218 def create_client(basedir, config):
219 if os.path.exists(basedir):
220 if os.listdir(basedir):
221 print "The base directory already exists: %s" % basedir
222 print "To avoid clobbering anything, I am going to quit now"
223 print "Please use a different directory, or delete this one"
225 # we're willing to use an empty directory
228 f = open(os.path.join(basedir, "client.tac"), "w")
231 if not config['quiet']:
232 print "client created in %s" % basedir
233 print " please copy introducer.furl and vdrive.furl into the directory"
235 def create_introducer(basedir, config):
236 if os.path.exists(basedir):
237 if os.listdir(basedir):
238 print "The base directory already exists: %s" % basedir
239 print "To avoid clobbering anything, I am going to quit now"
240 print "Please use a different directory, or delete this one"
242 # we're willing to use an empty directory
245 f = open(os.path.join(basedir, "introducer.tac"), "w")
246 f.write(introducer_tac)
248 if not config['quiet']:
249 print "introducer created in %s" % basedir
251 def start(basedir, config):
252 print "STARTING", basedir
253 if os.path.exists(os.path.join(basedir, "client.tac")):
256 elif os.path.exists(os.path.join(basedir, "introducer.tac")):
257 tac = "introducer.tac"
260 print "%s does not look like a node directory" % basedir
261 if not os.path.isdir(basedir):
262 print " in fact, it doesn't look like a directory at all!"
264 rc = subprocess.call(["python", twistd, "-y", tac,], cwd=basedir)
266 print "%s node probably started" % type
269 print "%s node probably not started" % type
272 def stop(basedir, config):
273 print "STOPPING", basedir
274 pidfile = os.path.join(basedir, "twistd.pid")
275 if not os.path.exists(pidfile):
276 print "%s does not look like a running node directory (no twistd.pid)" % basedir
278 pid = open(pidfile, "r").read()
282 os.kill(pid, signal.SIGTERM)
285 # poll once per second until twistd.pid goes away, up to 5 seconds
289 print "process %d is dead" % pid
293 print "never saw process go away"
296 def dump_uri_extension(config):
297 from allmydata import uri
299 filename = config['filename']
300 unpacked = uri.unpack_extension_readable(open(filename,"rb").read())
301 keys1 = ("size", "num_segments", "segment_size",
302 "needed_shares", "total_shares")
303 keys2 = ("codec_name", "codec_params", "tail_codec_params")
304 keys3 = ("plaintext_hash", "plaintext_root_hash",
305 "crypttext_hash", "crypttext_root_hash",
309 print "%19s: %s" % (k, unpacked[k])
313 print "%19s: %s" % (k, unpacked[k])
317 print "%19s: %s" % (k, unpacked[k])
319 leftover = set(unpacked.keys()) - set(keys1 + keys2 + keys3)
322 for k in sorted(leftover):
323 print "%s: %s" % (k, unpacked[k])