Commit 604fd605 authored by Zach Howard's avatar Zach Howard Committed by GitHub

kt-devnet: improves post-deployment output for nodes/services (#13707)

parent c1d9e420
package kurtosis
import (
"fmt"
"strconv"
"strings"
"github.com/ethereum-optimism/optimism/kurtosis-devnet/pkg/kurtosis/sources/inspect"
)
// ServiceFinder is the main entry point for finding service endpoints
// ServiceFinder is the main entry point for finding services and their endpoints
type ServiceFinder struct {
services inspect.ServiceMap
nodeServices []string
interestingPorts []string
l2ServicePrefix string
}
......@@ -26,13 +24,6 @@ func WithNodeServices(services []string) ServiceFinderOption {
}
}
// WithInterestingPorts sets the ports to look for
func WithInterestingPorts(ports []string) ServiceFinderOption {
return func(f *ServiceFinder) {
f.interestingPorts = ports
}
}
// WithL2ServicePrefix sets the prefix used to identify L2 services
func WithL2ServicePrefix(prefix string) ServiceFinderOption {
return func(f *ServiceFinder) {
......@@ -45,7 +36,6 @@ func NewServiceFinder(services inspect.ServiceMap, opts ...ServiceFinderOption)
f := &ServiceFinder{
services: services,
nodeServices: []string{"cl", "el"},
interestingPorts: []string{"rpc", "http"},
l2ServicePrefix: "op-",
}
for _, opt := range opts {
......@@ -54,8 +44,8 @@ func NewServiceFinder(services inspect.ServiceMap, opts ...ServiceFinderOption)
return f
}
// FindL1Endpoints finds L1 nodes. Currently returns empty endpoints as specified.
func (f *ServiceFinder) FindL1Endpoints() ([]Node, EndpointMap) {
// FindL1Services finds L1 nodes.
func (f *ServiceFinder) FindL1Services() ([]Node, ServiceMap) {
return f.findRPCEndpoints(func(serviceName string) (string, int, bool) {
// Only match services that start with one of the node service identifiers.
// We might have to change this if we need to support L1 services beyond nodes.
......@@ -69,8 +59,8 @@ func (f *ServiceFinder) FindL1Endpoints() ([]Node, EndpointMap) {
})
}
// FindL2Endpoints finds L2 nodes and endpoints for a specific network
func (f *ServiceFinder) FindL2Endpoints(network string) ([]Node, EndpointMap) {
// FindL2Services finds L2 nodes and services for a specific network
func (f *ServiceFinder) FindL2Services(network string) ([]Node, ServiceMap) {
networkSuffix := "-" + network
return f.findRPCEndpoints(func(serviceName string) (string, int, bool) {
if strings.HasSuffix(serviceName, networkSuffix) {
......@@ -83,47 +73,44 @@ func (f *ServiceFinder) FindL2Endpoints(network string) ([]Node, EndpointMap) {
}
// findRPCEndpoints looks for services matching the given predicate that have an RPC port
func (f *ServiceFinder) findRPCEndpoints(matchService func(string) (string, int, bool)) ([]Node, EndpointMap) {
endpointMap := make(EndpointMap)
func (f *ServiceFinder) findRPCEndpoints(matchService func(string) (string, int, bool)) ([]Node, ServiceMap) {
serviceMap := make(ServiceMap)
var nodes []Node
for serviceName, ports := range f.services {
var portInfo *inspect.PortInfo
for _, interestingPort := range f.interestingPorts {
if p, ok := ports[interestingPort]; ok {
portInfo = &p
break
}
}
if portInfo == nil {
continue
}
if serviceIdentifier, num, ok := matchService(serviceName); ok {
var allocated bool
for _, service := range f.nodeServices {
if serviceIdentifier == service {
if num > len(nodes) {
nodes = append(nodes, make(Node))
nodes = append(nodes, Node{
Services: make(ServiceMap),
})
}
host := portInfo.Host
if host == "" {
host = "localhost"
endpoints := make(EndpointMap)
for portName, portInfo := range ports {
endpoints[portName] = portInfo
}
nodes[num-1].Services[serviceIdentifier] = Service{
Name: serviceName,
Endpoints: endpoints,
}
nodes[num-1][serviceIdentifier] = fmt.Sprintf("http://%s:%d", host, portInfo.Port)
allocated = true
}
}
if !allocated {
host := portInfo.Host
if host == "" {
host = "localhost"
endpoints := make(EndpointMap)
for portName, portInfo := range ports {
endpoints[portName] = portInfo
}
serviceMap[serviceIdentifier] = Service{
Name: serviceName,
Endpoints: endpoints,
}
endpointMap[serviceIdentifier] = fmt.Sprintf("http://%s:%d", host, portInfo.Port)
}
}
}
return nodes, endpointMap
return nodes, serviceMap
}
// serviceTag returns the shorthand service tag and index if it's a service with multiple instances
......
......@@ -52,38 +52,82 @@ func TestFindRPCEndpoints(t *testing.T) {
tests := []struct {
name string
services inspect.ServiceMap
findFn func(*ServiceFinder) ([]Node, EndpointMap)
findFn func(*ServiceFinder) ([]Node, ServiceMap)
wantNodes []Node
wantEndpoints EndpointMap
wantServices ServiceMap
}{
{
name: "find L1 endpoints",
services: testServices,
findFn: func(f *ServiceFinder) ([]Node, EndpointMap) {
return f.FindL1Endpoints()
findFn: func(f *ServiceFinder) ([]Node, ServiceMap) {
return f.FindL1Services()
},
wantNodes: []Node{
{
"cl": "http://localhost:52693",
"el": "http://localhost:52645",
Services: ServiceMap{
"cl": Service{
Name: "cl-1-lighthouse-geth",
Endpoints: EndpointMap{
"metrics": {Port: 52691},
"tcp-discovery": {Port: 52692},
"udp-discovery": {Port: 58275},
"http": {Port: 52693},
},
},
"el": Service{
Name: "el-1-geth-lighthouse",
Endpoints: EndpointMap{
"metrics": {Port: 52643},
"tcp-discovery": {Port: 52644},
"udp-discovery": {Port: 51936},
"engine-rpc": {Port: 52642},
"rpc": {Port: 52645},
"ws": {Port: 52646},
},
},
},
},
wantEndpoints: EndpointMap{},
},
wantServices: ServiceMap{},
},
{
name: "find op-kurtosis L2 endpoints",
services: testServices,
findFn: func(f *ServiceFinder) ([]Node, EndpointMap) {
return f.FindL2Endpoints("op-kurtosis")
findFn: func(f *ServiceFinder) ([]Node, ServiceMap) {
return f.FindL2Services("op-kurtosis")
},
wantNodes: []Node{
{
"cl": "http://localhost:53503",
"el": "http://localhost:53402",
Services: ServiceMap{
"cl": Service{
Name: "op-cl-1-op-node-op-geth-op-kurtosis",
Endpoints: EndpointMap{
"udp-discovery": {Port: 50990},
"http": {Port: 53503},
"tcp-discovery": {Port: 53504},
},
},
"el": Service{
Name: "op-el-1-op-geth-op-node-op-kurtosis",
Endpoints: EndpointMap{
"udp-discovery": {Port: 53233},
"engine-rpc": {Port: 53399},
"metrics": {Port: 53400},
"tcp-discovery": {Port: 53401},
"rpc": {Port: 53402},
"ws": {Port: 53403},
},
},
},
},
},
wantServices: ServiceMap{
"batcher": Service{
Name: "op-batcher-op-kurtosis",
Endpoints: EndpointMap{
"http": {Port: 53572},
},
},
wantEndpoints: EndpointMap{
"batcher": "http://localhost:53572",
},
},
{
......@@ -93,12 +137,17 @@ func TestFindRPCEndpoints(t *testing.T) {
"http": {Host: "custom.host", Port: 8080},
},
},
findFn: func(f *ServiceFinder) ([]Node, EndpointMap) {
return f.FindL2Endpoints("custom-host")
findFn: func(f *ServiceFinder) ([]Node, ServiceMap) {
return f.FindL2Services("custom-host")
},
wantNodes: nil,
wantEndpoints: EndpointMap{
"batcher": "http://custom.host:8080",
wantServices: ServiceMap{
"batcher": Service{
Name: "op-batcher-custom-host",
Endpoints: EndpointMap{
"http": {Host: "custom.host", Port: 8080},
},
},
},
},
}
......@@ -106,9 +155,9 @@ func TestFindRPCEndpoints(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
finder := NewServiceFinder(tt.services)
gotNodes, gotEndpoints := tt.findFn(finder)
gotNodes, gotServices := tt.findFn(finder)
assert.Equal(t, tt.wantNodes, gotNodes)
assert.Equal(t, tt.wantEndpoints, gotEndpoints)
assert.Equal(t, tt.wantServices, gotServices)
})
}
}
......@@ -10,6 +10,7 @@ import (
"github.com/ethereum-optimism/optimism/kurtosis-devnet/pkg/kurtosis/api/run"
"github.com/ethereum-optimism/optimism/kurtosis-devnet/pkg/kurtosis/api/wrappers"
"github.com/ethereum-optimism/optimism/kurtosis-devnet/pkg/kurtosis/sources/deployer"
"github.com/ethereum-optimism/optimism/kurtosis-devnet/pkg/kurtosis/sources/inspect"
"github.com/ethereum-optimism/optimism/kurtosis-devnet/pkg/kurtosis/sources/spec"
)
......@@ -18,14 +19,23 @@ const (
DefaultEnclave = "devnet"
)
type EndpointMap map[string]string
type EndpointMap map[string]inspect.PortInfo
type Node = EndpointMap
type ServiceMap map[string]Service
type Service struct {
Name string `json:"name"`
Endpoints EndpointMap `json:"endpoints"`
}
type Node struct {
Services ServiceMap `json:"services"`
}
type Chain struct {
Name string `json:"name"`
ID string `json:"id,omitempty"`
Services EndpointMap `json:"services,omitempty"`
Services ServiceMap `json:"services,omitempty"`
Nodes []Node `json:"nodes"`
Addresses deployer.DeploymentAddresses `json:"addresses,omitempty"`
Wallets WalletMap `json:"wallets,omitempty"`
......@@ -169,10 +179,10 @@ func (d *KurtosisDeployer) GetEnvironmentInfo(ctx context.Context, spec *spec.En
// Find L1 endpoint
finder := NewServiceFinder(inspectResult.UserServices)
if nodes, endpoints := finder.FindL1Endpoints(); len(nodes) > 0 {
if nodes, services := finder.FindL1Services(); len(nodes) > 0 {
chain := &Chain{
Name: "Ethereum",
Services: endpoints,
Services: services,
Nodes: nodes,
}
if deployerState.State != nil {
......@@ -184,12 +194,12 @@ func (d *KurtosisDeployer) GetEnvironmentInfo(ctx context.Context, spec *spec.En
// Find L2 endpoints
for _, chainSpec := range spec.Chains {
nodes, endpoints := finder.FindL2Endpoints(chainSpec.Name)
nodes, services := finder.FindL2Services(chainSpec.Name)
chain := &Chain{
Name: chainSpec.Name,
ID: chainSpec.NetworkID,
Services: endpoints,
Services: services,
Nodes: nodes,
}
......
......@@ -8,8 +8,8 @@ import (
// PortInfo contains the host and port number for a service port
type PortInfo struct {
Host string
Port int
Host string `json:"host"`
Port int `json:"port"`
}
type PortMap map[string]PortInfo
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment