Skip to content

Conversation

0div
Copy link
Contributor

@0div 0div commented Jun 16, 2025

Description

We currently do not have a way to send events from inside a sandbox and programmatically handle them from the host, this is an attempt to solve that.

Setup networking in sandbox that routes http://events.e2b.dev requests to a server listening in orchestrator with customizable handlers.

  • add internal routing (/etc/hosts) in sandbox
  • add ip table rule to route sbx event requests to event server
  • parametrize event handler registering for event server
  • appends events to redis sorted set
  • abstract event store interface with getters and setters
  • track sandbox IPs via store on sandbox resume
  • use it to map back to sandbox ID in event handler
  • wire to ClickHouse
  • build API routes to fetch events

Test

[infra]
$ make build-and-upload/envd
$ make build-and-upload/template-manager
$ make build-and-upload/orchestrator
$ make plan
$ make apply 

[E2B/template/base]
$ e2b template build

[Sandbox]
$ e2b sbx sp base
user@e2b:~$ curl -X POST http://events.e2b.dev/test -d '{"your": "data"}'

{"event_ack": true, "path": "/test"}

user@e2b:~$ curl -X GET http://events.e2b.dev

[{"path":"/test","body":{"your": "data"}}]

Copy link

linear bot commented Jun 16, 2025

@0div 0div changed the title Create internal sandbox event endpoint e2b 2486 Create internal sandbox event endpoint Jun 16, 2025
@0div 0div self-assigned this Jun 17, 2025
@0div 0div added the feature New feature label Jun 17, 2025
@0div 0div changed the title Create internal sandbox event endpoint Create sandbox event hook Jun 20, 2025
@0div 0div marked this pull request as ready for review June 20, 2025 23:58
}

// Redirect http://event.e2b.dev traffic destined to event server
err = tables.Append("nat", "PREROUTING", "-i", s.VethName(), "-p", "tcp", "-d", "8.8.8.7", "--dport", "80", "-j", "REDIRECT", "--to-port", "5010")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use different IP than 8.8.8.7, I guess any IP from these should be more appropriate:

var blockedRanges = []string{
	"10.0.0.0/8",
	"169.254.0.0/16",
	"192.168.0.0/16",
	"172.16.0.0/12",
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally yes, i first tried private IPs, they don't leave the sandbox through the network bridge with current setup, i'd have to figure out a way to route one of the private ones this way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just note, these ranges are blocked by default, you need to enable the target IP address (maybe that might be why you haven't seen them routed)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we maybe not use public IP, but something like metadata IP used by envd for accessing Firecracker VM metadata?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More details on why Firecracker and cloud providers are using 169.254/16 https://datatracker.ietf.org/doc/html/rfc3927

Copy link
Member

@sitole sitole Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps provide the domain as an environment variable via envd so we are not locked into it for the future? Then does not matter what domain we will use now

Copy link
Contributor

@dobrac dobrac Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does matter in a sense where it will be encoded in all envds

Copy link
Member

@sitole sitole Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does matter in a sense where it will be encoded in all envds

That was my point with Perhaps provide the domain as an environment variable via envd so we are not locked into it for the future

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you mean through MMDS, not environment variable, correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sorry for confusion

@dobrac
Copy link
Contributor

dobrac commented Jun 24, 2025

Also, how will we handle events like sandbox creation, deletion, etc? Basically events emitted from outside of the sandbox

@0div
Copy link
Contributor Author

0div commented Jun 24, 2025

Also, how will we handle events like sandbox creation, deletion, etc? Basically events emitted from outside of the sandbox

This is not meant to replace events emitted from outside the sandbox.

Copy link
Contributor

dobrac commented Jun 24, 2025

I've meant that we don't have events emitted from the outside, so the question is if it maybe makes sense to have it united

@0div
Copy link
Contributor Author

0div commented Jun 24, 2025

I've meant that we don't have events emitted from the outside, so the question is if it maybe makes sense to have it united

any event that can be listened to from the outside should continue to be—especially if it's uncertain the VM is running—any event we would have to poll for inside the sandbox ideally shouldn't.

@0div 0div changed the title Create sandbox event hook Create sandbox event endpoint and handlers Jun 25, 2025
@sitole sitole self-requested a review July 3, 2025 03:15
Comment on lines +21 to +24
server := &http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: mux,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about running Gin here so we can use a strict Golang client in envd and track all version changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, we can use gin, but i'm not sure it's more strict than the std lib and also what do u mean by tracking version changes in this case?

Copy link
Member

@sitole sitole Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but i'm not sure it's more strict than the std lib and also what do u mean by tracking version changes in this case?

I was thinking that the "metrics server" can be Gin-backed by the OpenAPI scheme, as we are using for the API, so all breaking changes will be clear (because of the re-generated schema). You will also be able to use the generated Go client from EnvD to call metrics service endpoints.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point was just make it strong types on both caller and receiver

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @sitole

Comment on lines +426 to +431
sandboxIP := ips.slot.HostIPString()
eventStore.SetSandboxIP(config.SandboxId, sandboxIP)
cleanup.AddPriority(func(ctx context.Context) error {
return eventStore.DelSandboxIP(sandboxIP)
})

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can we not directly get the sandbox from the orchestrator cache and get the slot IP on it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if i'm wrong but that map uses sandbox ID as key? in my use case I need sandbox IP as key to get the ID.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right. But still, using Redis may not be needed here? You don't need to share state to a 3rd party service, because you will always receive requests just from sandboxes that are managed by the orchestrator itself, right? This way on Orchestrator, you should always know about all sandboxes without fetching them from Redis.

Probably there will be <300 sandboxes, which means the sandboxes map is not that big to iterate it every time you need to find an IP in it. The number of sandboxes will probably not grow, because of networking, memory, and CPU limitations. If you feel that it can be issue, then we can do some pattern that will create in-memory map "sbx ip -> sbx id" and make it synced with sandboxes map.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @sitole here

hostname := "e2b.local"
eventProxyHostname := "events.e2b.dev"

eventIP := env.GetEnv("SANDBOX_EVENT_IP", "203.0.113.0")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets make IP constant in some shared package

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, i was gonna introduce a consts.go like in other packages.

Copy link
Member

@jakubno jakubno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we use redis or clickhouse here?

hostname := "e2b.local"
eventProxyHostname := "events.e2b.dev"

eventIP := internal.GetSandboxEventIP()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to bake in into the template? Can't we use a mmds server here?

)

const (
defaultSandboxEventIP = "203.0.113.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you use TEST-NET-3 here?

Comment on lines +21 to +24
server := &http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: mux,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @sitole

@0div 0div marked this pull request as draft July 29, 2025 19:19
@sitole
Copy link
Member

sitole commented Aug 12, 2025

@0div is there some update?

I would like to use the sandbox -> orchestrator HTTP server you introduced here.
I'm thinking we could split it into separate PRs to make the review quicker?

@0div
Copy link
Contributor Author

0div commented Aug 13, 2025

@0div is there some update?

I would like to use the sandbox -> orchestrator HTTP server you introduced here. I'm thinking we could split it into separate PRs to make the review quicker?

@sitole , i put this back as draft bc i would start using it once i can consume it with the webhooks system i'm implenting.
What do you need this for exactly and how urgent do you need it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants