Skip to content

Commit c07ea71

Browse files
Networks refactor (#110)
* using {{.Field}} syntax in network helmfile templating * added id for namespace suffix * cleaner templating of just the values block * split templating to just a values.yaml.gotmpl file * added id to values.yaml and ensure namespace construction * updated CLAUDE.md * implemented basic sync command * enforcing helmfile as template * fix ethereum helmfile * added network delete * feat: bump helm/helmfile versions and fix ethereum network svc discovery * fix: add ethereum-ingress release and fix lighthouse execution endpoint config * replaced env vars with template field * updated CLAUDE.md * ensure field sort order * added simple yaml validation * fix: add missing network flag to lighthouse and cleanup whitespace * id improvements * fix: remove trailing spaces and fix indentation Remove trailing whitespace from case statements in obolup.sh and fix excessive indentation in helmfile.yaml.gotmpl * update claude * feat: add standardized pod labels for network discovery (#115) --------- Co-authored-by: bussyjd <[email protected]>
1 parent 5166799 commit c07ea71

File tree

15 files changed

+803
-377
lines changed

15 files changed

+803
-377
lines changed

CLAUDE.md

Lines changed: 172 additions & 97 deletions
Large diffs are not rendered by default.

cmd/obol/network.go

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"fmt"
5+
"slices"
56
"strings"
67

78
"github.com/ObolNetwork/obol-stack/internal/config"
@@ -36,22 +37,27 @@ func networkCommand(cfg *config.Config) *cli.Command {
3637
},
3738
},
3839
{
39-
Name: "delete",
40-
Usage: "Remove network and clean up cluster resources",
41-
ArgsUsage: "<network>",
42-
Flags: []cli.Flag{
43-
&cli.BoolFlag{
44-
Name: "force",
45-
Aliases: []string{"f"},
46-
Usage: "Skip confirmation prompt",
47-
},
40+
Name: "sync",
41+
Usage: "Deploy or update network configuration to cluster",
42+
ArgsUsage: "<network>/<id> or <network>-<id>",
43+
Action: func(c *cli.Context) error {
44+
if c.NArg() == 0 {
45+
return fmt.Errorf("deployment identifier required (e.g., ethereum/knowing-wahoo or ethereum-knowing-wahoo)")
46+
}
47+
deploymentIdentifier := c.Args().First()
48+
return network.Sync(cfg, deploymentIdentifier)
4849
},
50+
},
51+
{
52+
Name: "delete",
53+
Usage: "Remove network deployment and clean up cluster resources",
54+
ArgsUsage: "<network>/<id> or <network>-<id>",
4955
Action: func(c *cli.Context) error {
5056
if c.NArg() == 0 {
51-
return fmt.Errorf("network name required (e.g., ethereum, helios)")
57+
return fmt.Errorf("deployment identifier required (e.g., ethereum/test-deploy or ethereum-test-deploy)")
5258
}
53-
networkName := c.Args().First()
54-
return network.Delete(cfg, networkName, c.Bool("force"))
59+
deploymentIdentifier := c.Args().First()
60+
return network.Delete(cfg, deploymentIdentifier)
5561
},
5662
},
5763
},
@@ -68,76 +74,95 @@ func buildNetworkInstallCommands(cfg *config.Config) []*cli.Command {
6874

6975
var commands []*cli.Command
7076
for _, networkName := range networks {
71-
// Parse the embedded helmfile to get env vars
72-
envVars, err := network.ParseEmbeddedNetworkEnvVars(networkName)
77+
// Parse the embedded values template to get fields
78+
fields, err := network.ParseTemplateFields(networkName)
7379
if err != nil {
7480
// Skip networks we can't parse
7581
continue
7682
}
7783

78-
// Build flags from env vars
79-
flags := []cli.Flag{}
80-
for _, envVar := range envVars {
84+
// Build flags from template fields
85+
flags := []cli.Flag{
86+
// id flag is always present (special case - not parsed from template)
87+
&cli.StringFlag{
88+
Name: "id",
89+
Usage: fmt.Sprintf("Deployment identifier for namespace (e.g., 'my-node' becomes '%s-my-node', defaults to generated petname)", networkName),
90+
Required: false,
91+
},
92+
// force flag to allow overwriting existing deployments
93+
&cli.BoolFlag{
94+
Name: "force",
95+
Aliases: []string{"f"},
96+
Usage: "Overwrite existing deployment configuration if it already exists",
97+
},
98+
}
99+
100+
// Add flags from parsed template fields
101+
for _, field := range fields {
81102
// Build usage string
82-
usage := envVar.Description
103+
usage := field.Description
83104
if usage == "" {
84-
usage = fmt.Sprintf("Override %s", envVar.Name)
105+
usage = fmt.Sprintf("Override %s", field.Name)
85106
}
86107

87108
// Mark as required if no default value
88-
if envVar.Required {
109+
if field.Required {
89110
usage = "[REQUIRED] " + usage
90111
}
91112

92113
// Add enum options if available
93-
if len(envVar.EnumValues) > 0 {
94-
usage += fmt.Sprintf(" [options: %s]", strings.Join(envVar.EnumValues, ", "))
114+
if len(field.EnumValues) > 0 {
115+
usage += fmt.Sprintf(" [options: %s]", strings.Join(field.EnumValues, ", "))
95116
}
96117

97118
// Add default value
98-
if envVar.DefaultValue != "" {
99-
usage += fmt.Sprintf(" (default: %s)", envVar.DefaultValue)
119+
if field.DefaultValue != "" {
120+
usage += fmt.Sprintf(" (default: %s)", field.DefaultValue)
100121
}
101122

102123
flags = append(flags, &cli.StringFlag{
103-
Name: envVar.FlagName,
124+
Name: field.FlagName,
104125
Usage: usage,
105-
Required: envVar.Required,
126+
Required: field.Required,
106127
})
107128
}
108129

109130
// Create the network-specific install command
110131
netName := networkName // Capture for closure
111-
netEnvVars := envVars // Capture for validation
132+
netFields := fields // Capture for validation
112133
commands = append(commands, &cli.Command{
113134
Name: netName,
114135
Usage: fmt.Sprintf("Install %s network", netName),
115136
Flags: flags,
116137
Action: func(c *cli.Context) error {
117138
// Collect and validate flag values
118139
overrides := make(map[string]string)
119-
for _, envVar := range netEnvVars {
120-
value := c.String(envVar.FlagName)
140+
141+
// Collect id flag (special case - not in parsed fields)
142+
if idValue := c.String("id"); idValue != "" {
143+
overrides["id"] = idValue
144+
}
145+
146+
// Collect parsed template fields
147+
for _, field := range netFields {
148+
value := c.String(field.FlagName)
121149
if value != "" {
122150
// Validate enum constraint if defined
123-
if len(envVar.EnumValues) > 0 {
124-
valid := false
125-
for _, enumVal := range envVar.EnumValues {
126-
if value == enumVal {
127-
valid = true
128-
break
129-
}
130-
}
151+
if len(field.EnumValues) > 0 {
152+
valid := slices.Contains(field.EnumValues, value)
131153
if !valid {
132154
return fmt.Errorf("invalid value '%s' for --%s. Valid options: %s",
133-
value, envVar.FlagName, strings.Join(envVar.EnumValues, ", "))
155+
value, field.FlagName, strings.Join(field.EnumValues, ", "))
134156
}
135157
}
136-
overrides[envVar.FlagName] = value
158+
overrides[field.FlagName] = value
137159
}
138160
}
139161

140-
return network.Install(cfg, netName, overrides)
162+
// Get force flag
163+
force := c.Bool("force")
164+
165+
return network.Install(cfg, netName, overrides, force)
141166
},
142167
})
143168
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ go 1.25
44

55
require (
66
github.com/dustinkirkland/golang-petname v0.0.0-20240428194347-eebcea082ee0
7-
github.com/google/uuid v1.6.0
87
github.com/urfave/cli/v2 v2.27.7
8+
gopkg.in/yaml.v3 v3.0.1
99
)
1010

1111
require (

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3
22
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
33
github.com/dustinkirkland/golang-petname v0.0.0-20240428194347-eebcea082ee0 h1:aYo8nnk3ojoQkP5iErif5Xxv0Mo0Ga/FR5+ffl/7+Nk=
44
github.com/dustinkirkland/golang-petname v0.0.0-20240428194347-eebcea082ee0/go.mod h1:8AuBTZBRSFqEYBPYULd+NN474/zZBLP+6WeT5S9xlAc=
5-
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
6-
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
75
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
86
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
97
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
108
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
119
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
1210
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
11+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
12+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
13+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
14+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/embed/networks/aztec/helmfile.yaml.gotmpl

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,10 @@
1-
values:
2-
# @enum mainnet
3-
# @description Blockchain network to deploy
4-
- network: {{ env "AZTEC_NETWORK" | default "mainnet" }}
5-
# @description Attester private key (hex string)
6-
attesterPrivateKey: {{ env "AZTEC_ATTESTER_PRIVATE_KEY" }}
7-
# @description L1 Execution RPC URL override (defaults to local erpc endpoint based on network)
8-
l1ExecutionUrl: {{ env "AZTEC_L1_EXECUTION_URL" | default "" }}
9-
# @description L1 Consensus RPC URL
10-
l1ConsensusUrl: {{ env "AZTEC_L1_CONSENSUS_URL" | default "https://ethereum-beacon-api.publicnode.com" }}
11-
# Computed value: L1 Execution URL - uses override or defaults to erpc endpoint
12-
__l1ExecutionUrl: {{ if (env "AZTEC_L1_EXECUTION_URL") }}{{ env "AZTEC_L1_EXECUTION_URL" }}{{ else }}http://erpc.erpc.svc.cluster.local:4000/rpc/{{ env "AZTEC_NETWORK" | default "mainnet" }}{{ end }}
13-
14-
---
15-
161
repositories:
172
- name: obol
183
url: https://obolnetwork.github.io/helm-charts/
194

205
releases:
216
- name: aztec-sequencer
22-
namespace: aztec
7+
namespace: aztec-{{ .Values.id }}
238
createNamespace: true
249
chart: obol/aztec-node
2510
version: 0.2.0
@@ -45,20 +30,20 @@ releases:
4530
- --network
4631
- '{{ .Values.network }}'
4732
l1ExecutionUrls:
48-
- '{{ .Values.__l1ExecutionUrl }}'
33+
- '{{ if .Values.l1ExecutionUrl }}{{ .Values.l1ExecutionUrl }}{{ else }}http://erpc.erpc.svc.cluster.local:4000/rpc/{{ .Values.network }}{{ end }}'
4934
l1ConsensusUrls:
5035
- '{{ .Values.l1ConsensusUrl }}'
5136
resources:
5237
requests:
53-
cpu: "4"
54-
memory: "16Gi"
38+
cpu: "4"
39+
memory: "16Gi"
5540
limits:
56-
cpu: "8"
57-
memory: "32Gi"
41+
cpu: "8"
42+
memory: "32Gi"
5843
storage:
5944
dataDirectory: /data
60-
dataStoreMapSize: "134217728"
61-
worldStateMapSize: "134217728"
45+
dataStoreMapSize: "134217728"
46+
worldStateMapSize: "134217728"
6247
startupProbe:
6348
periodSeconds: 60
6449
failureThreshold: 60
@@ -74,7 +59,7 @@ releases:
7459
httpPort: 8080
7560
p2p:
7661
enabled: true
77-
nodePortEnabled: false
62+
nodePortEnabled: false
7863
port: 40400
7964
announcePort: 40400
8065
admin:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Configuration via CLI flags
2+
# Template fields populated by obol CLI during network installation
3+
4+
# @enum mainnet
5+
# @default mainnet
6+
# @description Blockchain network to deploy
7+
network: {{.Network}}
8+
9+
# @description Attester private key (hex string)
10+
attesterPrivateKey: {{.AttesterPrivateKey}}
11+
12+
# @default
13+
# @description L1 Execution RPC URL (defaults to ERPC: http://erpc.erpc.svc.cluster.local:4000/rpc/{network})
14+
l1ExecutionUrl: {{.L1ExecutionUrl}}
15+
16+
# @default https://ethereum-beacon-api.publicnode.com
17+
# @description L1 Consensus RPC URL
18+
l1ConsensusUrl: {{.L1ConsensusUrl}}
Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,25 @@
1-
# Configuration via environment variables
2-
# Override with: ETHEREUM_NETWORK, ETHEREUM_EXECUTION_CLIENT, ETHEREUM_CONSENSUS_CLIENT
3-
values:
4-
# @enum mainnet,sepolia,holesky,hoodi
5-
# @description Blockchain network to deploy
6-
- network: {{ env "ETHEREUM_NETWORK" | default "mainnet" }}
7-
# @enum reth,geth,nethermind,besu,erigon,ethereumjs
8-
# @description Execution layer client
9-
executionClient: {{ env "ETHEREUM_EXECUTION_CLIENT" | default "reth" }}
10-
# @enum lighthouse,prysm,teku,nimbus,lodestar,grandine
11-
# @description Consensus layer client
12-
consensusClient: {{ env "ETHEREUM_CONSENSUS_CLIENT" | default "lighthouse" }}
13-
14-
---
15-
161
repositories:
172
- name: ethereum-helm-charts
183
url: https://ethpandaops.github.io/ethereum-helm-charts
194

205
releases:
216
# Create PVCs first - before the Ethereum node
227
- name: ethereum-pvcs
23-
namespace: ethereum
8+
namespace: ethereum-{{ .Values.id }}
249
createNamespace: true
2510
chart: .
2611
values:
2712
# Pass only the values needed for PVC creation
28-
- executionClient: '{{ .Values.executionClient }}'
13+
- id: '{{ .Values.id }}'
14+
executionClient: '{{ .Values.executionClient }}'
2915
consensusClient: '{{ .Values.consensusClient }}'
3016
network: '{{ .Values.network }}'
3117

3218
# Ethereum node (execution and consensus clients)
3319
# Uses the external ethereum-helm-charts/ethereum-node umbrella chart
3420
# Depends on ethereum-pvcs to ensure PVCs exist first
3521
- name: ethereum
36-
namespace: ethereum
22+
namespace: ethereum-{{ .Values.id }}
3723
createNamespace: true
3824
chart: ethereum-helm-charts/ethereum-node
3925
needs: [ethereum-pvcs]
@@ -54,6 +40,18 @@ releases:
5440
- {{ .Values.executionClient }}:
5541
enabled: true
5642
nameOverride: execution-{{ .Values.executionClient }}-{{ .Values.network }}
43+
labels:
44+
app.kubernetes.io/part-of: obol.stack
45+
obol.stack/chain: ethereum
46+
obol.stack/network: {{ .Values.network }}
47+
obol.stack/type: execution
48+
obol.stack/client: {{ .Values.executionClient }}
49+
podLabels:
50+
app.kubernetes.io/part-of: obol.stack
51+
obol.stack/chain: ethereum
52+
obol.stack/network: {{ .Values.network }}
53+
obol.stack/type: execution
54+
obol.stack/client: {{ .Values.executionClient }}
5755
persistence:
5856
enabled: true
5957
size: 500Gi
@@ -64,9 +62,32 @@ releases:
6462
- {{ .Values.consensusClient }}:
6563
enabled: true
6664
nameOverride: consensus-{{ .Values.consensusClient }}-{{ .Values.network }}
65+
labels:
66+
app.kubernetes.io/part-of: obol.stack
67+
obol.stack/chain: ethereum
68+
obol.stack/network: {{ .Values.network }}
69+
obol.stack/type: consensus
70+
obol.stack/client: {{ .Values.consensusClient }}
71+
podLabels:
72+
app.kubernetes.io/part-of: obol.stack
73+
obol.stack/chain: ethereum
74+
obol.stack/network: {{ .Values.network }}
75+
obol.stack/type: consensus
76+
obol.stack/client: {{ .Values.consensusClient }}
77+
extraArgs:
78+
- --execution-endpoint=http://ethereum-execution-{{ .Values.executionClient }}-{{ .Values.network }}:8551
79+
- --network={{ .Values.network }}
6780
persistence:
6881
enabled: true
6982
size: 200Gi
7083
# Use existing PVC with network/client naming: consensus-{client}-{network}
7184
existingClaim: consensus-{{ .Values.consensusClient }}-{{ .Values.network }}
7285

86+
# Ingress for Ethereum node
87+
- name: ethereum-ingress
88+
namespace: ethereum-{{ .Values.id }}
89+
chart: .
90+
values:
91+
- executionClient: {{ .Values.executionClient }}
92+
consensusClient: {{ .Values.consensusClient }}
93+
network: {{ .Values.network }}

internal/embed/networks/ethereum/templates/ingress.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ spec:
1717
pathType: ImplementationSpecific
1818
backend:
1919
service:
20-
name: ethereum-execution
20+
name: ethereum-execution-{{ .Values.executionClient }}-{{ .Values.network }}
2121
port:
2222
number: 8545
2323
- path: /ethereum/beacon(/|$)(.*)
2424
pathType: ImplementationSpecific
2525
backend:
2626
service:
27-
name: ethereum-beacon
27+
name: ethereum-consensus-{{ .Values.consensusClient }}-{{ .Values.network }}
2828
port:
2929
number: 5052
3030
{{- end }}

0 commit comments

Comments
 (0)