Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ func main() {
GatewayName: os.Getenv("SEI_GATEWAY_NAME"),
GatewayNamespace: os.Getenv("SEI_GATEWAY_NAMESPACE"),
GatewayDomain: os.Getenv("SEI_GATEWAY_DOMAIN"),
GatewayPublicDomain: os.Getenv("SEI_GATEWAY_PUBLIC_DOMAIN"),
}

if err := platformCfg.Validate(); err != nil {
Expand Down Expand Up @@ -180,13 +181,14 @@ func main() {
//nolint:staticcheck // migrating to events.EventRecorder API is a separate effort
recorder := mgr.GetEventRecorderFor("seinodedeployment-controller")
if err := (&nodedeploymentcontroller.SeiNodeDeploymentReconciler{
Client: kc,
Scheme: mgr.GetScheme(),
Recorder: recorder,
ControllerSA: controllerSA,
GatewayName: platformCfg.GatewayName,
GatewayNamespace: platformCfg.GatewayNamespace,
GatewayDomain: platformCfg.GatewayDomain,
Client: kc,
Scheme: mgr.GetScheme(),
Recorder: recorder,
ControllerSA: controllerSA,
GatewayName: platformCfg.GatewayName,
GatewayNamespace: platformCfg.GatewayNamespace,
GatewayDomain: platformCfg.GatewayDomain,
GatewayPublicDomain: platformCfg.GatewayPublicDomain,
PlanExecutor: &planner.Executor[*seiv1alpha1.SeiNodeDeployment]{
Client: kc,
ConfigFor: func(ctx context.Context, group *seiv1alpha1.SeiNodeDeployment) task.ExecutionConfig {
Expand Down
7 changes: 4 additions & 3 deletions internal/controller/nodedeployment/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ type SeiNodeDeploymentReconciler struct {
// GatewayName, GatewayNamespace, and GatewayDomain identify the platform
// Gateway for HTTPRoute parentRefs and hostname derivation.
// Read from SEI_GATEWAY_NAME / SEI_GATEWAY_NAMESPACE / SEI_GATEWAY_DOMAIN.
GatewayName string
GatewayNamespace string
GatewayDomain string
GatewayName string
GatewayNamespace string
GatewayDomain string
GatewayPublicDomain string

// PlanExecutor drives group-level task plans (e.g. genesis assembly).
PlanExecutor planner.PlanExecutor[*seiv1alpha1.SeiNodeDeployment]
Expand Down
17 changes: 13 additions & 4 deletions internal/controller/nodedeployment/networking.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func portsForMode(mode seiconfig.NodeMode) []corev1.ServicePort {
}

func (r *SeiNodeDeploymentReconciler) reconcileRoute(ctx context.Context, group *seiv1alpha1.SeiNodeDeployment) error {
routes := resolveEffectiveRoutes(group, r.GatewayDomain)
routes := resolveEffectiveRoutes(group, r.GatewayDomain, r.GatewayPublicDomain)
if len(routes) == 0 {
removeCondition(group, seiv1alpha1.ConditionRouteReady)
return r.deleteHTTPRoutesByLabel(ctx, group)
Expand All @@ -234,7 +234,7 @@ func (r *SeiNodeDeploymentReconciler) deleteHTTPRoutesByLabel(ctx context.Contex
return nil
}

func resolveEffectiveRoutes(group *seiv1alpha1.SeiNodeDeployment, domain string) []effectiveRoute {
func resolveEffectiveRoutes(group *seiv1alpha1.SeiNodeDeployment, domain, publicDomain string) []effectiveRoute {
modePorts := seiconfig.NodePortsForMode(groupMode(group))

activePorts := make(map[string]bool, len(modePorts))
Expand All @@ -247,9 +247,18 @@ func resolveEffectiveRoutes(group *seiv1alpha1.SeiNodeDeployment, domain string)
if !isProtocolActiveForMode(proto.Prefix, activePorts) {
continue
}
subdomain := fmt.Sprintf("%s-%s", group.Name, proto.Prefix)
hostnames := []string{
fmt.Sprintf("%s.%s", subdomain, domain),
}
if publicDomain != "" {
hostnames = append(hostnames,
fmt.Sprintf("%s.%s.%s", subdomain, group.Namespace, publicDomain),
)
}
er := effectiveRoute{
Name: fmt.Sprintf("%s-%s", group.Name, proto.Prefix),
Hostnames: []string{fmt.Sprintf("%s.%s.%s", group.Name, proto.Prefix, domain)},
Name: subdomain,
Hostnames: hostnames,
Port: proto.Port,
}
if proto.Prefix == "evm" && activePorts["evm-ws"] {
Expand Down
91 changes: 54 additions & 37 deletions internal/controller/nodedeployment/networking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,29 +135,29 @@ func TestGenerateExternalService_FullModeIncludesAllPorts(t *testing.T) {

func TestResolveEffectiveRoutes_FullMode_FourRoutes(t *testing.T) {
g := NewWithT(t)
group := newTestGroup("pacific-1-rpc", "sei")
group := newTestGroup("pacific-1-wave", "pacific-1")
group.Spec.Networking = &seiv1alpha1.NetworkingConfig{
Service: &seiv1alpha1.ExternalServiceConfig{},
Gateway: &seiv1alpha1.GatewayRouteConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
g.Expect(routes).To(HaveLen(4))

type routeExpectation struct {
Name string
Hostname string
Port int32
Name string
Hostnames []string
Port int32
}
expected := []routeExpectation{
{"pacific-1-rpc-evm", "pacific-1-rpc.evm.prod.platform.sei.io", 8545},
{"pacific-1-rpc-rpc", "pacific-1-rpc.rpc.prod.platform.sei.io", 26657},
{"pacific-1-rpc-rest", "pacific-1-rpc.rest.prod.platform.sei.io", 1317},
{"pacific-1-rpc-grpc", "pacific-1-rpc.grpc.prod.platform.sei.io", 9090},
{"pacific-1-wave-evm", []string{"pacific-1-wave-evm.prod.platform.sei.io", "pacific-1-wave-evm.pacific-1.platform.sei.io"}, 8545},
{"pacific-1-wave-rpc", []string{"pacific-1-wave-rpc.prod.platform.sei.io", "pacific-1-wave-rpc.pacific-1.platform.sei.io"}, 26657},
{"pacific-1-wave-rest", []string{"pacific-1-wave-rest.prod.platform.sei.io", "pacific-1-wave-rest.pacific-1.platform.sei.io"}, 1317},
{"pacific-1-wave-grpc", []string{"pacific-1-wave-grpc.prod.platform.sei.io", "pacific-1-wave-grpc.pacific-1.platform.sei.io"}, 9090},
}
for i, exp := range expected {
g.Expect(routes[i].Name).To(Equal(exp.Name))
g.Expect(routes[i].Hostnames).To(Equal([]string{exp.Hostname}))
g.Expect(routes[i].Hostnames).To(Equal(exp.Hostnames))
g.Expect(routes[i].Port).To(Equal(exp.Port))
}
}
Expand All @@ -172,7 +172,7 @@ func TestResolveEffectiveRoutes_ArchiveMode_FourRoutes(t *testing.T) {
Gateway: &seiv1alpha1.GatewayRouteConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
g.Expect(routes).To(HaveLen(4))
}

Expand All @@ -186,44 +186,45 @@ func TestResolveEffectiveRoutes_ValidatorMode_NoRoutes(t *testing.T) {
Gateway: &seiv1alpha1.GatewayRouteConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
g.Expect(routes).To(BeEmpty())
}

func TestGenerateHTTPRoute_HostnamePattern(t *testing.T) {
g := NewWithT(t)
group := newTestGroup("pacific-1-rpc", "sei")
group := newTestGroup("pacific-1-wave", "pacific-1")
group.Spec.Networking = &seiv1alpha1.NetworkingConfig{
Service: &seiv1alpha1.ExternalServiceConfig{},
Gateway: &seiv1alpha1.GatewayRouteConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
g.Expect(routes).NotTo(BeEmpty())

for _, er := range routes {
route := generateHTTPRoute(group, er, "sei-gateway", "istio-system")
spec := route.Object["spec"].(map[string]any)
hostnames := spec["hostnames"].([]any)
g.Expect(hostnames).To(HaveLen(1))
g.Expect(hostnames[0]).To(MatchRegexp(`^pacific-1-rpc\.\w+\.prod\.platform\.sei\.io$`))
g.Expect(hostnames).To(HaveLen(2))
g.Expect(hostnames[0]).To(MatchRegexp(`^pacific-1-wave-\w+\.prod\.platform\.sei\.io$`))
g.Expect(hostnames[1]).To(MatchRegexp(`^pacific-1-wave-\w+\.pacific-1\.platform\.sei\.io$`))
}
}

func TestGenerateHTTPRoute_EVMMerged(t *testing.T) {
g := NewWithT(t)
group := newTestGroup("pacific-1-rpc", "sei")
group := newTestGroup("pacific-1-wave", "pacific-1")
group.Spec.Networking = &seiv1alpha1.NetworkingConfig{
Service: &seiv1alpha1.ExternalServiceConfig{},
Gateway: &seiv1alpha1.GatewayRouteConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")

var evmRoute effectiveRoute
evmCount := 0
for _, r := range routes {
if r.Name == "pacific-1-rpc-evm" {
if r.Name == "pacific-1-wave-evm" {
evmCount++
evmRoute = r
}
Expand All @@ -240,15 +241,15 @@ func TestGenerateHTTPRoute_EVMMerged(t *testing.T) {

func TestGenerateHTTPRoute_EVMWebSocketRule(t *testing.T) {
g := NewWithT(t)
group := newTestGroup("pacific-1-rpc", "sei")
group := newTestGroup("pacific-1-wave", "pacific-1")
group.Spec.Networking = &seiv1alpha1.NetworkingConfig{
Service: &seiv1alpha1.ExternalServiceConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
var evmRoute effectiveRoute
for _, r := range routes {
if r.Name == "pacific-1-rpc-evm" {
if r.Name == "pacific-1-wave-evm" {
evmRoute = r
break
}
Expand Down Expand Up @@ -284,7 +285,7 @@ func TestGenerateHTTPRoute_BasicFields(t *testing.T) {
Gateway: &seiv1alpha1.GatewayRouteConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
g.Expect(routes).NotTo(BeEmpty())
route := generateHTTPRoute(group, routes[0], "sei-gateway", "istio-system")

Expand All @@ -307,7 +308,7 @@ func TestGenerateHTTPRoute_ManagedByAnnotation(t *testing.T) {
Gateway: &seiv1alpha1.GatewayRouteConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
route := generateHTTPRoute(group, routes[0], "sei-gateway", "istio-system")
g.Expect(route.GetAnnotations()).To(HaveKeyWithValue("sei.io/managed-by", "seinodedeployment"))
}
Expand All @@ -320,7 +321,7 @@ func TestGenerateHTTPRoute_BackendRef(t *testing.T) {
Gateway: &seiv1alpha1.GatewayRouteConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
var rpcRoute effectiveRoute
for _, r := range routes {
if r.Name == "archive-rpc-rpc" {
Expand All @@ -344,17 +345,17 @@ func TestGenerateHTTPRoute_BackendRef(t *testing.T) {

func TestGenerateHTTPRoute_GRPCRoutePort(t *testing.T) {
g := NewWithT(t)
group := newTestGroup("pacific-1-rpc", "sei")
group := newTestGroup("pacific-1-wave", "pacific-1")
group.Spec.Networking = &seiv1alpha1.NetworkingConfig{
Service: &seiv1alpha1.ExternalServiceConfig{},
Gateway: &seiv1alpha1.GatewayRouteConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")

var grpcRoute effectiveRoute
for _, r := range routes {
if r.Name == "pacific-1-rpc-grpc" {
if r.Name == "pacific-1-wave-grpc" {
grpcRoute = r
break
}
Expand All @@ -364,12 +365,12 @@ func TestGenerateHTTPRoute_GRPCRoutePort(t *testing.T) {
httpRoute := generateHTTPRoute(group, grpcRoute, "sei-gateway", "istio-system")
spec := httpRoute.Object["spec"].(map[string]any)
hostnames := spec["hostnames"].([]any)
g.Expect(hostnames).To(ConsistOf("pacific-1-rpc.grpc.prod.platform.sei.io"))
g.Expect(hostnames).To(ConsistOf("pacific-1-wave-grpc.prod.platform.sei.io", "pacific-1-wave-grpc.pacific-1.platform.sei.io"))

rules := spec["rules"].([]any)
backend := rules[0].(map[string]any)["backendRefs"].([]any)[0].(map[string]any)
g.Expect(backend["port"]).To(Equal(int64(9090)))
g.Expect(backend["name"]).To(Equal("pacific-1-rpc-external"))
g.Expect(backend["name"]).To(Equal("pacific-1-wave-external"))
}

// --- isProtocolActiveForMode ---
Expand All @@ -387,14 +388,30 @@ func TestIsProtocolActiveForMode_EVMMapping(t *testing.T) {

func TestResolveEffectiveRoutes_EmptyDomain_MalformedHostnames(t *testing.T) {
g := NewWithT(t)
group := newTestGroup("pacific-1-rpc", "sei")
group := newTestGroup("pacific-1-wave", "pacific-1")
group.Spec.Networking = &seiv1alpha1.NetworkingConfig{
Service: &seiv1alpha1.ExternalServiceConfig{},
}

routes := resolveEffectiveRoutes(group, "")
routes := resolveEffectiveRoutes(group, "", "")
g.Expect(routes).To(HaveLen(4), "routes are still generated even with empty domain")
g.Expect(routes[0].Hostnames[0]).To(Equal("pacific-1-rpc.evm."), "empty domain produces trailing dot")
g.Expect(routes[0].Hostnames).To(HaveLen(1), "no public hostname when public domain is empty")
g.Expect(routes[0].Hostnames[0]).To(Equal("pacific-1-wave-evm."), "empty domain produces trailing dot")
}

func TestResolveEffectiveRoutes_NoPublicDomain_SingleHostname(t *testing.T) {
g := NewWithT(t)
group := newTestGroup("pacific-1-wave", "pacific-1")
group.Spec.Networking = &seiv1alpha1.NetworkingConfig{
Service: &seiv1alpha1.ExternalServiceConfig{},
}

routes := resolveEffectiveRoutes(group, "dev.platform.sei.io", "")
g.Expect(routes).To(HaveLen(4))
for _, r := range routes {
g.Expect(r.Hostnames).To(HaveLen(1), "only internal hostname when public domain is empty")
}
g.Expect(routes[0].Hostnames[0]).To(Equal("pacific-1-wave-evm.dev.platform.sei.io"))
}

func TestReconcileRoute_NoRoutesForValidatorMode(t *testing.T) {
Expand All @@ -405,20 +422,20 @@ func TestReconcileRoute_NoRoutesForValidatorMode(t *testing.T) {
Service: &seiv1alpha1.ExternalServiceConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
g.Expect(routes).To(BeEmpty(), "validator mode should produce zero routes")
}

func TestGenerateHTTPRoute_NonEVMRoute_SingleRule(t *testing.T) {
g := NewWithT(t)
group := newTestGroup("pacific-1-rpc", "sei")
group := newTestGroup("pacific-1-wave", "pacific-1")
group.Spec.Networking = &seiv1alpha1.NetworkingConfig{
Service: &seiv1alpha1.ExternalServiceConfig{},
}

routes := resolveEffectiveRoutes(group, "prod.platform.sei.io")
routes := resolveEffectiveRoutes(group, "prod.platform.sei.io", "platform.sei.io")
for _, r := range routes {
if r.Name == "pacific-1-rpc-rpc" {
if r.Name == "pacific-1-wave-rpc" {
httpRoute := generateHTTPRoute(group, r, "sei-gateway", "gateway")
spec := httpRoute.Object["spec"].(map[string]any)
rules := spec["rules"].([]any)
Expand Down
7 changes: 4 additions & 3 deletions internal/platform/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ type Config struct {
GenesisBucket string
GenesisRegion string

GatewayName string
GatewayNamespace string
GatewayDomain string
GatewayName string
GatewayNamespace string
GatewayDomain string
GatewayPublicDomain string
}

// Validate returns an error if required fields are missing.
Expand Down
Loading