Skip to content

Commit e1f8404

Browse files
authored
Merge pull request #4161 from onflow/petera/refactor-localnet-bootstrap
[Localnet] Refactor localnet to clean up port allocation
2 parents 81cd1cb + ee65539 commit e1f8404

File tree

4 files changed

+255
-90
lines changed

4 files changed

+255
-90
lines changed

integration/localnet/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
/trie/
55
docker-compose.nodes.yml
66
targets.nodes.json
7+
ports.nodes.json

integration/localnet/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ else
4646
go run -tags relic \
4747
-ldflags="-X 'github.com/onflow/flow-go/cmd/build.commit=${COMMIT}' \
4848
-X 'github.com/onflow/flow-go/cmd/build.semver=${VERSION}'" \
49-
bootstrap.go \
49+
builder/*.go \
5050
-loglevel=$(LOGLEVEL) \
5151
-collection=$(COLLECTION) \
5252
-consensus=$(CONSENSUS) \
Lines changed: 76 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"os"
1111
"path/filepath"
1212
"runtime"
13-
"strconv"
1413
"time"
1514

1615
"github.com/go-yaml/yaml"
@@ -30,10 +29,11 @@ const (
3029
DockerComposeFile = "./docker-compose.nodes.yml"
3130
DockerComposeFileVersion = "3.7"
3231
PrometheusTargetsFile = "./targets.nodes.json"
33-
DefaultObserverName = "observer"
32+
PortMapFile = "./ports.nodes.json"
33+
DefaultObserverRole = "observer"
3434
DefaultLogLevel = "DEBUG"
3535
DefaultGOMAXPROCS = 8
36-
DefaultMaxObservers = 1000
36+
DefaultMaxObservers = 100
3737
DefaultCollectionCount = 3
3838
DefaultConsensusCount = 3
3939
DefaultExecutionCount = 1
@@ -48,15 +48,6 @@ const (
4848
DefaultExtensiveTracing = false
4949
DefaultConsensusDelay = 800 * time.Millisecond
5050
DefaultCollectionDelay = 950 * time.Millisecond
51-
AccessAPIPort = 3569
52-
AccessPubNetworkPort = 1234
53-
ExecutionAPIPort = 3600
54-
MetricsPort = 8080
55-
RPCPort = 9000
56-
SecuredRPCPort = 9001
57-
AdminToolPort = 9002
58-
AdminToolLocalPort = 3700
59-
HTTPPort = 8000
6051
)
6152

6253
var (
@@ -78,6 +69,8 @@ var (
7869
consensusDelay time.Duration
7970
collectionDelay time.Duration
8071
logLevel string
72+
73+
ports *PortAllocator
8174
)
8275

8376
func init() {
@@ -119,6 +112,9 @@ func generateBootstrapData(flowNetworkConf testnet.NetworkConfig) []testnet.Cont
119112
func main() {
120113
flag.Parse()
121114

115+
// Allocate blocks of IPs for each node
116+
ports = NewPortAllocator()
117+
122118
// Prepare test node configurations of each type, access, execution, verification, etc
123119
flowNodes := prepareFlowNodes()
124120

@@ -155,8 +151,12 @@ func main() {
155151
panic(err)
156152
}
157153

154+
if err = ports.WriteMappingConfig(); err != nil {
155+
panic(err)
156+
}
157+
158158
fmt.Print("Bootstrapping success!\n\n")
159-
displayPortAssignments()
159+
ports.Print()
160160
fmt.Println()
161161

162162
fmt.Println("Run \"make start\" to re-build images and launch the network.")
@@ -171,20 +171,6 @@ func displayFlowNetworkConf(flowNetworkConf testnet.NetworkConfig) {
171171
fmt.Printf("- DKG Phase Length: %d\n", flowNetworkConf.ViewsInDKGPhase)
172172
}
173173

174-
func displayPortAssignments() {
175-
for i := 0; i < accessCount; i++ {
176-
fmt.Printf("Access %d Flow API will be accessible at localhost:%d\n", i+1, AccessAPIPort+i)
177-
fmt.Printf("Access %d public libp2p access will be accessible at localhost:%d\n\n", i+1, AccessPubNetworkPort+i)
178-
}
179-
for i := 0; i < executionCount; i++ {
180-
fmt.Printf("Execution API %d will be accessible at localhost:%d\n", i+1, ExecutionAPIPort+i)
181-
}
182-
fmt.Println()
183-
for i := 0; i < observerCount; i++ {
184-
fmt.Printf("Observer %d Flow API will be accessible at localhost:%d\n", i+1, (accessCount*2)+(AccessAPIPort)+2*i)
185-
}
186-
}
187-
188174
func prepareCommonHostFolders() {
189175
for _, dir := range []string{BootstrapDir, ProfilerDir, DataDir, TrieDir} {
190176
if err := os.RemoveAll(dir); err != nil && !errors.Is(err, fs.ErrNotExist) {
@@ -245,6 +231,14 @@ type Service struct {
245231
Volumes []string
246232
Ports []string `yaml:"ports,omitempty"`
247233
Labels map[string]string
234+
235+
name string // don't export
236+
}
237+
238+
func (s *Service) AddExposedPorts(containerPorts ...string) {
239+
for _, port := range containerPorts {
240+
s.Ports = append(s.Ports, fmt.Sprintf("%s:%s", ports.HostPort(s.name, port), port))
241+
}
248242
}
249243

250244
// Build ...
@@ -321,7 +315,7 @@ func prepareServiceDirs(role string, nodeId string) (string, string) {
321315
func prepareService(container testnet.ContainerConfig, i int, n int) Service {
322316
dataDir, profilerDir := prepareServiceDirs(container.Role.String(), container.NodeID.String())
323317

324-
service := defaultService(container.Role.String(), dataDir, profilerDir, i)
318+
service := defaultService(container.ContainerName, container.Role.String(), dataDir, profilerDir, i)
325319
service.Command = append(service.Command,
326320
fmt.Sprintf("--nodeid=%s", container.NodeID),
327321
)
@@ -341,8 +335,7 @@ func prepareConsensusService(container testnet.ContainerConfig, i int, n int) Se
341335
service := prepareService(container, i, n)
342336

343337
timeout := 1200*time.Millisecond + consensusDelay
344-
service.Command = append(
345-
service.Command,
338+
service.Command = append(service.Command,
346339
fmt.Sprintf("--block-rate-delay=%s", consensusDelay),
347340
fmt.Sprintf("--hotstuff-min-timeout=%s", timeout),
348341
"--chunk-alpha=1",
@@ -351,25 +344,16 @@ func prepareConsensusService(container testnet.ContainerConfig, i int, n int) Se
351344
"--access-node-ids=*",
352345
)
353346

354-
service.Ports = []string{
355-
fmt.Sprintf("%d:%d", AdminToolLocalPort+n, AdminToolPort),
356-
}
357-
358347
return service
359348
}
360349

361350
func prepareVerificationService(container testnet.ContainerConfig, i int, n int) Service {
362351
service := prepareService(container, i, n)
363352

364-
service.Command = append(
365-
service.Command,
353+
service.Command = append(service.Command,
366354
"--chunk-alpha=1",
367355
)
368356

369-
service.Ports = []string{
370-
fmt.Sprintf("%d:%d", AdminToolLocalPort+n, AdminToolPort),
371-
}
372-
373357
return service
374358
}
375359

@@ -378,19 +362,14 @@ func prepareCollectionService(container testnet.ContainerConfig, i int, n int) S
378362
service := prepareService(container, i, n)
379363

380364
timeout := 1200*time.Millisecond + collectionDelay
381-
service.Command = append(
382-
service.Command,
365+
service.Command = append(service.Command,
383366
fmt.Sprintf("--block-rate-delay=%s", collectionDelay),
384367
fmt.Sprintf("--hotstuff-min-timeout=%s", timeout),
385-
fmt.Sprintf("--ingress-addr=%s:%d", container.ContainerName, RPCPort),
368+
fmt.Sprintf("--ingress-addr=%s:%s", container.ContainerName, testnet.GRPCPort),
386369
"--insecure-access-api=false",
387370
"--access-node-ids=*",
388371
)
389372

390-
service.Ports = []string{
391-
fmt.Sprintf("%d:%d", AdminToolLocalPort+n, AdminToolPort),
392-
}
393-
394373
return service
395374
}
396375

@@ -411,25 +390,19 @@ func prepareExecutionService(container testnet.ContainerConfig, i int, n int) Se
411390
panic(err)
412391
}
413392

414-
service.Command = append(
415-
service.Command,
393+
service.Command = append(service.Command,
416394
"--triedir=/trie",
417-
fmt.Sprintf("--rpc-addr=%s:%d", container.ContainerName, RPCPort),
395+
fmt.Sprintf("--rpc-addr=%s:%s", container.ContainerName, testnet.GRPCPort),
418396
fmt.Sprintf("--cadence-tracing=%t", cadenceTracing),
419397
fmt.Sprintf("--extensive-tracing=%t", extesiveTracing),
420398
"--execution-data-dir=/data/execution-data",
421399
)
422400

423-
service.Volumes = append(
424-
service.Volumes,
401+
service.Volumes = append(service.Volumes,
425402
fmt.Sprintf("%s:/trie:z", trieDir),
426403
)
427404

428-
service.Ports = []string{
429-
fmt.Sprintf("%d:%d", ExecutionAPIPort+2*i, RPCPort),
430-
fmt.Sprintf("%d:%d", ExecutionAPIPort+(2*i+1), SecuredRPCPort),
431-
fmt.Sprintf("%d:%d", AdminToolLocalPort+n, AdminToolPort),
432-
}
405+
service.AddExposedPorts(testnet.GRPCPort)
433406

434407
return service
435408
}
@@ -438,25 +411,29 @@ func prepareAccessService(container testnet.ContainerConfig, i int, n int) Servi
438411
service := prepareService(container, i, n)
439412

440413
service.Command = append(service.Command,
441-
fmt.Sprintf("--rpc-addr=%s:%d", container.ContainerName, RPCPort),
442-
fmt.Sprintf("--secure-rpc-addr=%s:%d", container.ContainerName, SecuredRPCPort),
443-
fmt.Sprintf("--http-addr=%s:%d", container.ContainerName, HTTPPort),
444-
fmt.Sprintf("--collection-ingress-port=%d", RPCPort),
414+
fmt.Sprintf("--rpc-addr=%s:%s", container.ContainerName, testnet.GRPCPort),
415+
fmt.Sprintf("--secure-rpc-addr=%s:%s", container.ContainerName, testnet.GRPCSecurePort),
416+
fmt.Sprintf("--http-addr=%s:%s", container.ContainerName, testnet.GRPCWebPort),
417+
fmt.Sprintf("--rest-addr=%s:%s", container.ContainerName, testnet.RESTPort),
418+
fmt.Sprintf("--state-stream-addr=%s:%s", container.ContainerName, testnet.ExecutionStatePort),
419+
fmt.Sprintf("--collection-ingress-port=%s", testnet.GRPCPort),
445420
"--supports-observer=true",
446-
fmt.Sprintf("--public-network-address=%s:%d", container.ContainerName, AccessPubNetworkPort),
421+
fmt.Sprintf("--public-network-address=%s:%s", container.ContainerName, testnet.PublicNetworkPort),
447422
"--log-tx-time-to-finalized",
448423
"--log-tx-time-to-executed",
449424
"--log-tx-time-to-finalized-executed",
450425
"--execution-data-sync-enabled=true",
451426
"--execution-data-dir=/data/execution-data",
452427
)
453428

454-
service.Ports = []string{
455-
fmt.Sprintf("%d:%d", AccessPubNetworkPort+i, AccessPubNetworkPort),
456-
fmt.Sprintf("%d:%d", AccessAPIPort+2*i, RPCPort),
457-
fmt.Sprintf("%d:%d", AccessAPIPort+(2*i+1), SecuredRPCPort),
458-
fmt.Sprintf("%d:%d", AdminToolLocalPort+n, AdminToolPort),
459-
}
429+
service.AddExposedPorts(
430+
testnet.GRPCPort,
431+
testnet.GRPCSecurePort,
432+
testnet.GRPCWebPort,
433+
testnet.RESTPort,
434+
testnet.ExecutionStatePort,
435+
testnet.PublicNetworkPort,
436+
)
460437

461438
return service
462439
}
@@ -465,35 +442,41 @@ func prepareObserverService(i int, observerName string, agPublicKey string) Serv
465442
// Observers have a unique naming scheme omitting node id being on the public network
466443
dataDir, profilerDir := prepareServiceDirs(observerName, "")
467444

468-
observerService := defaultService(DefaultObserverName, dataDir, profilerDir, i)
469-
observerService.Command = append(observerService.Command,
470-
fmt.Sprintf("--bootstrap-node-addresses=%s:%d", testnet.PrimaryAN, AccessPubNetworkPort),
445+
service := defaultService(observerName, DefaultObserverRole, dataDir, profilerDir, i)
446+
service.Command = append(service.Command,
447+
fmt.Sprintf("--bootstrap-node-addresses=%s:%s", testnet.PrimaryAN, testnet.PublicNetworkPort),
471448
fmt.Sprintf("--bootstrap-node-public-keys=%s", agPublicKey),
472-
fmt.Sprintf("--upstream-node-addresses=%s:%d", testnet.PrimaryAN, SecuredRPCPort),
449+
fmt.Sprintf("--upstream-node-addresses=%s:%s", testnet.PrimaryAN, testnet.GRPCSecurePort),
473450
fmt.Sprintf("--upstream-node-public-keys=%s", agPublicKey),
474451
fmt.Sprintf("--observer-networking-key-path=/bootstrap/private-root-information/%s_key", observerName),
475452
"--bind=0.0.0.0:0",
476-
fmt.Sprintf("--rpc-addr=%s:%d", observerName, RPCPort),
477-
fmt.Sprintf("--secure-rpc-addr=%s:%d", observerName, SecuredRPCPort),
478-
fmt.Sprintf("--http-addr=%s:%d", observerName, HTTPPort),
453+
fmt.Sprintf("--rpc-addr=%s:%s", observerName, testnet.GRPCPort),
454+
fmt.Sprintf("--secure-rpc-addr=%s:%s", observerName, testnet.GRPCSecurePort),
455+
fmt.Sprintf("--http-addr=%s:%s", observerName, testnet.GRPCWebPort),
456+
)
457+
458+
service.AddExposedPorts(
459+
testnet.GRPCPort,
460+
testnet.GRPCSecurePort,
461+
testnet.GRPCWebPort,
462+
testnet.AdminPort,
479463
)
480464

481465
// observer services rely on the access gateway
482-
observerService.DependsOn = append(observerService.DependsOn, testnet.PrimaryAN)
483-
observerService.Ports = []string{
484-
// Flow API ports come in pairs, open and secure. While the guest port is always
485-
// the same from the guest's perspective, the host port numbering accounts for the presence
486-
// of multiple pairs of listeners on the host to avoid port collisions. Observer listener pairs
487-
// are numbered just after the Access listeners on the host network by prior convention
488-
fmt.Sprintf("%d:%d", (accessCount*2)+AccessAPIPort+(2*i), RPCPort),
489-
fmt.Sprintf("%d:%d", (accessCount*2)+AccessAPIPort+(2*i)+1, SecuredRPCPort),
490-
}
491-
return observerService
466+
service.DependsOn = append(service.DependsOn, testnet.PrimaryAN)
467+
468+
return service
492469
}
493470

494-
func defaultService(role, dataDir, profilerDir string, i int) Service {
471+
func defaultService(name, role, dataDir, profilerDir string, i int) Service {
472+
err := ports.AllocatePorts(name, role)
473+
if err != nil {
474+
panic(err)
475+
}
476+
495477
num := fmt.Sprintf("%03d", i+1)
496478
service := Service{
479+
name: name,
497480
Image: fmt.Sprintf("localnet-%s", role),
498481
Command: []string{
499482
"--bootstrapdir=/bootstrap",
@@ -505,7 +488,7 @@ func defaultService(role, dataDir, profilerDir string, i int) Service {
505488
fmt.Sprintf("--tracer-enabled=%t", tracing),
506489
"--profiler-dir=/profiler",
507490
"--profiler-interval=2m",
508-
fmt.Sprintf("--admin-addr=0.0.0.0:%d", AdminToolPort),
491+
fmt.Sprintf("--admin-addr=0.0.0.0:%s", testnet.AdminPort),
509492
},
510493
Volumes: []string{
511494
fmt.Sprintf("%s:/bootstrap:z", BootstrapDir),
@@ -525,6 +508,8 @@ func defaultService(role, dataDir, profilerDir string, i int) Service {
525508
},
526509
}
527510

511+
service.AddExposedPorts(testnet.AdminPort)
512+
528513
if i == 0 {
529514
// only specify build config for first service of each role
530515
service.Build = Build{
@@ -553,6 +538,7 @@ func writeDockerComposeConfig(services Services) error {
553538
if err != nil {
554539
return err
555540
}
541+
defer f.Close()
556542

557543
network := Network{
558544
Version: DockerComposeFileVersion,
@@ -585,7 +571,7 @@ func prepareServiceDiscovery(containers []testnet.ContainerConfig) PrometheusSer
585571
for _, container := range containers {
586572
counters[container.Role]++
587573
pt := PrometheusTarget{
588-
Targets: []string{net.JoinHostPort(container.ContainerName, strconv.Itoa(MetricsPort))},
574+
Targets: []string{net.JoinHostPort(container.ContainerName, testnet.MetricsPort)},
589575
Labels: map[string]string{
590576
"job": "flow",
591577
"role": container.Role.String(),
@@ -604,6 +590,7 @@ func writePrometheusConfig(serviceDisc PrometheusServiceDiscovery) error {
604590
if err != nil {
605591
return err
606592
}
593+
defer f.Close()
607594

608595
enc := json.NewEncoder(f)
609596

@@ -670,7 +657,7 @@ func prepareObserverServices(dockerServices Services, flowNodeContainerConfigs [
670657
}
671658

672659
for i := 0; i < observerCount; i++ {
673-
observerName := fmt.Sprintf("%s_%d", DefaultObserverName, i+1)
660+
observerName := fmt.Sprintf("%s_%d", DefaultObserverRole, i+1)
674661
observerService := prepareObserverService(i, observerName, agPublicKey)
675662

676663
// Add a docker container for this named Observer

0 commit comments

Comments
 (0)