]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/create_node.py
6663d125d2d5278dd6240c82c77d1a85b845f34e
[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.util.assertutil import precondition
5 from allmydata.util.encodingutil import listdir_unicode, argv_to_unicode, quote_output
6 import allmydata
7
8 class CreateClientOptions(BasedirOptions):
9     optParameters = [
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."),
17         ]
18
19     def getSynopsis(self):
20         return "Usage:  %s [global-opts] create-client [options] [NODEDIR]" % (self.command_name,)
21
22     # This is overridden in order to ensure we get a "Wrong number of arguments."
23     # error when more than one argument is given.
24     def parseArgs(self, basedir=None):
25         BasedirOptions.parseArgs(self, basedir)
26
27
28 class CreateNodeOptions(CreateClientOptions):
29     optFlags = [
30         ("no-storage", None, "Do not offer storage service to other nodes."),
31         ]
32
33     def getSynopsis(self):
34         return "Usage:  %s [global-opts] create-node [options] [NODEDIR]" % (self.command_name,)
35
36
37 class CreateIntroducerOptions(NoDefaultBasedirOptions):
38     subcommand_name = "create-introducer"
39
40
41 client_tac = """
42 # -*- python -*-
43
44 import pkg_resources
45 pkg_resources.require('%s')
46 pkg_resources.require('twisted')
47 from allmydata import client
48 from twisted.application import service
49
50 c = client.Client()
51
52 application = service.Application("allmydata_client")
53 c.setServiceParent(application)
54 """ % (allmydata.__appname__,)
55
56 introducer_tac = """
57 # -*- python -*-
58
59 import pkg_resources
60 pkg_resources.require('%s')
61 pkg_resources.require('twisted')
62 from allmydata import introducer
63 from twisted.application import service
64
65 c = introducer.IntroducerNode()
66
67 application = service.Application("allmydata_introducer")
68 c.setServiceParent(application)
69 """ % (allmydata.__appname__,)
70
71 def write_node_config(c, config):
72     # this is shared between clients and introducers
73     c.write("# -*- mode: conf; coding: utf-8 -*-\n")
74     c.write("\n")
75     c.write("# This file controls the configuration of the Tahoe node that\n")
76     c.write("# lives in this directory. It is only read at node startup.\n")
77     c.write("# For details about the keys that can be set here, please\n")
78     c.write("# read the 'docs/configuration.rst' file that came with your\n")
79     c.write("# Tahoe installation.\n")
80     c.write("\n\n")
81
82     c.write("[node]\n")
83     nickname = argv_to_unicode(config.get("nickname") or "")
84     c.write("nickname = %s\n" % (nickname.encode('utf-8'),))
85
86     # TODO: validate webport
87     webport = argv_to_unicode(config.get("webport") or "none")
88     if webport.lower() == "none":
89         webport = ""
90     c.write("web.port = %s\n" % (webport.encode('utf-8'),))
91     c.write("web.static = public_html\n")
92     c.write("#tub.port =\n")
93     c.write("#tub.location = \n")
94     c.write("#log_gatherer.furl =\n")
95     c.write("#timeout.keepalive =\n")
96     c.write("#timeout.disconnect =\n")
97     c.write("#ssh.port = 8022\n")
98     c.write("#ssh.authorized_keys_file = ~/.ssh/authorized_keys\n")
99     c.write("\n")
100
101
102 def create_node(config, out=sys.stdout, err=sys.stderr):
103     basedir = config['basedir']
104     # This should always be called with an absolute Unicode basedir.
105     precondition(isinstance(basedir, unicode), basedir)
106
107     if os.path.exists(basedir):
108         if listdir_unicode(basedir):
109             print >>err, "The base directory %s is not empty." % quote_output(basedir)
110             print >>err, "To avoid clobbering anything, I am going to quit now."
111             print >>err, "Please use a different directory, or empty this one."
112             return -1
113         # we're willing to use an empty directory
114     else:
115         os.mkdir(basedir)
116     f = open(os.path.join(basedir, "tahoe-client.tac"), "w")
117     f.write(client_tac)
118     f.close()
119
120     c = open(os.path.join(basedir, "tahoe.cfg"), "w")
121
122     write_node_config(c, config)
123
124     c.write("[client]\n")
125     c.write("# Which services should this client connect to?\n")
126     c.write("introducer.furl = %s\n" % config.get("introducer", ""))
127     c.write("helper.furl =\n")
128     c.write("#key_generator.furl =\n")
129     c.write("#stats_gatherer.furl =\n")
130     c.write("\n")
131     c.write("# What encoding parameters should this client use for uploads?\n")
132     c.write("#shares.needed = 3\n")
133     c.write("#shares.happy = 7\n")
134     c.write("#shares.total = 10\n")
135     c.write("\n")
136
137     boolstr = {True:"true", False:"false"}
138     c.write("[storage]\n")
139     c.write("# Shall this node provide storage service?\n")
140     storage_enabled = not config.get("no-storage", None)
141     c.write("enabled = %s\n" % boolstr[storage_enabled])
142     c.write("#readonly =\n")
143     c.write("reserved_space = 1G\n")
144     c.write("#expire.enabled =\n")
145     c.write("#expire.mode =\n")
146     c.write("\n")
147
148     c.write("[helper]\n")
149     c.write("# Shall this node run a helper service that clients can use?\n")
150     c.write("enabled = false\n")
151     c.write("\n")
152
153     c.write("[drop_upload]\n")
154     c.write("# Shall this node automatically upload files created or modified in a local directory?\n")
155     c.write("enabled = false\n")
156     c.write("# To specify the target of uploads, a mutable directory writecap URI must be placed\n"
157             "# in 'private/drop_upload_dircap'.\n")
158     c.write("local.directory = ~/drop_upload\n")
159     c.write("\n")
160
161     c.close()
162
163     from allmydata.util import fileutil
164     fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
165     print >>out, "Node created in %s" % quote_output(basedir)
166     if not config.get("introducer", ""):
167         print >>out, " Please set [client]introducer.furl= in tahoe.cfg!"
168         print >>out, " The node cannot connect to a grid without it."
169     if not config.get("nickname", ""):
170         print >>out, " Please set [node]nickname= in tahoe.cfg"
171     return 0
172
173 def create_client(config, out=sys.stdout, err=sys.stderr):
174     config['no-storage'] = True
175     return create_node(config, out=out, err=err)
176
177
178 def create_introducer(config, out=sys.stdout, err=sys.stderr):
179     basedir = config['basedir']
180     # This should always be called with an absolute Unicode basedir.
181     precondition(isinstance(basedir, unicode), basedir)
182
183     if os.path.exists(basedir):
184         if listdir_unicode(basedir):
185             print >>err, "The base directory %s is not empty." % quote_output(basedir)
186             print >>err, "To avoid clobbering anything, I am going to quit now."
187             print >>err, "Please use a different directory, or empty this one."
188             return -1
189         # we're willing to use an empty directory
190     else:
191         os.mkdir(basedir)
192     f = open(os.path.join(basedir, "tahoe-introducer.tac"), "w")
193     f.write(introducer_tac)
194     f.close()
195
196     c = open(os.path.join(basedir, "tahoe.cfg"), "w")
197     write_node_config(c, config)
198     c.close()
199
200     print >>out, "Introducer created in %s" % quote_output(basedir)
201     return 0
202
203
204 subCommands = [
205     ["create-node", None, CreateNodeOptions, "Create a node that acts as a client, server or both."],
206     ["create-client", None, CreateClientOptions, "Create a client node (with storage initially disabled)."],
207     ["create-introducer", None, CreateIntroducerOptions, "Create an introducer node."],
208 ]
209
210 dispatch = {
211     "create-node": create_node,
212     "create-client": create_client,
213     "create-introducer": create_introducer,
214     }