3 from allmydata.scripts.common import BasedirOptions, NoDefaultBasedirOptions
4 from allmydata.scripts.default_nodedir import _default_nodedir
5 from allmydata.util.assertutil import precondition
6 from allmydata.util.encodingutil import listdir_unicode, argv_to_unicode, quote_output, quote_local_unicode_path
9 class _CreateBaseOptions(BasedirOptions):
11 # we provide 'create-node'-time options for the most common
12 # configuration knobs. The rest can be controlled by editing
13 # tahoe.cfg before node startup.
14 ("nickname", "n", None, "Specify the nickname for this node."),
15 ("introducer", "i", None, "Specify the introducer FURL to use."),
16 ("webport", "p", "tcp:3456:interface=127.0.0.1",
17 "Specify which TCP port to run the HTTP interface on. Use 'none' to disable."),
18 ("basedir", "C", None, "Specify which Tahoe base directory should be used. This has the same effect as the global --node-directory option. [default: %s]"
19 % quote_local_unicode_path(_default_nodedir)),
23 # This is overridden in order to ensure we get a "Wrong number of
24 # arguments." error when more than one argument is given.
25 def parseArgs(self, basedir=None):
26 BasedirOptions.parseArgs(self, basedir)
28 class CreateClientOptions(_CreateBaseOptions):
29 synopsis = "[options] [NODEDIR]"
30 description = "Create a client-only Tahoe-LAFS node (no storage server)."
32 class CreateNodeOptions(CreateClientOptions):
34 ("no-storage", None, "Do not offer storage service to other nodes."),
36 synopsis = "[options] [NODEDIR]"
37 description = "Create a full Tahoe-LAFS node (client+server)."
39 class CreateIntroducerOptions(NoDefaultBasedirOptions):
40 subcommand_name = "create-introducer"
41 description = "Create a Tahoe-LAFS introducer."
48 pkg_resources.require('%s')
49 pkg_resources.require('twisted')
50 from allmydata import client
51 from twisted.application import service
55 application = service.Application("allmydata_client")
56 c.setServiceParent(application)
57 """ % (allmydata.__appname__,)
63 pkg_resources.require('%s')
64 pkg_resources.require('twisted')
65 from allmydata import introducer
66 from twisted.application import service
68 c = introducer.IntroducerNode()
70 application = service.Application("allmydata_introducer")
71 c.setServiceParent(application)
72 """ % (allmydata.__appname__,)
74 def write_node_config(c, config):
75 # this is shared between clients and introducers
76 c.write("# -*- mode: conf; coding: utf-8 -*-\n")
78 c.write("# This file controls the configuration of the Tahoe node that\n")
79 c.write("# lives in this directory. It is only read at node startup.\n")
80 c.write("# For details about the keys that can be set here, please\n")
81 c.write("# read the 'docs/configuration.rst' file that came with your\n")
82 c.write("# Tahoe installation.\n")
86 nickname = argv_to_unicode(config.get("nickname") or "")
87 c.write("nickname = %s\n" % (nickname.encode('utf-8'),))
89 # TODO: validate webport
90 webport = argv_to_unicode(config.get("webport") or "none")
91 if webport.lower() == "none":
93 c.write("web.port = %s\n" % (webport.encode('utf-8'),))
94 c.write("web.static = public_html\n")
95 c.write("#tub.port =\n")
96 c.write("#tub.location = \n")
97 c.write("#log_gatherer.furl =\n")
98 c.write("#timeout.keepalive =\n")
99 c.write("#timeout.disconnect =\n")
100 c.write("#ssh.port = 8022\n")
101 c.write("#ssh.authorized_keys_file = ~/.ssh/authorized_keys\n")
105 def create_node(config, out=sys.stdout, err=sys.stderr):
106 basedir = config['basedir']
107 # This should always be called with an absolute Unicode basedir.
108 precondition(isinstance(basedir, unicode), basedir)
110 if os.path.exists(basedir):
111 if listdir_unicode(basedir):
112 print >>err, "The base directory %s is not empty." % quote_output(basedir)
113 print >>err, "To avoid clobbering anything, I am going to quit now."
114 print >>err, "Please use a different directory, or empty this one."
116 # we're willing to use an empty directory
119 f = open(os.path.join(basedir, "tahoe-client.tac"), "w")
123 c = open(os.path.join(basedir, "tahoe.cfg"), "w")
125 write_node_config(c, config)
127 c.write("[client]\n")
128 c.write("# Which services should this client connect to?\n")
129 c.write("introducer.furl = %s\n" % config.get("introducer", ""))
130 c.write("helper.furl =\n")
131 c.write("#key_generator.furl =\n")
132 c.write("#stats_gatherer.furl =\n")
134 c.write("# What encoding parameters should this client use for uploads?\n")
135 c.write("#shares.needed = 3\n")
136 c.write("#shares.happy = 7\n")
137 c.write("#shares.total = 10\n")
140 boolstr = {True:"true", False:"false"}
141 c.write("[storage]\n")
142 c.write("# Shall this node provide storage service?\n")
143 storage_enabled = not config.get("no-storage", None)
144 c.write("enabled = %s\n" % boolstr[storage_enabled])
145 c.write("#readonly =\n")
146 c.write("reserved_space = 1G\n")
147 c.write("#expire.enabled =\n")
148 c.write("#expire.mode =\n")
151 c.write("[helper]\n")
152 c.write("# Shall this node run a helper service that clients can use?\n")
153 c.write("enabled = false\n")
156 c.write("[drop_upload]\n")
157 c.write("# Shall this node automatically upload files created or modified in a local directory?\n")
158 c.write("enabled = false\n")
159 c.write("# To specify the target of uploads, a mutable directory writecap URI must be placed\n"
160 "# in 'private/drop_upload_dircap'.\n")
161 c.write("local.directory = ~/drop_upload\n")
166 from allmydata.util import fileutil
167 fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
168 print >>out, "Node created in %s" % quote_output(basedir)
169 if not config.get("introducer", ""):
170 print >>out, " Please set [client]introducer.furl= in tahoe.cfg!"
171 print >>out, " The node cannot connect to a grid without it."
172 if not config.get("nickname", ""):
173 print >>out, " Please set [node]nickname= in tahoe.cfg"
176 def create_client(config, out=sys.stdout, err=sys.stderr):
177 config['no-storage'] = True
178 return create_node(config, out=out, err=err)
181 def create_introducer(config, out=sys.stdout, err=sys.stderr):
182 basedir = config['basedir']
183 # This should always be called with an absolute Unicode basedir.
184 precondition(isinstance(basedir, unicode), basedir)
186 if os.path.exists(basedir):
187 if listdir_unicode(basedir):
188 print >>err, "The base directory %s is not empty." % quote_output(basedir)
189 print >>err, "To avoid clobbering anything, I am going to quit now."
190 print >>err, "Please use a different directory, or empty this one."
192 # we're willing to use an empty directory
195 f = open(os.path.join(basedir, "tahoe-introducer.tac"), "w")
196 f.write(introducer_tac)
199 c = open(os.path.join(basedir, "tahoe.cfg"), "w")
200 write_node_config(c, config)
203 print >>out, "Introducer created in %s" % quote_output(basedir)
208 ["create-node", None, CreateNodeOptions, "Create a node that acts as a client, server or both."],
209 ["create-client", None, CreateClientOptions, "Create a client node (with storage initially disabled)."],
210 ["create-introducer", None, CreateIntroducerOptions, "Create an introducer node."],
214 "create-node": create_node,
215 "create-client": create_client,
216 "create-introducer": create_introducer,