-
Notifications
You must be signed in to change notification settings - Fork 0
/
userModeNetwork
executable file
·512 lines (387 loc) · 17.1 KB
/
userModeNetwork
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
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
#!/usr/bin/tclsh
# Copyright IBM Corp. 2016. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set usage {
Usage: userModeNetwork ?... args ...? <nPeers>
Start a Hyperledger fabric peer network as a collection of processes. The only
required argument is the number of peers, which must be greater than 0. The
network configuration, peer server logs and member service logs (for -security
runs) will be written to the directory named by the environment variable
$BUSYWORK_HOME. If BUSYWORK_HOME is not defined, and the -home parameter is
absent, then the subdirectory '.busywork' in the user's home directory is used
as the BUSYWORK_HOME.
Note: Although the peers run in user mode, any chaincodes will still be
deployed in Docker containers. In order for a non-root user to use Docker, the
user must have been set up with this ability in advance of executing this
script, and the user will also need password-less "sudo" permission to clean up
root-owned log files created by containers.
Optional arguments, with defaults after the colon:
-h | -help | --help : N/A
If one of these argument forms is present then this usage message is
printed and the script exits normally.
-home <busywork_home> : See below
This argument can be used to name a BUSYWORK_HOME directory to use for the
network on the command line. If not defined here then BUSYWORK_HOME is
taken from the environmnent, or if not present there, defaults to
~/.busywork.
-interface <interface> : 0.0.0.0
Use the -interface option to explicitly name an interface to use for the
peer network connections. The default is to run locally using all
interfaces, which is equivalent to '-interface 0.0.0.0'. This option may
be useful when creating a network on one system, and then targeting the
system from busywork client drivers or tools from another system. In this
case the $BUSYWORK_HOME/network file created by this script can be copied
to the client system and the peer targeting information will be
correct. Example:
userModeNetwork -interface `hostname` 4
-security | -noSecurity : -noSecurity
Either run with or without secrurity enabled. The default is to run
without security. If -security is enabled then the network will include
the 'membersrvc' server. Peer login credentials are obtained from the
fabric/membersrvc.yaml file.
-privacy | -noPrivacy : -noPrivacy
Controls whether privacy is enabled. This option only has effect if
-security is enabled.
-noops | -batch : -batch
Use one of these options to select the consensus mode. The default
consensus mode is PBFT 'batch' mode. Note that consensus modes other than
-noops require at least 4 peers.
-pristine | -clean | -dirty : -pristine
These options control how much the system environent is "cleaned up" prior
to creating the network.
-pristine (default): All running 'peer' and 'membersrvc' processes owned
by the user are killed. All docker containers hosting chaincodes on the
system are terminated. All chaincode images are deleted. The contents of
the BUSYWORK_HOME are deleted, which may require the script to attempt
this removal under "sudo" to remove root-owned logs.
-clean : UNIMPLEMENTED
-dirty : No cleanup of any kind is done.
-startupWait <duration> : 10s
This is the maximum amount of time to wait for the membersrvc and peer
servers to start after their processes are started, where "startup" is
defined as their main TCP service interface being up and running. The
default timeout of 10 seconds is relatively short to avoid wasting time in
the event that the servers crash at startup.
-scriptLogging : note
This option selects the logging level of this script. The argument is a
case-insensitive string chosen from "debug", "note", "warn" and "error",
and defaults to "note". Script logs are written to stderr.
-peerLogging : warning
This option sets the logging level for the peers in the network. The
full syntax of this option is documented in the fabric documentation, and
defaults to "warning".
-membersrvcLogging : See membersrvc.yaml
NOT IMPLEMENTED. Currently, membersrvc logging levels must be controlled
through the membersrvc.yaml file.
-profile | -noProfile : -profile
Since there is only trivial overhead to starting the profiling server
embedded in the peer, this server is started by default. Use -noProfile to
disable this if necessary. Profiling the membersrvc server is currently
not supported.
-stdio : Logging output goes to $BUSYWORK_HOME
If -stdio is selected, logging output goes to the terminal instead of to
files in $BUSYWORK_HOME. This is a debugging flag.
}
############################################################################
# Helper routines
############################################################################
array set CONSENSUS_TO_PLUGIN {
-noops noops -batch pbft
}
array set CONSENSUS_TO_MODE {
-noops noops -batch batch
}
array set CONSENSUS_TO_PRETTY {
-noops NOOPS
-batch "PBFT Batch"
}
# Create a pristine environment for this network
proc pristine {} {
note {} "Creating a pristine environment"
note {} " Killing all peer and membersrvc processes"
catch {exec pkill peer}
catch {exec pkill membersrvc}
note {} " Killing all running and stopped Docker containers"
catch {exec docker ps -a -q | xargs docker rm -f}
# This is hard to do as an 'exec' from Tcl, so we use the Make target.
note {} " Removing all chaincode containers"
catch {exec make -C [busywork::bin] docker_chaincode_clean}
# Clean out BUSYWORK_HOME. If this fails, we blindly assume that we need
# sudo privledge to clean out Docker logs and try again. That may fail
# too, but we forge ahead anyway, hoping everything will be OK in the end.
note {} " Cleaning out BUSYWORK_HOME"
if {[catch {eval exec rm -rf [glob $::BUSYWORK_HOME/*]}]} {
catch {eval exec sudo rm -rf [glob $::BUSYWORK_HOME/*]}
}
# BUG - Must wipe out the default database.
note {} " Cleaning out /var/hyperledger"
catch {eval exec rm -rf [glob /var/hyperledger/*]}
catch {eval exec sudo rm -rf [glob /var/hyperledger/*]}
}
############################################################################
# The script
############################################################################
# Initilaization and command parsing
lappend auto_path [file dirname [info script]]/../tcl
package require busywork
setLoggingPrefix network
set options {
{enum {-h -help --help} parms(help) 0 p_help}
{key -home parms(home) {}}
{key -interface parms(interface) {} p_interface}
{bool {-security -noSecurity} parms(security) 0}
{bool {-privacy -noPrivacy} parms(privacy) 0}
{enum {-noops -batch} parms(consensus) -batch}
{bool {-profile -noProfile} parms(profile) 1}
{enum {-pristine -clean -dirty} parms(clean) -pristine}
{key -startupWait parms(startupWait) 10s}
{key -scriptLogging parms(scriptLogging) note}
{key -peerLogging parms(peerLogging) warning}
{bool -stdio parms(stdio) 0}
}
# TBD: {key -membersrvcLogging parms(membersrvcLogging) ?}
mapKeywordArgs $argv $options parms(nPeers)
if {$p_help} {
puts $usage
exit 0
}
setLoggingLevel {} [parms scriptLogging]
note {} "$argv0 $argv"
if {![string is integer [parms nPeers]] || ([parms nPeers] < 1)} {
errorExit \
"The number of peers must be a single integer greater than 0"
}
set BUSYWORK_HOME [busywork::home [parms home]]
set FABRIC [busywork::fabric]
# System cleanup
switch -- [parms clean] {
-pristine {
pristine
}
-clean {
errorExit "Sorry, the -clean mode is not yet implememnted"
}
-dirty {
note {} "The network will be created without any cleanup"
}
}
note {} "Running with $CONSENSUS_TO_PRETTY([parms consensus]) consensus"
# In -security mode, parse the membersrvc.yaml file to obtain user names and
# passwords, and make sure that there are enough peers. We assume the peer
# names are test_vp<n>.
if {[parms security]} {
busywork::usersAndPasswordsToArray ::parms security.
parms vpUsers \
[mapeach user [parms security.users] {
if {![string match test_vp* $user]} continue
}]
if {[llength [parms vpUsers]] < [parms nPeers]} {
errorExit \
"There are only [llength [parms vpUsers]] validating peer " \
"user names defined, but [parms nPeers] were requested."
}
}
# The following is a simple approach to creating a user-mode network. Each
# peer needs 5 ports: A gRPC port, a REST API port, an event-hub server port,
# a CLI callback port and a profiling port. We begin by creating dummy
# servers for each required port, simply to reserve the dynamic TCP port
# numbers. As each actual peer is started, we kill the dummy servers and bind
# the peer to the now-free ports.
# The membersrvc server is a bit simpler in that it only requires 1 port,
# however for consistency we go ahead and allocate 4 ports for it as well.
# In the future we may explore what it would take to set up a real network
# bridge and start the processes behind the bridge, but this simple approach
# works for now.
# Allocate/reserve TCP ports dynamically. Note that the fabric requires the
# peers to be named "vp<n>". The membersrvc server does not have a name.
set PORTS_PER_PEER 5
set nServers [parms nPeers]
if {[parms security]} {
incr nServers
}
if {$p_interface} {
set interface "-myaddr [parms interface]"
} else {
set interface {}
}
set peerMap \
[mapeach peer [range $nServers] {
set portMap \
[mapeach port [range $PORTS_PER_PEER] {
set sock [eval socket -server ignore $interface 0]
set sockInfo [chan configure $sock -sockname]
# {<tcl socket> <host name> <TCP port>}
return [list $sock [first $sockInfo] [third $sockInfo]]
}]
set peerID vp$peer
return [list $peer $peerID $portMap]
}]
# peerMap host
proc host {l} {
return [second $l]
}
# peerMap server port
proc port {l} {
return [third $l]
}
# peerMap server address
proc server {l} {
return [second $l]:[third $l]
}
if {[parms security]} {
# We created an extra set of ports for use by membersrvc (Certificate
# Authority); they're peeled off here.
set caMap [last $peerMap]
set peerMap [butlast $peerMap]
}
# Set global configuration environment options that apply to all peers and
# membersrvc.
set ::env(CORE_LOGGING_LEVEL) [parms peerLogging]
set ::env(CORE_VM_ENDPOINT) [busywork::dockerEndpoint]
set ::env(CORE_PEER_ADDRESS_AUTODETECT) true
set ::env(CORE_PEER_PROFILE_ENABLED) [? [parms profile] true false]
set ::env(CORE_PBFT_GENERAL_N) [parms nPeers]
set ::env(CORE_PBFT_GENERAL_MODE) $CONSENSUS_TO_MODE([parms consensus])
set ::env(CORE_PEER_VALIDATOR_CONSENSUS_PLUGIN) \
$CONSENSUS_TO_PLUGIN([parms consensus])
# As we spin up the network we simulataneously create the log for the user as
# well as the $BUSYWORK_HOME/network configuration file.
note {} "Network Port and PID Map:"
note {} "------------------------------------------------------------"
note {} " PeerID | gRPC | REST | Events | CLI | Profile | PID "
note {} "------------------------------------------------------------"
proc networkTable {id grpc rest events cli profile pid} {
note {} [format "%7s | %5s | %5s | %5s | %5s | %5s | %5s" \
$id $grpc $rest $events $cli $profile $pid]
}
set config [open $BUSYWORK_HOME/network w]
puts $config "{"
puts $config " \"networkMode\": \"user\","
puts $config " \"chaincodeMode\": \"vm\","
puts $config " \"host\": \"local\","
puts $config " \"date\": \"[timestamp]\","
puts $config " \"createdBy\": \"userModeNetwork\","
puts $config " \"security\": \"[? [parms security] true false]\","
puts $config " \"privacy\": \"[? [parms privacy] true false]\","
puts $config " \"consensus\": \"$CONSENSUS_TO_MODE([parms consensus])\","
puts $config " \"peerProfileServer\": \"[? [parms profile] true false]\","
# Start membersrvc and wait until the service port is responding before
# continuing.
if {[parms security]} {
exec mkdir -p $BUSYWORK_HOME/membersrvc
if {[parms stdio]} {
set caStdout {}
set caStderr {}
} else {
set caStdout >$BUSYWORK_HOME/membersrvc/stdout
set caStderr 2>$BUSYWORK_HOME/membersrvc/stderr
}
# FABRIC BUG - membersrvc can only run on 7054
#set service [first [third [first $caMap]]]
set service {x 0.0.0.0 7054}
set ::env(SERVER_PORT) :[port $service]
foreach clause [third $caMap] {
close [first $clause]
}
set pid [exec $FABRIC/membersrvc/membersrvc $caStdout $caStderr &]
networkTable CA [port $service] {} {} {} {} $pid
puts $config " \"membersrvc\":"
puts $config " { \"service\": \"[server $service]\","
puts $config " \"pid\": \"$pid\""
puts $config " },"
if {![busywork::wait-for-it [server $service] [parms startupWait]]} {
errorExit \
"The membersrvc server did not start up within [parms startupWait]"
}
set ::env(CORE_PEER_PKI_ECA_PADDR) [server $service]
set ::env(CORE_PEER_PKI_TCA_PADDR) [server $service]
set ::env(CORE_PEER_PKI_TLSCA_PADDR) [server $service]
}
# Now start the peers
puts $config " \"peers\": \["
foreach clause $peerMap {
foreach {peerN peerID portMap} $clause break
exec mkdir -p $BUSYWORK_HOME/$peerID
set peerDatabase $BUSYWORK_HOME/$peerID/data
if {[parms stdio]} {
set peerStdout {}
set peerStderr {}
} else {
set peerStdout >$BUSYWORK_HOME/$peerID/stdout
set peerStderr 2>$BUSYWORK_HOME/$peerID/stderr
}
set grpc [first $portMap]
set rest [second $portMap]
set events [third $portMap]
set cli [fourth $portMap]
set profile [fifth $portMap]
set ::env(CORE_PEER_ID) $peerID
set ::env(CORE_PEER_FILESYSTEMPATH) $peerDatabase
set ::env(CORE_PEER_ADDRESS) [server $grpc]
set ::env(CORE_PEER_LISTENADDRESS) [server $grpc]
set ::env(CORE_REST_ADDRESS) [server $rest]
set ::env(CORE_PEER_VALIDATOR_EVENTS_ADDRESS) [server $events]
set ::env(CORE_CLI_ADDRESS) [server $cli]
set ::env(CORE_PEER_PROFILE_LISTENADDRESS) [server $profile]
if {[parms nPeers] > 1} {
if {$peerN == 0} {
set peer0Address [server $grpc]
} else {
set ::env(CORE_PEER_DISCOVERY_ROOTNODE) $peer0Address
}
}
if {[parms security]} {
set user test_vp$peerN
set password [parms security.user.$user.password]
set ::env(CORE_SECURITY_ENROLLID) $user
set ::env(CORE_SECURITY_ENROLLSECRET) $password
set ::env(CORE_SECURITY_ENABLED) true
set ::env(CORE_SECURITY_PRIVACY) [? [parms privacy] true false]
} else {
set ::env(CORE_SECURITY_ENABLED) false
}
foreach clause $portMap {
close [first $clause]
}
set pid [exec $FABRIC/peer/peer node start $peerStdout $peerStderr &]
networkTable $peerID [port $grpc] [port $rest] [port $events] \
[port $cli] [port $profile] $pid
if {$peerN != 0} {
puts $config " ,"
}
puts $config " { \"id\": \"$peerID\","
puts $config " \"grpc\": \"[server $grpc]\","
puts $config " \"rest\": \"[server $rest]\","
puts $config " \"events\": \"[server $events]\","
puts $config " \"cli\": \"[server $cli]\","
puts $config " \"profile\": \"[server $profile]\","
puts $config " \"pid\": \"$pid\""
puts $config " }"
}
note {} "------------------------------------------------------------"
puts $config " \]"
puts $config "}"
close $config
# Now, having started the peers, we will wait for their REST ports to be
# active before exiting.
note {} "Waiting for peers to start"
foreach clause $peerMap {
foreach {peerN peerID portMap} $clause break
set rest [second $portMap]
if {![busywork::wait-for-it [server $rest] [parms startupWait]]} {
errorExit \
"Peer $peerN, $peerID, did not start within [parms startupWait]"
}
}
note {} "Network is up"