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_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_local_unicode_path(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")
158 from allmydata.util import fileutil
159 fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
160 print >>out, "Node created in %s" % quote_local_unicode_path(basedir)
161 if not config.get("introducer", ""):
162 print >>out, " Please set [client]introducer.furl= in tahoe.cfg!"
163 print >>out, " The node cannot connect to a grid without it."
164 if not config.get("nickname", ""):
165 print >>out, " Please set [node]nickname= in tahoe.cfg"
168 def create_client(config, out=sys.stdout, err=sys.stderr):
169 config['no-storage'] = True
170 return create_node(config, out=out, err=err)
173 def create_introducer(config, out=sys.stdout, err=sys.stderr):
174 basedir = config['basedir']
175 # This should always be called with an absolute Unicode basedir.
176 precondition(isinstance(basedir, unicode), basedir)
178 if os.path.exists(basedir):
179 if listdir_unicode(basedir):
180 print >>err, "The base directory %s is not empty." % quote_local_unicode_path(basedir)
181 print >>err, "To avoid clobbering anything, I am going to quit now."
182 print >>err, "Please use a different directory, or empty this one."
184 # we're willing to use an empty directory
187 f = open(os.path.join(basedir, "tahoe-introducer.tac"), "w")
188 f.write(introducer_tac)
191 c = open(os.path.join(basedir, "tahoe.cfg"), "w")
192 write_node_config(c, config)
195 print >>out, "Introducer created in %s" % quote_local_unicode_path(basedir)
200 ["create-node", None, CreateNodeOptions, "Create a node that acts as a client, server or both."],
201 ["create-client", None, CreateClientOptions, "Create a client node (with storage initially disabled)."],
202 ["create-introducer", None, CreateIntroducerOptions, "Create an introducer node."],
206 "create-node": create_node,
207 "create-client": create_client,
208 "create-introducer": create_introducer,