diff --git a/.github/actions/start-services/action.yml b/.github/actions/start-services/action.yml index 4b86e072d4..d4bad962df 100644 --- a/.github/actions/start-services/action.yml +++ b/.github/actions/start-services/action.yml @@ -75,12 +75,20 @@ runs: make -C packages/clickhouse migrate-without-build shell: bash + - name: Run Redis + run: | + echo "REDIS_URL=localhost:6379" >> .env.test + + docker run -d --name redis -p 6379:6379 redis:7.4.2-alpine + shell: bash + - name: Start Services env: ENVD_TIMEOUT: "60s" ORCHESTRATOR_SERVICES: "orchestrator,template-manager" SANDBOX_ACCESS_TOKEN_HASH_SEED: "abcdefghijklmnopqrstuvwxyz" TEMPLATE_MANAGER_HOST: "localhost:5008" + REDIS_URL: "localhost:6379" ARTIFACTS_REGISTRY_PROVIDER: "Local" STORAGE_PROVIDER: "Local" ENVIRONMENT: "local" diff --git a/packages/api/go.mod b/packages/api/go.mod index 06449bdfb3..26ce023de8 100644 --- a/packages/api/go.mod +++ b/packages/api/go.mod @@ -253,7 +253,7 @@ require ( golang.org/x/mod v0.25.0 // indirect golang.org/x/net v0.41.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.15.0 + golang.org/x/sync v0.17.0 golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.26.0 // indirect golang.org/x/time v0.11.0 // indirect diff --git a/packages/api/go.sum b/packages/api/go.sum index 5c7574c925..eac09f3e98 100644 --- a/packages/api/go.sum +++ b/packages/api/go.sum @@ -1178,8 +1178,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/packages/client-proxy/go.mod b/packages/client-proxy/go.mod index 71fe550cec..566da6811c 100644 --- a/packages/client-proxy/go.mod +++ b/packages/client-proxy/go.mod @@ -82,7 +82,7 @@ require ( golang.org/x/crypto v0.39.0 // indirect golang.org/x/mod v0.25.0 // indirect golang.org/x/net v0.41.0 // indirect - golang.org/x/sync v0.15.0 // indirect + golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.26.0 // indirect golang.org/x/tools v0.34.0 // indirect diff --git a/packages/client-proxy/go.sum b/packages/client-proxy/go.sum index dee7bb388e..38970cd090 100644 --- a/packages/client-proxy/go.sum +++ b/packages/client-proxy/go.sum @@ -907,8 +907,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/packages/db/go.mod b/packages/db/go.mod index cec485cf80..d89ba6af8d 100644 --- a/packages/db/go.mod +++ b/packages/db/go.mod @@ -81,7 +81,7 @@ require ( golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect golang.org/x/mod v0.25.0 // indirect golang.org/x/net v0.41.0 // indirect - golang.org/x/sync v0.15.0 // indirect + golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.26.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect diff --git a/packages/db/go.sum b/packages/db/go.sum index 6051654469..0db3fb3cad 100644 --- a/packages/db/go.sum +++ b/packages/db/go.sum @@ -326,8 +326,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/packages/docker-reverse-proxy/go.mod b/packages/docker-reverse-proxy/go.mod index 2944e6d418..b78836f48e 100644 --- a/packages/docker-reverse-proxy/go.mod +++ b/packages/docker-reverse-proxy/go.mod @@ -26,6 +26,6 @@ require ( github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/zclconf/go-cty v1.14.1 // indirect golang.org/x/mod v0.25.0 // indirect - golang.org/x/sync v0.15.0 // indirect + golang.org/x/sync v0.17.0 // indirect golang.org/x/text v0.26.0 // indirect ) diff --git a/packages/docker-reverse-proxy/go.sum b/packages/docker-reverse-proxy/go.sum index 9e06dd421e..9f328a39b5 100644 --- a/packages/docker-reverse-proxy/go.sum +++ b/packages/docker-reverse-proxy/go.sum @@ -53,8 +53,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/packages/envd/go.mod b/packages/envd/go.mod index 1f141c07a4..795936dd05 100644 --- a/packages/envd/go.mod +++ b/packages/envd/go.mod @@ -52,7 +52,7 @@ require ( github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect golang.org/x/mod v0.25.0 // indirect - golang.org/x/sync v0.15.0 // indirect + golang.org/x/sync v0.17.0 // indirect golang.org/x/text v0.26.0 // indirect golang.org/x/tools v0.34.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/packages/envd/go.sum b/packages/envd/go.sum index 63ce83da6d..ce28523776 100644 --- a/packages/envd/go.sum +++ b/packages/envd/go.sum @@ -176,8 +176,8 @@ golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/packages/orchestrator/go.mod b/packages/orchestrator/go.mod index 4f50718896..f4aca117a2 100644 --- a/packages/orchestrator/go.mod +++ b/packages/orchestrator/go.mod @@ -37,7 +37,7 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.36.0 go.opentelemetry.io/otel/trace v1.36.0 go.uber.org/zap v1.27.0 - golang.org/x/sync v0.15.0 + golang.org/x/sync v0.17.0 golang.org/x/sys v0.33.0 google.golang.org/grpc v1.73.0 google.golang.org/protobuf v1.36.6 diff --git a/packages/orchestrator/go.sum b/packages/orchestrator/go.sum index 062df6daa6..4bd109ab3c 100644 --- a/packages/orchestrator/go.sum +++ b/packages/orchestrator/go.sum @@ -1301,8 +1301,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/packages/orchestrator/internal/consts.go b/packages/orchestrator/internal/consts.go new file mode 100644 index 0000000000..a0c3f72414 --- /dev/null +++ b/packages/orchestrator/internal/consts.go @@ -0,0 +1,20 @@ +package internal + +import ( + "github.com/e2b-dev/infra/packages/shared/pkg/env" +) + +const ( + // Private IP don't leave the sandbox through the network bridge, so we use a reserved IP address for it: + // See TEST-NET-3 on https://en.wikipedia.org/wiki/Reserved_IP_addresses + defaultSandboxEventIP = "203.0.113.0" + defaultEventProxyPort = "5010" +) + +func GetSandboxEventIP() string { + return env.GetEnv("SANDBOX_EVENT_IP", defaultSandboxEventIP) +} + +func GetEventProxyPort() string { + return env.GetEnv("SANDBOX_EVENT_PROXY_PORT", defaultEventProxyPort) +} diff --git a/packages/orchestrator/internal/events/events_service.go b/packages/orchestrator/internal/events/events_service.go index 715340d582..e197fdc4cf 100644 --- a/packages/orchestrator/internal/events/events_service.go +++ b/packages/orchestrator/internal/events/events_service.go @@ -4,7 +4,7 @@ import ( "context" ) -type EventsService[T any] interface { +type EventService[T any] interface { HandleEvent(ctx context.Context, event T) Close(ctx context.Context) error } diff --git a/packages/orchestrator/internal/events/mock_events_service.go b/packages/orchestrator/internal/events/mock_events_service.go index 7ce807d90e..11a8d947df 100644 --- a/packages/orchestrator/internal/events/mock_events_service.go +++ b/packages/orchestrator/internal/events/mock_events_service.go @@ -4,23 +4,23 @@ import ( "context" ) -// MockEventsService implements EventsService interface for testing -type MockEventsService[T any] struct { +// MockEventService implements EventsService interface for testing +type MockEventService[T any] struct { HandleEventFunc func(ctx context.Context, event T) error CloseFunc func(ctx context.Context) error } -func NewMockEventsService[T any]() *MockEventsService[T] { - return &MockEventsService[T]{ +func NewMockEventsService[T any]() *MockEventService[T] { + return &MockEventService[T]{ HandleEventFunc: func(ctx context.Context, event T) error { return nil }, CloseFunc: func(ctx context.Context) error { return nil }, } } -func (m *MockEventsService[T]) HandleEvent(ctx context.Context, event T) error { +func (m *MockEventService[T]) HandleEvent(ctx context.Context, event T) error { return m.HandleEventFunc(ctx, event) } -func (m *MockEventsService[T]) Close(ctx context.Context) error { +func (m *MockEventService[T]) Close(ctx context.Context) error { return m.CloseFunc(ctx) } diff --git a/packages/orchestrator/internal/events/mock_sandbox_events_proxy.go b/packages/orchestrator/internal/events/mock_sandbox_events_proxy.go new file mode 100644 index 0000000000..229a31a8d2 --- /dev/null +++ b/packages/orchestrator/internal/events/mock_sandbox_events_proxy.go @@ -0,0 +1,22 @@ +package events + +import ( + "context" +) + +// NoopSandboxEventProxy is a simple Noop that doesn't do anything +type NoopSandboxEventProxy struct{} + +func NewNoopSandboxEventProxy() *NoopSandboxEventProxy { + return &NoopSandboxEventProxy{} +} + +func (m *NoopSandboxEventProxy) Start() error { + // No-op + return nil +} + +func (m *NoopSandboxEventProxy) Close(ctx context.Context) error { + // No-op + return nil +} diff --git a/packages/orchestrator/internal/events/mock_sandbox_events_service.go b/packages/orchestrator/internal/events/mock_sandbox_events_service.go new file mode 100644 index 0000000000..32a18acef8 --- /dev/null +++ b/packages/orchestrator/internal/events/mock_sandbox_events_service.go @@ -0,0 +1,23 @@ +package events + +import ( + "context" + + "github.com/e2b-dev/infra/packages/shared/pkg/events/event" +) + +// NoopSandboxEventsService is a simple Noop that doesn't do anything +type NoopSandboxEventsService struct{} + +func NewNoopSandboxEventsService() *NoopSandboxEventsService { + return &NoopSandboxEventsService{} +} + +func (m *NoopSandboxEventsService) HandleEvent(ctx context.Context, event event.SandboxEvent) { + // No-op +} + +func (m *NoopSandboxEventsService) Close(ctx context.Context) error { + // No-op + return nil +} diff --git a/packages/orchestrator/internal/events/mock_sandbox_events_store.go b/packages/orchestrator/internal/events/mock_sandbox_events_store.go new file mode 100644 index 0000000000..59759bc39a --- /dev/null +++ b/packages/orchestrator/internal/events/mock_sandbox_events_store.go @@ -0,0 +1,53 @@ +package events + +import ( + "context" + "time" +) + +// NoopSandboxEventStore is a simple Noop that doesn't do anything +type NoopSandboxEventStore struct{} + +func NewNoopSandboxEventStore() SandboxEventStore { + return &NoopSandboxEventStore{} +} + +func (m *NoopSandboxEventStore) SetSandboxIP(ctx context.Context, sandboxID string, sandboxIP string) error { + // No-op + return nil +} + +func (m *NoopSandboxEventStore) GetSandboxID(ctx context.Context, sandboxIP string) (string, error) { + // No-op + return "", nil +} + +func (m *NoopSandboxEventStore) DelSandboxIP(ctx context.Context, sandboxIP string) error { + // No-op + return nil +} + +func (m *NoopSandboxEventStore) GetLastEvent(ctx context.Context, sandboxID string) (*SandboxEvent, error) { + // No-op + return nil, nil +} + +func (m *NoopSandboxEventStore) GetLastNEvents(ctx context.Context, sandboxID string, n int) ([]*SandboxEvent, error) { + // No-op + return nil, nil +} + +func (m *NoopSandboxEventStore) AddEvent(ctx context.Context, sandboxID string, event *SandboxEvent, expiration time.Duration) error { + // No-op + return nil +} + +func (m *NoopSandboxEventStore) DelEvent(ctx context.Context, sandboxID string) error { + // No-op + return nil +} + +func (m *NoopSandboxEventStore) Close(ctx context.Context) error { + // No-op + return nil +} diff --git a/packages/orchestrator/internal/events/sandbox_events_handlers.go b/packages/orchestrator/internal/events/sandbox_events_handlers.go new file mode 100644 index 0000000000..fdbe51fa0e --- /dev/null +++ b/packages/orchestrator/internal/events/sandbox_events_handlers.go @@ -0,0 +1,99 @@ +package events + +import ( + "encoding/json" + "io" + "net/http" + "strings" + + "go.uber.org/zap" +) + +type SandboxEventHandler interface { + Path() string + HandlerFunc(w http.ResponseWriter, r *http.Request) +} + +// This is used to track ad-hoc events that are not handled by the event server. +type DefaultSandboxEventHandler struct { + store SandboxEventStore +} + +func NewDefaultSandboxEventHandler(store SandboxEventStore) *DefaultSandboxEventHandler { + return &DefaultSandboxEventHandler{store} +} + +func (h *DefaultSandboxEventHandler) Path() string { + return "/" +} + +func (h *DefaultSandboxEventHandler) HandlerFunc(w http.ResponseWriter, r *http.Request) { + addr := r.RemoteAddr + sandboxIP := strings.Split(addr, ":")[0] + sandboxID, err := h.store.GetSandboxID(r.Context(), sandboxIP) + if err != nil { + zap.L().Error("Failed to get sandbox ID from IP", zap.Error(err)) + http.Error(w, "Error handling event", http.StatusInternalServerError) + return + } + + zap.L().Debug("Received request from sandbox", zap.String("sandbox_id", sandboxID), zap.String("sandbox_ip", sandboxIP)) + + if r.Method == http.MethodGet { + events, err := h.store.GetLastNEvents(r.Context(), sandboxID, 10) + if err != nil { + zap.L().Error("Failed to get event data for sandbox "+sandboxID, zap.Error(err)) + http.Error(w, "Failed to get event data for sandbox "+sandboxID, http.StatusInternalServerError) + return + } + + eventJSON, err := json.Marshal(events) + if err != nil { + zap.L().Error("Failed to marshal event data", zap.Error(err)) + http.Error(w, "Failed to marshal event data", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(eventJSON) + return + } + + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + // Create event data with path and body + eventData := SandboxEvent{ + Path: r.URL.Path, + } + + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "Failed to read request body", http.StatusInternalServerError) + return + } + + zap.L().Info("Received event", zap.String("body", string(body))) + + eventData.Body = make(map[string]any) + err = json.Unmarshal(body, &eventData.Body) + if err != nil { + zap.L().Error("Failed to unmarshal request body", zap.Error(err)) + http.Error(w, "Failed to unmarshal request body", http.StatusInternalServerError) + return + } + + // Store in Redis with sandboxID as key + err = h.store.AddEvent(r.Context(), sandboxID, &eventData, 0) + if err != nil { + zap.L().Error("Failed to store event data", zap.Error(err)) + http.Error(w, "Failed to store event data", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusCreated) + w.Write([]byte(`{"event_ack":true}`)) +} diff --git a/packages/orchestrator/internal/events/sandbox_events_proxy.go b/packages/orchestrator/internal/events/sandbox_events_proxy.go new file mode 100644 index 0000000000..271497d4cc --- /dev/null +++ b/packages/orchestrator/internal/events/sandbox_events_proxy.go @@ -0,0 +1,54 @@ +package events + +import ( + "context" + "fmt" + "net/http" +) + +type SandboxEventProxier interface { + Start() error + Close(ctx context.Context) error +} + +// SandboxEventServer handles outbound HTTP requests from sandboxes calling the event.e2b.com endpoint +type SandboxEventProxy struct { + server *http.Server +} + +func NewSandboxEventProxy(port uint, store SandboxEventStore, handlers ...SandboxEventHandler) SandboxEventProxier { + mux := http.NewServeMux() + + handlers = append(handlers, NewDefaultSandboxEventHandler(store)) + for _, handler := range handlers { + mux.HandleFunc(handler.Path(), handler.HandlerFunc) + } + + server := &http.Server{ + Addr: fmt.Sprintf(":%d", port), + Handler: mux, + } + + return &SandboxEventProxy{ + server: server, + } +} + +func (p *SandboxEventProxy) Start() error { + return p.server.ListenAndServe() +} + +func (p *SandboxEventProxy) Close(ctx context.Context) error { + var err error + select { + case <-ctx.Done(): + err = p.server.Close() + default: + err = p.server.Shutdown(ctx) + } + if err != nil { + return fmt.Errorf("failed to shutdown event server: %w", err) + } + + return nil +} diff --git a/packages/orchestrator/internal/events/sandbox_events_store.go b/packages/orchestrator/internal/events/sandbox_events_store.go new file mode 100644 index 0000000000..aae34ba6eb --- /dev/null +++ b/packages/orchestrator/internal/events/sandbox_events_store.go @@ -0,0 +1,135 @@ +package events + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/redis/go-redis/v9" + "go.opentelemetry.io/otel" +) + +var tracer = otel.Tracer("github.com/e2b-dev/infra/packages/orchestrator/internal/events") + +const ( + cacheTL = time.Hour * 24 * 30 + + EventPrefix = "ev:" + IPPrefix = "ip:" +) + +type SandboxEvent struct { + Path string `json:"path"` + Body map[string]any `json:"body"` +} + +func (i SandboxEvent) MarshalBinary() ([]byte, error) { + return json.Marshal(i) +} + +type sandboxEventStore struct { + redisClient redis.UniversalClient +} + +type SandboxEventStore interface { + SetSandboxIP(ctx context.Context, sandboxID string, sandboxIP string) error + GetSandboxID(ctx context.Context, sandboxIP string) (string, error) + DelSandboxIP(ctx context.Context, sandboxIP string) error + + GetLastEvent(ctx context.Context, sandboxID string) (*SandboxEvent, error) + GetLastNEvents(ctx context.Context, sandboxID string, n int) ([]*SandboxEvent, error) + AddEvent(ctx context.Context, sandboxID string, SandboxEvent *SandboxEvent, expiration time.Duration) error + DelEvent(ctx context.Context, sandboxID string) error + + Close(ctx context.Context) error +} + +func NewSandboxEventStore(redisClient redis.UniversalClient) SandboxEventStore { + return &sandboxEventStore{ + redisClient: redisClient, + } +} + +func (c *sandboxEventStore) SetSandboxIP(ctx context.Context, sandboxID string, sandboxIP string) error { + if c.redisClient == nil { + return fmt.Errorf("redisClient is nil") + } + return c.redisClient.Set(ctx, IPPrefix+sandboxIP, sandboxID, cacheTL).Err() +} + +func (c *sandboxEventStore) GetSandboxID(ctx context.Context, sandboxIP string) (string, error) { + return c.redisClient.Get(ctx, IPPrefix+sandboxIP).Result() +} + +func (c *sandboxEventStore) DelSandboxIP(ctx context.Context, sandboxIP string) error { + return c.redisClient.Del(ctx, IPPrefix+sandboxIP).Err() +} + +func (c *sandboxEventStore) GetLastEvent(ctx context.Context, sandboxID string) (*SandboxEvent, error) { + _, span := tracer.Start(ctx, "sandbox-event-get-last") + defer span.End() + + result, err := c.redisClient.ZRevRangeWithScores(ctx, EventPrefix+sandboxID, 0, 0).Result() + if err != nil { + return nil, err + } + if len(result) == 0 { + return nil, redis.Nil + } + rawEvent := result[0].Member.(string) + + var event SandboxEvent + err = json.Unmarshal([]byte(rawEvent), &event) + if err != nil { + return nil, err + } + return &event, nil +} + +func (c *sandboxEventStore) GetLastNEvents(ctx context.Context, sandboxID string, n int) ([]*SandboxEvent, error) { + _, span := tracer.Start(ctx, "sandbox-event-get-last-n") + defer span.End() + + result, err := c.redisClient.ZRevRangeWithScores(ctx, EventPrefix+sandboxID, 0, int64(n-1)).Result() + if err != nil { + return nil, err + } + if len(result) == 0 { + return nil, redis.Nil + } + + events := make([]*SandboxEvent, 0, len(result)) + for _, item := range result { + rawEvent := item.Member.(string) + var event SandboxEvent + err = json.Unmarshal([]byte(rawEvent), &event) + if err != nil { + return nil, err + } + events = append(events, &event) + } + + return events, nil +} + +func (c *sandboxEventStore) AddEvent(ctx context.Context, sandboxID string, event *SandboxEvent, expiration time.Duration) error { + _, span := tracer.Start(ctx, "sandbox-event-store") + defer span.End() + + return c.redisClient.ZAdd(ctx, EventPrefix+sandboxID, redis.Z{ + Score: float64(time.Now().UnixNano()), + Member: event, + }).Err() +} + +func (c *sandboxEventStore) DelEvent(ctx context.Context, sandboxID string) error { + _, span := tracer.Start(ctx, "sandbox-event-delete") + defer span.End() + + return c.redisClient.Del(ctx, EventPrefix+sandboxID).Err() +} + +func (c *sandboxEventStore) Close(ctx context.Context) error { + return c.redisClient.Close() +} diff --git a/packages/orchestrator/internal/sandbox/sandbox.go b/packages/orchestrator/internal/sandbox/sandbox.go index 0472195dbc..130ba84c9f 100644 --- a/packages/orchestrator/internal/sandbox/sandbox.go +++ b/packages/orchestrator/internal/sandbox/sandbox.go @@ -14,6 +14,7 @@ import ( "go.uber.org/zap" globalconfig "github.com/e2b-dev/infra/packages/orchestrator/internal/config" + "github.com/e2b-dev/infra/packages/orchestrator/internal/events" "github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/block" "github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/build" "github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/fc" @@ -316,6 +317,7 @@ func ResumeSandbox( devicePool *nbd.DevicePool, useClickhouseMetrics bool, apiConfigToStore *orchestrator.SandboxConfig, + eventStore events.SandboxEventStore, ) (s *Sandbox, e error) { ctx, childSpan := tracer.Start(ctx, "resume-sandbox") defer childSpan.End() @@ -536,6 +538,23 @@ func ResumeSandbox( return nil, fmt.Errorf("failed to wait for sandbox start: %w", err) } + if eventStore != nil { + sandboxIP := ips.slot.HostIPString() + + err = eventStore.SetSandboxIP(context.WithoutCancel(ctx), runtime.SandboxID, sandboxIP) + if err != nil { + // soft fail to not block this critical path + zap.L().Error("failed to set sandbox IP", zap.String("sandbox_id", runtime.SandboxID), zap.String("ip", ips.slot.HostIPString()), zap.Error(err)) + } + cleanup.AddPriority(func(ctx context.Context) error { + err = eventStore.DelSandboxIP(ctx, sandboxIP) + if err != nil { + return fmt.Errorf("failed to delete sandbox IP: %w", err) + } + return nil + }) + } + go sbx.Checks.Start() // nolint:contextcheck // TODO: fix this later go func() { diff --git a/packages/orchestrator/internal/server/main.go b/packages/orchestrator/internal/server/main.go index cac16009f9..1884c60e7d 100644 --- a/packages/orchestrator/internal/server/main.go +++ b/packages/orchestrator/internal/server/main.go @@ -36,8 +36,9 @@ type server struct { devicePool *nbd.DevicePool persistence storage.StorageProvider featureFlags *featureflags.Client - sbxEventsService events.EventsService[event.SandboxEvent] + sbxEventService events.EventService[event.SandboxEvent] startingSandboxes *semaphore.Weighted + sbxEventStore events.SandboxEventStore } type Service struct { @@ -54,17 +55,18 @@ type Service struct { } type ServiceConfig struct { - GRPC *grpcserver.GRPCServer - Tel *telemetry.Client - NetworkPool *network.Pool - DevicePool *nbd.DevicePool - TemplateCache *template.Cache - Info *service.ServiceInfo - Proxy *proxy.SandboxProxy - Sandboxes *smap.Map[*sandbox.Sandbox] - Persistence storage.StorageProvider - FeatureFlags *featureflags.Client - SbxEventsService events.EventsService[event.SandboxEvent] + GRPC *grpcserver.GRPCServer + Tel *telemetry.Client + NetworkPool *network.Pool + DevicePool *nbd.DevicePool + TemplateCache *template.Cache + Info *service.ServiceInfo + Proxy *proxy.SandboxProxy + Sandboxes *smap.Map[*sandbox.Sandbox] + Persistence storage.StorageProvider + FeatureFlags *featureflags.Client + SbxEventService events.EventService[event.SandboxEvent] + SbxEventStore events.SandboxEventStore } func New( @@ -85,7 +87,8 @@ func New( devicePool: cfg.DevicePool, persistence: cfg.Persistence, featureFlags: cfg.FeatureFlags, - sbxEventsService: cfg.SbxEventsService, + sbxEventService: cfg.SbxEventService, + sbxEventStore: cfg.SbxEventStore, startingSandboxes: semaphore.NewWeighted(maxStartingInstancesPerNode), } diff --git a/packages/orchestrator/internal/server/sandboxes.go b/packages/orchestrator/internal/server/sandboxes.go index d4cbf82088..bbc314eb37 100644 --- a/packages/orchestrator/internal/server/sandboxes.go +++ b/packages/orchestrator/internal/server/sandboxes.go @@ -123,6 +123,7 @@ func (s *server) Create(ctx context.Context, req *orchestrator.SandboxCreateRequ s.devicePool, metricsWriteFlag, req.Sandbox, + s.sbxEventStore, ) if err != nil { err := errors.Join(err, context.Cause(ctx)) @@ -181,7 +182,7 @@ func (s *server) Create(ctx context.Context, req *orchestrator.SandboxCreateRequ buildId = sbx.APIStoredConfig.BuildId } - go s.sbxEventsService.HandleEvent(ctx, event.SandboxEvent{ + go s.sbxEventService.HandleEvent(ctx, event.SandboxEvent{ Timestamp: time.Now().UTC(), SandboxID: sbx.Runtime.SandboxID, SandboxExecutionID: sbx.Runtime.ExecutionID, @@ -229,7 +230,7 @@ func (s *server) Update(ctx context.Context, req *orchestrator.SandboxUpdateRequ buildId = sbx.APIStoredConfig.BuildId } - go s.sbxEventsService.HandleEvent(ctx, event.SandboxEvent{ + go s.sbxEventService.HandleEvent(ctx, event.SandboxEvent{ Timestamp: time.Now().UTC(), SandboxID: sbx.Runtime.SandboxID, SandboxExecutionID: sbx.Runtime.ExecutionID, @@ -324,7 +325,7 @@ func (s *server) Delete(ctxConn context.Context, in *orchestrator.SandboxDeleteR eventCtx := context.WithoutCancel(ctx) - go s.sbxEventsService.HandleEvent(eventCtx, event.SandboxEvent{ + go s.sbxEventService.HandleEvent(eventCtx, event.SandboxEvent{ Timestamp: time.Now().UTC(), SandboxID: sbx.Runtime.SandboxID, SandboxExecutionID: sbx.Runtime.ExecutionID, @@ -439,7 +440,7 @@ func (s *server) Pause(ctx context.Context, in *orchestrator.SandboxPauseRequest } eventCtx := context.WithoutCancel(ctx) - go s.sbxEventsService.HandleEvent(eventCtx, event.SandboxEvent{ + go s.sbxEventService.HandleEvent(eventCtx, event.SandboxEvent{ Timestamp: time.Now().UTC(), SandboxID: sbx.Runtime.SandboxID, SandboxExecutionID: sbx.Runtime.ExecutionID, diff --git a/packages/orchestrator/internal/template/build/layer/resume_sandbox.go b/packages/orchestrator/internal/template/build/layer/resume_sandbox.go index 18a16943f5..9b07a65ad6 100644 --- a/packages/orchestrator/internal/template/build/layer/resume_sandbox.go +++ b/packages/orchestrator/internal/template/build/layer/resume_sandbox.go @@ -7,6 +7,7 @@ import ( "github.com/google/uuid" + "github.com/e2b-dev/infra/packages/orchestrator/internal/events" "github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox" sbxtemplate "github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/template" "github.com/e2b-dev/infra/packages/orchestrator/internal/template/build/config" @@ -15,14 +16,15 @@ import ( // ResumeSandbox creates sandboxes for resuming existing templates type ResumeSandbox struct { - config sandbox.Config - timeout time.Duration + config sandbox.Config + timeout time.Duration + eventStore events.SandboxEventStore } var _ SandboxCreator = (*ResumeSandbox)(nil) -func NewResumeSandbox(config sandbox.Config, timeout time.Duration) *ResumeSandbox { - return &ResumeSandbox{config: config, timeout: timeout} +func NewResumeSandbox(config sandbox.Config, timeout time.Duration, eventStore events.SandboxEventStore) *ResumeSandbox { + return &ResumeSandbox{config: config, timeout: timeout, eventStore: eventStore} } func (rs *ResumeSandbox) Sandbox( @@ -46,6 +48,7 @@ func (rs *ResumeSandbox) Sandbox( layerExecutor.devicePool, false, nil, + rs.eventStore, ) if err != nil { return nil, fmt.Errorf("resume sandbox: %w", err) diff --git a/packages/orchestrator/internal/template/build/phases/steps/builder.go b/packages/orchestrator/internal/template/build/phases/steps/builder.go index 7057aa9296..fe4f3a6fe9 100644 --- a/packages/orchestrator/internal/template/build/phases/steps/builder.go +++ b/packages/orchestrator/internal/template/build/phases/steps/builder.go @@ -174,7 +174,7 @@ func (sb *StepBuilder) Build( }, ) } else { - sandboxCreator = layer.NewResumeSandbox(sbxConfig, layerTimeout) + sandboxCreator = layer.NewResumeSandbox(sbxConfig, layerTimeout, nil) } actionExecutor := layer.NewFunctionAction(func(ctx context.Context, sbx *sandbox.Sandbox, meta metadata.Template) (metadata.Template, error) { diff --git a/packages/orchestrator/main.go b/packages/orchestrator/main.go index 61e7d4a214..078d911578 100644 --- a/packages/orchestrator/main.go +++ b/packages/orchestrator/main.go @@ -54,8 +54,9 @@ type Closeable interface { } const ( - defaultPort = 5008 - defaultProxyPort = 5007 + defaultPort = 5008 + defaultProxyPort = 5007 + defaultEventProxyPort = 5010 version = "0.1.0" @@ -70,6 +71,7 @@ var ( func main() { port := flag.Uint("port", defaultPort, "orchestrator server port") proxyPort := flag.Uint("proxy-port", defaultProxyPort, "orchestrator proxy port") + eventProxyPort := flag.Uint("event-proxy-port", defaultEventProxyPort, "orchestrator sandbox event proxy port") flag.Parse() if *port > math.MaxUint16 { @@ -80,7 +82,7 @@ func main() { log.Fatalf("%d is larger than maximum possible proxy port %d", proxyPort, math.MaxInt16) } - success := run(*port, *proxyPort) + success := run(*port, *proxyPort, *eventProxyPort) log.Println("Stopping orchestrator, success:", success) @@ -89,7 +91,7 @@ func main() { } } -func run(port, proxyPort uint) (success bool) { +func run(port, proxyPort, eventProxyPort uint) (success bool) { success = true services := service.GetServices() @@ -334,14 +336,23 @@ func run(port, proxyPort uint) (success bool) { zap.L().Info("Connected to Redis cluster") } - var redisPubSub pubsub.PubSub[event.SandboxEvent, webhooks.SandboxWebhooksMetaData] + var ( + redisPubSub pubsub.PubSub[event.SandboxEvent, webhooks.SandboxWebhooksMetaData] + sbxEventStore events.SandboxEventStore + sbxEventService events.EventService[event.SandboxEvent] + sbxEventProxy events.SandboxEventProxier + ) if redisClient != nil { redisPubSub = pubsub.NewRedisPubSub[event.SandboxEvent, webhooks.SandboxWebhooksMetaData](redisClient, "sandbox-webhooks") + sbxEventService = events.NewSandboxEventsService(featureFlags, redisPubSub, sandboxEventBatcher, globalLogger) + sbxEventStore = events.NewSandboxEventStore(redisClient) + sbxEventProxy = events.NewSandboxEventProxy(eventProxyPort, sbxEventStore) } else { - redisPubSub = pubsub.NewMockPubSub[event.SandboxEvent, webhooks.SandboxWebhooksMetaData]() + sbxEventService = events.NewNoopSandboxEventsService() + sbxEventStore = events.NewNoopSandboxEventStore() + sbxEventProxy = events.NewNoopSandboxEventProxy() } - sbxEventsService := events.NewSandboxEventsService(featureFlags, redisPubSub, sandboxEventBatcher, globalLogger) sandboxObserver, err := metrics.NewSandboxObserver(ctx, nodeID, serviceName, commitSHA, version, serviceInstanceID, sandboxes) if err != nil { zap.L().Fatal("failed to create sandbox observer", zap.Error(err)) @@ -350,17 +361,18 @@ func run(port, proxyPort uint) (success bool) { _, err = server.New( ctx, server.ServiceConfig{ - GRPC: grpcSrv, - Tel: tel, - NetworkPool: networkPool, - DevicePool: devicePool, - TemplateCache: templateCache, - Info: serviceInfo, - Proxy: sandboxProxy, - Sandboxes: sandboxes, - Persistence: persistence, - FeatureFlags: featureFlags, - SbxEventsService: sbxEventsService, + GRPC: grpcSrv, + Tel: tel, + NetworkPool: networkPool, + DevicePool: devicePool, + TemplateCache: templateCache, + Info: serviceInfo, + Proxy: sandboxProxy, + Sandboxes: sandboxes, + Persistence: persistence, + FeatureFlags: featureFlags, + SbxEventService: sbxEventService, + SbxEventStore: sbxEventStore, }, ) if err != nil { @@ -394,6 +406,8 @@ func run(port, proxyPort uint) (success bool) { sandboxObserver, limiter, sandboxEventBatcher, + sbxEventStore, + sbxEventProxy, ) // Initialize the template manager only if the service is enabled @@ -463,6 +477,24 @@ func run(port, proxyPort uint) (success bool) { return nil }) + g.Go(func() error { + sbxEventProxyErr := sbxEventProxy.Start() + if sbxEventProxyErr != nil && !errors.Is(sbxEventProxyErr, http.ErrServerClosed) { + zap.L().Error("sandbox event proxy error", zap.Error(sbxEventProxyErr)) + + select { + case serviceError <- sbxEventProxyErr: + default: + // Don't block if the serviceError channel is already closed + // or if the error is already sent + } + + return sbxEventProxyErr + } + + return nil + }) + // Wait for the shutdown signal or if some service fails select { case <-sig.Done(): diff --git a/packages/shared/go.mod b/packages/shared/go.mod index f6c4f2b887..3d3b4c59a3 100644 --- a/packages/shared/go.mod +++ b/packages/shared/go.mod @@ -49,7 +49,7 @@ require ( go.uber.org/zap v1.27.0 golang.org/x/mod v0.25.0 golang.org/x/oauth2 v0.30.0 - golang.org/x/sync v0.15.0 + golang.org/x/sync v0.17.0 google.golang.org/api v0.214.0 google.golang.org/grpc v1.73.0 google.golang.org/protobuf v1.36.6 diff --git a/packages/shared/go.sum b/packages/shared/go.sum index 4e47d8b144..5bf6cf9df6 100644 --- a/packages/shared/go.sum +++ b/packages/shared/go.sum @@ -1070,8 +1070,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/tests/integration/Makefile b/tests/integration/Makefile index 77ee020ecb..9a45817f95 100644 --- a/tests/integration/Makefile +++ b/tests/integration/Makefile @@ -36,6 +36,8 @@ seed: test: test/. test/%: @export POSTGRES_CONNECTION_STRING=$(POSTGRES_CONNECTION_STRING); \ + export REDIS_URL=$(REDIS_URL); \ + export REDIS_CLUSTER_URL=$(REDIS_CLUSTER_URL); \ export TESTS_API_SERVER_URL=$(TESTS_API_SERVER_URL); \ export TESTS_ORCHESTRATOR_HOST=$(TESTS_ORCHESTRATOR_HOST); \ export TESTS_ENVD_PROXY=$(TESTS_ENVD_PROXY); \ diff --git a/tests/integration/go.mod b/tests/integration/go.mod index 5cf5f78cb8..de11dde3ba 100644 --- a/tests/integration/go.mod +++ b/tests/integration/go.mod @@ -14,7 +14,7 @@ require ( github.com/oapi-codegen/runtime v1.1.1 github.com/stretchr/testify v1.10.0 golang.org/x/net v0.41.0 - golang.org/x/sync v0.15.0 + golang.org/x/sync v0.17.0 google.golang.org/grpc v1.73.0 google.golang.org/protobuf v1.36.6 ) diff --git a/tests/integration/go.sum b/tests/integration/go.sum index f0bfc40326..2118caf6e3 100644 --- a/tests/integration/go.sum +++ b/tests/integration/go.sum @@ -259,8 +259,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=