Skip to content

Commit

Permalink
cmd/juno: add --instance flag
Browse files Browse the repository at this point in the history
  • Loading branch information
weiihann committed Jun 13, 2024
1 parent 4e6dcd7 commit 93a0c19
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 1 deletion.
33 changes: 32 additions & 1 deletion cmd/juno/juno.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const (
cnUnverifiableRangeF = "cn-unverifiable-range"
callMaxStepsF = "rpc-call-max-steps"
corsEnableF = "rpc-cors-enable"
instanceF = "instance"

defaultConfig = ""
defaulHost = "localhost"
Expand Down Expand Up @@ -117,6 +118,8 @@ const (
defaultCallMaxSteps = 4_000_000
defaultGwTimeout = 5 * time.Second
defaultCorsEnable = false
defaultInstance = 1
defaultInstanceInc = 10

configFlagUsage = "The YAML configuration file."
logLevelFlagUsage = "Options: trace, debug, info, warn, error."
Expand Down Expand Up @@ -166,6 +169,9 @@ const (
callMaxStepsUsage = "Maximum number of steps to be executed in starknet_call requests. " +
"The upper limit is 4 million steps, and any higher value will still be capped at 4 million."
corsEnableUsage = "Enable CORS on RPC endpoints"
instanceUsage = "Configures the ports to avoid conflicts. Useful for running multiple instances on the same machine." +
" Changes to the following port numbers: - `grpc-port`, `http-port`, `metrics-port`, `pprof-port`, `ws-port`." +
" Each instance count increments the default value of respective ports by 10."
)

var Version string
Expand Down Expand Up @@ -211,7 +217,7 @@ func main() {
// 3. The config struct is populated.
// 4. Cobra calls the run function.
//
//nolint:funlen
//nolint:funlen, gocyclo
func NewCmd(config *node.Config, run func(*cobra.Command, []string) error) *cobra.Command {
junoCmd := &cobra.Command{
Use: "juno [flags]",
Expand Down Expand Up @@ -280,6 +286,30 @@ func NewCmd(config *node.Config, run func(*cobra.Command, []string) error) *cobr
}
}

// Configure ports for multiple instances
if config.Instance > defaultInstance {
inc := defaultInstanceInc * (config.Instance - defaultInstance)
if !v.IsSet(httpPortF) {
config.HTTPPort = defaultHTTPPort + inc
}

if !v.IsSet(wsPortF) {
config.WebsocketPort = defaultWSPort + inc
}

if !v.IsSet(grpcPortF) {
config.GRPCPort = defaultGRPCPort + inc
}

if !v.IsSet(metricsPortF) {
config.MetricsPort = defaultMetricsPort + inc
}

if !v.IsSet(pprofPortF) {
config.PprofPort = defaultPprofPort + inc
}
}

return nil
}

Expand Down Expand Up @@ -345,6 +375,7 @@ func NewCmd(config *node.Config, run func(*cobra.Command, []string) error) *cobr
junoCmd.Flags().Uint(callMaxStepsF, defaultCallMaxSteps, callMaxStepsUsage)
junoCmd.Flags().Duration(gwTimeoutF, defaultGwTimeout, gwTimeoutUsage)
junoCmd.Flags().Bool(corsEnableF, defaultCorsEnable, corsEnableUsage)
junoCmd.Flags().Uint(instanceF, defaultInstance, instanceUsage)
junoCmd.MarkFlagsMutuallyExclusive(p2pFeederNodeF, p2pPeersF)
junoCmd.AddCommand(GenP2PKeyPair())

Expand Down
146 changes: 146 additions & 0 deletions cmd/juno/juno_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,152 @@ func TestGenP2PKeyPair(t *testing.T) {
require.NoError(t, cmd.Execute())
}

func TestInstance(t *testing.T) {
type ports struct {
HTTPPort uint16
WebsocketPort uint16
GRPCPort uint16
MetricsPort uint16
PprofPort uint16
}

tests := map[string]struct {
cfgFile bool
cfgFileContents string
env []string
inputArgs []string
expectedPorts *ports
}{
"default instance on flag": {
inputArgs: []string{"--instance", "1"},
expectedPorts: &ports{
HTTPPort: 6060,
WebsocketPort: 6061,
GRPCPort: 6064,
MetricsPort: 9090,
PprofPort: 6062,
},
},
"instance 2 on flag": {
inputArgs: []string{"--instance", "2"},
expectedPorts: &ports{
HTTPPort: 6070,
WebsocketPort: 6071,
GRPCPort: 6074,
MetricsPort: 9100,
PprofPort: 6072,
},
},
"instance 2 on config": {
cfgFile: true,
cfgFileContents: `instance: 2`,
expectedPorts: &ports{
HTTPPort: 6070,
WebsocketPort: 6071,
GRPCPort: 6074,
MetricsPort: 9100,
PprofPort: 6072,
},
},
"instance 2 on env": {
env: []string{"JUNO_INSTANCE", "2"},
expectedPorts: &ports{
HTTPPort: 6070,
WebsocketPort: 6071,
GRPCPort: 6074,
MetricsPort: 9100,
PprofPort: 6072,
},
},
"instance 2 on flag with ports override": {
inputArgs: []string{"--instance", "2", "--http-port", "8080", "--ws-port", "8081", "--grpc-port", "8084", "--metrics-port", "10000", "--pprof-port", "8082"},
expectedPorts: &ports{
HTTPPort: 8080,
WebsocketPort: 8081,
GRPCPort: 8084,
MetricsPort: 10000,
PprofPort: 8082,
},
},
"instance 2 on config with ports override": {
cfgFile: true,
cfgFileContents: `instance: 2
http-port: 8080
ws-port: 8081
grpc-port: 8084
metrics-port: 10000
pprof-port: 8082`,
expectedPorts: &ports{
HTTPPort: 8080,
WebsocketPort: 8081,
GRPCPort: 8084,
MetricsPort: 10000,
PprofPort: 8082,
},
},
"instance 2 on env with ports override": {
env: []string{"JUNO_INSTANCE", "2", "JUNO_HTTP_PORT", "8080", "JUNO_WS_PORT", "8081", "JUNO_GRPC_PORT", "8084", "JUNO_METRICS_PORT", "10000", "JUNO_PPROF_PORT", "8082"},
expectedPorts: &ports{
HTTPPort: 8080,
WebsocketPort: 8081,
GRPCPort: 8084,
MetricsPort: 10000,
PprofPort: 8082,
},
},
"instance 2 with a mix of flags, config and env": {
cfgFile: true,
cfgFileContents: `grpc-port: 8084`,
inputArgs: []string{"--instance", "2", "--http-port", "8083"},
env: []string{"JUNO_INSTANCE", "2", "JUNO_WS_PORT", "8088"},
expectedPorts: &ports{
HTTPPort: 8083,
WebsocketPort: 8088,
GRPCPort: 8084,
MetricsPort: 9100,
PprofPort: 6072,
},
},
}

junoEnv := unsetJunoPrefixedEnv(t)

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
if tc.cfgFile {
fileN := tempCfgFile(t, tc.cfgFileContents)
tc.inputArgs = append(tc.inputArgs, "--config", fileN)
}

require.True(t, len(tc.env)%2 == 0, "The number of env variables should be an even number")

if len(tc.env) > 0 {
for i := 0; i < len(tc.env)/2; i++ {
require.NoError(t, os.Setenv(tc.env[2*i], tc.env[2*i+1]))
}
}

config := new(node.Config)
cmd := juno.NewCmd(config, func(_ *cobra.Command, _ []string) error { return nil })
cmd.SetArgs(tc.inputArgs)
require.NoError(t, cmd.Execute())

assert.Equal(t, tc.expectedPorts.HTTPPort, config.HTTPPort)
assert.Equal(t, tc.expectedPorts.WebsocketPort, config.WebsocketPort)
assert.Equal(t, tc.expectedPorts.GRPCPort, config.GRPCPort)
assert.Equal(t, tc.expectedPorts.MetricsPort, config.MetricsPort)
assert.Equal(t, tc.expectedPorts.PprofPort, config.PprofPort)

if len(tc.env) > 0 {
for i := 0; i < len(tc.env)/2; i++ {
require.NoError(t, os.Unsetenv(tc.env[2*i]))
}
}
})
}
setJunoPrefixedEnv(t, junoEnv)
}

func tempCfgFile(t *testing.T, cfg string) string {
t.Helper()

Expand Down
1 change: 1 addition & 0 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type Config struct {
Colour bool `mapstructure:"colour"`
PendingPollInterval time.Duration `mapstructure:"pending-poll-interval"`
RemoteDB string `mapstructure:"remote-db"`
Instance uint16 `mapstructure:"instance"`

Metrics bool `mapstructure:"metrics"`
MetricsHost string `mapstructure:"metrics-host"`
Expand Down

0 comments on commit 93a0c19

Please sign in to comment.