-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathsqlchain-config
executable file
·424 lines (390 loc) · 24.5 KB
/
sqlchain-config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#! /usr/bin/env python
import os, sys, signal, pwd, locale, random, string, shutil, json
import MySQLdb as db
from cStringIO import StringIO
from collections import OrderedDict
from dialog import Dialog
from sqlchain.version import version
from sqlchain.democvt import democvt
SQLCHAIN_INSTALL_PATH = '/usr/local/share/sqlchain'
DATA_DIR = 0
BLKDAT_DIR = 1
DAEMON_BIN = 2
DEF_COIN_USER = 3
DEF_RPC_PORT = 4
DEF_API_PORT = 5
CAN_PRUNE = 6
CAN_BLKDAT = 7
coin_var = OrderedDict([
('bitcoin', [ 'bitcoin', '', 'bitcoind', 'btc', 8332, 8085, True, True ]),
('testnet', [ 'bitcoin', 'testnet3', 'bitcoind', 'btc', 18332, 18085, True, True ]),
('litecoin',[ 'litecoin', '', 'litecoind', 'ltc', 9332, 8086, True, False ]),
('reddcoin',[ 'reddcoin', '', 'reddcoind', 'rdd', 45443, 8087, False, False ]),
('dogecoin',[ 'dogecoin', '', 'dogecoind', 'doge',22555, 8088, False, False ]),
('vertcoin',[ 'vertcoin', '', 'vertcoind', 'vtc', 5888, 8089, False, False ])
])
cwd = os.getcwd()
sqlroot = "/var/data/sqlchain"
op_mode_help = [
"""Normally the underlying full node stores all historic blocks making up the blockchain. But these are not used again by sqlchain once the data has been processed into the SQL database. So by enabling pruning mode the processed blocks can be discarded and significant disk space saved.\n\nHowever, typically the node software can accept and verify blocks faster than sqlchain which means that unless something pauses the node it still needs a large amount of disk space even if later released. The "blkbtc" utility included with sqlchain can block ports that stalls the node allowing sqlchain to catch up. This allows processing the entire blockchain with less disk space, such as on small VPS nodes.\n\nAn SSD is essential for syncing with sqlchain but afterwards it is feasible to move data to slower media.""",
"""The default is for sqlchain to get new blocks using the RPC interface. When the underlying node is busy syncing the RPC interface can respond slowly, starving sqlchain. Using 'direct mode' enables sqlchain to access the blockchain files directly, read new blocks and process them without being held back or interfering with node operation.\n\nIt does depend on fixed formats, with 'magic' numbers, and can be broken by new node versions or non-standard changes and so should be regarded as 'experimental'. Also, it is disabled once sqlchain nears full sync and not used for ongoing operation.""",
"""The signature and witness data is needed to verify transaction validity but that has already been done by the underlying node.\n\nThere may be some applications that need to provide signature/witness data for completeness but in many cases it is not required and much disk space can be saved by discarding the data.\n\nFull raw transaction data cannot be requested from sqlchain if signature/witness data is discarded.""",
"""This installs system logrotate config files so that logs get rotated weekly, and compressed for older cycles, saving disk space.\n\nThese configs can be manually edited to alter options (/etc/logrotate.d/...) and during sync it may help to manually rotate as they grow large quickly, eg.\n\nsudo logrotate -f /etc/logrotate.d/sqlchain\n\nwill trigger a rotation."""
]
def initcfg(d, cfg, cointype):
if cfg is not None and d.yesno("Copy last settings for %s?" % cointype.capitalize()) == d.OK:
oldtype = cfg['cointype']
olduser = cfg['coinuser']
for x in cfg:
cfg[x] = cfg[x].replace(oldtype, cointype).replace(olduser, coin_var[cointype][DEF_COIN_USER])
return cfg
dbeng = 'MyISAM' if not os.path.exists('/var/lib/mysql/.rocksdb') else 'RocksDB'
return {
'cointype':cointype,'coindir':"/var/data/"+coin_var[cointype][DATA_DIR],'sqldir':sqlroot+'/'+cointype,'cfgdir':'/etc/sqlchain',
'coinboot':'No','sqlboot':'No','apiboot':'No','coinuser':coin_var[cointype][DEF_COIN_USER],'coinrpc':coin_var[cointype][DEF_COIN_USER],
'dbuser':coin_var[cointype][DEF_COIN_USER],'coinpwd':''.join(random.sample(string.ascii_letters+string.digits,20)),
'dbpwd':''.join(random.sample(string.ascii_letters+string.digits,20)),'coinprune':'No','blkdat':'No','nosigs':'Yes',
'dbname':cointype,'dbeng':dbeng,'wwwdir':'/var/www/'+cointype,'nginx':'/etc/nginx/conf.d/%s.conf' % cointype,
'apidomain':'api.%s.info' % cointype,'sslpath':'/etc/letsencrypt/live/api.%s.info' % cointype,
'listen':"localhost:%d" % coin_var[cointype][DEF_API_PORT],'logrotate':'Yes','coinzmq':'Yes'
}
def sigterm_handler(_signo, _stack_frame):
print "\nClean shutdown"
sys.exit(0)
def doCfg():
d = Dialog(dialog="dialog")
d.set_background_title("sqlChain Config - %s" % version)
if os.geteuid() != 0:
d.msgbox("This program requires admin (root) privileges.\nTry again with: sudo %s" % sys.argv[0],7,55)
return
if not os.path.exists(SQLCHAIN_INSTALL_PATH):
d.msgbox("Please install sqlchain before running config.\neg. sudo pip install sqlchain",7,55)
return
intro = "\nThis program will configure sqlChain for your system.\n\nIt can optionally create the required users, "\
"database, and config files for multiple supported \"coins\". Re-running this can update settings including "\
"passwords but will not clear the database or remove old files.\n\nContinue?"
if d.yesno(intro,15,70) == d.OK:
cfg = None
while True:
code,coins_todo = d.checklist("",15,60, choices=[ (c.capitalize(),'',False) for c in coin_var ],
title='You can choose multiple and configure each in turn:', backtitle='Only One Blockchain Rules Them All',
ok_label='Configure', cancel_label='Quit')
if code in [d.CANCEL,d.ESC]:
break
for cointype_selected in coins_todo:
cfg = doCoinSettings(d, initcfg(d, cfg, cointype_selected.lower()))
def doCoinSettings(d, cfg): # pylint:disable=too-many-branches,too-many-statements
d.set_background_title('sqlChain - %s Settings' % cfg['cointype'].capitalize())
while True:
code,tag = d.menu('%s Settings - Choose a setting to change:' % cfg['cointype'].capitalize(),18,80,
choices=[("(1)", "File Locations => %s, %s" % (cfg['coindir'], cfg['sqldir'])),
("(2)", "System Boot Options => Node:%s, sqlChain:%s, API:%s" % (cfg['coinboot'],cfg['sqlboot'],cfg['apiboot'])),
("(3)", "User Options & Pwds => Node:%s, RPC:%s, DB:%s" % (cfg['coinuser'],cfg['coinrpc'],cfg['dbuser'])),
("(4)", "Operating Modes => Prune:%s, Direct:%s, NoSigs:%s, ZMQ:%s" % (cfg['coinprune'],cfg['blkdat'],cfg['nosigs'],cfg['coinzmq'])),
("(5)", "Database Config => Name:%s, Engine:%s" % (cfg['dbname'],cfg['dbeng'])),
("(6)", "Web/API Server Options => Root:%s, Proxy:%s" % (cfg['wwwdir'],'No' if cfg['nginx'] =='' else 'Yes')),
("", ""),
("(8)", "Configure -> Update ALL Settings" )
], ok_label="Change", menu_height=9)
if code in [d.CANCEL,d.ESC]:
if d.yesno("Canceling will lose changes. Are you sure?",5,48) == d.OK:
return None
elif tag[1] == '1':
code,tmp = d.form("Set paths for sqlchain files:",[
("%s data directory:" % cfg['cointype'].capitalize(),1,0,cfg['coindir'],1,27,50,0),
("sqlChain data directory:",2,0,cfg['sqldir'],2,27,50,0),
("Config directory:",3,0,cfg['cfgdir'],3,27,50,0)
],title="sqlChain Locations")
if code == d.OK:
cfg['coindir'],cfg['sqldir'],cfg['cfgdir'] = tmp
elif tag[1] == '2':
code,tmp = d.checklist("Mark the daemons that should start at boot:", 10, 60, choices=[
('1','%s node' % coin_var[cfg['cointype']][DAEMON_BIN],cfg['coinboot']=='Yes'),
('2','sqlchaind daemon',cfg['sqlboot']=='Yes'),
('3','sqlchain-api daemon',cfg['apiboot']=='Yes')
],title="System Boot Options")
if code == d.OK:
cfg['coinboot'] = 'Yes' if '1' in tmp else 'No'
cfg['sqlboot'] = 'Yes' if '2' in tmp else 'No'
cfg['apiboot'] = 'Yes' if '3' in tmp else 'No'
elif tag[1] == '3':
code,tmp = d.form("Set userid / password (random default):",[
('%s/sqlchain (run as):' % coin_var[cfg['cointype']][DAEMON_BIN],1,0,cfg['coinuser'],1,30,25,10),
('RPC user id:',2,0,cfg['coinrpc'],2,30,25,0),
('RPC password:',3,0,cfg['coinpwd'],3,30,25,0),
('DB user id:',4,0,cfg['dbuser'],4,30,25,0),
('DB password:',5,0,cfg['dbpwd'],5,30,25,0)],title="User Ids / Passwords")
if code == d.OK:
cfg['coinuser'],cfg['coinrpc'],cfg['coinpwd'],cfg['dbuser'],cfg['dbpwd'] = tmp
elif tag[1] == '4':
while True:
code,tmp = d.checklist("Mark the options to enable:", 12, 60, choices=[
('1','Enable %s pruning (save space)' % coin_var[cfg['cointype']][DAEMON_BIN], coin_var[cfg['cointype']][CAN_PRUNE] and cfg['coinprune']=='Yes'),
('2','Direct read blockchain, not RPC (faster)', coin_var[cfg['cointype']][CAN_BLKDAT] and cfg['blkdat']=='Yes'),
('3','Discard signature/witness data (save space)',cfg['nosigs']=='Yes'),
('4','Enable weekly log rotation',cfg['logrotate']=='Yes'),
('5','Enable ZMQ sync with %s'% coin_var[cfg['cointype']][DAEMON_BIN],cfg['coinzmq']=='Yes')
],title="Operating Modes",list_height=5,help_button=True)
if code == d.HELP:
d.msgbox(op_mode_help[int(tmp)-1],20,75)
continue
elif code == d.OK:
cfg['coinprune'] = 'Yes' if coin_var[cfg['cointype']][CAN_PRUNE] and '1' in tmp else 'No'
cfg['blkdat'] = 'Yes' if coin_var[cfg['cointype']][CAN_BLKDAT] and '2' in tmp else 'No'
cfg['nosigs'] = 'Yes' if '3' in tmp else 'No'
cfg['logrotate'] = 'Yes' if '4' in tmp else 'No'
cfg['coinzmq'] = 'Yes' if '5' in tmp else 'No'
break
elif tag[1] == '5':
code,tmp = d.form("",[
('Database Name:',1,0,cfg['dbname'],1,20,12,0,"Any valid sql database name possible. If <dbname>.sql exists in current directory it overrides schema."),
('Database Engine:',2,0,cfg['dbeng'],2,20,12,0,"MyISAM: simple, fast read-only; RocksDB: fast, ~50% space; TokuDB: slower, saves ~50%; InnoDB,Aria: untested.")
],form_height=2,title="Database Options",item_help=True)
if code == d.OK:
cfg['dbname'],cfg['dbeng'] = tmp
elif tag[1] == '6':
code,tmp = d.form("Set web server / proxy options:",[
('Web root directory:',1,0,cfg['wwwdir'],1,40,45,0,"Path to web root (html,js,css) files. Used by sqlchain-api or Nginx depending on proxy setting."),
('Web/API Server Host:Port:',2,0,cfg['listen'],2,40,45,0,"Usually localhost if proxying or testing, or 0.0.0.0:443 for direct public serving with SSL (not recommended)."),
('SSL certificate path:',3,0,cfg['sslpath'],3,40,45,0,"Free SSL cert-authority Lets Encrypt as default. Blank for non-SSL (chg port to 80)."),
('Nginx config path (blank = no proxy):',4,0,cfg['nginx'],4,40,45,0,"Set blank if not using reverse proxy, in which case sqlchain-api serves both files and API."),
('Domain name (if Nginx proxy):',5,0,cfg['apidomain'],5,40,45,0,"Set your (virtual host) domain name if using Nginx to serve web files.")
],title="Web / API Server Options",item_help=True)
if code == d.OK:
cfg['wwwdir'],cfg['listen'],cfg['sslpath'],cfg['nginx'],cfg['apidomain'] = tmp
elif tag[1] == '8':
if d.yesno("Overwrite config files?",5,35) == d.OK:
doUpdate(d, cfg)
return cfg
def doUpdate(d, cfg):
log = CheckDirs(cfg)
log += ConfigSystemd(cfg)
log += SetupDB(d, cfg)
log += ConfigDaemons(cfg)
if cfg['logrotate']:
log += ConfigLogging(cfg)
if cfg['nginx']:
log += ConfigProxy(cfg)
d.msgbox(log,25,80)
def CheckDirs(cfg): #pylint:disable=too-many-branches
log = '\n'
os.chdir(SQLCHAIN_INSTALL_PATH)
## Create user for running coin and sqlchain daemons
try:
usr = pwd.getpwnam(cfg['coinuser'])
except KeyError:
log += "Creating user: %s\n" % cfg['coinuser']
os.system('useradd -r -s /bin/false '+cfg['coinuser'])
usr = pwd.getpwnam(cfg['coinuser'])
### Create directories if not already
if not os.path.exists(cfg['cfgdir']):
log += "Creating directory: %s\n" % cfg['cfgdir']
os.makedirs(cfg['cfgdir'])
os.chown(cfg['cfgdir'], usr.pw_uid, usr.pw_gid)
if not os.path.exists(cfg['coindir']):
log += "Creating directory: %s\n" % cfg['coindir']
os.makedirs(cfg['coindir'])
os.chown(cfg['coindir'], usr.pw_uid, usr.pw_gid)
if not os.path.exists(cfg['sqldir']):
log += "Creating directory: %s\n" % cfg['sqldir']
os.makedirs(cfg['sqldir'])
os.chown(cfg['sqldir'], usr.pw_uid, usr.pw_gid)
if cfg['wwwdir'] in ['n','N','/','none']:
cfg['wwwdir'] = ''
elif not os.path.exists(cfg['wwwdir']):
log += "Creating directory: %s\n" % cfg['wwwdir']
os.makedirs(cfg['wwwdir'])
os.chown(cfg['wwwdir'], usr.pw_uid, usr.pw_gid)
log += "Copying demo web app files."
for root, dirs, files in os.walk('www'):
dst = root[root.index('/'):] if '/' in root else '/'
for d in dirs:
os.mkdir(os.path.join(cfg['wwwdir']+dst, d))
os.chown(os.path.join(cfg['wwwdir']+dst, d), usr.pw_uid, usr.pw_gid)
for f in files:
shutil.copy2(os.path.join(root, f), os.path.join(cfg['wwwdir']+dst, f))
os.chown(os.path.join(cfg['wwwdir']+dst, f), usr.pw_uid, usr.pw_gid)
if cfg['cointype'] != 'bitcoin':
if democvt(os.path.join('www', 'main.html'), os.path.join(cfg['wwwdir'], 'main.html'), cfg['cointype']):
log += " Demo main.html converted to %s\n" % cfg['cointype']
else:
log += " No demo page for %s, using bitcoin\n" % cfg['cointype']
### Create empty data files and set ownership
log += "\n"
for f in ['/blobs.0.dat','/hdrs.dat']:
try:
os.utime(cfg['sqldir']+f, None)
except OSError:
log += "Creating data file: %s" % cfg['sqldir']+f+'\n'
open(cfg['sqldir']+f, 'a').close()
os.chown(cfg['sqldir']+f, usr.pw_uid, usr.pw_gid)
return log
def ConfigSystemd(cfg):
log = '\n'
initsrc = open('etc/systemd.template').read()
coinbin = '/usr/local/bin/'+coin_var[cfg['cointype']][DAEMON_BIN]
if not os.path.exists(coinbin):
coinbin = '/usr/bin/'+coin_var[cfg['cointype']][DAEMON_BIN]
initfile = '/lib/systemd/system/%s.service' % cfg['cointype']
try:
os.utime(initfile, None)
except OSError:
log += "Creating systemd init file: %s\n" % initfile
with open(initfile, 'w') as f:
s = "ExecStart=/sbin/start-stop-daemon --start --pidfile %s/%s.pid --chuid %s:%s --exec %s -- -conf=%s/%s.conf -datadir=%s\n" % (cfg['sqldir'],coin_var[cfg['cointype']][DAEMON_BIN],cfg['coinuser'],cfg['coinuser'],coinbin,cfg['cfgdir'],cfg['cointype'],cfg['coindir'])
f.write(initsrc.replace('ExecStart',s).replace('title','%s Daemon' % coin_var[cfg['cointype']][DAEMON_BIN]))
log += mkSysdBoot(cfg['coinboot'] == 'Yes', '%s.service', cfg['cointype'])
initfile = '/lib/systemd/system/[email protected]'
try:
os.utime(initfile, None)
except OSError:
log += "Creating systemd init file: %s\n" % initfile
with open(initfile, 'w') as f:
s = "ExecStart=/sbin/start-stop-daemon --start --pidfile %s/%%i/daemon.pid --exec /usr/local/bin/sqlchaind -- %s/sqlchain.%%i.cfg\n" % (sqlroot,cfg['cfgdir'])
f.write(initsrc.replace('Type=forking\n','').replace('ExecStart',s).replace('title','SQL Sync Daemon'))
log += mkSysdBoot(cfg['sqlboot'] == 'Yes', 'sqlchain@%s.service', cfg['cointype'])
initfile = '/lib/systemd/system/[email protected]'
try:
os.utime(initfile, None)
except OSError:
log += "Creating systemd init file: %s\n" % initfile
with open(initfile, 'w') as f:
s = "ExecStart=/sbin/start-stop-daemon --start --pidfile %s/%%i/api.pid --exec /usr/local/bin/sqlchain-api -- %s/sqlchain-api.%%i.cfg\n" % (sqlroot,cfg['cfgdir'])
f.write(initsrc.replace('Type=forking\n','').replace('ExecStart',s).replace('title','Web/API Server Daemon'))
log += mkSysdBoot(cfg['coinboot'] == 'Yes', 'sqlchain-api@%s.service', cfg['cointype'])
return log
def mkSysdBoot(boot, target, cointype=''):
if boot and not os.path.exists('/lib/systemd/system/multi-user.target.wants/'+target%cointype):
os.symlink('../'+target%'', '/lib/systemd/system/multi-user.target.wants/'+target%cointype)
return "Inserting "+target%cointype+" boot link\n"
elif not boot and os.path.exists('/lib/systemd/system/multi-user.target.wants/'+target%cointype):
os.unlink('/lib/systemd/system/multi-user.target.wants/'+target%cointype)
return "Removing "+target%cointype+" boot link\n"
return ''
def SetupDB(d, cfg):
log = '\n'
code,rootpwd = d.passwordbox("Enter MySQL root password (to create database & user):",insecure=True)
if code in [d.CANCEL,d.ESC]:
return 'Database setup skipped: canceled by user\n'
sqldef = cwd+'/%s.sql' % cfg['dbname'] # user supplied dbname overrides custom dbname
if not os.path.exists(sqldef):
sqldef = 'etc/%s.sql' % cfg['dbname'] # custom dbname overrides cointype
if not os.path.exists(sqldef):
sqldef = 'etc/%s.sql' % cfg['cointype'] # cointype overrides default
if not os.path.exists(sqldef):
sqldef = 'etc/sqlchain.sql' # default sqlchain schema
log += "Creating MySQL database: %s using schema: %s\n\n" % (cfg['dbname'], os.path.split(sqldef)[1])
try:
sys.stderr = StringIO()
sqlcode = ''
sqlsrc = open(sqldef).read().format(**cfg) # read and replace vars
for line in sqlsrc.splitlines():
if line != '' and line[:2] != '--':
sqlcode += line
sql = db.connect(user='root', passwd=rootpwd)
cur = sql.cursor()
for stmnt in sqlcode.split(';'):
if stmnt:
cur.execute(stmnt)
sqllog = sys.stderr.getvalue()
if len(sqllog) > 0:
log += '---- from mysql server ----\n'+sqllog+'---- end mysql server ----\n'
except (IOError, ImportError):
log += "Cannot open: %s\n" % sqldef
log += "Skipping further MySQL DB setup\n"
except db.Error, e: # pylint:disable=no-member
log += "MySQL Error: %s\n" % str(e)
log += "Skipping further MySQL DB setup\n"
finally:
sys.stderr = sys.__stderr__
return log
def ConfigDaemons(cfg):
log = '\n'
usr = pwd.getpwnam(cfg['coinuser'])
cfgcoin = {}
try: # try to read existing conf, if exists
conf = open(cfg['cfgdir']+'/%s.conf' % cfg['cointype']).read()
log += "Updating file: %s/%s.conf\n" % (cfg['cfgdir'],cfg['cointype'])
for line in conf.splitlines():
if '=' in line:
k,v = line.split('=')
cfgcoin[k] = v
except (IOError, ImportError):
log += "Creating node conf file: %s/%s.conf\n" % (cfg['cfgdir'],cfg['cointype'])
# Write blockchain node conf
cfgcoin.update({'server':1, 'daemon':1, 'prune':1 if cfg['coinprune'] == 'Yes' else 0, 'rpcport':coin_var[cfg['cointype']][DEF_RPC_PORT], \
'datadir':cfg['coindir'], 'pid':cfg['sqldir']+'/%s.pid' % coin_var[cfg['cointype']][DAEMON_BIN], 'disablewallet':1 })
if cfg['coinrpc'] != 'Yes':
cfgcoin.update({'rpcuser':cfg['coinrpc'], 'rpcpassword':cfg['coinpwd'] })
elif 'rpcuser' not in cfgcoin:
cfgcoin.update({'rpcuser':'%s' % coin_var[cfg['cointype']][DEF_COIN_USER], 'rpcpassword':cfg['coinpwd'] })
if cfg['cointype'] == 'testnet':
cfgcoin.update({'testnet':1 })
if cfg['coinzmq'] == 'Yes':
zmqport = coin_var[cfg['cointype']][DEF_RPC_PORT]+100
cfgcoin.update({'zmqpubrawtx':'tcp://127.0.0.1:%d' % zmqport,'zmqpubrawblock':'tcp://127.0.0.1:%d' % zmqport})
with open(cfg['cfgdir']+'/%s.conf' % cfg['cointype'], 'w') as f:
for k in cfgcoin:
f.write("%s=%s\n" % (k,cfgcoin[k]))
os.chown(cfg['cfgdir']+'/%s.conf' % cfg['cointype'], usr.pw_uid, usr.pw_gid)
os.chmod(cfg['cfgdir']+'/%s.conf' % cfg['cointype'], 0660)
### Write sqlchaind.cfg
sqlcfg = { "log": cfg['sqldir']+"/daemon.log", "pid": cfg['sqldir']+"/daemon.pid", "path": cfg['sqldir'], "db": "localhost:%s:%s:%s" % (cfg['dbuser'],cfg['dbpwd'],cfg['dbname']), \
"queue": 8, "rpc": "http://%s:%s@localhost:%d" % (cfgcoin['rpcuser'],cfgcoin['rpcpassword'],coin_var[cfg['cointype']][DEF_RPC_PORT]), \
"debug": False, "user": cfg['coinuser'], "no-sigs": cfg['nosigs'] == 'Yes', "cointype": cfg['cointype'] }
if cfg['blkdat'] == 'Yes':
sqlcfg["blkdat"] = cfg['coindir'] + '/' + coin_var[cfg['cointype']][BLKDAT_DIR]
if cfg['coinzmq'] == 'Yes':
sqlcfg['zmq'] = 'tcp://127.0.0.1:%d' % (coin_var[cfg['cointype']][DEF_RPC_PORT]+100)
log += 'Writing config file: '+cfg['cfgdir']+'/sqlchain.%s.cfg\n' % cfg['cointype']
with open(cfg['cfgdir']+'/sqlchain.%s.cfg' % cfg['cointype'], 'w') as f:
json.dump(sqlcfg, f, indent=2)
os.chown(cfg['cfgdir']+'/sqlchain.%s.cfg' % cfg['cointype'], usr.pw_uid, usr.pw_gid)
os.chmod(cfg['cfgdir']+'/sqlchain.%s.cfg' % cfg['cointype'], 0660)
### Write sqlchain-api.cfg
apicfg = { "www": cfg['wwwdir'], "user": cfg['coinuser'], "db": "localhost:%s:%s:%s" % (cfg['dbuser'],cfg['dbpwd'],cfg['dbname']), "dbinfo": -1, "dbinfo-ts": "0", \
"rpc": "http://%s:%s@localhost:%d" % (cfgcoin['rpcuser'],cfgcoin['rpcpassword'],coin_var[cfg['cointype']][DEF_RPC_PORT]), \
"pool": 4, "log": cfg['sqldir']+"/api.log", "pid": cfg['sqldir']+"/api.pid", "cointype": cfg['cointype'], \
"path": cfg['sqldir'], "debug": False, "block": 0, "listen": "localhost:%d" % coin_var[cfg['cointype']][DEF_API_PORT], "sync": 0,
"apis": [["/api","sqlchain.insight","do_API"],["/bci","sqlchain.bci","do_BCI"],["/rpc", "sqlchain.rpc","do_RPC"],
["/ws","","BCIWebSocket"],["/","","do_Root"]] }
log += 'Writing config file: '+cfg['cfgdir']+'/sqlchain-api.%s.cfg\n' % cfg['cointype']
with open(cfg['cfgdir']+'/sqlchain-api.%s.cfg' % cfg['cointype'], 'w') as f:
json.dump(apicfg, f, indent=2)
os.chown(cfg['cfgdir']+'/sqlchain-api.%s.cfg' % cfg['cointype'], usr.pw_uid, usr.pw_gid)
os.chmod(cfg['cfgdir']+'/sqlchain-api.%s.cfg' % cfg['cointype'], 0660)
return log
def ConfigLogging(cfg):
log = '\n'
logconf = open('etc/node.log.template').read()
logconfpath = '/etc/logrotate.d/sqlchain.%s' % cfg['cointype']
if not os.path.exists(logconfpath):
log += "Creating logrotate file: %s\n" % logconfpath
with open(logconfpath, 'w') as f:
f.write(logconf.format(**cfg))
logconf = open('etc/sqlchain.log.template').read()
logconfpath = '/etc/logrotate.d/%s' % cfg['cointype']
if not os.path.exists(logconfpath):
log += "Creating logrotate file: %s\n" % logconfpath
with open(logconfpath, 'w') as f:
f.write(logconf.format(**cfg))
return log
def ConfigProxy(cfg):
log = '\n'
nginxconf = open('etc/nginx.template').read()
nginx_path,_ = os.path.split(cfg['nginx'])
if not os.path.exists(nginx_path):
log += "Creating directory: %s\n" % nginx_path
os.makedirs(nginx_path)
try:
os.utime(cfg['nginx'], None)
log += "Nginx config exists, not modified: "+cfg['nginx']
except OSError:
log += "Creating nginx config: "+cfg['nginx']
with open(cfg['nginx'], 'w') as f:
f.write(nginxconf.format(**cfg))
return log
if __name__ == '__main__':
signal.signal(signal.SIGINT, sigterm_handler)
locale.setlocale(locale.LC_ALL, '')
doCfg()