Skip to content

Commit d117ba0

Browse files
SDK v2 - Add beta pause and update Sandbox list (#854)
Introduce beta submodule with beta features - pause and resume Update Sandbox list to also return paused sandboxes --------- Co-authored-by: Tomas Valenta <[email protected]>
1 parent 1fbad37 commit d117ba0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+2796
-689
lines changed

.changeset/strange-hornets-judge.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.github/workflows/generated_files.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
cache-to: type=gha,mode=max
4949

5050
- name: Run codegen
51-
run: make codegen
51+
run: CODEGEN_IMAGE=codegen-env:latest make codegen
5252

5353
- name: Check for uncommitted changes
5454
run: |

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
.PHONY: codegen
22
codegen:
33
@echo "Generating SDK code from openapi and envd spec"
4-
@docker run -v "$$(pwd):/workspace" $$(docker build -q -t codegen-env . -f codegen.Dockerfile)
4+
@CODEGEN_IMAGE=$${CODEGEN_IMAGE:-$$(docker build -q -t codegen-env . -f codegen.Dockerfile)} ; \
5+
echo "Using codegen image: $$CODEGEN_IMAGE" \
6+
&& docker run -v $$PWD:/workspace $$CODEGEN_IMAGE make generate
7+
58
generate: generate-js generate-python
69

710
generate-js:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Python
6464
```py
6565
from e2b_code_interpreter import Sandbox
6666

67-
with Sandbox() as sandbox:
67+
with Sandbox.create() as sandbox:
6868
sandbox.run_code("x = 1")
6969
execution = sandbox.run_code("x+=1; x")
7070
print(execution.text) # outputs 2

codegen.Dockerfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ COPY --from=0 /go /go
3232
# Add Go binary to PATH
3333
ENV PATH="/go/bin:${PATH}"
3434

35-
# Install Python deps
36-
RUN pip install black==23.7.0 pyyaml==6.0.2 openapi-python-client==0.24.3
35+
# Install Python deps (e2b-openapi-python-client is patched version to fix issue with explode)
36+
# https://github.com/openapi-generators/openapi-python-client/pull/1296
37+
RUN pip install black==23.7.0 pyyaml==6.0.2 e2b-openapi-python-client==0.26.2
3738

3839
# Install Node.js and npm
3940
RUN apt-get update && \

packages/cli/src/commands/sandbox/spawn.ts renamed to packages/cli/src/commands/sandbox/create.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@ import { getConfigPath, loadConfig } from '../../config'
1010
import fs from 'fs'
1111
import { configOption, pathOption } from '../../options'
1212

13-
export const spawnCommand = new commander.Command('spawn')
14-
.description('spawn sandbox and connect terminal to it')
13+
export const createCommand = new commander.Command('create')
14+
.description('create sandbox and connect terminal to it')
1515
.argument(
1616
'[template]',
17-
`spawn and connect to sandbox specified by ${asBold('[template]')}`,
17+
`create and connect to sandbox specified by ${asBold('[template]')}`
1818
)
1919
.addOption(pathOption)
2020
.addOption(configOption)
21-
.alias('sp')
21+
.alias('cr')
2222
.action(
2323
async (
2424
template: string | undefined,
2525
opts: {
2626
name?: string
2727
path?: string
2828
config?: string
29-
},
29+
}
3030
) => {
3131
try {
3232
const apiKey = ensureAPIKey()
@@ -49,15 +49,15 @@ export const spawnCommand = new commander.Command('spawn')
4949
? [config.template_name]
5050
: undefined,
5151
},
52-
relativeConfigPath,
53-
)}`,
52+
relativeConfigPath
53+
)}`
5454
)
5555
templateID = config.template_id
5656
}
5757

5858
if (!templateID) {
5959
console.error(
60-
'You need to specify sandbox template ID or path to sandbox template config',
60+
'You need to specify sandbox template ID or path to sandbox template config'
6161
)
6262
process.exit(1)
6363
}
@@ -68,7 +68,7 @@ export const spawnCommand = new commander.Command('spawn')
6868
console.error(err)
6969
process.exit(1)
7070
}
71-
},
71+
}
7272
)
7373

7474
export async function connectSandbox({
@@ -87,8 +87,8 @@ export async function connectSandbox({
8787

8888
console.log(
8989
`Terminal connecting to template ${asFormattedSandboxTemplate(
90-
template,
91-
)} with sandbox ID ${asBold(`${sandbox.sandboxId}`)}`,
90+
template
91+
)} with sandbox ID ${asBold(`${sandbox.sandboxId}`)}`
9292
)
9393
try {
9494
await spawnConnectedTerminal(sandbox)
@@ -97,8 +97,8 @@ export async function connectSandbox({
9797
await sandbox.kill()
9898
console.log(
9999
`Closing terminal connection to template ${asFormattedSandboxTemplate(
100-
template,
101-
)} with sandbox ID ${asBold(`${sandbox.sandboxId}`)}`,
100+
template
101+
)} with sandbox ID ${asBold(`${sandbox.sandboxId}`)}`
102102
)
103103
}
104104
}

packages/cli/src/commands/sandbox/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as commander from 'commander'
33
import { connectCommand } from './connect'
44
import { listCommand } from './list'
55
import { killCommand } from './kill'
6-
import { spawnCommand } from './spawn'
6+
import { createCommand } from './create'
77
import { logsCommand } from './logs'
88
import { metricsCommand } from './metrics'
99

@@ -13,6 +13,6 @@ export const sandboxCommand = new commander.Command('sandbox')
1313
.addCommand(connectCommand)
1414
.addCommand(listCommand)
1515
.addCommand(killCommand)
16-
.addCommand(spawnCommand)
16+
.addCommand(createCommand)
1717
.addCommand(logsCommand)
1818
.addCommand(metricsCommand)

packages/cli/src/commands/sandbox/kill.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as commander from 'commander'
33
import { ensureAPIKey } from 'src/api'
44
import { asBold } from 'src/utils/format'
55
import * as e2b from 'e2b'
6+
import { listSandboxes } from './list'
67

78
async function killSandbox(sandboxID: string, apiKey: string) {
89
const killed = await e2b.Sandbox.kill(sandboxID, { apiKey })
@@ -17,7 +18,7 @@ export const killCommand = new commander.Command('kill')
1718
.description('kill sandbox')
1819
.argument(
1920
'[sandboxID]',
20-
`kill the sandbox specified by ${asBold('[sandboxID]')}`,
21+
`kill the sandbox specified by ${asBold('[sandboxID]')}`
2122
)
2223
.alias('kl')
2324
.option('-a, --all', 'kill all running sandboxes')
@@ -28,31 +29,32 @@ export const killCommand = new commander.Command('kill')
2829
if (!sandboxID && !all) {
2930
console.error(
3031
`You need to specify ${asBold('[sandboxID]')} or use ${asBold(
31-
'-a/--all',
32-
)} flag`,
32+
'-a/--all'
33+
)} flag`
3334
)
3435
process.exit(1)
3536
}
3637

3738
if (all && sandboxID) {
3839
console.error(
3940
`You cannot use ${asBold('-a/--all')} flag while specifying ${asBold(
40-
'[sandboxID]',
41-
)}`,
41+
'[sandboxID]'
42+
)}`
4243
)
4344
process.exit(1)
4445
}
4546

4647
if (all) {
47-
const sandboxes = await e2b.Sandbox.list({ apiKey })
48-
48+
const sandboxes = await listSandboxes({
49+
state: ['running'],
50+
})
4951
if (sandboxes.length === 0) {
5052
console.log('No running sandboxes')
5153
process.exit(0)
5254
}
5355

5456
await Promise.all(
55-
sandboxes.map((sandbox) => killSandbox(sandbox.sandboxId, apiKey)),
57+
sandboxes.map((sandbox) => killSandbox(sandbox.sandboxID, apiKey))
5658
)
5759
} else {
5860
await killSandbox(sandboxID, apiKey)

packages/cli/src/commands/sandbox/list.ts

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
import * as tablePrinter from 'console-table-printer'
22
import * as commander from 'commander'
3-
import * as e2b from 'e2b'
3+
import { components } from 'e2b'
44

55
import { client, connectionConfig, ensureAPIKey } from 'src/api'
66
import { handleE2BRequestError } from '../../utils/errors'
77

88
export const listCommand = new commander.Command('list')
99
.description('list all running sandboxes')
1010
.alias('ls')
11-
.action(async () => {
11+
.option(
12+
'-s, --state <state>',
13+
'filter by state, eg. running, stopped',
14+
(value) => value.split(',')
15+
)
16+
.option(
17+
'-m, --metadata <metadata>',
18+
'filter by metadata, eg. key1=value1',
19+
(value) => value.replace(/,/g, '&')
20+
)
21+
.option(
22+
'-l, --limit <limit>',
23+
'limit the number of sandboxes returned',
24+
(value) => parseInt(value)
25+
)
26+
.action(async (options) => {
1227
try {
13-
const sandboxes = await listSandboxes()
28+
const sandboxes = await listSandboxes({
29+
limit: options.limit,
30+
state: options.state,
31+
metadata: options.metadata,
32+
})
1433

1534
if (!sandboxes?.length) {
16-
console.log('No running sandboxes.')
35+
console.log('No sandboxes found')
1736
} else {
1837
const table = new tablePrinter.Table({
1938
title: 'Running sandboxes',
@@ -28,6 +47,7 @@ export const listCommand = new commander.Command('list')
2847
{ name: 'alias', alignment: 'left', title: 'Alias' },
2948
{ name: 'startedAt', alignment: 'left', title: 'Started at' },
3049
{ name: 'endAt', alignment: 'left', title: 'End at' },
50+
{ name: 'state', alignment: 'left', title: 'State' },
3151
{ name: 'cpuCount', alignment: 'left', title: 'vCPUs' },
3252
{ name: 'memoryMB', alignment: 'left', title: 'RAM MiB' },
3353
{ name: 'metadata', alignment: 'left', title: 'Metadata' },
@@ -39,6 +59,8 @@ export const listCommand = new commander.Command('list')
3959
sandboxID: sandbox.sandboxID,
4060
startedAt: new Date(sandbox.startedAt).toLocaleString(),
4161
endAt: new Date(sandbox.endAt).toLocaleString(),
62+
state:
63+
sandbox.state.charAt(0).toUpperCase() + sandbox.state.slice(1), // capitalize
4264
metadata: JSON.stringify(sandbox.metadata),
4365
}))
4466
.sort(
@@ -81,15 +103,51 @@ export const listCommand = new commander.Command('list')
81103
}
82104
})
83105

84-
export async function listSandboxes(): Promise<
85-
e2b.components['schemas']['ListedSandbox'][]
106+
type ListSandboxesOptions = {
107+
limit?: number
108+
state?: components['schemas']['SandboxState'][]
109+
metadata?: string
110+
}
111+
112+
export async function listSandboxes({
113+
limit,
114+
state,
115+
metadata,
116+
}: ListSandboxesOptions = {}): Promise<
117+
components['schemas']['ListedSandbox'][]
86118
> {
87119
ensureAPIKey()
88120

89121
const signal = connectionConfig.getSignal()
90-
const res = await client.api.GET('/sandboxes', { signal })
91122

92-
handleE2BRequestError(res, 'Error getting running sandboxes')
123+
let hasNext = true
124+
let nextToken: string | undefined
125+
let remainingLimit: number | undefined = limit
126+
127+
const sandboxes: components['schemas']['ListedSandbox'][] = []
128+
129+
while (hasNext && (!limit || (remainingLimit && remainingLimit > 0))) {
130+
const res = await client.api.GET('/v2/sandboxes', {
131+
params: {
132+
query: {
133+
state,
134+
metadata,
135+
nextToken,
136+
limit: remainingLimit,
137+
},
138+
},
139+
signal,
140+
})
141+
142+
handleE2BRequestError(res, 'Error getting running sandboxes')
143+
144+
nextToken = res.response.headers.get('x-next-token') || undefined
145+
hasNext = !!nextToken
146+
sandboxes.push(...res.data)
147+
if (limit && remainingLimit) {
148+
remainingLimit -= res.data.length
149+
}
150+
}
93151

94-
return res.data
152+
return sandboxes
95153
}

packages/cli/src/commands/sandbox/logs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export const logsCommand = new commander.Command('logs')
104104
console.log(`\nLogs for sandbox ${asBold(sandboxID)}:`)
105105
}
106106

107-
const isRunningPromise = listSandboxes()
107+
const isRunningPromise = listSandboxes({ state: ['running'] })
108108
.then((r) => r.find((s) => s.sandboxID === getShortID(sandboxID)))
109109
.then((s) => !!s)
110110

0 commit comments

Comments
 (0)