]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/create_node.py
Quote local paths correctly in the output of node creation commands. fixes ticket...
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / scripts / create_node.py
1
2 import os, sys
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
7 import allmydata
8
9 class _CreateBaseOptions(BasedirOptions):
10     optParameters = [
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)),
20
21         ]
22
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)
27
28 class CreateClientOptions(_CreateBaseOptions):
29     synopsis = "[options] [NODEDIR]"
30     description = "Create a client-only Tahoe-LAFS node (no storage server)."
31
32 class CreateNodeOptions(CreateClientOptions):
33     optFlags = [
34         ("no-storage", None, "Do not offer storage service to other nodes."),
35         ]
36     synopsis = "[options] [NODEDIR]"
37     description = "Create a full Tahoe-LAFS node (client+server)."
38
39 class CreateIntroducerOptions(NoDefaultBasedirOptions):
40     subcommand_name = "create-introducer"
41     description = "Create a Tahoe-LAFS introducer."
42
43
44 client_tac = """
45 # -*- python -*-
46
47 import pkg_resources
48 pkg_resources.require('%s')
49 pkg_resources.require('twisted')
50 from allmydata import client
51 from twisted.application import service
52
53 c = client.Client()
54
55 application = service.Application("allmydata_client")
56 c.setServiceParent(application)
57 """ % (allmydata.__appname__,)
58
59 introducer_tac = """
60 # -*- python -*-
61
62 import pkg_resources
63 pkg_resources.require('%s')
64 pkg_resources.require('twisted')
65 from allmydata import introducer
66 from twisted.application import service
67
68 c = introducer.IntroducerNode()
69
70 application = service.Application("allmydata_introducer")
71 c.setServiceParent(application)
72 """ % (allmydata.__appname__,)
73
74 def write_node_config(c, config):
75     # this is shared between clients and introducers
76     c.write("# -*- mode: conf; coding: utf-8 -*-\n")
77     c.write("\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")
83     c.write("\n\n")
84
85     c.write("[node]\n")
86     nickname = argv_to_unicode(config.get("nickname") or "")
87     c.write("nickname = %s\n" % (nickname.encode('utf-8'),))
88
89     # TODO: validate webport
90     webport = argv_to_unicode(config.get("webport") or "none")
91     if webport.lower() == "none":
92         webport = ""
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")
102     c.write("\n")
103
104
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)
109
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."
115             return -1
116         # we're willing to use an empty directory
117     else:
118         os.mkdir(basedir)
119     f = open(os.path.join(basedir, "tahoe-client.tac"), "w")
120     f.write(client_tac)
121     f.close()
122
123     c = open(os.path.join(basedir, "tahoe.cfg"), "w")
124
125     write_node_config(c, config)
126
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")
133     c.write("\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")
138     c.write("\n")
139
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")
149     c.write("\n")
150
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")
154     c.write("\n")
155
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")
162     c.write("\n")
163
164     c.close()
165
166     from allmydata.util import fileutil
167     fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
168     print >>out, "Node created in %s" % quote_local_unicode_path(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"
174     return 0
175
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)
179
180
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)
185
186     if os.path.exists(basedir):
187         if listdir_unicode(basedir):
188             print >>err, "The base directory %s is not empty." % quote_local_unicode_path(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."
191             return -1
192         # we're willing to use an empty directory
193     else:
194         os.mkdir(basedir)
195     f = open(os.path.join(basedir, "tahoe-introducer.tac"), "w")
196     f.write(introducer_tac)
197     f.close()
198
199     c = open(os.path.join(basedir, "tahoe.cfg"), "w")
200     write_node_config(c, config)
201     c.close()
202
203     print >>out, "Introducer created in %s" % quote_local_unicode_path(basedir)
204     return 0
205
206
207 subCommands = [
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."],
211 ]
212
213 dispatch = {
214     "create-node": create_node,
215     "create-client": create_client,
216     "create-introducer": create_introducer,
217     }