From f4c4bbde6a84d0f5fa485d17e3ac720a9975fef8 Mon Sep 17 00:00:00 2001 From: 0div Date: Mon, 23 Dec 2024 17:38:04 +0100 Subject: [PATCH 01/12] created boilerplate for integration tests within js-sdk --- packages/js-sdk/package.json | 3 +- .../js-sdk/tests/integration/stress.test.ts | 73 +++++++++++++++++++ .../tests/integration/template/README.md | 5 ++ .../tests/integration/template/e2b.Dockerfile | 8 ++ .../tests/integration/template/e2b.toml | 18 +++++ packages/js-sdk/tests/setup.ts | 3 +- packages/js-sdk/vitest.workspace.mts | 35 +++++---- 7 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 packages/js-sdk/tests/integration/stress.test.ts create mode 100644 packages/js-sdk/tests/integration/template/README.md create mode 100644 packages/js-sdk/tests/integration/template/e2b.Dockerfile create mode 100644 packages/js-sdk/tests/integration/template/e2b.toml diff --git a/packages/js-sdk/package.json b/packages/js-sdk/package.json index d57b08e15..ad2fdc50e 100644 --- a/packages/js-sdk/package.json +++ b/packages/js-sdk/package.json @@ -35,7 +35,8 @@ "update-deps": "ncu -u && pnpm i", "postPublish": "./scripts/post-publish.sh || true", "test:bun": "bun test tests/runtimes/bun --env-file=.env", - "test:deno": "deno test tests/runtimes/deno/ --allow-net --allow-read --allow-env --unstable-sloppy-imports --trace-leaks" + "test:deno": "deno test tests/runtimes/deno/ --allow-net --allow-read --allow-env --unstable-sloppy-imports --trace-leaks", + "test:integration": "E2B_INTEGRATION_TEST=1 vitest run tests/integration/**" }, "devDependencies": { "@testing-library/react": "^16.0.1", diff --git a/packages/js-sdk/tests/integration/stress.test.ts b/packages/js-sdk/tests/integration/stress.test.ts new file mode 100644 index 000000000..b82830372 --- /dev/null +++ b/packages/js-sdk/tests/integration/stress.test.ts @@ -0,0 +1,73 @@ +import { test } from 'vitest' + +import Sandbox from '../../src/index.js' +import { wait, isIntegrationTest } from '../setup.js' + +const heavyArray = new ArrayBuffer(256 * 1024 * 1024) // 256 MiB = 256 * 1024 * 1024 bytes +const view = new Uint8Array(heavyArray) +for (let i = 0; i < view.length; i++) { + view[i] = Math.floor(Math.random() * 256) +} + +const integrationTestTemplate = 'jonas_base' + +test.skipIf(!isIntegrationTest)( + 'stress test heavy file writes and reads', + async () => { + const promises: Array> = [] + for (let i = 0; i < 500; i++) { + promises.push( + Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }) + .then((sbx) => { + console.log(sbx.sandboxId) + return sbx.files + .write('heavy-file', heavyArray) + .then(() => sbx.files.read('heavy-file')) + }) + .catch(console.error) + ) + } + await wait(10_000) + await Promise.all(promises) + } +) + +test.skipIf(!isIntegrationTest)('stress network ingress', async ({}) => { + const promises: Array> = [] + + for (let i = 0; i < 10; i++) { + promises.push( + Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }).then((sbx) => { + console.log('created sandbox', sbx.sandboxId) + sbx.files + .write('heavy-file', heavyArray) + .then(() => { + sbx.commands.run('python -m http.server 8000', { background: true }) + }) + .then(() => { + new Promise((resolve, reject) => { + try { + resolve(sbx.getHost(8000)) + } catch (e) { + console.error('error getting sbx host', e) + reject(e) + } + }).then((host) => { + const url = `https://${host}` + console.log('fetching url', url) + fetch(url) + }) + + try { + sbx.kill() + } catch (e) { + console.error('error killing sbx', e) + } + }) + }) + ) + } + + await wait(10_000) + await Promise.all(promises) +}) diff --git a/packages/js-sdk/tests/integration/template/README.md b/packages/js-sdk/tests/integration/template/README.md new file mode 100644 index 000000000..2d4155dc3 --- /dev/null +++ b/packages/js-sdk/tests/integration/template/README.md @@ -0,0 +1,5 @@ +# Integration test template + +# Build the template + +`$ e2b template build"` diff --git a/packages/js-sdk/tests/integration/template/e2b.Dockerfile b/packages/js-sdk/tests/integration/template/e2b.Dockerfile new file mode 100644 index 000000000..65ceb7d65 --- /dev/null +++ b/packages/js-sdk/tests/integration/template/e2b.Dockerfile @@ -0,0 +1,8 @@ +FROM e2bdev/code-interpreter:latest + +# Clone the Next.js app repository +RUN git clone https://github.com/ezesundayeze/basic-nextjs-app + +# Install dependencies +RUN cd basic-nextjs-app && npm install + diff --git a/packages/js-sdk/tests/integration/template/e2b.toml b/packages/js-sdk/tests/integration/template/e2b.toml new file mode 100644 index 000000000..4f6dff736 --- /dev/null +++ b/packages/js-sdk/tests/integration/template/e2b.toml @@ -0,0 +1,18 @@ +# This is a config for E2B sandbox template. +# You can use template ID (2e2z80zhv34yumbrybvn) or template name (integration-test-v1) to create a sandbox: + +# Python SDK +# from e2b import Sandbox, AsyncSandbox +# sandbox = Sandbox("integration-test-v1") # Sync sandbox +# sandbox = await AsyncSandbox.create("integration-test-v1") # Async sandbox + +# JS SDK +# import { Sandbox } from 'e2b' +# const sandbox = await Sandbox.create('integration-test-v1') + +team_id = "b9c07023-d095-4bdc-9634-e25d5530ba47" +memory_mb = 1_024 +start_cmd = "npm run dev" +dockerfile = "e2b.Dockerfile" +template_name = "integration-test-v1" +template_id = "2e2z80zhv34yumbrybvn" diff --git a/packages/js-sdk/tests/setup.ts b/packages/js-sdk/tests/setup.ts index 7cdbd5e0c..30889c60f 100644 --- a/packages/js-sdk/tests/setup.ts +++ b/packages/js-sdk/tests/setup.ts @@ -1,7 +1,7 @@ import { Sandbox } from '../src' import { test as base } from 'vitest' -export const template = 'base' +export const template = 'jonas_base' interface SandboxFixture { sandbox: Sandbox @@ -30,6 +30,7 @@ export const sandboxTest = base.extend({ }) export const isDebug = process.env.E2B_DEBUG !== undefined +export const isIntegrationTest = process.env.E2B_INTEGRATION_TEST !== undefined export async function wait(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)) diff --git a/packages/js-sdk/vitest.workspace.mts b/packages/js-sdk/vitest.workspace.mts index 8ce2118f6..38006cd44 100644 --- a/packages/js-sdk/vitest.workspace.mts +++ b/packages/js-sdk/vitest.workspace.mts @@ -5,20 +5,11 @@ const env = config() export default defineWorkspace([ { test: { - include: [ - 'tests/**/*.test.ts', - ], - exclude: [ - 'tests/runtimes/**', - ], - poolOptions: { - threads: { - minThreads: 1, - maxThreads: 4, - }, - }, + include: ['tests/**/*.test.ts'], + exclude: ['tests/runtimes/**', 'tests/integration/**'], + isolate: false, // for projects that don't rely on side effects, disabling isolation will improve the speed of the tests globals: false, - testTimeout: 30000, + testTimeout: 30_000, environment: 'node', bail: 1, server: {}, @@ -26,7 +17,7 @@ export default defineWorkspace([ interopDefault: true, }, env: { - ...process.env as Record, + ...(process.env as Record), ...env.parsed, }, }, @@ -43,8 +34,8 @@ export default defineWorkspace([ providerOptions: {}, }, env: { - ...process.env as Record, - ...env.parsed, + ...(process.env as Record), + ...env.parsed, }, }, }, @@ -55,4 +46,16 @@ export default defineWorkspace([ environment: 'edge-runtime', }, }, + { + test: { + include: ['tests/integration/**/*.test.ts'], + globals: false, + testTimeout: 60_000, + environment: 'node', + env: { + ...(process.env as Record), + ...env.parsed, + }, + }, + }, ]) From 411631385d742cedbb7e3d9ef6fdb188e3baf82f Mon Sep 17 00:00:00 2001 From: 0div Date: Mon, 23 Dec 2024 17:42:39 +0100 Subject: [PATCH 02/12] rm integration test template work --- .../js-sdk/tests/integration/stress.test.ts | 73 ------------------- .../tests/integration/template/README.md | 5 -- .../tests/integration/template/e2b.Dockerfile | 8 -- .../tests/integration/template/e2b.toml | 18 ----- 4 files changed, 104 deletions(-) delete mode 100644 packages/js-sdk/tests/integration/stress.test.ts delete mode 100644 packages/js-sdk/tests/integration/template/README.md delete mode 100644 packages/js-sdk/tests/integration/template/e2b.Dockerfile delete mode 100644 packages/js-sdk/tests/integration/template/e2b.toml diff --git a/packages/js-sdk/tests/integration/stress.test.ts b/packages/js-sdk/tests/integration/stress.test.ts deleted file mode 100644 index b82830372..000000000 --- a/packages/js-sdk/tests/integration/stress.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { test } from 'vitest' - -import Sandbox from '../../src/index.js' -import { wait, isIntegrationTest } from '../setup.js' - -const heavyArray = new ArrayBuffer(256 * 1024 * 1024) // 256 MiB = 256 * 1024 * 1024 bytes -const view = new Uint8Array(heavyArray) -for (let i = 0; i < view.length; i++) { - view[i] = Math.floor(Math.random() * 256) -} - -const integrationTestTemplate = 'jonas_base' - -test.skipIf(!isIntegrationTest)( - 'stress test heavy file writes and reads', - async () => { - const promises: Array> = [] - for (let i = 0; i < 500; i++) { - promises.push( - Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }) - .then((sbx) => { - console.log(sbx.sandboxId) - return sbx.files - .write('heavy-file', heavyArray) - .then(() => sbx.files.read('heavy-file')) - }) - .catch(console.error) - ) - } - await wait(10_000) - await Promise.all(promises) - } -) - -test.skipIf(!isIntegrationTest)('stress network ingress', async ({}) => { - const promises: Array> = [] - - for (let i = 0; i < 10; i++) { - promises.push( - Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }).then((sbx) => { - console.log('created sandbox', sbx.sandboxId) - sbx.files - .write('heavy-file', heavyArray) - .then(() => { - sbx.commands.run('python -m http.server 8000', { background: true }) - }) - .then(() => { - new Promise((resolve, reject) => { - try { - resolve(sbx.getHost(8000)) - } catch (e) { - console.error('error getting sbx host', e) - reject(e) - } - }).then((host) => { - const url = `https://${host}` - console.log('fetching url', url) - fetch(url) - }) - - try { - sbx.kill() - } catch (e) { - console.error('error killing sbx', e) - } - }) - }) - ) - } - - await wait(10_000) - await Promise.all(promises) -}) diff --git a/packages/js-sdk/tests/integration/template/README.md b/packages/js-sdk/tests/integration/template/README.md deleted file mode 100644 index 2d4155dc3..000000000 --- a/packages/js-sdk/tests/integration/template/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Integration test template - -# Build the template - -`$ e2b template build"` diff --git a/packages/js-sdk/tests/integration/template/e2b.Dockerfile b/packages/js-sdk/tests/integration/template/e2b.Dockerfile deleted file mode 100644 index 65ceb7d65..000000000 --- a/packages/js-sdk/tests/integration/template/e2b.Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM e2bdev/code-interpreter:latest - -# Clone the Next.js app repository -RUN git clone https://github.com/ezesundayeze/basic-nextjs-app - -# Install dependencies -RUN cd basic-nextjs-app && npm install - diff --git a/packages/js-sdk/tests/integration/template/e2b.toml b/packages/js-sdk/tests/integration/template/e2b.toml deleted file mode 100644 index 4f6dff736..000000000 --- a/packages/js-sdk/tests/integration/template/e2b.toml +++ /dev/null @@ -1,18 +0,0 @@ -# This is a config for E2B sandbox template. -# You can use template ID (2e2z80zhv34yumbrybvn) or template name (integration-test-v1) to create a sandbox: - -# Python SDK -# from e2b import Sandbox, AsyncSandbox -# sandbox = Sandbox("integration-test-v1") # Sync sandbox -# sandbox = await AsyncSandbox.create("integration-test-v1") # Async sandbox - -# JS SDK -# import { Sandbox } from 'e2b' -# const sandbox = await Sandbox.create('integration-test-v1') - -team_id = "b9c07023-d095-4bdc-9634-e25d5530ba47" -memory_mb = 1_024 -start_cmd = "npm run dev" -dockerfile = "e2b.Dockerfile" -template_name = "integration-test-v1" -template_id = "2e2z80zhv34yumbrybvn" From d90fc02ed1586b5ffba4bcc7113442b37cf952e8 Mon Sep 17 00:00:00 2001 From: 0div Date: Mon, 23 Dec 2024 17:43:24 +0100 Subject: [PATCH 03/12] add stress tests --- .../js-sdk/tests/integration/stress.test.ts | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 packages/js-sdk/tests/integration/stress.test.ts diff --git a/packages/js-sdk/tests/integration/stress.test.ts b/packages/js-sdk/tests/integration/stress.test.ts new file mode 100644 index 000000000..b82830372 --- /dev/null +++ b/packages/js-sdk/tests/integration/stress.test.ts @@ -0,0 +1,73 @@ +import { test } from 'vitest' + +import Sandbox from '../../src/index.js' +import { wait, isIntegrationTest } from '../setup.js' + +const heavyArray = new ArrayBuffer(256 * 1024 * 1024) // 256 MiB = 256 * 1024 * 1024 bytes +const view = new Uint8Array(heavyArray) +for (let i = 0; i < view.length; i++) { + view[i] = Math.floor(Math.random() * 256) +} + +const integrationTestTemplate = 'jonas_base' + +test.skipIf(!isIntegrationTest)( + 'stress test heavy file writes and reads', + async () => { + const promises: Array> = [] + for (let i = 0; i < 500; i++) { + promises.push( + Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }) + .then((sbx) => { + console.log(sbx.sandboxId) + return sbx.files + .write('heavy-file', heavyArray) + .then(() => sbx.files.read('heavy-file')) + }) + .catch(console.error) + ) + } + await wait(10_000) + await Promise.all(promises) + } +) + +test.skipIf(!isIntegrationTest)('stress network ingress', async ({}) => { + const promises: Array> = [] + + for (let i = 0; i < 10; i++) { + promises.push( + Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }).then((sbx) => { + console.log('created sandbox', sbx.sandboxId) + sbx.files + .write('heavy-file', heavyArray) + .then(() => { + sbx.commands.run('python -m http.server 8000', { background: true }) + }) + .then(() => { + new Promise((resolve, reject) => { + try { + resolve(sbx.getHost(8000)) + } catch (e) { + console.error('error getting sbx host', e) + reject(e) + } + }).then((host) => { + const url = `https://${host}` + console.log('fetching url', url) + fetch(url) + }) + + try { + sbx.kill() + } catch (e) { + console.error('error killing sbx', e) + } + }) + }) + ) + } + + await wait(10_000) + await Promise.all(promises) +}) From 7dc89ac7368309e1db40dce1726307eca8458c9e Mon Sep 17 00:00:00 2001 From: 0div Date: Mon, 23 Dec 2024 17:56:19 +0100 Subject: [PATCH 04/12] boilerplate for integration test template build --- .../tests/integration/template/e2b.Dockerfile | 8 ++++++++ .../js-sdk/tests/integration/template/e2b.toml | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 packages/js-sdk/tests/integration/template/e2b.Dockerfile create mode 100644 packages/js-sdk/tests/integration/template/e2b.toml diff --git a/packages/js-sdk/tests/integration/template/e2b.Dockerfile b/packages/js-sdk/tests/integration/template/e2b.Dockerfile new file mode 100644 index 000000000..65ceb7d65 --- /dev/null +++ b/packages/js-sdk/tests/integration/template/e2b.Dockerfile @@ -0,0 +1,8 @@ +FROM e2bdev/code-interpreter:latest + +# Clone the Next.js app repository +RUN git clone https://github.com/ezesundayeze/basic-nextjs-app + +# Install dependencies +RUN cd basic-nextjs-app && npm install + diff --git a/packages/js-sdk/tests/integration/template/e2b.toml b/packages/js-sdk/tests/integration/template/e2b.toml new file mode 100644 index 000000000..4f6dff736 --- /dev/null +++ b/packages/js-sdk/tests/integration/template/e2b.toml @@ -0,0 +1,18 @@ +# This is a config for E2B sandbox template. +# You can use template ID (2e2z80zhv34yumbrybvn) or template name (integration-test-v1) to create a sandbox: + +# Python SDK +# from e2b import Sandbox, AsyncSandbox +# sandbox = Sandbox("integration-test-v1") # Sync sandbox +# sandbox = await AsyncSandbox.create("integration-test-v1") # Async sandbox + +# JS SDK +# import { Sandbox } from 'e2b' +# const sandbox = await Sandbox.create('integration-test-v1') + +team_id = "b9c07023-d095-4bdc-9634-e25d5530ba47" +memory_mb = 1_024 +start_cmd = "npm run dev" +dockerfile = "e2b.Dockerfile" +template_name = "integration-test-v1" +template_id = "2e2z80zhv34yumbrybvn" From 3245acd4d9829763e739c9ee7c6a34c1fcdfce2f Mon Sep 17 00:00:00 2001 From: 0div Date: Thu, 26 Dec 2024 11:27:24 +0100 Subject: [PATCH 05/12] fix template build command to include npm start command and add nextjs stress test to integration suite --- .../js-sdk/tests/integration/stress.test.ts | 41 +++++++++++++++++-- .../tests/integration/template/README.md | 5 +++ 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 packages/js-sdk/tests/integration/template/README.md diff --git a/packages/js-sdk/tests/integration/stress.test.ts b/packages/js-sdk/tests/integration/stress.test.ts index b82830372..c880dcbb2 100644 --- a/packages/js-sdk/tests/integration/stress.test.ts +++ b/packages/js-sdk/tests/integration/stress.test.ts @@ -9,13 +9,14 @@ for (let i = 0; i < view.length; i++) { view[i] = Math.floor(Math.random() * 256) } -const integrationTestTemplate = 'jonas_base' +const integrationTestTemplate = 'integration-test-v1' +const sanboxCount = 10 test.skipIf(!isIntegrationTest)( 'stress test heavy file writes and reads', async () => { const promises: Array> = [] - for (let i = 0; i < 500; i++) { + for (let i = 0; i < sanboxCount; i++) { promises.push( Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }) .then((sbx) => { @@ -35,7 +36,7 @@ test.skipIf(!isIntegrationTest)( test.skipIf(!isIntegrationTest)('stress network ingress', async ({}) => { const promises: Array> = [] - for (let i = 0; i < 10; i++) { + for (let i = 0; i < sanboxCount; i++) { promises.push( Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }).then((sbx) => { console.log('created sandbox', sbx.sandboxId) @@ -71,3 +72,37 @@ test.skipIf(!isIntegrationTest)('stress network ingress', async ({}) => { await wait(10_000) await Promise.all(promises) }) + +test.skipIf(!isIntegrationTest)('stress requests to nextjs app', async ({}) => { + const promises: Array> = [] + + for (let i = 0; i < sanboxCount; i++) { + promises.push( + Sandbox.create(integrationTestTemplate, { timeoutMs: 60_000 }) + .then((sbx) => { + console.log('created sandbox', sbx.sandboxId) + return new Promise((resolve, reject) => { + try { + resolve(sbx.getHost(3000)) + } catch (e) { + console.error('error getting sbx host', e) + reject(e) + } + }).then(async (host) => { + const url = `https://${host}` + console.log('fetching url', url) + await fetch(url).then(async (res) => { + console.log('response', res.status) + await res.text().then((text) => { + console.log('response body', text) + }) + }) + }) + }) + .catch(console.error) + ) + } + + await wait(10_000) + await Promise.all(promises) +}) diff --git a/packages/js-sdk/tests/integration/template/README.md b/packages/js-sdk/tests/integration/template/README.md new file mode 100644 index 000000000..7da9296a3 --- /dev/null +++ b/packages/js-sdk/tests/integration/template/README.md @@ -0,0 +1,5 @@ +# Integration test template + +# Build the template + +`$ e2b template build -c "cd /basic-nextjs-app/ && sudo npm run dev"` From e84bf8d0b4f431a3e03dd1da95bd87dd7edb2649 Mon Sep 17 00:00:00 2001 From: 0div Date: Thu, 26 Dec 2024 12:06:13 +0100 Subject: [PATCH 06/12] improve nextjs stress test --- .../js-sdk/tests/integration/stress.test.ts | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/js-sdk/tests/integration/stress.test.ts b/packages/js-sdk/tests/integration/stress.test.ts index c880dcbb2..7f2e3bd78 100644 --- a/packages/js-sdk/tests/integration/stress.test.ts +++ b/packages/js-sdk/tests/integration/stress.test.ts @@ -74,12 +74,12 @@ test.skipIf(!isIntegrationTest)('stress network ingress', async ({}) => { }) test.skipIf(!isIntegrationTest)('stress requests to nextjs app', async ({}) => { - const promises: Array> = [] + const hostPromises: Array> = [] for (let i = 0; i < sanboxCount; i++) { - promises.push( - Sandbox.create(integrationTestTemplate, { timeoutMs: 60_000 }) - .then((sbx) => { + hostPromises.push( + Sandbox.create(integrationTestTemplate, { timeoutMs: 60_000 }).then( + (sbx) => { console.log('created sandbox', sbx.sandboxId) return new Promise((resolve, reject) => { try { @@ -88,21 +88,30 @@ test.skipIf(!isIntegrationTest)('stress requests to nextjs app', async ({}) => { console.error('error getting sbx host', e) reject(e) } - }).then(async (host) => { - const url = `https://${host}` - console.log('fetching url', url) - await fetch(url).then(async (res) => { - console.log('response', res.status) - await res.text().then((text) => { - console.log('response body', text) - }) - }) }) - }) - .catch(console.error) + } + ) ) } await wait(10_000) - await Promise.all(promises) + const hosts = await Promise.all(hostPromises) + + const fetchPromises: Array> = [] + + for (let i = 0; i < 100; i++) { + for (const host of hosts) { + fetchPromises.push( + new Promise((resolve) => { + fetch('https://' + host) + .then((res) => { + console.log(`response for ${host}: ${res.status}`) + }) + .then(resolve) + }) + ) + } + } + + await Promise.all(fetchPromises) }) From c7ae7161fd7b86b4da77c2027ec2df9d989bd00b Mon Sep 17 00:00:00 2001 From: 0div <98087403+0div@users.noreply.github.com> Date: Fri, 17 Jan 2025 04:45:17 +0100 Subject: [PATCH 07/12] Update packages/js-sdk/tests/setup.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jakub Novák --- packages/js-sdk/tests/setup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/js-sdk/tests/setup.ts b/packages/js-sdk/tests/setup.ts index 30889c60f..5e5955f7f 100644 --- a/packages/js-sdk/tests/setup.ts +++ b/packages/js-sdk/tests/setup.ts @@ -1,7 +1,7 @@ import { Sandbox } from '../src' import { test as base } from 'vitest' -export const template = 'jonas_base' +export const template = 'base' interface SandboxFixture { sandbox: Sandbox From a76ce3f6f23e4b660704d02ff50c76136634445c Mon Sep 17 00:00:00 2001 From: 0div Date: Thu, 16 Jan 2025 20:16:42 -0800 Subject: [PATCH 08/12] used create-next-app in template; remove old draft test --- .../js-sdk/tests/integration/stress.test.ts | 42 +------------------ .../tests/integration/template/e2b.Dockerfile | 4 +- 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/packages/js-sdk/tests/integration/stress.test.ts b/packages/js-sdk/tests/integration/stress.test.ts index 7f2e3bd78..69da1472d 100644 --- a/packages/js-sdk/tests/integration/stress.test.ts +++ b/packages/js-sdk/tests/integration/stress.test.ts @@ -1,7 +1,7 @@ import { test } from 'vitest' import Sandbox from '../../src/index.js' -import { wait, isIntegrationTest } from '../setup.js' +import { isIntegrationTest, wait } from '../setup.js' const heavyArray = new ArrayBuffer(256 * 1024 * 1024) // 256 MiB = 256 * 1024 * 1024 bytes const view = new Uint8Array(heavyArray) @@ -33,46 +33,6 @@ test.skipIf(!isIntegrationTest)( } ) -test.skipIf(!isIntegrationTest)('stress network ingress', async ({}) => { - const promises: Array> = [] - - for (let i = 0; i < sanboxCount; i++) { - promises.push( - Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }).then((sbx) => { - console.log('created sandbox', sbx.sandboxId) - sbx.files - .write('heavy-file', heavyArray) - .then(() => { - sbx.commands.run('python -m http.server 8000', { background: true }) - }) - .then(() => { - new Promise((resolve, reject) => { - try { - resolve(sbx.getHost(8000)) - } catch (e) { - console.error('error getting sbx host', e) - reject(e) - } - }).then((host) => { - const url = `https://${host}` - console.log('fetching url', url) - fetch(url) - }) - - try { - sbx.kill() - } catch (e) { - console.error('error killing sbx', e) - } - }) - }) - ) - } - - await wait(10_000) - await Promise.all(promises) -}) - test.skipIf(!isIntegrationTest)('stress requests to nextjs app', async ({}) => { const hostPromises: Array> = [] diff --git a/packages/js-sdk/tests/integration/template/e2b.Dockerfile b/packages/js-sdk/tests/integration/template/e2b.Dockerfile index 65ceb7d65..2284ca7d3 100644 --- a/packages/js-sdk/tests/integration/template/e2b.Dockerfile +++ b/packages/js-sdk/tests/integration/template/e2b.Dockerfile @@ -1,7 +1,7 @@ FROM e2bdev/code-interpreter:latest -# Clone the Next.js app repository -RUN git clone https://github.com/ezesundayeze/basic-nextjs-app +# Create a basic Next.js app +RUN npx -y create-next-app@latest test --yes --ts --use-npm # Install dependencies RUN cd basic-nextjs-app && npm install From c1a883b61516c9efacc74436d2b7ef896ec4f43e Mon Sep 17 00:00:00 2001 From: Vasek Mlejnsky Date: Fri, 17 Jan 2025 09:50:30 -0800 Subject: [PATCH 09/12] Update docs page about env vars --- .../app/(docs)/docs/sandbox/environment-variables/page.mdx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/(docs)/docs/sandbox/environment-variables/page.mdx b/apps/web/src/app/(docs)/docs/sandbox/environment-variables/page.mdx index f9e94bd08..4aea88861 100644 --- a/apps/web/src/app/(docs)/docs/sandbox/environment-variables/page.mdx +++ b/apps/web/src/app/(docs)/docs/sandbox/environment-variables/page.mdx @@ -4,9 +4,8 @@ This page covers how to set and use environment variables in a sandbox, and defa ## Default environment variables ### Knowing if you are inside a sandbox - -Sometimes it's useful to know if you are inside a sandbox. Upon creating a sandbox, an environment variable `E2B_SANDBOX` is set to `true`. - +Sometimes it's useful to know if the code is running inside a sandbox. Upon creating a sandbox, an environment variable `E2B_SANDBOX` is automatically set to `true`. +You can try it out by running the following code in the sandbox: ```js @@ -15,7 +14,7 @@ const result = await sandbox.commands.run('echo $E2B_SANDBOX') ``` ```python sandbox = Sandbox() -result = sandbox.run_code("import os; os.getenv('E2B_SANDBOX')") +result = sandbox.commands.run("echo $E2B_SANDBOX") ``` From 594bb174d29a1ddf19aa551ec9aad71681c13930 Mon Sep 17 00:00:00 2001 From: Jakub Novak Date: Fri, 17 Jan 2025 11:01:40 -0800 Subject: [PATCH 10/12] Generate only relevant api routes for the client in SDKs --- packages/js-sdk/package.json | 2 +- packages/js-sdk/src/api/schema.gen.ts | 151 +++++++++-- packages/python-sdk/Makefile | 5 +- .../e2b/api/client/api/auth/__init__.py | 0 .../e2b/api/client/api/auth/get_teams.py | 137 ---------- .../e2b/api/client/api/default/__init__.py | 0 .../e2b/api/client/api/default/get_health.py | 81 ------ .../sandboxes/delete_sandboxes_sandbox_id.py | 4 +- .../api/client/api/sandboxes/get_sandboxes.py | 50 +++- .../get_sandboxes_sandbox_id_logs.py | 6 +- .../client/api/sandboxes/post_sandboxes.py | 6 +- .../e2b/api/client/api/templates/__init__.py | 0 .../templates/delete_templates_template_id.py | 97 -------- .../api/client/api/templates/get_templates.py | 169 ------------- ...ates_template_id_builds_build_id_status.py | 193 -------------- .../client/api/templates/post_templates.py | 166 ------------- .../templates/post_templates_template_id.py | 179 ------------- ...t_templates_template_id_builds_build_id.py | 104 -------- .../e2b/api/client/models/__init__.py | 14 ++ .../e2b/api/client/models/new_sandbox.py | 28 +-- .../e2b/api/client/models/running_sandbox.py | 60 ++--- .../e2b/api/client/models/sandbox.py | 32 +-- .../e2b/api/client/models/sandbox_log.py | 16 +- .../python-sdk/e2b/api/client/models/team.py | 32 +-- .../e2b/api/client/models/template.py | 89 ++++++- .../e2b/api/client/models/template_build.py | 32 +-- .../client/models/template_build_request.py | 36 +-- spec/openapi.yml | 235 +++++++++++++++++- spec/remove_extra_tags.py | 35 +++ 29 files changed, 662 insertions(+), 1297 deletions(-) delete mode 100644 packages/python-sdk/e2b/api/client/api/auth/__init__.py delete mode 100644 packages/python-sdk/e2b/api/client/api/auth/get_teams.py delete mode 100644 packages/python-sdk/e2b/api/client/api/default/__init__.py delete mode 100644 packages/python-sdk/e2b/api/client/api/default/get_health.py delete mode 100644 packages/python-sdk/e2b/api/client/api/templates/__init__.py delete mode 100644 packages/python-sdk/e2b/api/client/api/templates/delete_templates_template_id.py delete mode 100644 packages/python-sdk/e2b/api/client/api/templates/get_templates.py delete mode 100644 packages/python-sdk/e2b/api/client/api/templates/get_templates_template_id_builds_build_id_status.py delete mode 100644 packages/python-sdk/e2b/api/client/api/templates/post_templates.py delete mode 100644 packages/python-sdk/e2b/api/client/api/templates/post_templates_template_id.py delete mode 100644 packages/python-sdk/e2b/api/client/api/templates/post_templates_template_id_builds_build_id.py create mode 100644 spec/remove_extra_tags.py diff --git a/packages/js-sdk/package.json b/packages/js-sdk/package.json index d57b08e15..6fc6cd57e 100644 --- a/packages/js-sdk/package.json +++ b/packages/js-sdk/package.json @@ -28,7 +28,7 @@ "dev": "tsup --watch", "example": "tsx example.mts", "test": "vitest run", - "generate": "openapi-typescript ../../spec/openapi.yml -x api_key --support-array-length --alphabetize --output src/api/schema.gen.ts", + "generate": "python ./../../spec/remove_extra_tags.py sandboxes templates && openapi-typescript ../../spec/openapi_generated.yml -x api_key --support-array-length --alphabetize --output src/api/schema.gen.ts", "generate-envd-api": "openapi-typescript ../../spec/envd/envd.yaml -x api_key --support-array-length --alphabetize --output src/envd/schema.gen.ts", "generate-ref": "./scripts/generate_sdk_ref.sh", "check-deps": "knip", diff --git a/packages/js-sdk/src/api/schema.gen.ts b/packages/js-sdk/src/api/schema.gen.ts index 3cc9a39e3..6fe8e4642 100644 --- a/packages/js-sdk/src/api/schema.gen.ts +++ b/packages/js-sdk/src/api/schema.gen.ts @@ -5,21 +5,15 @@ export interface paths { - "/health": { - /** @description Health check */ - get: { - responses: { - /** @description Request was successful */ - 200: { - content: never; - }; - 401: components["responses"]["401"]; - }; - }; - }; "/sandboxes": { /** @description List all running sandboxes */ get: { + parameters: { + query?: { + /** @description A list of filters with key-value pairs (e.g. user:abc, app:prod). */ + filter?: string[]; + }; + }; responses: { /** @description Successfully returned all running sandboxes */ 200: { @@ -53,6 +47,25 @@ export interface paths { }; }; "/sandboxes/{sandboxID}": { + /** @description Get a sandbox by id */ + get: { + parameters: { + path: { + sandboxID: components["parameters"]["sandboxID"]; + }; + }; + responses: { + /** @description Successfully returned the sandbox */ + 200: { + content: { + "application/json": components["schemas"]["RunningSandbox"]; + }; + }; + 401: components["responses"]["401"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; /** @description Kill a sandbox */ delete: { parameters: { @@ -98,6 +111,26 @@ export interface paths { }; }; }; + "/sandboxes/{sandboxID}/pause": { + /** @description Pause the sandbox */ + post: { + parameters: { + path: { + sandboxID: components["parameters"]["sandboxID"]; + }; + }; + responses: { + /** @description The sandbox was paused successfully and can be resumed */ + 204: { + content: never; + }; + 401: components["responses"]["401"]; + 404: components["responses"]["404"]; + 409: components["responses"]["409"]; + 500: components["responses"]["500"]; + }; + }; + }; "/sandboxes/{sandboxID}/refreshes": { /** @description Refresh the sandbox extending its time to live */ post: { @@ -124,6 +157,33 @@ export interface paths { }; }; }; + "/sandboxes/{sandboxID}/resume": { + /** @description Resume the sandbox */ + post: { + parameters: { + path: { + sandboxID: components["parameters"]["sandboxID"]; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ResumedSandbox"]; + }; + }; + responses: { + /** @description The sandbox was resumed successfully */ + 201: { + content: { + "application/json": components["schemas"]["Sandbox"]; + }; + }; + 401: components["responses"]["401"]; + 404: components["responses"]["404"]; + 409: components["responses"]["409"]; + 500: components["responses"]["500"]; + }; + }; + }; "/sandboxes/{sandboxID}/timeout": { /** @description Set the timeout for the sandbox. The sandbox will expire x seconds from the time of the request. Calling this method multiple times overwrites the TTL, each time using the current timestamp as the starting point to measure the timeout duration. */ post: { @@ -154,21 +214,6 @@ export interface paths { }; }; }; - "/teams": { - /** @description List all teams */ - get: { - responses: { - /** @description Successfully returned all teams */ - 200: { - content: { - "application/json": components["schemas"]["Team"][]; - }; - }; - 401: components["responses"]["401"]; - 500: components["responses"]["500"]; - }; - }; - }; "/templates": { /** @description List all templates */ get: { @@ -355,6 +400,51 @@ export interface components { */ timeout?: number; }; + Node: { + /** + * Format: int32 + * @description Number of allocated CPU cores + */ + allocatedCPU: number; + /** + * Format: int32 + * @description Amount of allocated memory in MiB + */ + allocatedMemoryMiB: number; + /** @description Identifier of the node */ + nodeID: string; + /** + * Format: int32 + * @description Number of sandboxes running on the node + */ + sandboxCount: number; + status: components["schemas"]["NodeStatus"]; + }; + NodeDetail: { + /** @description List of cached builds id on the node */ + cachedBuilds: string[]; + /** @description Identifier of the node */ + nodeID: string; + /** @description List of sandboxes running on the node */ + sandboxes: components["schemas"]["RunningSandbox"][]; + status: components["schemas"]["NodeStatus"]; + }; + /** + * @description Status of the node + * @enum {string} + */ + NodeStatus: "ready" | "draining"; + NodeStatusChange: { + status: components["schemas"]["NodeStatus"]; + }; + ResumedSandbox: { + /** + * Format: int32 + * @description Time to live for the sandbox in seconds. + * @default 15 + */ + timeout?: number; + }; RunningSandbox: { /** @description Alias of the template */ alias?: string; @@ -516,6 +606,12 @@ export interface components { "application/json": components["schemas"]["Error"]; }; }; + /** @description Conflict */ + 409: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; /** @description Server error */ 500: { content: { @@ -525,6 +621,7 @@ export interface components { }; parameters: { buildID: string; + nodeID: string; sandboxID: string; templateID: string; }; diff --git a/packages/python-sdk/Makefile b/packages/python-sdk/Makefile index c99288d06..c1b169c53 100644 --- a/packages/python-sdk/Makefile +++ b/packages/python-sdk/Makefile @@ -1,8 +1,9 @@ generate-api: - openapi-python-client generate --output-path e2b/api/api --overwrite --path ../../spec/openapi.yml + python ./../../spec/remove_extra_tags.py sandboxes + openapi-python-client generate --output-path e2b/api/api --overwrite --path ../../spec/openapi_generated.yml rm -rf e2b/api/client mv e2b/api/api/e2b_api_client e2b/api/client rm -rf e2b/api/api init: - pip install openapi-python-client \ No newline at end of file + pip install openapi-python-client diff --git a/packages/python-sdk/e2b/api/client/api/auth/__init__.py b/packages/python-sdk/e2b/api/client/api/auth/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/python-sdk/e2b/api/client/api/auth/get_teams.py b/packages/python-sdk/e2b/api/client/api/auth/get_teams.py deleted file mode 100644 index d26eb508b..000000000 --- a/packages/python-sdk/e2b/api/client/api/auth/get_teams.py +++ /dev/null @@ -1,137 +0,0 @@ -from http import HTTPStatus -from typing import Any, Dict, List, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.team import Team -from ...types import Response - - -def _get_kwargs() -> Dict[str, Any]: - _kwargs: Dict[str, Any] = { - "method": "get", - "url": "/teams", - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, List["Team"]]]: - if response.status_code == HTTPStatus.OK: - response_200 = [] - _response_200 = response.json() - for response_200_item_data in _response_200: - response_200_item = Team.from_dict(response_200_item_data) - - response_200.append(response_200_item) - - return response_200 - if response.status_code == HTTPStatus.UNAUTHORIZED: - response_401 = cast(Any, None) - return response_401 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: - response_500 = cast(Any, None) - return response_500 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, List["Team"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: AuthenticatedClient, -) -> Response[Union[Any, List["Team"]]]: - """List all teams - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, List['Team']]] - """ - - kwargs = _get_kwargs() - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: AuthenticatedClient, -) -> Optional[Union[Any, List["Team"]]]: - """List all teams - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, List['Team']] - """ - - return sync_detailed( - client=client, - ).parsed - - -async def asyncio_detailed( - *, - client: AuthenticatedClient, -) -> Response[Union[Any, List["Team"]]]: - """List all teams - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, List['Team']]] - """ - - kwargs = _get_kwargs() - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: AuthenticatedClient, -) -> Optional[Union[Any, List["Team"]]]: - """List all teams - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, List['Team']] - """ - - return ( - await asyncio_detailed( - client=client, - ) - ).parsed diff --git a/packages/python-sdk/e2b/api/client/api/default/__init__.py b/packages/python-sdk/e2b/api/client/api/default/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/python-sdk/e2b/api/client/api/default/get_health.py b/packages/python-sdk/e2b/api/client/api/default/get_health.py deleted file mode 100644 index 339a6905f..000000000 --- a/packages/python-sdk/e2b/api/client/api/default/get_health.py +++ /dev/null @@ -1,81 +0,0 @@ -from http import HTTPStatus -from typing import Any, Dict, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...types import Response - - -def _get_kwargs() -> Dict[str, Any]: - _kwargs: Dict[str, Any] = { - "method": "get", - "url": "/health", - } - - return _kwargs - - -def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: - if response.status_code == HTTPStatus.OK: - return None - if response.status_code == HTTPStatus.UNAUTHORIZED: - return None - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Any]: - """Health check - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - - kwargs = _get_kwargs() - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -async def asyncio_detailed( - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Any]: - """Health check - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - - kwargs = _get_kwargs() - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py b/packages/python-sdk/e2b/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py index fa9f37750..30a419c00 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py @@ -22,10 +22,10 @@ def _get_kwargs( def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: if response.status_code == HTTPStatus.NO_CONTENT: return None - if response.status_code == HTTPStatus.NOT_FOUND: - return None if response.status_code == HTTPStatus.UNAUTHORIZED: return None + if response.status_code == HTTPStatus.NOT_FOUND: + return None if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: return None if client.raise_on_unexpected_status: diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes.py b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes.py index 70bb816f7..71539e473 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes.py @@ -6,13 +6,27 @@ from ... import errors from ...client import AuthenticatedClient, Client from ...models.running_sandbox import RunningSandbox -from ...types import Response +from ...types import UNSET, Response, Unset -def _get_kwargs() -> Dict[str, Any]: +def _get_kwargs( + *, + filter_: Union[Unset, List[str]] = UNSET, +) -> Dict[str, Any]: + params: Dict[str, Any] = {} + + json_filter_: Union[Unset, List[str]] = UNSET + if not isinstance(filter_, Unset): + json_filter_ = filter_ + + params["filter"] = json_filter_ + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + _kwargs: Dict[str, Any] = { "method": "get", "url": "/sandboxes", + "params": params, } return _kwargs @@ -30,12 +44,12 @@ def _parse_response( response_200.append(response_200_item) return response_200 - if response.status_code == HTTPStatus.UNAUTHORIZED: - response_401 = cast(Any, None) - return response_401 if response.status_code == HTTPStatus.BAD_REQUEST: response_400 = cast(Any, None) return response_400 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = cast(Any, None) + return response_401 if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: response_500 = cast(Any, None) return response_500 @@ -59,9 +73,13 @@ def _build_response( def sync_detailed( *, client: AuthenticatedClient, + filter_: Union[Unset, List[str]] = UNSET, ) -> Response[Union[Any, List["RunningSandbox"]]]: """List all running sandboxes + Args: + filter_ (Union[Unset, List[str]]): + Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. @@ -70,7 +88,9 @@ def sync_detailed( Response[Union[Any, List['RunningSandbox']]] """ - kwargs = _get_kwargs() + kwargs = _get_kwargs( + filter_=filter_, + ) response = client.get_httpx_client().request( **kwargs, @@ -82,9 +102,13 @@ def sync_detailed( def sync( *, client: AuthenticatedClient, + filter_: Union[Unset, List[str]] = UNSET, ) -> Optional[Union[Any, List["RunningSandbox"]]]: """List all running sandboxes + Args: + filter_ (Union[Unset, List[str]]): + Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. @@ -95,15 +119,20 @@ def sync( return sync_detailed( client=client, + filter_=filter_, ).parsed async def asyncio_detailed( *, client: AuthenticatedClient, + filter_: Union[Unset, List[str]] = UNSET, ) -> Response[Union[Any, List["RunningSandbox"]]]: """List all running sandboxes + Args: + filter_ (Union[Unset, List[str]]): + Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. @@ -112,7 +141,9 @@ async def asyncio_detailed( Response[Union[Any, List['RunningSandbox']]] """ - kwargs = _get_kwargs() + kwargs = _get_kwargs( + filter_=filter_, + ) response = await client.get_async_httpx_client().request(**kwargs) @@ -122,9 +153,13 @@ async def asyncio_detailed( async def asyncio( *, client: AuthenticatedClient, + filter_: Union[Unset, List[str]] = UNSET, ) -> Optional[Union[Any, List["RunningSandbox"]]]: """List all running sandboxes + Args: + filter_ (Union[Unset, List[str]]): + Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. @@ -136,5 +171,6 @@ async def asyncio( return ( await asyncio_detailed( client=client, + filter_=filter_, ) ).parsed diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py index 97325e59b..7c70e28b7 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py @@ -39,12 +39,12 @@ def _parse_response( response_200 = SandboxLogs.from_dict(response.json()) return response_200 - if response.status_code == HTTPStatus.NOT_FOUND: - response_404 = cast(Any, None) - return response_404 if response.status_code == HTTPStatus.UNAUTHORIZED: response_401 = cast(Any, None) return response_401 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = cast(Any, None) + return response_404 if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: response_500 = cast(Any, None) return response_500 diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes.py b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes.py index 56220c047..70fa540da 100644 --- a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes.py +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes.py @@ -37,12 +37,12 @@ def _parse_response( response_201 = Sandbox.from_dict(response.json()) return response_201 - if response.status_code == HTTPStatus.UNAUTHORIZED: - response_401 = cast(Any, None) - return response_401 if response.status_code == HTTPStatus.BAD_REQUEST: response_400 = cast(Any, None) return response_400 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = cast(Any, None) + return response_401 if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: response_500 = cast(Any, None) return response_500 diff --git a/packages/python-sdk/e2b/api/client/api/templates/__init__.py b/packages/python-sdk/e2b/api/client/api/templates/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/python-sdk/e2b/api/client/api/templates/delete_templates_template_id.py b/packages/python-sdk/e2b/api/client/api/templates/delete_templates_template_id.py deleted file mode 100644 index d493420f3..000000000 --- a/packages/python-sdk/e2b/api/client/api/templates/delete_templates_template_id.py +++ /dev/null @@ -1,97 +0,0 @@ -from http import HTTPStatus -from typing import Any, Dict, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...types import Response - - -def _get_kwargs( - template_id: str, -) -> Dict[str, Any]: - _kwargs: Dict[str, Any] = { - "method": "delete", - "url": f"/templates/{template_id}", - } - - return _kwargs - - -def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: - if response.status_code == HTTPStatus.NO_CONTENT: - return None - if response.status_code == HTTPStatus.UNAUTHORIZED: - return None - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: - return None - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - template_id: str, - *, - client: AuthenticatedClient, -) -> Response[Any]: - """Delete a template - - Args: - template_id (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - - kwargs = _get_kwargs( - template_id=template_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -async def asyncio_detailed( - template_id: str, - *, - client: AuthenticatedClient, -) -> Response[Any]: - """Delete a template - - Args: - template_id (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - - kwargs = _get_kwargs( - template_id=template_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) diff --git a/packages/python-sdk/e2b/api/client/api/templates/get_templates.py b/packages/python-sdk/e2b/api/client/api/templates/get_templates.py deleted file mode 100644 index d50150950..000000000 --- a/packages/python-sdk/e2b/api/client/api/templates/get_templates.py +++ /dev/null @@ -1,169 +0,0 @@ -from http import HTTPStatus -from typing import Any, Dict, List, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.template import Template -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - *, - team_id: Union[Unset, str] = UNSET, -) -> Dict[str, Any]: - params: Dict[str, Any] = {} - - params["teamID"] = team_id - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: Dict[str, Any] = { - "method": "get", - "url": "/templates", - "params": params, - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, List["Template"]]]: - if response.status_code == HTTPStatus.OK: - response_200 = [] - _response_200 = response.json() - for response_200_item_data in _response_200: - response_200_item = Template.from_dict(response_200_item_data) - - response_200.append(response_200_item) - - return response_200 - if response.status_code == HTTPStatus.UNAUTHORIZED: - response_401 = cast(Any, None) - return response_401 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: - response_500 = cast(Any, None) - return response_500 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, List["Template"]]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: AuthenticatedClient, - team_id: Union[Unset, str] = UNSET, -) -> Response[Union[Any, List["Template"]]]: - """List all templates - - Args: - team_id (Union[Unset, str]): Identifier of the team - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, List['Template']]] - """ - - kwargs = _get_kwargs( - team_id=team_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: AuthenticatedClient, - team_id: Union[Unset, str] = UNSET, -) -> Optional[Union[Any, List["Template"]]]: - """List all templates - - Args: - team_id (Union[Unset, str]): Identifier of the team - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, List['Template']] - """ - - return sync_detailed( - client=client, - team_id=team_id, - ).parsed - - -async def asyncio_detailed( - *, - client: AuthenticatedClient, - team_id: Union[Unset, str] = UNSET, -) -> Response[Union[Any, List["Template"]]]: - """List all templates - - Args: - team_id (Union[Unset, str]): Identifier of the team - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, List['Template']]] - """ - - kwargs = _get_kwargs( - team_id=team_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: AuthenticatedClient, - team_id: Union[Unset, str] = UNSET, -) -> Optional[Union[Any, List["Template"]]]: - """List all templates - - Args: - team_id (Union[Unset, str]): Identifier of the team - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, List['Template']] - """ - - return ( - await asyncio_detailed( - client=client, - team_id=team_id, - ) - ).parsed diff --git a/packages/python-sdk/e2b/api/client/api/templates/get_templates_template_id_builds_build_id_status.py b/packages/python-sdk/e2b/api/client/api/templates/get_templates_template_id_builds_build_id_status.py deleted file mode 100644 index 6918199ce..000000000 --- a/packages/python-sdk/e2b/api/client/api/templates/get_templates_template_id_builds_build_id_status.py +++ /dev/null @@ -1,193 +0,0 @@ -from http import HTTPStatus -from typing import Any, Dict, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.template_build import TemplateBuild -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - template_id: str, - build_id: str, - *, - logs_offset: Union[Unset, int] = 0, -) -> Dict[str, Any]: - params: Dict[str, Any] = {} - - params["logsOffset"] = logs_offset - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: Dict[str, Any] = { - "method": "get", - "url": f"/templates/{template_id}/builds/{build_id}/status", - "params": params, - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, TemplateBuild]]: - if response.status_code == HTTPStatus.OK: - response_200 = TemplateBuild.from_dict(response.json()) - - return response_200 - if response.status_code == HTTPStatus.UNAUTHORIZED: - response_401 = cast(Any, None) - return response_401 - if response.status_code == HTTPStatus.NOT_FOUND: - response_404 = cast(Any, None) - return response_404 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: - response_500 = cast(Any, None) - return response_500 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, TemplateBuild]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - template_id: str, - build_id: str, - *, - client: AuthenticatedClient, - logs_offset: Union[Unset, int] = 0, -) -> Response[Union[Any, TemplateBuild]]: - """Get template build info - - Args: - template_id (str): - build_id (str): - logs_offset (Union[Unset, int]): Default: 0. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, TemplateBuild]] - """ - - kwargs = _get_kwargs( - template_id=template_id, - build_id=build_id, - logs_offset=logs_offset, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - template_id: str, - build_id: str, - *, - client: AuthenticatedClient, - logs_offset: Union[Unset, int] = 0, -) -> Optional[Union[Any, TemplateBuild]]: - """Get template build info - - Args: - template_id (str): - build_id (str): - logs_offset (Union[Unset, int]): Default: 0. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, TemplateBuild] - """ - - return sync_detailed( - template_id=template_id, - build_id=build_id, - client=client, - logs_offset=logs_offset, - ).parsed - - -async def asyncio_detailed( - template_id: str, - build_id: str, - *, - client: AuthenticatedClient, - logs_offset: Union[Unset, int] = 0, -) -> Response[Union[Any, TemplateBuild]]: - """Get template build info - - Args: - template_id (str): - build_id (str): - logs_offset (Union[Unset, int]): Default: 0. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, TemplateBuild]] - """ - - kwargs = _get_kwargs( - template_id=template_id, - build_id=build_id, - logs_offset=logs_offset, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - template_id: str, - build_id: str, - *, - client: AuthenticatedClient, - logs_offset: Union[Unset, int] = 0, -) -> Optional[Union[Any, TemplateBuild]]: - """Get template build info - - Args: - template_id (str): - build_id (str): - logs_offset (Union[Unset, int]): Default: 0. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, TemplateBuild] - """ - - return ( - await asyncio_detailed( - template_id=template_id, - build_id=build_id, - client=client, - logs_offset=logs_offset, - ) - ).parsed diff --git a/packages/python-sdk/e2b/api/client/api/templates/post_templates.py b/packages/python-sdk/e2b/api/client/api/templates/post_templates.py deleted file mode 100644 index bf0e5bd2e..000000000 --- a/packages/python-sdk/e2b/api/client/api/templates/post_templates.py +++ /dev/null @@ -1,166 +0,0 @@ -from http import HTTPStatus -from typing import Any, Dict, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.template import Template -from ...models.template_build_request import TemplateBuildRequest -from ...types import Response - - -def _get_kwargs( - *, - body: TemplateBuildRequest, -) -> Dict[str, Any]: - headers: Dict[str, Any] = {} - - _kwargs: Dict[str, Any] = { - "method": "post", - "url": "/templates", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, Template]]: - if response.status_code == HTTPStatus.ACCEPTED: - response_202 = Template.from_dict(response.json()) - - return response_202 - if response.status_code == HTTPStatus.UNAUTHORIZED: - response_401 = cast(Any, None) - return response_401 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: - response_500 = cast(Any, None) - return response_500 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, Template]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: AuthenticatedClient, - body: TemplateBuildRequest, -) -> Response[Union[Any, Template]]: - """Create a new template - - Args: - body (TemplateBuildRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, Template]] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: AuthenticatedClient, - body: TemplateBuildRequest, -) -> Optional[Union[Any, Template]]: - """Create a new template - - Args: - body (TemplateBuildRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, Template] - """ - - return sync_detailed( - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - *, - client: AuthenticatedClient, - body: TemplateBuildRequest, -) -> Response[Union[Any, Template]]: - """Create a new template - - Args: - body (TemplateBuildRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, Template]] - """ - - kwargs = _get_kwargs( - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: AuthenticatedClient, - body: TemplateBuildRequest, -) -> Optional[Union[Any, Template]]: - """Create a new template - - Args: - body (TemplateBuildRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, Template] - """ - - return ( - await asyncio_detailed( - client=client, - body=body, - ) - ).parsed diff --git a/packages/python-sdk/e2b/api/client/api/templates/post_templates_template_id.py b/packages/python-sdk/e2b/api/client/api/templates/post_templates_template_id.py deleted file mode 100644 index 9221efb8f..000000000 --- a/packages/python-sdk/e2b/api/client/api/templates/post_templates_template_id.py +++ /dev/null @@ -1,179 +0,0 @@ -from http import HTTPStatus -from typing import Any, Dict, Optional, Union, cast - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.template import Template -from ...models.template_build_request import TemplateBuildRequest -from ...types import Response - - -def _get_kwargs( - template_id: str, - *, - body: TemplateBuildRequest, -) -> Dict[str, Any]: - headers: Dict[str, Any] = {} - - _kwargs: Dict[str, Any] = { - "method": "post", - "url": f"/templates/{template_id}", - } - - _body = body.to_dict() - - _kwargs["json"] = _body - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[Any, Template]]: - if response.status_code == HTTPStatus.ACCEPTED: - response_202 = Template.from_dict(response.json()) - - return response_202 - if response.status_code == HTTPStatus.UNAUTHORIZED: - response_401 = cast(Any, None) - return response_401 - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: - response_500 = cast(Any, None) - return response_500 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[Any, Template]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - template_id: str, - *, - client: AuthenticatedClient, - body: TemplateBuildRequest, -) -> Response[Union[Any, Template]]: - """Rebuild an template - - Args: - template_id (str): - body (TemplateBuildRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, Template]] - """ - - kwargs = _get_kwargs( - template_id=template_id, - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - template_id: str, - *, - client: AuthenticatedClient, - body: TemplateBuildRequest, -) -> Optional[Union[Any, Template]]: - """Rebuild an template - - Args: - template_id (str): - body (TemplateBuildRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, Template] - """ - - return sync_detailed( - template_id=template_id, - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - template_id: str, - *, - client: AuthenticatedClient, - body: TemplateBuildRequest, -) -> Response[Union[Any, Template]]: - """Rebuild an template - - Args: - template_id (str): - body (TemplateBuildRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[Any, Template]] - """ - - kwargs = _get_kwargs( - template_id=template_id, - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - template_id: str, - *, - client: AuthenticatedClient, - body: TemplateBuildRequest, -) -> Optional[Union[Any, Template]]: - """Rebuild an template - - Args: - template_id (str): - body (TemplateBuildRequest): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[Any, Template] - """ - - return ( - await asyncio_detailed( - template_id=template_id, - client=client, - body=body, - ) - ).parsed diff --git a/packages/python-sdk/e2b/api/client/api/templates/post_templates_template_id_builds_build_id.py b/packages/python-sdk/e2b/api/client/api/templates/post_templates_template_id_builds_build_id.py deleted file mode 100644 index 67e21c739..000000000 --- a/packages/python-sdk/e2b/api/client/api/templates/post_templates_template_id_builds_build_id.py +++ /dev/null @@ -1,104 +0,0 @@ -from http import HTTPStatus -from typing import Any, Dict, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...types import Response - - -def _get_kwargs( - template_id: str, - build_id: str, -) -> Dict[str, Any]: - _kwargs: Dict[str, Any] = { - "method": "post", - "url": f"/templates/{template_id}/builds/{build_id}", - } - - return _kwargs - - -def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: - if response.status_code == HTTPStatus.ACCEPTED: - return None - if response.status_code == HTTPStatus.UNAUTHORIZED: - return None - if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: - return None - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - template_id: str, - build_id: str, - *, - client: AuthenticatedClient, -) -> Response[Any]: - """Start the build - - Args: - template_id (str): - build_id (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - - kwargs = _get_kwargs( - template_id=template_id, - build_id=build_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -async def asyncio_detailed( - template_id: str, - build_id: str, - *, - client: AuthenticatedClient, -) -> Response[Any]: - """Start the build - - Args: - template_id (str): - build_id (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Any] - """ - - kwargs = _get_kwargs( - template_id=template_id, - build_id=build_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) diff --git a/packages/python-sdk/e2b/api/client/models/__init__.py b/packages/python-sdk/e2b/api/client/models/__init__.py index d55b958c2..ec61ba395 100644 --- a/packages/python-sdk/e2b/api/client/models/__init__.py +++ b/packages/python-sdk/e2b/api/client/models/__init__.py @@ -2,30 +2,44 @@ from .error import Error from .new_sandbox import NewSandbox +from .node import Node +from .node_detail import NodeDetail +from .node_status import NodeStatus +from .node_status_change import NodeStatusChange from .post_sandboxes_sandbox_id_refreshes_body import PostSandboxesSandboxIDRefreshesBody from .post_sandboxes_sandbox_id_timeout_body import PostSandboxesSandboxIDTimeoutBody +from .resumed_sandbox import ResumedSandbox from .running_sandbox import RunningSandbox from .sandbox import Sandbox from .sandbox_log import SandboxLog from .sandbox_logs import SandboxLogs from .team import Team +from .team_user import TeamUser from .template import Template from .template_build import TemplateBuild from .template_build_request import TemplateBuildRequest from .template_build_status import TemplateBuildStatus +from .template_update_request import TemplateUpdateRequest __all__ = ( "Error", "NewSandbox", + "Node", + "NodeDetail", + "NodeStatus", + "NodeStatusChange", "PostSandboxesSandboxIDRefreshesBody", "PostSandboxesSandboxIDTimeoutBody", + "ResumedSandbox", "RunningSandbox", "Sandbox", "SandboxLog", "SandboxLogs", "Team", + "TeamUser", "Template", "TemplateBuild", "TemplateBuildRequest", "TemplateBuildStatus", + "TemplateUpdateRequest", ) diff --git a/packages/python-sdk/e2b/api/client/models/new_sandbox.py b/packages/python-sdk/e2b/api/client/models/new_sandbox.py index 2094bb5a6..10cf61310 100644 --- a/packages/python-sdk/e2b/api/client/models/new_sandbox.py +++ b/packages/python-sdk/e2b/api/client/models/new_sandbox.py @@ -13,25 +13,25 @@ class NewSandbox: """ Attributes: template_id (str): Identifier of the required template - timeout (Union[Unset, int]): Time to live for the sandbox in seconds. Default: 15. - metadata (Union[Unset, Any]): env_vars (Union[Unset, Any]): + metadata (Union[Unset, Any]): + timeout (Union[Unset, int]): Time to live for the sandbox in seconds. Default: 15. """ template_id: str - timeout: Union[Unset, int] = 15 - metadata: Union[Unset, Any] = UNSET env_vars: Union[Unset, Any] = UNSET + metadata: Union[Unset, Any] = UNSET + timeout: Union[Unset, int] = 15 additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: template_id = self.template_id - timeout = self.timeout + env_vars = self.env_vars metadata = self.metadata - env_vars = self.env_vars + timeout = self.timeout field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) @@ -40,12 +40,12 @@ def to_dict(self) -> Dict[str, Any]: "templateID": template_id, } ) - if timeout is not UNSET: - field_dict["timeout"] = timeout - if metadata is not UNSET: - field_dict["metadata"] = metadata if env_vars is not UNSET: field_dict["envVars"] = env_vars + if metadata is not UNSET: + field_dict["metadata"] = metadata + if timeout is not UNSET: + field_dict["timeout"] = timeout return field_dict @@ -54,17 +54,17 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() template_id = d.pop("templateID") - timeout = d.pop("timeout", UNSET) + env_vars = d.pop("envVars", UNSET) metadata = d.pop("metadata", UNSET) - env_vars = d.pop("envVars", UNSET) + timeout = d.pop("timeout", UNSET) new_sandbox = cls( template_id=template_id, - timeout=timeout, - metadata=metadata, env_vars=env_vars, + metadata=metadata, + timeout=timeout, ) new_sandbox.additional_properties = d diff --git a/packages/python-sdk/e2b/api/client/models/running_sandbox.py b/packages/python-sdk/e2b/api/client/models/running_sandbox.py index 46c6757a6..c329511b5 100644 --- a/packages/python-sdk/e2b/api/client/models/running_sandbox.py +++ b/packages/python-sdk/e2b/api/client/models/running_sandbox.py @@ -14,43 +14,43 @@ class RunningSandbox: """ Attributes: - template_id (str): Identifier of the template from which is the sandbox created - sandbox_id (str): Identifier of the sandbox client_id (str): Identifier of the client - started_at (datetime.datetime): Time when the sandbox was started - end_at (datetime.datetime): Time when the sandbox will expire cpu_count (int): CPU cores for the sandbox + end_at (datetime.datetime): Time when the sandbox will expire memory_mb (int): Memory for the sandbox in MB + sandbox_id (str): Identifier of the sandbox + started_at (datetime.datetime): Time when the sandbox was started + template_id (str): Identifier of the template from which is the sandbox created alias (Union[Unset, str]): Alias of the template metadata (Union[Unset, Any]): """ - template_id: str - sandbox_id: str client_id: str - started_at: datetime.datetime - end_at: datetime.datetime cpu_count: int + end_at: datetime.datetime memory_mb: int + sandbox_id: str + started_at: datetime.datetime + template_id: str alias: Union[Unset, str] = UNSET metadata: Union[Unset, Any] = UNSET additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - template_id = self.template_id - - sandbox_id = self.sandbox_id - client_id = self.client_id - started_at = self.started_at.isoformat() + cpu_count = self.cpu_count end_at = self.end_at.isoformat() - cpu_count = self.cpu_count - memory_mb = self.memory_mb + sandbox_id = self.sandbox_id + + started_at = self.started_at.isoformat() + + template_id = self.template_id + alias = self.alias metadata = self.metadata @@ -59,13 +59,13 @@ def to_dict(self) -> Dict[str, Any]: field_dict.update(self.additional_properties) field_dict.update( { - "templateID": template_id, - "sandboxID": sandbox_id, "clientID": client_id, - "startedAt": started_at, - "endAt": end_at, "cpuCount": cpu_count, + "endAt": end_at, "memoryMB": memory_mb, + "sandboxID": sandbox_id, + "startedAt": started_at, + "templateID": template_id, } ) if alias is not UNSET: @@ -78,32 +78,32 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() - template_id = d.pop("templateID") - - sandbox_id = d.pop("sandboxID") - client_id = d.pop("clientID") - started_at = isoparse(d.pop("startedAt")) + cpu_count = d.pop("cpuCount") end_at = isoparse(d.pop("endAt")) - cpu_count = d.pop("cpuCount") - memory_mb = d.pop("memoryMB") + sandbox_id = d.pop("sandboxID") + + started_at = isoparse(d.pop("startedAt")) + + template_id = d.pop("templateID") + alias = d.pop("alias", UNSET) metadata = d.pop("metadata", UNSET) running_sandbox = cls( - template_id=template_id, - sandbox_id=sandbox_id, client_id=client_id, - started_at=started_at, - end_at=end_at, cpu_count=cpu_count, + end_at=end_at, memory_mb=memory_mb, + sandbox_id=sandbox_id, + started_at=started_at, + template_id=template_id, alias=alias, metadata=metadata, ) diff --git a/packages/python-sdk/e2b/api/client/models/sandbox.py b/packages/python-sdk/e2b/api/client/models/sandbox.py index a331e9a6b..baf5b4890 100644 --- a/packages/python-sdk/e2b/api/client/models/sandbox.py +++ b/packages/python-sdk/e2b/api/client/models/sandbox.py @@ -12,39 +12,39 @@ class Sandbox: """ Attributes: - template_id (str): Identifier of the template from which is the sandbox created - sandbox_id (str): Identifier of the sandbox client_id (str): Identifier of the client envd_version (str): Version of the envd running in the sandbox + sandbox_id (str): Identifier of the sandbox + template_id (str): Identifier of the template from which is the sandbox created alias (Union[Unset, str]): Alias of the template """ - template_id: str - sandbox_id: str client_id: str envd_version: str + sandbox_id: str + template_id: str alias: Union[Unset, str] = UNSET additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - template_id = self.template_id - - sandbox_id = self.sandbox_id - client_id = self.client_id envd_version = self.envd_version + sandbox_id = self.sandbox_id + + template_id = self.template_id + alias = self.alias field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { - "templateID": template_id, - "sandboxID": sandbox_id, "clientID": client_id, "envdVersion": envd_version, + "sandboxID": sandbox_id, + "templateID": template_id, } ) if alias is not UNSET: @@ -55,21 +55,21 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() - template_id = d.pop("templateID") - - sandbox_id = d.pop("sandboxID") - client_id = d.pop("clientID") envd_version = d.pop("envdVersion") + sandbox_id = d.pop("sandboxID") + + template_id = d.pop("templateID") + alias = d.pop("alias", UNSET) sandbox = cls( - template_id=template_id, - sandbox_id=sandbox_id, client_id=client_id, envd_version=envd_version, + sandbox_id=sandbox_id, + template_id=template_id, alias=alias, ) diff --git a/packages/python-sdk/e2b/api/client/models/sandbox_log.py b/packages/python-sdk/e2b/api/client/models/sandbox_log.py index 3e5dc9cfa..44c990e9a 100644 --- a/packages/python-sdk/e2b/api/client/models/sandbox_log.py +++ b/packages/python-sdk/e2b/api/client/models/sandbox_log.py @@ -13,25 +13,25 @@ class SandboxLog: """Log entry with timestamp and line Attributes: - timestamp (datetime.datetime): Timestamp of the log entry line (str): Log line content + timestamp (datetime.datetime): Timestamp of the log entry """ - timestamp: datetime.datetime line: str + timestamp: datetime.datetime additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - timestamp = self.timestamp.isoformat() - line = self.line + timestamp = self.timestamp.isoformat() + field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { - "timestamp": timestamp, "line": line, + "timestamp": timestamp, } ) @@ -40,13 +40,13 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() - timestamp = isoparse(d.pop("timestamp")) - line = d.pop("line") + timestamp = isoparse(d.pop("timestamp")) + sandbox_log = cls( - timestamp=timestamp, line=line, + timestamp=timestamp, ) sandbox_log.additional_properties = d diff --git a/packages/python-sdk/e2b/api/client/models/team.py b/packages/python-sdk/e2b/api/client/models/team.py index 38cc16a8d..c957f9384 100644 --- a/packages/python-sdk/e2b/api/client/models/team.py +++ b/packages/python-sdk/e2b/api/client/models/team.py @@ -10,35 +10,35 @@ class Team: """ Attributes: - team_id (str): Identifier of the team - name (str): Name of the team api_key (str): API key for the team is_default (bool): Whether the team is the default team + name (str): Name of the team + team_id (str): Identifier of the team """ - team_id: str - name: str api_key: str is_default: bool + name: str + team_id: str additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - team_id = self.team_id - - name = self.name - api_key = self.api_key is_default = self.is_default + name = self.name + + team_id = self.team_id + field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { - "teamID": team_id, - "name": name, "apiKey": api_key, "isDefault": is_default, + "name": name, + "teamID": team_id, } ) @@ -47,19 +47,19 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() - team_id = d.pop("teamID") - - name = d.pop("name") - api_key = d.pop("apiKey") is_default = d.pop("isDefault") + name = d.pop("name") + + team_id = d.pop("teamID") + team = cls( - team_id=team_id, - name=name, api_key=api_key, is_default=is_default, + name=name, + team_id=team_id, ) team.additional_properties = d diff --git a/packages/python-sdk/e2b/api/client/models/template.py b/packages/python-sdk/e2b/api/client/models/template.py index 7120815e2..7e76153e9 100644 --- a/packages/python-sdk/e2b/api/client/models/template.py +++ b/packages/python-sdk/e2b/api/client/models/template.py @@ -1,10 +1,16 @@ -from typing import Any, Dict, List, Type, TypeVar, Union, cast +import datetime +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, Union, cast from attrs import define as _attrs_define from attrs import field as _attrs_field +from dateutil.parser import isoparse from ..types import UNSET, Unset +if TYPE_CHECKING: + from ..models.team_user import TeamUser + + T = TypeVar("T", bound="Template") @@ -12,33 +18,63 @@ class Template: """ Attributes: - template_id (str): Identifier of the template + build_count (int): Number of times the template was built build_id (str): Identifier of the last successful build for given template cpu_count (int): CPU cores for the sandbox + created_at (datetime.datetime): Time when the template was created + created_by (Union['TeamUser', None]): + last_spawned_at (datetime.datetime): Time when the template was last used memory_mb (int): Memory for the sandbox in MB public (bool): Whether the template is public or only accessible by the team + spawn_count (int): Number of times the template was used + template_id (str): Identifier of the template + updated_at (datetime.datetime): Time when the template was last updated aliases (Union[Unset, List[str]]): Aliases of the template """ - template_id: str + build_count: int build_id: str cpu_count: int + created_at: datetime.datetime + created_by: Union["TeamUser", None] + last_spawned_at: datetime.datetime memory_mb: int public: bool + spawn_count: int + template_id: str + updated_at: datetime.datetime aliases: Union[Unset, List[str]] = UNSET additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - template_id = self.template_id + from ..models.team_user import TeamUser + + build_count = self.build_count build_id = self.build_id cpu_count = self.cpu_count + created_at = self.created_at.isoformat() + + created_by: Union[Dict[str, Any], None] + if isinstance(self.created_by, TeamUser): + created_by = self.created_by.to_dict() + else: + created_by = self.created_by + + last_spawned_at = self.last_spawned_at.isoformat() + memory_mb = self.memory_mb public = self.public + spawn_count = self.spawn_count + + template_id = self.template_id + + updated_at = self.updated_at.isoformat() + aliases: Union[Unset, List[str]] = UNSET if not isinstance(self.aliases, Unset): aliases = self.aliases @@ -47,11 +83,17 @@ def to_dict(self) -> Dict[str, Any]: field_dict.update(self.additional_properties) field_dict.update( { - "templateID": template_id, + "buildCount": build_count, "buildID": build_id, "cpuCount": cpu_count, + "createdAt": created_at, + "createdBy": created_by, + "lastSpawnedAt": last_spawned_at, "memoryMB": memory_mb, "public": public, + "spawnCount": spawn_count, + "templateID": template_id, + "updatedAt": updated_at, } ) if aliases is not UNSET: @@ -61,25 +103,58 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.team_user import TeamUser + d = src_dict.copy() - template_id = d.pop("templateID") + build_count = d.pop("buildCount") build_id = d.pop("buildID") cpu_count = d.pop("cpuCount") + created_at = isoparse(d.pop("createdAt")) + + def _parse_created_by(data: object) -> Union["TeamUser", None]: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + created_by_type_1 = TeamUser.from_dict(data) + + return created_by_type_1 + except: # noqa: E722 + pass + return cast(Union["TeamUser", None], data) + + created_by = _parse_created_by(d.pop("createdBy")) + + last_spawned_at = isoparse(d.pop("lastSpawnedAt")) + memory_mb = d.pop("memoryMB") public = d.pop("public") + spawn_count = d.pop("spawnCount") + + template_id = d.pop("templateID") + + updated_at = isoparse(d.pop("updatedAt")) + aliases = cast(List[str], d.pop("aliases", UNSET)) template = cls( - template_id=template_id, + build_count=build_count, build_id=build_id, cpu_count=cpu_count, + created_at=created_at, + created_by=created_by, + last_spawned_at=last_spawned_at, memory_mb=memory_mb, public=public, + spawn_count=spawn_count, + template_id=template_id, + updated_at=updated_at, aliases=aliases, ) diff --git a/packages/python-sdk/e2b/api/client/models/template_build.py b/packages/python-sdk/e2b/api/client/models/template_build.py index 082e96ac3..ed05e1114 100644 --- a/packages/python-sdk/e2b/api/client/models/template_build.py +++ b/packages/python-sdk/e2b/api/client/models/template_build.py @@ -12,35 +12,35 @@ class TemplateBuild: """ Attributes: - logs (List[str]): Build logs - template_id (str): Identifier of the template build_id (str): Identifier of the build + logs (List[str]): Build logs status (TemplateBuildStatus): Status of the template + template_id (str): Identifier of the template """ - logs: List[str] - template_id: str build_id: str + logs: List[str] status: TemplateBuildStatus + template_id: str additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: - logs = self.logs - - template_id = self.template_id - build_id = self.build_id + logs = self.logs + status = self.status.value + template_id = self.template_id + field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( { - "logs": logs, - "templateID": template_id, "buildID": build_id, + "logs": logs, "status": status, + "templateID": template_id, } ) @@ -49,19 +49,19 @@ def to_dict(self) -> Dict[str, Any]: @classmethod def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: d = src_dict.copy() - logs = cast(List[str], d.pop("logs")) - - template_id = d.pop("templateID") - build_id = d.pop("buildID") + logs = cast(List[str], d.pop("logs")) + status = TemplateBuildStatus(d.pop("status")) + template_id = d.pop("templateID") + template_build = cls( - logs=logs, - template_id=template_id, build_id=build_id, + logs=logs, status=status, + template_id=template_id, ) template_build.additional_properties = d diff --git a/packages/python-sdk/e2b/api/client/models/template_build_request.py b/packages/python-sdk/e2b/api/client/models/template_build_request.py index d93c68fb6..08ac58490 100644 --- a/packages/python-sdk/e2b/api/client/models/template_build_request.py +++ b/packages/python-sdk/e2b/api/client/models/template_build_request.py @@ -14,18 +14,18 @@ class TemplateBuildRequest: Attributes: dockerfile (str): Dockerfile for the template alias (Union[Unset, str]): Alias of the template - team_id (Union[Unset, str]): Identifier of the team - start_cmd (Union[Unset, str]): Start command to execute in the template after the build cpu_count (Union[Unset, int]): CPU cores for the sandbox memory_mb (Union[Unset, int]): Memory for the sandbox in MB + start_cmd (Union[Unset, str]): Start command to execute in the template after the build + team_id (Union[Unset, str]): Identifier of the team """ dockerfile: str alias: Union[Unset, str] = UNSET - team_id: Union[Unset, str] = UNSET - start_cmd: Union[Unset, str] = UNSET cpu_count: Union[Unset, int] = UNSET memory_mb: Union[Unset, int] = UNSET + start_cmd: Union[Unset, str] = UNSET + team_id: Union[Unset, str] = UNSET additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> Dict[str, Any]: @@ -33,14 +33,14 @@ def to_dict(self) -> Dict[str, Any]: alias = self.alias - team_id = self.team_id - - start_cmd = self.start_cmd - cpu_count = self.cpu_count memory_mb = self.memory_mb + start_cmd = self.start_cmd + + team_id = self.team_id + field_dict: Dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( @@ -50,14 +50,14 @@ def to_dict(self) -> Dict[str, Any]: ) if alias is not UNSET: field_dict["alias"] = alias - if team_id is not UNSET: - field_dict["teamID"] = team_id - if start_cmd is not UNSET: - field_dict["startCmd"] = start_cmd if cpu_count is not UNSET: field_dict["cpuCount"] = cpu_count if memory_mb is not UNSET: field_dict["memoryMB"] = memory_mb + if start_cmd is not UNSET: + field_dict["startCmd"] = start_cmd + if team_id is not UNSET: + field_dict["teamID"] = team_id return field_dict @@ -68,21 +68,21 @@ def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: alias = d.pop("alias", UNSET) - team_id = d.pop("teamID", UNSET) - - start_cmd = d.pop("startCmd", UNSET) - cpu_count = d.pop("cpuCount", UNSET) memory_mb = d.pop("memoryMB", UNSET) + start_cmd = d.pop("startCmd", UNSET) + + team_id = d.pop("teamID", UNSET) + template_build_request = cls( dockerfile=dockerfile, alias=alias, - team_id=team_id, - start_cmd=start_cmd, cpu_count=cpu_count, memory_mb=memory_mb, + start_cmd=start_cmd, + team_id=team_id, ) template_build_request.additional_properties = d diff --git a/spec/openapi.yml b/spec/openapi.yml index 17a1db854..32bbc8763 100644 --- a/spec/openapi.yml +++ b/spec/openapi.yml @@ -16,6 +16,10 @@ components: type: http scheme: bearer bearerFormat: access_token + AdminTokenAuth: + type: apiKey + in: header + name: X-Admin-Token parameters: templateID: @@ -36,6 +40,12 @@ components: required: true schema: type: string + nodeID: + name: nodeID + in: path + required: true + schema: + type: string responses: "400": @@ -56,7 +66,12 @@ components: application/json: schema: $ref: "#/components/schemas/Error" - + "409": + description: Conflict + content: + application/json: + schema: + $ref: "#/components/schemas/Error" "500": description: Server error content: @@ -230,6 +245,15 @@ components: envVars: $ref: "#/components/schemas/EnvVars" + ResumedSandbox: + properties: + timeout: + type: integer + format: int32 + minimum: 0 + default: 15 + description: Time to live for the sandbox in seconds. + Template: required: - templateID @@ -335,6 +359,70 @@ components: - ready - error + NodeStatus: + type: string + description: Status of the node + enum: + - ready + - draining + + NodeStatusChange: + required: + - status + properties: + status: + $ref: "#/components/schemas/NodeStatus" + + Node: + required: + - nodeID + - status + - sandboxCount + - allocatedCPU + - allocatedMemoryMiB + properties: + nodeID: + type: string + description: Identifier of the node + status: + $ref: "#/components/schemas/NodeStatus" + sandboxCount: + type: integer + format: int32 + description: Number of sandboxes running on the node + allocatedCPU: + type: integer + format: int32 + description: Number of allocated CPU cores + allocatedMemoryMiB: + type: integer + format: int32 + description: Amount of allocated memory in MiB + + NodeDetail: + required: + - nodeID + - status + - sandboxes + - cachedBuilds + properties: + nodeID: + type: string + description: Identifier of the node + status: + $ref: "#/components/schemas/NodeStatus" + sandboxes: + type: array + description: List of sandboxes running on the node + items: + $ref: "#/components/schemas/RunningSandbox" + cachedBuilds: + type: array + description: List of cached builds id on the node + items: + type: string + + Error: required: - code @@ -390,6 +478,15 @@ paths: tags: [sandboxes] security: - ApiKeyAuth: [] + parameters: + - name: filter + in: query + description: A list of filters with key-value pairs (e.g. user:abc, app:prod). + required: false + schema: + type: array + items: + type: string responses: "200": description: Successfully returned all running sandboxes @@ -469,6 +566,27 @@ paths: $ref: "#/components/responses/500" /sandboxes/{sandboxID}: + get: + description: Get a sandbox by id + tags: [sandboxes] + security: + - ApiKeyAuth: [] + parameters: + - $ref: "#/components/parameters/sandboxID" + responses: + "200": + description: Successfully returned the sandbox + content: + application/json: + schema: + $ref: "#/components/schemas/RunningSandbox" + "404": + $ref: "#/components/responses/404" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + delete: description: Kill a sandbox tags: [sandboxes] @@ -486,6 +604,57 @@ paths: "500": $ref: "#/components/responses/500" + # TODO: Pause and resume might be exposed as POST /sandboxes/{sandboxID}/snapshot and then POST /sandboxes with specified snapshotting setup + /sandboxes/{sandboxID}/pause: + post: + description: Pause the sandbox + tags: [sandboxes] + security: + - ApiKeyAuth: [] + parameters: + - $ref: "#/components/parameters/sandboxID" + responses: + "204": + description: The sandbox was paused successfully and can be resumed + "409": + $ref: "#/components/responses/409" + "404": + $ref: "#/components/responses/404" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + + /sandboxes/{sandboxID}/resume: + post: + description: Resume the sandbox + tags: [sandboxes] + security: + - ApiKeyAuth: [] + parameters: + - $ref: "#/components/parameters/sandboxID" + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/ResumedSandbox" + responses: + "201": + description: The sandbox was resumed successfully + content: + application/json: + schema: + $ref: "#/components/schemas/Sandbox" + "409": + $ref: "#/components/responses/409" + "404": + $ref: "#/components/responses/404" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + /sandboxes/{sandboxID}/timeout: post: description: Set the timeout for the sandbox. The sandbox will expire x seconds from the time of the request. Calling this method multiple times overwrites the TTL, each time using the current timestamp as the starting point to measure the timeout duration. @@ -705,3 +874,67 @@ paths: $ref: "#/components/responses/404" "500": $ref: "#/components/responses/500" + + /nodes: + get: + description: List all nodes + tags: [admin] + security: + - AdminTokenAuth: [] + responses: + "200": + description: Successfully returned all nodes + content: + application/json: + schema: + type: array + items: + allOf: + - $ref: "#/components/schemas/Node" + "401": + $ref: "#/components/responses/401" + "500": + $ref: "#/components/responses/500" + + /nodes/{nodeID}: + get: + description: Get node info + tags: [admin] + security: + - AdminTokenAuth: [] + parameters: + - $ref: "#/components/parameters/nodeID" + responses: + "200": + description: Successfully returned the node + content: + application/json: + schema: + $ref: "#/components/schemas/NodeDetail" + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" + post: + description: Change status of a node + tags: [admin] + security: + - AdminTokenAuth: [] + parameters: + - $ref: "#/components/parameters/nodeID" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/NodeStatusChange" + responses: + "204": + description: The node status was changed successfully + "401": + $ref: "#/components/responses/401" + "404": + $ref: "#/components/responses/404" + "500": + $ref: "#/components/responses/500" \ No newline at end of file diff --git a/spec/remove_extra_tags.py b/spec/remove_extra_tags.py new file mode 100644 index 000000000..387052d63 --- /dev/null +++ b/spec/remove_extra_tags.py @@ -0,0 +1,35 @@ +import os +import sys + +import yaml + +# Get directory of this script +directory = os.path.dirname(os.path.abspath(__file__)) +path = os.path.join(directory, "openapi.yml") + +# Load OpenAPI spec +with open(path, "r") as file: + spec = yaml.safe_load(file) + +tags_to_keep = sys.argv[1:] if len(sys.argv) > 1 else None +filtered_paths = {} + +for path, methods in spec.get("paths", {}).items(): + for method, operation in methods.items(): + if "tags" in operation: + for tag in tags_to_keep: + if tag in operation["tags"]: + if path in filtered_paths: + filtered_paths[path][method] = operation + else: + filtered_paths[path] = {method: operation} + break + + +# Create a new spec with only the filtered paths +filtered_spec = spec.copy() +filtered_spec["paths"] = filtered_paths + +# Save the filtered spec +with open(os.path.join(directory, "openapi_generated.yml"), "w") as file: + yaml.dump(filtered_spec, file) From 238887b03dffccd8e71eecf7cf7510a4195fa912 Mon Sep 17 00:00:00 2001 From: Jakub Novak Date: Fri, 17 Jan 2025 14:23:48 -0800 Subject: [PATCH 11/12] Add retry block to host and stdin tests --- .../tests/sandbox/commands/sendStdin.test.ts | 23 +++++++++++++++++++ packages/js-sdk/tests/sandbox/host.test.ts | 12 ++++++++-- .../tests/async/sandbox_async/test_host.py | 17 ++++++++------ .../tests/sync/sandbox_sync/test_host.py | 11 ++++++--- 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/packages/js-sdk/tests/sandbox/commands/sendStdin.test.ts b/packages/js-sdk/tests/sandbox/commands/sendStdin.test.ts index 550c04a15..56bcd025a 100644 --- a/packages/js-sdk/tests/sandbox/commands/sendStdin.test.ts +++ b/packages/js-sdk/tests/sandbox/commands/sendStdin.test.ts @@ -7,6 +7,14 @@ sandboxTest('send stdin to process', async ({ sandbox }) => { await sandbox.commands.sendStdin(cmd.pid, text) + + for (let i = 0; i < 5; i++) { + if (cmd.stdout === text) { + break + } + await new Promise((r) => setTimeout(r, 500)) + } + await cmd.kill() assert.equal(cmd.stdout, text) @@ -29,6 +37,13 @@ sandboxTest('send special characters to stdin', async ({ sandbox }) => { await sandbox.commands.sendStdin(cmd.pid, text) + for (let i = 0; i < 5; i++) { + if (cmd.stdout === text) { + break + } + await new Promise((r) => setTimeout(r, 500)) + } + await cmd.kill() assert.equal(cmd.stdout, text) @@ -40,7 +55,15 @@ sandboxTest('send multiline string to stdin', async ({ sandbox }) => { await sandbox.commands.sendStdin(cmd.pid, text) + for (let i = 0; i < 5; i++) { + if (cmd.stdout === text) { + break + } + await new Promise((r) => setTimeout(r, 500)) + } + await cmd.kill() + assert.equal(cmd.stdout, text) }) diff --git a/packages/js-sdk/tests/sandbox/host.test.ts b/packages/js-sdk/tests/sandbox/host.test.ts index f499f7d3e..b0a176362 100644 --- a/packages/js-sdk/tests/sandbox/host.test.ts +++ b/packages/js-sdk/tests/sandbox/host.test.ts @@ -10,8 +10,16 @@ sandboxTest('ping server in sandbox', async ({ sandbox }) => { const host = sandbox.getHost(8000) - const res = await fetch(`${isDebug ? 'http' : 'https'}://${host}`) + let res = await fetch(`${isDebug ? 'http' : 'https'}://${host}`) + for (let i = 0; i < 10; i++) { + if (res.status === 200) { + break + } + + res = await fetch(`${isDebug ? 'http' : 'https'}://${host}`) + await wait(500) + } assert.equal(res.status, 200) } finally { try { @@ -20,4 +28,4 @@ sandboxTest('ping server in sandbox', async ({ sandbox }) => { console.error(e) } } -}) +}, { timeout: 60000 }) diff --git a/packages/python-sdk/tests/async/sandbox_async/test_host.py b/packages/python-sdk/tests/async/sandbox_async/test_host.py index a8bd3c74c..6637029af 100644 --- a/packages/python-sdk/tests/async/sandbox_async/test_host.py +++ b/packages/python-sdk/tests/async/sandbox_async/test_host.py @@ -1,7 +1,6 @@ -import httpx -import pytest +import asyncio -from time import sleep +import httpx from e2b import AsyncSandbox @@ -13,12 +12,16 @@ async def test_ping_server(async_sandbox: AsyncSandbox, debug): ) try: - sleep(1) host = async_sandbox.get_host(8000) + status_code = None async with httpx.AsyncClient() as client: - res = await client.get(f"{'http' if debug else 'https'}://{host}") - assert res.status_code == 200 - + for _ in range(5): + res = await client.get(f"{'http' if debug else 'https'}://{host}") + status_code = res.status_code + if res.status_code == 200: + break + await asyncio.sleep(0.5) + assert status_code == 200 finally: await cmd.kill() diff --git a/packages/python-sdk/tests/sync/sandbox_sync/test_host.py b/packages/python-sdk/tests/sync/sandbox_sync/test_host.py index 18de6d5c1..461b98b62 100644 --- a/packages/python-sdk/tests/sync/sandbox_sync/test_host.py +++ b/packages/python-sdk/tests/sync/sandbox_sync/test_host.py @@ -7,10 +7,15 @@ def test_ping_server(sandbox, debug): cmd = sandbox.commands.run("python -m http.server 8001", background=True) try: - sleep(1) host = sandbox.get_host(8001) - res = httpx.get(f"{'http' if debug else 'https'}://{host}") - assert res.status_code == 200 + status_code = None + for _ in range(5): + res = httpx.get(f"{'http' if debug else 'https'}://{host}") + status_code = res.status_code + if res.status_code == 200: + break + sleep(0.5) + assert status_code == 200 finally: cmd.kill() From 4b5d17e8a404587892362f045e0bed138e73f73e Mon Sep 17 00:00:00 2001 From: Jakub Novak Date: Fri, 17 Jan 2025 14:28:42 -0800 Subject: [PATCH 12/12] Add missing files --- .gitignore | 1 + .../api/sandboxes/get_sandboxes_sandbox_id.py | 159 +++++++++++++++ .../post_sandboxes_sandbox_id_pause.py | 101 ++++++++++ .../post_sandboxes_sandbox_id_resume.py | 185 ++++++++++++++++++ .../python-sdk/e2b/api/client/models/node.py | 92 +++++++++ .../e2b/api/client/models/node_detail.py | 98 ++++++++++ .../e2b/api/client/models/node_status.py | 9 + .../api/client/models/node_status_change.py | 60 ++++++ .../e2b/api/client/models/resumed_sandbox.py | 58 ++++++ .../e2b/api/client/models/team_user.py | 66 +++++++ .../client/models/template_update_request.py | 58 ++++++ 11 files changed, 887 insertions(+) create mode 100644 packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id.py create mode 100644 packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py create mode 100644 packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py create mode 100644 packages/python-sdk/e2b/api/client/models/node.py create mode 100644 packages/python-sdk/e2b/api/client/models/node_detail.py create mode 100644 packages/python-sdk/e2b/api/client/models/node_status.py create mode 100644 packages/python-sdk/e2b/api/client/models/node_status_change.py create mode 100644 packages/python-sdk/e2b/api/client/models/resumed_sandbox.py create mode 100644 packages/python-sdk/e2b/api/client/models/team_user.py create mode 100644 packages/python-sdk/e2b/api/client/models/template_update_request.py diff --git a/.gitignore b/.gitignore index 74d83b006..f88780942 100644 --- a/.gitignore +++ b/.gitignore @@ -292,3 +292,4 @@ cython_debug/ # SDK reference artifacts sdk_ref/ sdkRefRoutes.json +spec/openapi_generated.yml \ No newline at end of file diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id.py b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id.py new file mode 100644 index 000000000..7ab59ee7e --- /dev/null +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/get_sandboxes_sandbox_id.py @@ -0,0 +1,159 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.running_sandbox import RunningSandbox +from ...types import Response + + +def _get_kwargs( + sandbox_id: str, +) -> Dict[str, Any]: + _kwargs: Dict[str, Any] = { + "method": "get", + "url": f"/sandboxes/{sandbox_id}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, RunningSandbox]]: + if response.status_code == HTTPStatus.OK: + response_200 = RunningSandbox.from_dict(response.json()) + + return response_200 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = cast(Any, None) + return response_401 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = cast(Any, None) + return response_404 + if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + response_500 = cast(Any, None) + return response_500 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, RunningSandbox]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + sandbox_id: str, + *, + client: AuthenticatedClient, +) -> Response[Union[Any, RunningSandbox]]: + """Get a sandbox by id + + Args: + sandbox_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, RunningSandbox]] + """ + + kwargs = _get_kwargs( + sandbox_id=sandbox_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + sandbox_id: str, + *, + client: AuthenticatedClient, +) -> Optional[Union[Any, RunningSandbox]]: + """Get a sandbox by id + + Args: + sandbox_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, RunningSandbox] + """ + + return sync_detailed( + sandbox_id=sandbox_id, + client=client, + ).parsed + + +async def asyncio_detailed( + sandbox_id: str, + *, + client: AuthenticatedClient, +) -> Response[Union[Any, RunningSandbox]]: + """Get a sandbox by id + + Args: + sandbox_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, RunningSandbox]] + """ + + kwargs = _get_kwargs( + sandbox_id=sandbox_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + sandbox_id: str, + *, + client: AuthenticatedClient, +) -> Optional[Union[Any, RunningSandbox]]: + """Get a sandbox by id + + Args: + sandbox_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, RunningSandbox] + """ + + return ( + await asyncio_detailed( + sandbox_id=sandbox_id, + client=client, + ) + ).parsed diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py new file mode 100644 index 000000000..8133ed132 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py @@ -0,0 +1,101 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import Response + + +def _get_kwargs( + sandbox_id: str, +) -> Dict[str, Any]: + _kwargs: Dict[str, Any] = { + "method": "post", + "url": f"/sandboxes/{sandbox_id}/pause", + } + + return _kwargs + + +def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[Any]: + if response.status_code == HTTPStatus.NO_CONTENT: + return None + if response.status_code == HTTPStatus.UNAUTHORIZED: + return None + if response.status_code == HTTPStatus.NOT_FOUND: + return None + if response.status_code == HTTPStatus.CONFLICT: + return None + if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + return None + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + sandbox_id: str, + *, + client: AuthenticatedClient, +) -> Response[Any]: + """Pause the sandbox + + Args: + sandbox_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + sandbox_id=sandbox_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + sandbox_id: str, + *, + client: AuthenticatedClient, +) -> Response[Any]: + """Pause the sandbox + + Args: + sandbox_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + sandbox_id=sandbox_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py new file mode 100644 index 000000000..1433aa513 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py @@ -0,0 +1,185 @@ +from http import HTTPStatus +from typing import Any, Dict, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.resumed_sandbox import ResumedSandbox +from ...models.sandbox import Sandbox +from ...types import Response + + +def _get_kwargs( + sandbox_id: str, + *, + body: ResumedSandbox, +) -> Dict[str, Any]: + headers: Dict[str, Any] = {} + + _kwargs: Dict[str, Any] = { + "method": "post", + "url": f"/sandboxes/{sandbox_id}/resume", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, Sandbox]]: + if response.status_code == HTTPStatus.CREATED: + response_201 = Sandbox.from_dict(response.json()) + + return response_201 + if response.status_code == HTTPStatus.UNAUTHORIZED: + response_401 = cast(Any, None) + return response_401 + if response.status_code == HTTPStatus.NOT_FOUND: + response_404 = cast(Any, None) + return response_404 + if response.status_code == HTTPStatus.CONFLICT: + response_409 = cast(Any, None) + return response_409 + if response.status_code == HTTPStatus.INTERNAL_SERVER_ERROR: + response_500 = cast(Any, None) + return response_500 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, Sandbox]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + sandbox_id: str, + *, + client: AuthenticatedClient, + body: ResumedSandbox, +) -> Response[Union[Any, Sandbox]]: + """Resume the sandbox + + Args: + sandbox_id (str): + body (ResumedSandbox): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Sandbox]] + """ + + kwargs = _get_kwargs( + sandbox_id=sandbox_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + sandbox_id: str, + *, + client: AuthenticatedClient, + body: ResumedSandbox, +) -> Optional[Union[Any, Sandbox]]: + """Resume the sandbox + + Args: + sandbox_id (str): + body (ResumedSandbox): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Sandbox] + """ + + return sync_detailed( + sandbox_id=sandbox_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + sandbox_id: str, + *, + client: AuthenticatedClient, + body: ResumedSandbox, +) -> Response[Union[Any, Sandbox]]: + """Resume the sandbox + + Args: + sandbox_id (str): + body (ResumedSandbox): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, Sandbox]] + """ + + kwargs = _get_kwargs( + sandbox_id=sandbox_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + sandbox_id: str, + *, + client: AuthenticatedClient, + body: ResumedSandbox, +) -> Optional[Union[Any, Sandbox]]: + """Resume the sandbox + + Args: + sandbox_id (str): + body (ResumedSandbox): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, Sandbox] + """ + + return ( + await asyncio_detailed( + sandbox_id=sandbox_id, + client=client, + body=body, + ) + ).parsed diff --git a/packages/python-sdk/e2b/api/client/models/node.py b/packages/python-sdk/e2b/api/client/models/node.py new file mode 100644 index 000000000..8c207759f --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/node.py @@ -0,0 +1,92 @@ +from typing import Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.node_status import NodeStatus + +T = TypeVar("T", bound="Node") + + +@_attrs_define +class Node: + """ + Attributes: + allocated_cpu (int): Number of allocated CPU cores + allocated_memory_mi_b (int): Amount of allocated memory in MiB + node_id (str): Identifier of the node + sandbox_count (int): Number of sandboxes running on the node + status (NodeStatus): Status of the node + """ + + allocated_cpu: int + allocated_memory_mi_b: int + node_id: str + sandbox_count: int + status: NodeStatus + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + allocated_cpu = self.allocated_cpu + + allocated_memory_mi_b = self.allocated_memory_mi_b + + node_id = self.node_id + + sandbox_count = self.sandbox_count + + status = self.status.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "allocatedCPU": allocated_cpu, + "allocatedMemoryMiB": allocated_memory_mi_b, + "nodeID": node_id, + "sandboxCount": sandbox_count, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + allocated_cpu = d.pop("allocatedCPU") + + allocated_memory_mi_b = d.pop("allocatedMemoryMiB") + + node_id = d.pop("nodeID") + + sandbox_count = d.pop("sandboxCount") + + status = NodeStatus(d.pop("status")) + + node = cls( + allocated_cpu=allocated_cpu, + allocated_memory_mi_b=allocated_memory_mi_b, + node_id=node_id, + sandbox_count=sandbox_count, + status=status, + ) + + node.additional_properties = d + return node + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/node_detail.py b/packages/python-sdk/e2b/api/client/models/node_detail.py new file mode 100644 index 000000000..a2326e054 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/node_detail.py @@ -0,0 +1,98 @@ +from typing import TYPE_CHECKING, Any, Dict, List, Type, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.node_status import NodeStatus + +if TYPE_CHECKING: + from ..models.running_sandbox import RunningSandbox + + +T = TypeVar("T", bound="NodeDetail") + + +@_attrs_define +class NodeDetail: + """ + Attributes: + cached_builds (List[str]): List of cached builds id on the node + node_id (str): Identifier of the node + sandboxes (List['RunningSandbox']): List of sandboxes running on the node + status (NodeStatus): Status of the node + """ + + cached_builds: List[str] + node_id: str + sandboxes: List["RunningSandbox"] + status: NodeStatus + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + cached_builds = self.cached_builds + + node_id = self.node_id + + sandboxes = [] + for sandboxes_item_data in self.sandboxes: + sandboxes_item = sandboxes_item_data.to_dict() + sandboxes.append(sandboxes_item) + + status = self.status.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "cachedBuilds": cached_builds, + "nodeID": node_id, + "sandboxes": sandboxes, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + from ..models.running_sandbox import RunningSandbox + + d = src_dict.copy() + cached_builds = cast(List[str], d.pop("cachedBuilds")) + + node_id = d.pop("nodeID") + + sandboxes = [] + _sandboxes = d.pop("sandboxes") + for sandboxes_item_data in _sandboxes: + sandboxes_item = RunningSandbox.from_dict(sandboxes_item_data) + + sandboxes.append(sandboxes_item) + + status = NodeStatus(d.pop("status")) + + node_detail = cls( + cached_builds=cached_builds, + node_id=node_id, + sandboxes=sandboxes, + status=status, + ) + + node_detail.additional_properties = d + return node_detail + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/node_status.py b/packages/python-sdk/e2b/api/client/models/node_status.py new file mode 100644 index 000000000..87a77905b --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/node_status.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class NodeStatus(str, Enum): + DRAINING = "draining" + READY = "ready" + + def __str__(self) -> str: + return str(self.value) diff --git a/packages/python-sdk/e2b/api/client/models/node_status_change.py b/packages/python-sdk/e2b/api/client/models/node_status_change.py new file mode 100644 index 000000000..43628b809 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/node_status_change.py @@ -0,0 +1,60 @@ +from typing import Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.node_status import NodeStatus + +T = TypeVar("T", bound="NodeStatusChange") + + +@_attrs_define +class NodeStatusChange: + """ + Attributes: + status (NodeStatus): Status of the node + """ + + status: NodeStatus + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + status = self.status.value + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + status = NodeStatus(d.pop("status")) + + node_status_change = cls( + status=status, + ) + + node_status_change.additional_properties = d + return node_status_change + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/resumed_sandbox.py b/packages/python-sdk/e2b/api/client/models/resumed_sandbox.py new file mode 100644 index 000000000..ae872a6d1 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/resumed_sandbox.py @@ -0,0 +1,58 @@ +from typing import Any, Dict, List, Type, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ResumedSandbox") + + +@_attrs_define +class ResumedSandbox: + """ + Attributes: + timeout (Union[Unset, int]): Time to live for the sandbox in seconds. Default: 15. + """ + + timeout: Union[Unset, int] = 15 + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + timeout = self.timeout + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if timeout is not UNSET: + field_dict["timeout"] = timeout + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + timeout = d.pop("timeout", UNSET) + + resumed_sandbox = cls( + timeout=timeout, + ) + + resumed_sandbox.additional_properties = d + return resumed_sandbox + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/team_user.py b/packages/python-sdk/e2b/api/client/models/team_user.py new file mode 100644 index 000000000..9aa62dfb5 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/team_user.py @@ -0,0 +1,66 @@ +from typing import Any, Dict, List, Type, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="TeamUser") + + +@_attrs_define +class TeamUser: + """ + Attributes: + email (str): Email of the user + id (str): Identifier of the user + """ + + email: str + id: str + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + email = self.email + + id = self.id + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + "id": id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + email = d.pop("email") + + id = d.pop("id") + + team_user = cls( + email=email, + id=id, + ) + + team_user.additional_properties = d + return team_user + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/packages/python-sdk/e2b/api/client/models/template_update_request.py b/packages/python-sdk/e2b/api/client/models/template_update_request.py new file mode 100644 index 000000000..66e235c41 --- /dev/null +++ b/packages/python-sdk/e2b/api/client/models/template_update_request.py @@ -0,0 +1,58 @@ +from typing import Any, Dict, List, Type, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="TemplateUpdateRequest") + + +@_attrs_define +class TemplateUpdateRequest: + """ + Attributes: + public (Union[Unset, bool]): Whether the template is public or only accessible by the team + """ + + public: Union[Unset, bool] = UNSET + additional_properties: Dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> Dict[str, Any]: + public = self.public + + field_dict: Dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if public is not UNSET: + field_dict["public"] = public + + return field_dict + + @classmethod + def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T: + d = src_dict.copy() + public = d.pop("public", UNSET) + + template_update_request = cls( + public=public, + ) + + template_update_request.additional_properties = d + return template_update_request + + @property + def additional_keys(self) -> List[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties