Skip to content

Commit e910983

Browse files
authored
Use concrete artifacts on services (#121)
* Use concrete artifacts * Change one thing * Add fix
1 parent 9973d99 commit e910983

File tree

4 files changed

+154
-30
lines changed

4 files changed

+154
-30
lines changed

internal/artifacts.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,19 @@ func (o *output) Remove(path string) error {
433433
return os.RemoveAll(filepath.Join(o.dst, path))
434434
}
435435

436+
// CreateDir creates a new dir in the output folder and returns the
437+
// absolute file path
438+
func (o *output) CreateDir(path string) (string, error) {
439+
absPath, err := filepath.Abs(filepath.Join(o.dst, path))
440+
if err != nil {
441+
return "", err
442+
}
443+
if err := os.MkdirAll(absPath, 0755); err != nil {
444+
return "", fmt.Errorf("failed to create directory: %w", err)
445+
}
446+
return absPath, nil
447+
}
448+
436449
func (o *output) CopyFile(src string, dst string) error {
437450
// Open the source file
438451
sourceFile, err := os.Open(src)

internal/components.go

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ func (r *RollupBoost) Run(service *service, ctx *ExContext) {
2222
WithTag("0.4rc1").
2323
WithArgs(
2424
"--rpc-port", `{{Port "authrpc" 8551}}`,
25-
"--l2-jwt-path", "{{.Dir}}/jwtsecret",
25+
"--l2-jwt-path", "/data/jwtsecret",
2626
"--l2-url", Connect(r.ELNode, "authrpc"),
27-
"--builder-jwt-path", "{{.Dir}}/jwtsecret",
27+
"--builder-jwt-path", "/data/jwtsecret",
2828
"--builder-url", r.Builder,
29-
)
29+
).WithArtifact("/data/jwtsecret", "jwtsecret")
3030
}
3131

3232
func (r *RollupBoost) Name() string {
@@ -82,12 +82,12 @@ func (o *OpNode) Run(service *service, ctx *ExContext) {
8282
"--l1.epoch-poll-interval", "12s",
8383
"--l1.http-poll-interval", "6s",
8484
"--l2", Connect(o.L2Node, "authrpc"),
85-
"--l2.jwt-secret", "{{.Dir}}/jwtsecret",
85+
"--l2.jwt-secret", "/data/jwtsecret",
8686
"--sequencer.enabled",
8787
"--sequencer.l1-confs", "0",
8888
"--verifier.l1-confs", "0",
8989
"--p2p.sequencer.key", "8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba",
90-
"--rollup.config", "{{.Dir}}/rollup.json",
90+
"--rollup.config", "/data/rollup.json",
9191
"--rpc.addr", "0.0.0.0",
9292
"--rpc.port", `{{Port "http" 8549}}`,
9393
"--p2p.listen.ip", "0.0.0.0",
@@ -100,8 +100,11 @@ func (o *OpNode) Run(service *service, ctx *ExContext) {
100100
"--metrics.port", `{{Port "metrics" 7300}}`,
101101
"--pprof.enabled",
102102
"--rpc.enable-admin",
103-
"--safedb.path", "{{.Dir}}/db",
104-
)
103+
"--safedb.path", "/data_db",
104+
).
105+
WithArtifact("/data/jwtsecret", "jwtsecret").
106+
WithArtifact("/data/rollup.json", "rollup.json").
107+
WithVolume("data", "/data_db")
105108
}
106109

107110
func (o *OpNode) Name() string {
@@ -135,7 +138,7 @@ func logLevelToGethVerbosity(logLevel LogLevel) string {
135138
func (o *OpGeth) Run(service *service, ctx *ExContext) {
136139
var nodeKeyFlag string
137140
if o.UseDeterministicP2PKey {
138-
nodeKeyFlag = "--nodekey {{.Dir}}/deterministic_p2p_key.txt "
141+
nodeKeyFlag = "--nodekey /data/deterministic_p2p_key.txt "
139142
}
140143

141144
service.
@@ -145,9 +148,9 @@ func (o *OpGeth) Run(service *service, ctx *ExContext) {
145148
WithLabel("metrics_path", "/debug/metrics/prometheus").
146149
WithArgs(
147150
"-c",
148-
"geth init --datadir {{.Dir}}/data_opgeth --state.scheme hash {{.Dir}}/l2-genesis.json && "+
151+
"geth init --datadir /data_opgeth --state.scheme hash /data/l2-genesis.json && "+
149152
"exec geth "+
150-
"--datadir {{.Dir}}/data_opgeth "+
153+
"--datadir /data_opgeth "+
151154
"--verbosity "+logLevelToGethVerbosity(ctx.LogLevel)+" "+
152155
"--http "+
153156
"--http.corsdomain \"*\" "+
@@ -167,15 +170,19 @@ func (o *OpGeth) Run(service *service, ctx *ExContext) {
167170
"--authrpc.addr 0.0.0.0 "+
168171
"--authrpc.port "+`{{Port "authrpc" 8551}} `+
169172
"--authrpc.vhosts \"*\" "+
170-
"--authrpc.jwtsecret {{.Dir}}/jwtsecret "+
173+
"--authrpc.jwtsecret /data/jwtsecret "+
171174
"--gcmode archive "+
172175
"--state.scheme hash "+
173176
"--port "+`{{Port "rpc" 30303}} `+
174177
nodeKeyFlag+
175178
"--metrics "+
176179
"--metrics.addr 0.0.0.0 "+
177180
"--metrics.port "+`{{Port "metrics" 6061}}`,
178-
)
181+
).
182+
WithVolume("data", "/data_opgeth").
183+
WithArtifact("/data/l2-genesis.json", "l2-genesis.json").
184+
WithArtifact("/data/jwtsecret", "jwtsecret").
185+
WithArtifact("/data/deterministic_p2p_key.txt", "deterministic_p2p_key.txt")
179186
}
180187

181188
func (o *OpGeth) Name() string {
@@ -253,10 +260,10 @@ func (r *RethEL) Run(svc *service, ctx *ExContext) {
253260
WithEntrypoint("/usr/local/bin/reth").
254261
WithArgs(
255262
"node",
256-
"--chain", "{{.Dir}}/genesis.json",
257-
"--datadir", "{{.Dir}}/data_reth",
263+
"--chain", "/data/genesis.json",
264+
"--datadir", "/data_reth",
258265
"--color", "never",
259-
"--ipcpath", "{{.Dir}}/reth.ipc",
266+
"--ipcpath", "/data_reth/reth.ipc",
260267
"--addr", "127.0.0.1",
261268
"--port", `{{Port "rpc" 30303}}`,
262269
// "--disable-discovery",
@@ -267,12 +274,15 @@ func (r *RethEL) Run(svc *service, ctx *ExContext) {
267274
"--http.port", `{{Port "http" 8545}}`,
268275
"--authrpc.port", `{{Port "authrpc" 8551}}`,
269276
"--authrpc.addr", "0.0.0.0",
270-
"--authrpc.jwtsecret", "{{.Dir}}/jwtsecret",
277+
"--authrpc.jwtsecret", "/data/jwtsecret",
271278
"--metrics", `0.0.0.0:{{Port "metrics" 9090}}`,
272279
// For reth version 1.2.0 the "legacy" engine was removed, so we now require these arguments:
273280
"--engine.persistence-threshold", "0", "--engine.memory-block-buffer-target", "0",
274281
logLevelToRethVerbosity(ctx.LogLevel),
275-
)
282+
).
283+
WithArtifact("/data/genesis.json", "genesis.json").
284+
WithArtifact("/data/jwtsecret", "jwtsecret").
285+
WithVolume("data", "/data_reth")
276286

277287
if r.UseNativeReth {
278288
// we need to use this otherwise the db cannot be binded
@@ -303,8 +313,8 @@ func (l *LighthouseBeaconNode) Run(svc *service, ctx *ExContext) {
303313
WithEntrypoint("lighthouse").
304314
WithArgs(
305315
"bn",
306-
"--datadir", "{{.Dir}}/data_beacon_node",
307-
"--testnet-dir", "{{.Dir}}/testnet",
316+
"--datadir", "/data_beacon",
317+
"--testnet-dir", "/data/testnet-dir",
308318
"--enable-private-discovery",
309319
"--disable-peer-scoring",
310320
"--staking",
@@ -321,11 +331,14 @@ func (l *LighthouseBeaconNode) Run(svc *service, ctx *ExContext) {
321331
"--disable-packet-filter",
322332
"--target-peers", "0",
323333
"--execution-endpoint", Connect(l.ExecutionNode, "authrpc"),
324-
"--execution-jwt", "{{.Dir}}/jwtsecret",
334+
"--execution-jwt", "/data/jwtsecret",
325335
"--always-prepare-payload",
326336
"--prepare-payload-lookahead", "8000",
327337
"--suggested-fee-recipient", "0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990",
328338
).
339+
WithArtifact("/data/testnet-dir", "testnet").
340+
WithArtifact("/data/jwtsecret", "jwtsecret").
341+
WithVolume("data", "/data_beacon").
329342
WithReady(ReadyCheck{
330343
QueryURL: "http://localhost:3500/eth/v1/node/syncing",
331344
Interval: 1 * time.Second,
@@ -359,14 +372,16 @@ func (l *LighthouseValidator) Run(service *service, ctx *ExContext) {
359372
WithEntrypoint("lighthouse").
360373
WithArgs(
361374
"vc",
362-
"--datadir", "{{.Dir}}/data_validator",
363-
"--testnet-dir", "{{.Dir}}/testnet",
375+
"--datadir", "/data/validator",
376+
"--testnet-dir", "/data/testnet-dir",
364377
"--init-slashing-protection",
365378
"--beacon-nodes", Connect(l.BeaconNode, "http"),
366379
"--suggested-fee-recipient", "0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990",
367380
"--builder-proposals",
368381
"--prefer-builder-proposals",
369-
)
382+
).
383+
WithArtifact("/data/validator", "data_validator").
384+
WithArtifact("/data/testnet-dir", "testnet")
370385
}
371386

372387
func (l *LighthouseValidator) Name() string {
@@ -512,16 +527,19 @@ func (o *OpReth) Run(service *service, ctx *ExContext) {
512527
"node",
513528
"--authrpc.port", `{{Port "authrpc" 8551}}`,
514529
"--authrpc.addr", "0.0.0.0",
515-
"--authrpc.jwtsecret", "{{.Dir}}/jwtsecret",
530+
"--authrpc.jwtsecret", "/data/jwtsecret",
516531
"--http",
517532
"--http.addr", "0.0.0.0",
518533
"--http.port", `{{Port "http" 8545}}`,
519-
"--chain", "{{.Dir}}/l2-genesis.json",
520-
"--datadir", "{{.Dir}}/data_op_reth",
534+
"--chain", "/data/l2-genesis.json",
535+
"--datadir", "/data_op_reth",
521536
"--disable-discovery",
522537
"--color", "never",
523538
"--metrics", `0.0.0.0:{{Port "metrics" 9090}}`,
524-
"--port", `{{Port "rpc" 30303}}`)
539+
"--port", `{{Port "rpc" 30303}}`).
540+
WithArtifact("/data/jwtsecret", "jwtsecret").
541+
WithArtifact("/data/l2-genesis.json", "l2-genesis.json").
542+
WithVolume("data", "/data_op_reth")
525543
}
526544

527545
func (o *OpReth) Name() string {

internal/local_runner.go

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net"
88
"os"
99
"os/exec"
10+
"path/filepath"
1011
"runtime"
1112
"strings"
1213
"sync"
@@ -562,14 +563,34 @@ func (d *LocalRunner) toDockerComposeService(s *service) (map[string]interface{}
562563
labels[fmt.Sprintf("port.%s", port.Name)] = fmt.Sprintf("%d", port.Port)
563564
}
564565

566+
// Use files mapped to figure out which files from the artifacts is using the service
567+
volumes := map[string]string{
568+
outputFolder: "/artifacts", // placeholder
569+
}
570+
for k, v := range s.filesMapped {
571+
volumes[filepath.Join(outputFolder, v)] = k
572+
}
573+
574+
// create the bind volumes
575+
for localPath, volumeName := range s.volumesMapped {
576+
volumeDirAbsPath, err := d.createVolume(s.Name, volumeName)
577+
if err != nil {
578+
return nil, err
579+
}
580+
volumes[volumeDirAbsPath] = localPath
581+
}
582+
583+
volumesInLine := []string{}
584+
for k, v := range volumes {
585+
volumesInLine = append(volumesInLine, fmt.Sprintf("%s:%s", k, v))
586+
}
587+
565588
// add the ports to the labels as well
566589
service := map[string]interface{}{
567590
"image": imageName,
568591
"command": args,
569592
// Add volume mount for the output directory
570-
"volumes": []string{
571-
fmt.Sprintf("%s:/artifacts", outputFolder),
572-
},
593+
"volumes": volumesInLine,
573594
// Add the ethereum network
574595
"networks": []string{d.networkName},
575596
"labels": labels,
@@ -693,6 +714,15 @@ func (d *LocalRunner) generateDockerCompose() ([]byte, error) {
693714
return yamlData, nil
694715
}
695716

717+
func (d *LocalRunner) createVolume(service, volumeName string) (string, error) {
718+
// create the volume in the output folder
719+
volumeDirAbsPath, err := d.out.CreateDir(fmt.Sprintf("volume-%s-%s", service, volumeName))
720+
if err != nil {
721+
return "", fmt.Errorf("failed to create volume dir %s: %w", volumeName, err)
722+
}
723+
return volumeDirAbsPath, nil
724+
}
725+
696726
// runOnHost runs the service on the host machine
697727
func (d *LocalRunner) runOnHost(ss *service) error {
698728
// TODO: Use env vars in host processes
@@ -701,6 +731,34 @@ func (d *LocalRunner) runOnHost(ss *service) error {
701731
return fmt.Errorf("failed to apply template, err: %w", err)
702732
}
703733

734+
// Create the volumes for this service
735+
volumesMapped := map[string]string{}
736+
for pathInDocker, volumeName := range ss.volumesMapped {
737+
volumeDirAbsPath, err := d.createVolume(ss.Name, volumeName)
738+
if err != nil {
739+
return err
740+
}
741+
volumesMapped[pathInDocker] = volumeDirAbsPath
742+
}
743+
744+
// We have to replace the names of the files it is using as artifacts for the full names
745+
// Just a string replacement should be enough
746+
for i, arg := range args {
747+
// If any of the args contains any of the files mapped, we need to replace it
748+
for pathInDocker, artifactName := range ss.filesMapped {
749+
if strings.Contains(arg, pathInDocker) {
750+
args[i] = strings.ReplaceAll(arg, pathInDocker, filepath.Join(d.out.dst, artifactName))
751+
}
752+
}
753+
// If any of the args contains any of the volumes mapped, we need to create
754+
// the volume and replace it
755+
for pathInDocker, volumeAbsPath := range volumesMapped {
756+
if strings.Contains(arg, pathInDocker) {
757+
args[i] = strings.ReplaceAll(arg, pathInDocker, volumeAbsPath)
758+
}
759+
}
760+
}
761+
704762
execPath := d.overrides[ss.Name]
705763
cmd := exec.Command(execPath, args...)
706764

internal/manifest.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"io"
77
"os"
8+
"path/filepath"
89
"strings"
910
"text/template"
1011
"time"
@@ -207,6 +208,21 @@ func (s *Manifest) Validate() error {
207208
s.overrides[ss.Name] = bin
208209
}
209210
}
211+
212+
// validate that the mounts are correct
213+
for _, ss := range s.services {
214+
for _, fileNameRef := range ss.filesMapped {
215+
fileLoc := filepath.Join(s.out.dst, fileNameRef)
216+
217+
if _, err := os.Stat(fileLoc); err != nil {
218+
if os.IsNotExist(err) {
219+
return fmt.Errorf("service %s includes an unknown file %s does not exist", ss.Name, fileLoc)
220+
}
221+
return fmt.Errorf("failed to stat file %s: %w", fileLoc, err)
222+
}
223+
}
224+
}
225+
210226
return nil
211227
}
212228

@@ -282,6 +298,9 @@ type service struct {
282298
ports []*Port
283299
nodeRefs []*NodeRef
284300

301+
filesMapped map[string]string
302+
volumesMapped map[string]string
303+
285304
tag string
286305
image string
287306
entrypoint string
@@ -411,6 +430,22 @@ func (s *service) WithArgs(args ...string) *service {
411430
return s
412431
}
413432

433+
func (s *service) WithVolume(name string, localPath string) *service {
434+
if s.volumesMapped == nil {
435+
s.volumesMapped = make(map[string]string)
436+
}
437+
s.volumesMapped[localPath] = name
438+
return s
439+
}
440+
441+
func (s *service) WithArtifact(localPath string, artifactName string) *service {
442+
if s.filesMapped == nil {
443+
s.filesMapped = make(map[string]string)
444+
}
445+
s.filesMapped[localPath] = artifactName
446+
return s
447+
}
448+
414449
func (s *service) WithReady(check ReadyCheck) *service {
415450
s.readyCheck = &check
416451
return s

0 commit comments

Comments
 (0)