3 from allmydata.scripts.common import BasedirMixin, BaseOptions
4 from allmydata.util.assertutil import precondition
5 from allmydata.util.encodingutil import listdir_unicode, argv_to_unicode, quote_output
8 class CreateClientOptions(BasedirMixin, BaseOptions):
10 # we provide 'create-node'-time options for the most common
11 # configuration knobs. The rest can be controlled by editing
12 # tahoe.cfg before node startup.
13 ("nickname", "n", None, "Specify the nickname for this node."),
14 ("introducer", "i", None, "Specify the introducer FURL to use."),
15 ("webport", "p", "tcp:3456:interface=127.0.0.1",
16 "Specify which TCP port to run the HTTP interface on. Use 'none' to disable."),
19 def getSynopsis(self):
20 return "Usage: %s create-client [options] [NODEDIR]" % (os.path.basename(sys.argv[0]),)
23 class CreateNodeOptions(CreateClientOptions):
25 ("no-storage", None, "Do not offer storage service to other nodes."),
28 def getSynopsis(self):
29 return "Usage: %s create-node [options] [NODEDIR]" % (os.path.basename(sys.argv[0]),)
32 class CreateIntroducerOptions(BasedirMixin, BaseOptions):
33 default_nodedir = None
36 ["node-directory", "d", None, "Specify which directory the introducer should be created in. [no default]"],
39 def getSynopsis(self):
40 return "Usage: %s create-introducer [options] NODEDIR" % (os.path.basename(sys.argv[0]),)
47 pkg_resources.require('%s')
48 pkg_resources.require('twisted')
49 from allmydata import client
50 from twisted.application import service
54 application = service.Application("allmydata_client")
55 c.setServiceParent(application)
56 """ % (allmydata.__appname__,)
62 pkg_resources.require('%s')
63 pkg_resources.require('twisted')
64 from allmydata import introducer
65 from twisted.application import service
67 c = introducer.IntroducerNode()
69 application = service.Application("allmydata_introducer")
70 c.setServiceParent(application)
71 """ % (allmydata.__appname__,)
73 def write_node_config(c, config):
74 # this is shared between clients and introducers
75 c.write("# -*- mode: conf; coding: utf-8 -*-\n")
77 c.write("# This file controls the configuration of the Tahoe node that\n")
78 c.write("# lives in this directory. It is only read at node startup.\n")
79 c.write("# For details about the keys that can be set here, please\n")
80 c.write("# read the 'docs/configuration.rst' file that came with your\n")
81 c.write("# Tahoe installation.\n")
85 nickname = argv_to_unicode(config.get("nickname") or "")
86 c.write("nickname = %s\n" % (nickname.encode('utf-8'),))
88 # TODO: validate webport
89 webport = argv_to_unicode(config.get("webport") or "none")
90 if webport.lower() == "none":
92 c.write("web.port = %s\n" % (webport.encode('utf-8'),))
93 c.write("web.static = public_html\n")
94 c.write("#tub.port =\n")
95 c.write("#tub.location = \n")
96 c.write("#log_gatherer.furl =\n")
97 c.write("#timeout.keepalive =\n")
98 c.write("#timeout.disconnect =\n")
99 c.write("#ssh.port = 8022\n")
100 c.write("#ssh.authorized_keys_file = ~/.ssh/authorized_keys\n")
104 def create_node(config, out=sys.stdout, err=sys.stderr):
105 basedir = config['basedir']
106 # This should always be called with an absolute Unicode basedir.
107 precondition(isinstance(basedir, unicode), basedir)
109 if os.path.exists(basedir):
110 if listdir_unicode(basedir):
111 print >>err, "The base directory %s is not empty." % quote_output(basedir)
112 print >>err, "To avoid clobbering anything, I am going to quit now."
113 print >>err, "Please use a different directory, or empty this one."
115 # we're willing to use an empty directory
118 f = open(os.path.join(basedir, "tahoe-client.tac"), "w")
122 c = open(os.path.join(basedir, "tahoe.cfg"), "w")
124 write_node_config(c, config)
126 c.write("[client]\n")
127 c.write("# Which services should this client connect to?\n")
128 c.write("introducer.furl = %s\n" % config.get("introducer", ""))
129 c.write("helper.furl =\n")
130 c.write("#key_generator.furl =\n")
131 c.write("#stats_gatherer.furl =\n")
133 c.write("# What encoding parameters should this client use for uploads?\n")
134 c.write("#shares.needed = 3\n")
135 c.write("#shares.happy = 7\n")
136 c.write("#shares.total = 10\n")
139 boolstr = {True:"true", False:"false"}
140 c.write("[storage]\n")
141 c.write("# Shall this node provide storage service?\n")
142 storage_enabled = not config.get("no-storage", None)
143 c.write("enabled = %s\n" % boolstr[storage_enabled])
144 c.write("#readonly =\n")
145 c.write("reserved_space = 1G\n")
146 c.write("#expire.enabled =\n")
147 c.write("#expire.mode =\n")
150 c.write("[helper]\n")
151 c.write("# Shall this node run a helper service that clients can use?\n")
152 c.write("enabled = false\n")
157 from allmydata.util import fileutil
158 fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
159 print >>out, "Node created in %s" % quote_output(basedir)
160 if not config.get("introducer", ""):
161 print >>out, " Please set [client]introducer.furl= in tahoe.cfg!"
162 print >>out, " The node cannot connect to a grid without it."
163 if not config.get("nickname", ""):
164 print >>out, " Please set [node]nickname= in tahoe.cfg"
167 def create_client(config, out=sys.stdout, err=sys.stderr):
168 config['no-storage'] = True
169 return create_node(config, out=out, err=err)
172 def create_introducer(config, out=sys.stdout, err=sys.stderr):
173 basedir = config['basedir']
174 # This should always be called with an absolute Unicode basedir.
175 precondition(isinstance(basedir, unicode), basedir)
177 if os.path.exists(basedir):
178 if listdir_unicode(basedir):
179 print >>err, "The base directory %s is not empty." % quote_output(basedir)
180 print >>err, "To avoid clobbering anything, I am going to quit now."
181 print >>err, "Please use a different directory, or empty this one."
183 # we're willing to use an empty directory
186 f = open(os.path.join(basedir, "tahoe-introducer.tac"), "w")
187 f.write(introducer_tac)
190 c = open(os.path.join(basedir, "tahoe.cfg"), "w")
191 write_node_config(c, config)
194 print >>out, "Introducer created in %s" % quote_output(basedir)
199 ["create-node", None, CreateNodeOptions, "Create a node that acts as a client, server or both."],
200 ["create-client", None, CreateClientOptions, "Create a client node (with storage initially disabled)."],
201 ["create-introducer", None, CreateIntroducerOptions, "Create an introducer node."],
205 "create-node": create_node,
206 "create-client": create_client,
207 "create-introducer": create_introducer,