scalebox-sdk 0.1.20__py3-none-any.whl → 0.1.21__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scalebox/__init__.py +1 -1
- scalebox/sandbox_async/main.py +647 -646
- scalebox/sandbox_sync/main.py +789 -790
- scalebox/version.py +2 -2
- {scalebox_sdk-0.1.20.dist-info → scalebox_sdk-0.1.21.dist-info}/METADATA +1 -1
- {scalebox_sdk-0.1.20.dist-info → scalebox_sdk-0.1.21.dist-info}/RECORD +10 -10
- {scalebox_sdk-0.1.20.dist-info → scalebox_sdk-0.1.21.dist-info}/WHEEL +0 -0
- {scalebox_sdk-0.1.20.dist-info → scalebox_sdk-0.1.21.dist-info}/entry_points.txt +0 -0
- {scalebox_sdk-0.1.20.dist-info → scalebox_sdk-0.1.21.dist-info}/licenses/LICENSE +0 -0
- {scalebox_sdk-0.1.20.dist-info → scalebox_sdk-0.1.21.dist-info}/top_level.txt +0 -0
scalebox/sandbox_sync/main.py
CHANGED
|
@@ -1,790 +1,789 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
import logging
|
|
3
|
-
import socket
|
|
4
|
-
import time
|
|
5
|
-
from typing import Dict, List, Optional, TypedDict, overload
|
|
6
|
-
|
|
7
|
-
import httpx
|
|
8
|
-
import urllib3
|
|
9
|
-
from httpx import Timeout
|
|
10
|
-
from packaging.version import Version
|
|
11
|
-
from urllib3 import Retry
|
|
12
|
-
|
|
13
|
-
from ..api.client.types import Unset
|
|
14
|
-
from ..connection_config import ConnectionConfig, ProxyTypes
|
|
15
|
-
from ..exceptions import SandboxException, request_timeout_error
|
|
16
|
-
from ..generated.api import ENVD_API_HEALTH_ROUTE, handle_envd_api_exception
|
|
17
|
-
from ..sandbox.main import SandboxSetup
|
|
18
|
-
from ..sandbox.sandbox_api import SandboxMetrics
|
|
19
|
-
from ..sandbox.utils import class_method_variant
|
|
20
|
-
from ..sandbox_sync.commands.command import Commands
|
|
21
|
-
from ..sandbox_sync.commands.pty import Pty
|
|
22
|
-
from ..sandbox_sync.filesystem.filesystem import Filesystem
|
|
23
|
-
from ..sandbox_sync.sandbox_api import SandboxApi, SandboxInfo
|
|
24
|
-
|
|
25
|
-
logger = logging.getLogger(__name__)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class TransportWithLogger(httpx.HTTPTransport):
|
|
29
|
-
def handle_request(self, request):
|
|
30
|
-
url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
|
|
31
|
-
logger.info(f"Request: {request.method} {url}")
|
|
32
|
-
response = super().handle_request(request)
|
|
33
|
-
|
|
34
|
-
# data = connect.GzipCompressor.decompress(response.read()).decode()
|
|
35
|
-
logger.info(f"Response: {response.status_code} {url}")
|
|
36
|
-
|
|
37
|
-
return response
|
|
38
|
-
|
|
39
|
-
class SandboxOpts(TypedDict):
|
|
40
|
-
sandbox_id: str
|
|
41
|
-
sandbox_domain: Optional[str]
|
|
42
|
-
envd_version: Optional[str]
|
|
43
|
-
envd_access_token: Optional[str]
|
|
44
|
-
connection_config: ConnectionConfig
|
|
45
|
-
|
|
46
|
-
class Sandbox(SandboxSetup, SandboxApi):
|
|
47
|
-
"""
|
|
48
|
-
E2B cloud sandbox is a secure and isolated cloud environment.
|
|
49
|
-
|
|
50
|
-
The sandbox allows you to:
|
|
51
|
-
- Access Linux OS
|
|
52
|
-
- Create, list, and delete files and directories
|
|
53
|
-
- Run commands
|
|
54
|
-
- Run isolated code
|
|
55
|
-
- Access the internet
|
|
56
|
-
|
|
57
|
-
Check docs [here](https://..dev/docs).
|
|
58
|
-
|
|
59
|
-
Use the `Sandbox()` to create a new sandbox.
|
|
60
|
-
|
|
61
|
-
Example:
|
|
62
|
-
```python
|
|
63
|
-
from e2b import Sandbox
|
|
64
|
-
|
|
65
|
-
sandbox = Sandbox()
|
|
66
|
-
```
|
|
67
|
-
"""
|
|
68
|
-
|
|
69
|
-
@property
|
|
70
|
-
def files(self) -> Filesystem:
|
|
71
|
-
"""
|
|
72
|
-
Module for interacting with the sandbox filesystem.
|
|
73
|
-
"""
|
|
74
|
-
return self._filesystem
|
|
75
|
-
|
|
76
|
-
@property
|
|
77
|
-
def commands(self) -> Commands:
|
|
78
|
-
"""
|
|
79
|
-
Module for running commands in the sandbox.
|
|
80
|
-
"""
|
|
81
|
-
return self._commands
|
|
82
|
-
|
|
83
|
-
@property
|
|
84
|
-
def pty(self) -> Pty:
|
|
85
|
-
"""
|
|
86
|
-
Module for interacting with the sandbox pseudo-terminal.
|
|
87
|
-
"""
|
|
88
|
-
return self._pty
|
|
89
|
-
|
|
90
|
-
@property
|
|
91
|
-
def sandbox_id(self) -> str:
|
|
92
|
-
"""
|
|
93
|
-
Unique identifier of the sandbox.
|
|
94
|
-
"""
|
|
95
|
-
return self._sandbox_id
|
|
96
|
-
|
|
97
|
-
@property
|
|
98
|
-
def sandbox_domain(self) -> str:
|
|
99
|
-
"""
|
|
100
|
-
Domain where the sandbox is hosted.
|
|
101
|
-
"""
|
|
102
|
-
return self._sandbox_domain
|
|
103
|
-
|
|
104
|
-
@property
|
|
105
|
-
def envd_api_url(self) -> str:
|
|
106
|
-
return self._envd_api_url
|
|
107
|
-
|
|
108
|
-
@property
|
|
109
|
-
def _envd_access_token(self) -> str:
|
|
110
|
-
"""Private property to access the envd token"""
|
|
111
|
-
return self.__envd_access_token
|
|
112
|
-
|
|
113
|
-
@_envd_access_token.setter
|
|
114
|
-
def _envd_access_token(self, value: Optional[str]):
|
|
115
|
-
"""Private setter for envd token"""
|
|
116
|
-
self.__envd_access_token = value
|
|
117
|
-
|
|
118
|
-
@property
|
|
119
|
-
def connection_config(self) -> ConnectionConfig:
|
|
120
|
-
return self._connection_config
|
|
121
|
-
|
|
122
|
-
# def __init__(
|
|
123
|
-
# self,
|
|
124
|
-
# template: Optional[str] = None,
|
|
125
|
-
# timeout: Optional[int] = None,
|
|
126
|
-
# metadata: Optional[Dict[str, str]] = None,
|
|
127
|
-
# envs: Optional[Dict[str, str]] = None,
|
|
128
|
-
# secure: Optional[bool] = None,
|
|
129
|
-
# api_key: Optional[str] = None,
|
|
130
|
-
# domain: Optional[str] = None,
|
|
131
|
-
# debug: Optional[bool] = None,
|
|
132
|
-
# sandbox_id: Optional[str] = None,
|
|
133
|
-
# request_timeout: Optional[float] = None,
|
|
134
|
-
# proxy: Optional[ProxyTypes] = None,
|
|
135
|
-
# allow_internet_access: Optional[bool] = True,
|
|
136
|
-
# ):
|
|
137
|
-
def __init__(self, **opts):
|
|
138
|
-
"""
|
|
139
|
-
Create a new sandbox.
|
|
140
|
-
|
|
141
|
-
By default, the sandbox is created from the default `base` sandbox template.
|
|
142
|
-
|
|
143
|
-
:param template: Sandbox template name or ID
|
|
144
|
-
:param timeout: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users
|
|
145
|
-
:param metadata: Custom metadata for the sandbox
|
|
146
|
-
:param envs: Custom environment variables for the sandbox
|
|
147
|
-
:param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
|
|
148
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
149
|
-
:param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
|
|
150
|
-
:param allow_internet_access: Allow sandbox to access the internet, defaults to `True`
|
|
151
|
-
|
|
152
|
-
:return: sandbox instance for the new sandbox
|
|
153
|
-
"""
|
|
154
|
-
super().__init__()
|
|
155
|
-
self._connection_config = opts["connection_config"]
|
|
156
|
-
|
|
157
|
-
self._sandbox_id = opts["sandbox_id"]
|
|
158
|
-
self._sandbox_domain = opts["sandbox_domain"] or self.connection_config.domain
|
|
159
|
-
debug = self._connection_config.debug
|
|
160
|
-
# connection_headers = {"Authorization": "Bearer root", }
|
|
161
|
-
|
|
162
|
-
# if debug:
|
|
163
|
-
# self._sandbox_id = "debug_sandbox_id"
|
|
164
|
-
# self._sandbox_domain = None
|
|
165
|
-
# self._envd_version = None
|
|
166
|
-
# self._envd_access_token = None
|
|
167
|
-
# elif sandbox_id is not None:
|
|
168
|
-
# response = SandboxApi._cls_get_info(
|
|
169
|
-
# sandbox_id,
|
|
170
|
-
# api_key=api_key,
|
|
171
|
-
# domain=domain,
|
|
172
|
-
# debug=debug,
|
|
173
|
-
# request_timeout=request_timeout,
|
|
174
|
-
# proxy=proxy,
|
|
175
|
-
# )
|
|
176
|
-
#
|
|
177
|
-
# self._sandbox_id = sandbox_id
|
|
178
|
-
# self._sandbox_domain = response.sandbox_domain
|
|
179
|
-
# self._envd_version = response.envd_version
|
|
180
|
-
# self._envd_access_token = response._envd_access_token
|
|
181
|
-
#
|
|
182
|
-
# if response._envd_access_token is not None and not isinstance(
|
|
183
|
-
# response._envd_access_token, Unset
|
|
184
|
-
# ):
|
|
185
|
-
# connection_headers["X-Access-Token"] = response._envd_access_token
|
|
186
|
-
# else:
|
|
187
|
-
# template = template or self.default_template
|
|
188
|
-
# timeout = timeout or self.default_sandbox_timeout
|
|
189
|
-
# response = SandboxApi._create_sandbox(
|
|
190
|
-
# template=template,
|
|
191
|
-
# api_key=api_key,
|
|
192
|
-
# timeout=timeout,
|
|
193
|
-
# metadata=metadata,
|
|
194
|
-
# env_vars=envs,
|
|
195
|
-
# domain=domain,
|
|
196
|
-
# debug=debug,
|
|
197
|
-
# request_timeout=request_timeout,
|
|
198
|
-
# secure=secure or False,
|
|
199
|
-
# proxy=proxy,
|
|
200
|
-
# allow_internet_access=allow_internet_access,
|
|
201
|
-
# )
|
|
202
|
-
#
|
|
203
|
-
# self._sandbox_id = response.sandbox_id
|
|
204
|
-
# self._sandbox_domain = response.sandbox_domain
|
|
205
|
-
# self._envd_version = response.envd_version
|
|
206
|
-
#
|
|
207
|
-
# if response.envd_access_token is not None and not isinstance(
|
|
208
|
-
# response.envd_access_token, Unset
|
|
209
|
-
# ):
|
|
210
|
-
# self._envd_access_token = response.envd_access_token
|
|
211
|
-
# connection_headers["X-Access-Token"] = response.envd_access_token
|
|
212
|
-
# else:
|
|
213
|
-
# self._envd_access_token = None
|
|
214
|
-
# self._transport = TransportWithLogger(limits=self._limits, proxy=proxy)
|
|
215
|
-
# self._connection_config = ConnectionConfig(
|
|
216
|
-
# api_key=api_key,
|
|
217
|
-
# domain=domain,
|
|
218
|
-
# debug=debug,
|
|
219
|
-
# request_timeout=request_timeout,
|
|
220
|
-
# headers=connection_headers,
|
|
221
|
-
# proxy=proxy,
|
|
222
|
-
# )
|
|
223
|
-
|
|
224
|
-
self._sandbox_domain = self._sandbox_domain or self._connection_config.domain
|
|
225
|
-
# self._envd_api_url = f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(self.envd_port)}"
|
|
226
|
-
if debug:
|
|
227
|
-
self._envd_api_url = f"http://{self.get_host(8888)}"
|
|
228
|
-
# elif self._sandbox_id is not None:
|
|
229
|
-
# response = SandboxApi._cls_get_info(
|
|
230
|
-
# self._sandbox_id,
|
|
231
|
-
# api_key=self._api_key(),
|
|
232
|
-
# domain=self._sandbox_domain,
|
|
233
|
-
# debug=debug,
|
|
234
|
-
# request_timeout=self.request_timeout,
|
|
235
|
-
# proxy=self.proxy,
|
|
236
|
-
# )
|
|
237
|
-
#
|
|
238
|
-
# self._sandbox_id = self._sandbox_id
|
|
239
|
-
# self._sandbox_domain = response.sandbox_domain
|
|
240
|
-
# self._envd_version = response.envd_version
|
|
241
|
-
# self._envd_access_token = response._envd_access_token
|
|
242
|
-
#
|
|
243
|
-
# if response._envd_access_token is not None and not isinstance(
|
|
244
|
-
# response._envd_access_token, Unset
|
|
245
|
-
# ):
|
|
246
|
-
# self._connection_config["X-Access-Token"] = response._envd_access_token
|
|
247
|
-
# self._envd_api_url = f"http://{self.get_host(self.envd_port)}"
|
|
248
|
-
else:
|
|
249
|
-
self._envd_api_url = f"https://{self.get_host(self.envd_port)}"
|
|
250
|
-
self._transport = TransportWithLogger(limits=self._limits, proxy=self._connection_config.proxy)
|
|
251
|
-
# self._envd_api_url = f"http://localhost:8088"
|
|
252
|
-
# self._envd_api_url = f"http://{self.get_host(self.envd_port)}"
|
|
253
|
-
# self._envd_api_url = f"http://localhost:31000"
|
|
254
|
-
self._envd_api = httpx.Client(
|
|
255
|
-
base_url=self._envd_api_url,
|
|
256
|
-
transport=self._transport,
|
|
257
|
-
headers=self.connection_config.headers,
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
self._envd_version=f"v1.0"
|
|
261
|
-
# 准备连接池参数
|
|
262
|
-
connection_pool_kw = {
|
|
263
|
-
# 连接池大小
|
|
264
|
-
"maxsize": 100,
|
|
265
|
-
"block": False,
|
|
266
|
-
# 超时设置
|
|
267
|
-
"timeout": self._connection_config.request_timeout,
|
|
268
|
-
# 重试策略
|
|
269
|
-
"retries": Retry(
|
|
270
|
-
total=3,
|
|
271
|
-
backoff_factor=0.1,
|
|
272
|
-
status_forcelist=[500, 502, 503, 504]
|
|
273
|
-
),
|
|
274
|
-
# SSL 设置
|
|
275
|
-
# "cert_reqs": 'CERT_NONE',
|
|
276
|
-
"ca_certs": None,
|
|
277
|
-
# 套接字选项
|
|
278
|
-
"socket_options": [
|
|
279
|
-
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
|
|
280
|
-
(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),
|
|
281
|
-
],
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
# 如果有代理配置,添加到连接池参数
|
|
285
|
-
if hasattr(self._connection_config, 'proxy') and self._connection_config.proxy:
|
|
286
|
-
connection_pool_kw["proxy_url"] = self._connection_config.proxy
|
|
287
|
-
|
|
288
|
-
# 创建 urllib3.PoolManager 连接池
|
|
289
|
-
self._urllib3_pool = urllib3.PoolManager(
|
|
290
|
-
num_pools=10, # 池的数量
|
|
291
|
-
headers=self._connection_config.headers, # 默认头部
|
|
292
|
-
**connection_pool_kw # 连接池参数
|
|
293
|
-
)
|
|
294
|
-
|
|
295
|
-
self._filesystem = Filesystem(
|
|
296
|
-
self.envd_api_url,
|
|
297
|
-
self._envd_version,
|
|
298
|
-
self.connection_config,
|
|
299
|
-
self._urllib3_pool,
|
|
300
|
-
self._envd_api,
|
|
301
|
-
)
|
|
302
|
-
self._commands = Commands(
|
|
303
|
-
self.envd_api_url,
|
|
304
|
-
self.connection_config,
|
|
305
|
-
self._urllib3_pool,
|
|
306
|
-
)
|
|
307
|
-
self._pty = Pty(
|
|
308
|
-
self.envd_api_url,
|
|
309
|
-
self.connection_config,
|
|
310
|
-
self._urllib3_pool,
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
@classmethod
|
|
314
|
-
def create(
|
|
315
|
-
cls,
|
|
316
|
-
template: Optional[str] = None,
|
|
317
|
-
timeout: Optional[int] = None,
|
|
318
|
-
metadata: Optional[Dict[str, str]] = None,
|
|
319
|
-
envs: Optional[Dict[str, str]] = None,
|
|
320
|
-
api_key: Optional[str] = None,
|
|
321
|
-
domain: Optional[str] = None,
|
|
322
|
-
debug: Optional[bool] = None,
|
|
323
|
-
sandbox_id: Optional[str] = None,
|
|
324
|
-
request_timeout: Optional[float] = None,
|
|
325
|
-
proxy: Optional[ProxyTypes] = None,
|
|
326
|
-
secure: Optional[bool] = None,
|
|
327
|
-
allow_internet_access: Optional[bool] = True,
|
|
328
|
-
):
|
|
329
|
-
"""
|
|
330
|
-
Create a new sandbox.
|
|
331
|
-
|
|
332
|
-
By default, the sandbox is created from the default `base` sandbox template.
|
|
333
|
-
|
|
334
|
-
:param template: Sandbox template name or ID
|
|
335
|
-
:param timeout: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
|
|
336
|
-
:param metadata: Custom metadata for the sandbox
|
|
337
|
-
:param envs: Custom environment variables for the sandbox
|
|
338
|
-
:param api_key: scalebox API Key to use for authentication, defaults to `CSX_API_KEY` environment variable
|
|
339
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
340
|
-
:param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
|
|
341
|
-
:param secure: Envd is secured with access token and cannot be used without it
|
|
342
|
-
:param allow_internet_access: Allow sandbox to access the internet, defaults to `True`.
|
|
343
|
-
|
|
344
|
-
:return: sandbox instance for the new sandbox
|
|
345
|
-
|
|
346
|
-
Use this method instead of using the constructor to create a new sandbox.
|
|
347
|
-
"""
|
|
348
|
-
if sandbox_id and (metadata is not None or template is not None):
|
|
349
|
-
raise SandboxException(
|
|
350
|
-
"Cannot set metadata or timeout when connecting to an existing sandbox. "
|
|
351
|
-
"Use Sandbox.connect method instead.",
|
|
352
|
-
)
|
|
353
|
-
connection_headers = {"Authorization": "Bearer root", }
|
|
354
|
-
if debug:
|
|
355
|
-
sandbox_id = "debug_sandbox_id"
|
|
356
|
-
sandbox_domain = None
|
|
357
|
-
envd_version = None
|
|
358
|
-
envd_access_token =
|
|
359
|
-
elif sandbox_id is not None:
|
|
360
|
-
response = SandboxApi._cls_get_info(
|
|
361
|
-
sandbox_id,
|
|
362
|
-
api_key=api_key,
|
|
363
|
-
domain=domain,
|
|
364
|
-
debug=debug,
|
|
365
|
-
request_timeout=request_timeout,
|
|
366
|
-
proxy=proxy,
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
sandbox_domain = response.sandbox_domain
|
|
370
|
-
envd_version = response.envd_version
|
|
371
|
-
envd_access_token = response._envd_access_token
|
|
372
|
-
|
|
373
|
-
if response._envd_access_token is not None and not isinstance(
|
|
374
|
-
response._envd_access_token, Unset
|
|
375
|
-
):
|
|
376
|
-
connection_headers["X-Access-Token"] = response._envd_access_token
|
|
377
|
-
else:
|
|
378
|
-
response = SandboxApi._create_sandbox(
|
|
379
|
-
template=template or cls.default_template,
|
|
380
|
-
api_key=api_key,
|
|
381
|
-
timeout=timeout or cls.default_sandbox_timeout,
|
|
382
|
-
metadata=metadata,
|
|
383
|
-
domain=domain,
|
|
384
|
-
debug=debug,
|
|
385
|
-
request_timeout=request_timeout,
|
|
386
|
-
env_vars=envs,
|
|
387
|
-
secure=secure,
|
|
388
|
-
proxy=proxy,
|
|
389
|
-
allow_internet_access=allow_internet_access,
|
|
390
|
-
)
|
|
391
|
-
|
|
392
|
-
sandbox_id = response.sandbox_id
|
|
393
|
-
sandbox_domain = response.sandbox_domain
|
|
394
|
-
envd_version = response.envd_version
|
|
395
|
-
envd_access_token = response.envd_access_token
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
connection_config = ConnectionConfig(
|
|
403
|
-
api_key=api_key,
|
|
404
|
-
domain=domain,
|
|
405
|
-
debug=debug,
|
|
406
|
-
request_timeout=request_timeout,
|
|
407
|
-
headers=connection_headers,
|
|
408
|
-
proxy=proxy,
|
|
409
|
-
)
|
|
410
|
-
print("connection_config" + str(connection_config.__dict__))
|
|
411
|
-
sanbox= cls(
|
|
412
|
-
sandbox_id=sandbox_id,
|
|
413
|
-
sandbox_domain=sandbox_domain,
|
|
414
|
-
envd_version=envd_version,
|
|
415
|
-
envd_access_token=envd_access_token,
|
|
416
|
-
connection_config=connection_config,
|
|
417
|
-
)
|
|
418
|
-
|
|
419
|
-
timeout = 5.0
|
|
420
|
-
interval = 0.3
|
|
421
|
-
elapsed = 0.0
|
|
422
|
-
while elapsed <= timeout:
|
|
423
|
-
try:
|
|
424
|
-
isRunning = sanbox.is_running(request_timeout=1)
|
|
425
|
-
if isRunning:
|
|
426
|
-
break
|
|
427
|
-
except Exception:
|
|
428
|
-
pass
|
|
429
|
-
time.sleep(interval)
|
|
430
|
-
elapsed += interval
|
|
431
|
-
else:
|
|
432
|
-
print("connect "+sandbox_domain+ENVD_API_HEALTH_ROUTE +" timeout 5s")
|
|
433
|
-
return sanbox
|
|
434
|
-
|
|
435
|
-
def is_running(self, request_timeout: Optional[float] = None) -> bool:
|
|
436
|
-
"""
|
|
437
|
-
Check if the sandbox is running.
|
|
438
|
-
|
|
439
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
440
|
-
|
|
441
|
-
:return: `True` if the sandbox is running, `False` otherwise
|
|
442
|
-
|
|
443
|
-
Example
|
|
444
|
-
```python
|
|
445
|
-
sandbox = Sandbox()
|
|
446
|
-
sandbox.is_running() # Returns True
|
|
447
|
-
|
|
448
|
-
sandbox.kill()
|
|
449
|
-
sandbox.is_running() # Returns False
|
|
450
|
-
```
|
|
451
|
-
"""
|
|
452
|
-
try:
|
|
453
|
-
r = self._envd_api.get(
|
|
454
|
-
ENVD_API_HEALTH_ROUTE,
|
|
455
|
-
timeout=self.connection_config.get_request_timeout(request_timeout),
|
|
456
|
-
)
|
|
457
|
-
print(r)
|
|
458
|
-
if r.status_code == 502:
|
|
459
|
-
return False
|
|
460
|
-
|
|
461
|
-
err = handle_envd_api_exception(r)
|
|
462
|
-
|
|
463
|
-
if err:
|
|
464
|
-
raise err
|
|
465
|
-
|
|
466
|
-
except httpx.TimeoutException:
|
|
467
|
-
raise request_timeout_error()
|
|
468
|
-
|
|
469
|
-
return True
|
|
470
|
-
|
|
471
|
-
@classmethod
|
|
472
|
-
def connect(
|
|
473
|
-
cls,
|
|
474
|
-
sandbox_id: str,
|
|
475
|
-
api_key: Optional[str] = None,
|
|
476
|
-
domain: Optional[str] = None,
|
|
477
|
-
debug: Optional[bool] = None,
|
|
478
|
-
proxy: Optional[ProxyTypes] = None,
|
|
479
|
-
):
|
|
480
|
-
"""
|
|
481
|
-
Connects to an existing Sandbox.
|
|
482
|
-
With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
|
|
483
|
-
|
|
484
|
-
:param sandbox_id: Sandbox ID
|
|
485
|
-
:param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
|
|
486
|
-
:param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
|
|
487
|
-
|
|
488
|
-
:return: sandbox instance for the existing sandbox
|
|
489
|
-
|
|
490
|
-
@example
|
|
491
|
-
```python
|
|
492
|
-
sandbox = Sandbox()
|
|
493
|
-
sandbox_id = sandbox.sandbox_id
|
|
494
|
-
|
|
495
|
-
# Another code block
|
|
496
|
-
same_sandbox = Sandbox.connect(sandbox_id)
|
|
497
|
-
```
|
|
498
|
-
"""
|
|
499
|
-
connection_headers = {"Authorization": "Bearer root"}
|
|
500
|
-
|
|
501
|
-
response = SandboxApi._cls_get_info(
|
|
502
|
-
sandbox_id,
|
|
503
|
-
api_key=api_key,
|
|
504
|
-
domain=domain,
|
|
505
|
-
debug=debug,
|
|
506
|
-
proxy=proxy,
|
|
507
|
-
)
|
|
508
|
-
|
|
509
|
-
if response._envd_access_token is not None and not isinstance(
|
|
510
|
-
response._envd_access_token, Unset
|
|
511
|
-
):
|
|
512
|
-
connection_headers["X-Access-Token"] = response._envd_access_token
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
@
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
:param
|
|
561
|
-
:param
|
|
562
|
-
:param
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
:
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
config_dict
|
|
578
|
-
config_dict.pop("
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
:param
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
@
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
:param
|
|
626
|
-
:param
|
|
627
|
-
:param
|
|
628
|
-
:param
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
config_dict
|
|
640
|
-
config_dict.pop("
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
:
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
@
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
:param
|
|
678
|
-
:param
|
|
679
|
-
:param
|
|
680
|
-
:param
|
|
681
|
-
:param
|
|
682
|
-
:param
|
|
683
|
-
:
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
:
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
config_dict
|
|
699
|
-
config_dict.pop("
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
:param
|
|
721
|
-
:param
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
@
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
:param
|
|
743
|
-
:param
|
|
744
|
-
:param
|
|
745
|
-
:param
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
:param
|
|
763
|
-
:param
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
config_dict
|
|
780
|
-
config_dict.pop("
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
)
|
|
1
|
+
import datetime
|
|
2
|
+
import logging
|
|
3
|
+
import socket
|
|
4
|
+
import time
|
|
5
|
+
from typing import Dict, List, Optional, TypedDict, overload
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
import urllib3
|
|
9
|
+
from httpx import Timeout
|
|
10
|
+
from packaging.version import Version
|
|
11
|
+
from urllib3 import Retry
|
|
12
|
+
|
|
13
|
+
from ..api.client.types import Unset
|
|
14
|
+
from ..connection_config import ConnectionConfig, ProxyTypes
|
|
15
|
+
from ..exceptions import SandboxException, request_timeout_error
|
|
16
|
+
from ..generated.api import ENVD_API_HEALTH_ROUTE, handle_envd_api_exception
|
|
17
|
+
from ..sandbox.main import SandboxSetup
|
|
18
|
+
from ..sandbox.sandbox_api import SandboxMetrics
|
|
19
|
+
from ..sandbox.utils import class_method_variant
|
|
20
|
+
from ..sandbox_sync.commands.command import Commands
|
|
21
|
+
from ..sandbox_sync.commands.pty import Pty
|
|
22
|
+
from ..sandbox_sync.filesystem.filesystem import Filesystem
|
|
23
|
+
from ..sandbox_sync.sandbox_api import SandboxApi, SandboxInfo
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TransportWithLogger(httpx.HTTPTransport):
|
|
29
|
+
def handle_request(self, request):
|
|
30
|
+
url = f"{request.url.scheme}://{request.url.host}{request.url.path}"
|
|
31
|
+
logger.info(f"Request: {request.method} {url}")
|
|
32
|
+
response = super().handle_request(request)
|
|
33
|
+
|
|
34
|
+
# data = connect.GzipCompressor.decompress(response.read()).decode()
|
|
35
|
+
logger.info(f"Response: {response.status_code} {url}")
|
|
36
|
+
|
|
37
|
+
return response
|
|
38
|
+
|
|
39
|
+
class SandboxOpts(TypedDict):
|
|
40
|
+
sandbox_id: str
|
|
41
|
+
sandbox_domain: Optional[str]
|
|
42
|
+
envd_version: Optional[str]
|
|
43
|
+
envd_access_token: Optional[str]
|
|
44
|
+
connection_config: ConnectionConfig
|
|
45
|
+
|
|
46
|
+
class Sandbox(SandboxSetup, SandboxApi):
|
|
47
|
+
"""
|
|
48
|
+
E2B cloud sandbox is a secure and isolated cloud environment.
|
|
49
|
+
|
|
50
|
+
The sandbox allows you to:
|
|
51
|
+
- Access Linux OS
|
|
52
|
+
- Create, list, and delete files and directories
|
|
53
|
+
- Run commands
|
|
54
|
+
- Run isolated code
|
|
55
|
+
- Access the internet
|
|
56
|
+
|
|
57
|
+
Check docs [here](https://..dev/docs).
|
|
58
|
+
|
|
59
|
+
Use the `Sandbox()` to create a new sandbox.
|
|
60
|
+
|
|
61
|
+
Example:
|
|
62
|
+
```python
|
|
63
|
+
from e2b import Sandbox
|
|
64
|
+
|
|
65
|
+
sandbox = Sandbox()
|
|
66
|
+
```
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def files(self) -> Filesystem:
|
|
71
|
+
"""
|
|
72
|
+
Module for interacting with the sandbox filesystem.
|
|
73
|
+
"""
|
|
74
|
+
return self._filesystem
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def commands(self) -> Commands:
|
|
78
|
+
"""
|
|
79
|
+
Module for running commands in the sandbox.
|
|
80
|
+
"""
|
|
81
|
+
return self._commands
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def pty(self) -> Pty:
|
|
85
|
+
"""
|
|
86
|
+
Module for interacting with the sandbox pseudo-terminal.
|
|
87
|
+
"""
|
|
88
|
+
return self._pty
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def sandbox_id(self) -> str:
|
|
92
|
+
"""
|
|
93
|
+
Unique identifier of the sandbox.
|
|
94
|
+
"""
|
|
95
|
+
return self._sandbox_id
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def sandbox_domain(self) -> str:
|
|
99
|
+
"""
|
|
100
|
+
Domain where the sandbox is hosted.
|
|
101
|
+
"""
|
|
102
|
+
return self._sandbox_domain
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def envd_api_url(self) -> str:
|
|
106
|
+
return self._envd_api_url
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def _envd_access_token(self) -> str:
|
|
110
|
+
"""Private property to access the envd token"""
|
|
111
|
+
return self.__envd_access_token
|
|
112
|
+
|
|
113
|
+
@_envd_access_token.setter
|
|
114
|
+
def _envd_access_token(self, value: Optional[str]):
|
|
115
|
+
"""Private setter for envd token"""
|
|
116
|
+
self.__envd_access_token = value
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def connection_config(self) -> ConnectionConfig:
|
|
120
|
+
return self._connection_config
|
|
121
|
+
|
|
122
|
+
# def __init__(
|
|
123
|
+
# self,
|
|
124
|
+
# template: Optional[str] = None,
|
|
125
|
+
# timeout: Optional[int] = None,
|
|
126
|
+
# metadata: Optional[Dict[str, str]] = None,
|
|
127
|
+
# envs: Optional[Dict[str, str]] = None,
|
|
128
|
+
# secure: Optional[bool] = None,
|
|
129
|
+
# api_key: Optional[str] = None,
|
|
130
|
+
# domain: Optional[str] = None,
|
|
131
|
+
# debug: Optional[bool] = None,
|
|
132
|
+
# sandbox_id: Optional[str] = None,
|
|
133
|
+
# request_timeout: Optional[float] = None,
|
|
134
|
+
# proxy: Optional[ProxyTypes] = None,
|
|
135
|
+
# allow_internet_access: Optional[bool] = True,
|
|
136
|
+
# ):
|
|
137
|
+
def __init__(self, **opts):
|
|
138
|
+
"""
|
|
139
|
+
Create a new sandbox.
|
|
140
|
+
|
|
141
|
+
By default, the sandbox is created from the default `base` sandbox template.
|
|
142
|
+
|
|
143
|
+
:param template: Sandbox template name or ID
|
|
144
|
+
:param timeout: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users
|
|
145
|
+
:param metadata: Custom metadata for the sandbox
|
|
146
|
+
:param envs: Custom environment variables for the sandbox
|
|
147
|
+
:param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
|
|
148
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
149
|
+
:param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
|
|
150
|
+
:param allow_internet_access: Allow sandbox to access the internet, defaults to `True`
|
|
151
|
+
|
|
152
|
+
:return: sandbox instance for the new sandbox
|
|
153
|
+
"""
|
|
154
|
+
super().__init__()
|
|
155
|
+
self._connection_config = opts["connection_config"]
|
|
156
|
+
|
|
157
|
+
self._sandbox_id = opts["sandbox_id"]
|
|
158
|
+
self._sandbox_domain = opts["sandbox_domain"] or self.connection_config.domain
|
|
159
|
+
debug = self._connection_config.debug
|
|
160
|
+
# connection_headers = {"Authorization": "Bearer root", }
|
|
161
|
+
|
|
162
|
+
# if debug:
|
|
163
|
+
# self._sandbox_id = "debug_sandbox_id"
|
|
164
|
+
# self._sandbox_domain = None
|
|
165
|
+
# self._envd_version = None
|
|
166
|
+
# self._envd_access_token = None
|
|
167
|
+
# elif sandbox_id is not None:
|
|
168
|
+
# response = SandboxApi._cls_get_info(
|
|
169
|
+
# sandbox_id,
|
|
170
|
+
# api_key=api_key,
|
|
171
|
+
# domain=domain,
|
|
172
|
+
# debug=debug,
|
|
173
|
+
# request_timeout=request_timeout,
|
|
174
|
+
# proxy=proxy,
|
|
175
|
+
# )
|
|
176
|
+
#
|
|
177
|
+
# self._sandbox_id = sandbox_id
|
|
178
|
+
# self._sandbox_domain = response.sandbox_domain
|
|
179
|
+
# self._envd_version = response.envd_version
|
|
180
|
+
# self._envd_access_token = response._envd_access_token
|
|
181
|
+
#
|
|
182
|
+
# if response._envd_access_token is not None and not isinstance(
|
|
183
|
+
# response._envd_access_token, Unset
|
|
184
|
+
# ):
|
|
185
|
+
# connection_headers["X-Access-Token"] = response._envd_access_token
|
|
186
|
+
# else:
|
|
187
|
+
# template = template or self.default_template
|
|
188
|
+
# timeout = timeout or self.default_sandbox_timeout
|
|
189
|
+
# response = SandboxApi._create_sandbox(
|
|
190
|
+
# template=template,
|
|
191
|
+
# api_key=api_key,
|
|
192
|
+
# timeout=timeout,
|
|
193
|
+
# metadata=metadata,
|
|
194
|
+
# env_vars=envs,
|
|
195
|
+
# domain=domain,
|
|
196
|
+
# debug=debug,
|
|
197
|
+
# request_timeout=request_timeout,
|
|
198
|
+
# secure=secure or False,
|
|
199
|
+
# proxy=proxy,
|
|
200
|
+
# allow_internet_access=allow_internet_access,
|
|
201
|
+
# )
|
|
202
|
+
#
|
|
203
|
+
# self._sandbox_id = response.sandbox_id
|
|
204
|
+
# self._sandbox_domain = response.sandbox_domain
|
|
205
|
+
# self._envd_version = response.envd_version
|
|
206
|
+
#
|
|
207
|
+
# if response.envd_access_token is not None and not isinstance(
|
|
208
|
+
# response.envd_access_token, Unset
|
|
209
|
+
# ):
|
|
210
|
+
# self._envd_access_token = response.envd_access_token
|
|
211
|
+
# connection_headers["X-Access-Token"] = response.envd_access_token
|
|
212
|
+
# else:
|
|
213
|
+
# self._envd_access_token = None
|
|
214
|
+
# self._transport = TransportWithLogger(limits=self._limits, proxy=proxy)
|
|
215
|
+
# self._connection_config = ConnectionConfig(
|
|
216
|
+
# api_key=api_key,
|
|
217
|
+
# domain=domain,
|
|
218
|
+
# debug=debug,
|
|
219
|
+
# request_timeout=request_timeout,
|
|
220
|
+
# headers=connection_headers,
|
|
221
|
+
# proxy=proxy,
|
|
222
|
+
# )
|
|
223
|
+
|
|
224
|
+
self._sandbox_domain = self._sandbox_domain or self._connection_config.domain
|
|
225
|
+
# self._envd_api_url = f"{'http' if self.connection_config.debug else 'https'}://{self.get_host(self.envd_port)}"
|
|
226
|
+
if debug:
|
|
227
|
+
self._envd_api_url = f"http://{self.get_host(8888)}"
|
|
228
|
+
# elif self._sandbox_id is not None:
|
|
229
|
+
# response = SandboxApi._cls_get_info(
|
|
230
|
+
# self._sandbox_id,
|
|
231
|
+
# api_key=self._api_key(),
|
|
232
|
+
# domain=self._sandbox_domain,
|
|
233
|
+
# debug=debug,
|
|
234
|
+
# request_timeout=self.request_timeout,
|
|
235
|
+
# proxy=self.proxy,
|
|
236
|
+
# )
|
|
237
|
+
#
|
|
238
|
+
# self._sandbox_id = self._sandbox_id
|
|
239
|
+
# self._sandbox_domain = response.sandbox_domain
|
|
240
|
+
# self._envd_version = response.envd_version
|
|
241
|
+
# self._envd_access_token = response._envd_access_token
|
|
242
|
+
#
|
|
243
|
+
# if response._envd_access_token is not None and not isinstance(
|
|
244
|
+
# response._envd_access_token, Unset
|
|
245
|
+
# ):
|
|
246
|
+
# self._connection_config["X-Access-Token"] = response._envd_access_token
|
|
247
|
+
# self._envd_api_url = f"http://{self.get_host(self.envd_port)}"
|
|
248
|
+
else:
|
|
249
|
+
self._envd_api_url = f"https://{self.get_host(self.envd_port)}"
|
|
250
|
+
self._transport = TransportWithLogger(limits=self._limits, proxy=self._connection_config.proxy)
|
|
251
|
+
# self._envd_api_url = f"http://localhost:8088"
|
|
252
|
+
# self._envd_api_url = f"http://{self.get_host(self.envd_port)}"
|
|
253
|
+
# self._envd_api_url = f"http://localhost:31000"
|
|
254
|
+
self._envd_api = httpx.Client(
|
|
255
|
+
base_url=self._envd_api_url,
|
|
256
|
+
transport=self._transport,
|
|
257
|
+
headers=self.connection_config.headers,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
self._envd_version=f"v1.0"
|
|
261
|
+
# 准备连接池参数
|
|
262
|
+
connection_pool_kw = {
|
|
263
|
+
# 连接池大小
|
|
264
|
+
"maxsize": 100,
|
|
265
|
+
"block": False,
|
|
266
|
+
# 超时设置
|
|
267
|
+
"timeout": self._connection_config.request_timeout,
|
|
268
|
+
# 重试策略
|
|
269
|
+
"retries": Retry(
|
|
270
|
+
total=3,
|
|
271
|
+
backoff_factor=0.1,
|
|
272
|
+
status_forcelist=[500, 502, 503, 504]
|
|
273
|
+
),
|
|
274
|
+
# SSL 设置
|
|
275
|
+
# "cert_reqs": 'CERT_NONE',
|
|
276
|
+
"ca_certs": None,
|
|
277
|
+
# 套接字选项
|
|
278
|
+
"socket_options": [
|
|
279
|
+
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
|
|
280
|
+
(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),
|
|
281
|
+
],
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
# 如果有代理配置,添加到连接池参数
|
|
285
|
+
if hasattr(self._connection_config, 'proxy') and self._connection_config.proxy:
|
|
286
|
+
connection_pool_kw["proxy_url"] = self._connection_config.proxy
|
|
287
|
+
|
|
288
|
+
# 创建 urllib3.PoolManager 连接池
|
|
289
|
+
self._urllib3_pool = urllib3.PoolManager(
|
|
290
|
+
num_pools=10, # 池的数量
|
|
291
|
+
headers=self._connection_config.headers, # 默认头部
|
|
292
|
+
**connection_pool_kw # 连接池参数
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
self._filesystem = Filesystem(
|
|
296
|
+
self.envd_api_url,
|
|
297
|
+
self._envd_version,
|
|
298
|
+
self.connection_config,
|
|
299
|
+
self._urllib3_pool,
|
|
300
|
+
self._envd_api,
|
|
301
|
+
)
|
|
302
|
+
self._commands = Commands(
|
|
303
|
+
self.envd_api_url,
|
|
304
|
+
self.connection_config,
|
|
305
|
+
self._urllib3_pool,
|
|
306
|
+
)
|
|
307
|
+
self._pty = Pty(
|
|
308
|
+
self.envd_api_url,
|
|
309
|
+
self.connection_config,
|
|
310
|
+
self._urllib3_pool,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
@classmethod
|
|
314
|
+
def create(
|
|
315
|
+
cls,
|
|
316
|
+
template: Optional[str] = None,
|
|
317
|
+
timeout: Optional[int] = None,
|
|
318
|
+
metadata: Optional[Dict[str, str]] = None,
|
|
319
|
+
envs: Optional[Dict[str, str]] = None,
|
|
320
|
+
api_key: Optional[str] = None,
|
|
321
|
+
domain: Optional[str] = None,
|
|
322
|
+
debug: Optional[bool] = None,
|
|
323
|
+
sandbox_id: Optional[str] = None,
|
|
324
|
+
request_timeout: Optional[float] = None,
|
|
325
|
+
proxy: Optional[ProxyTypes] = None,
|
|
326
|
+
secure: Optional[bool] = None,
|
|
327
|
+
allow_internet_access: Optional[bool] = True,
|
|
328
|
+
):
|
|
329
|
+
"""
|
|
330
|
+
Create a new sandbox.
|
|
331
|
+
|
|
332
|
+
By default, the sandbox is created from the default `base` sandbox template.
|
|
333
|
+
|
|
334
|
+
:param template: Sandbox template name or ID
|
|
335
|
+
:param timeout: Timeout for the sandbox in **seconds**, default to 300 seconds. Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
|
|
336
|
+
:param metadata: Custom metadata for the sandbox
|
|
337
|
+
:param envs: Custom environment variables for the sandbox
|
|
338
|
+
:param api_key: scalebox API Key to use for authentication, defaults to `CSX_API_KEY` environment variable
|
|
339
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
340
|
+
:param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
|
|
341
|
+
:param secure: Envd is secured with access token and cannot be used without it
|
|
342
|
+
:param allow_internet_access: Allow sandbox to access the internet, defaults to `True`.
|
|
343
|
+
|
|
344
|
+
:return: sandbox instance for the new sandbox
|
|
345
|
+
|
|
346
|
+
Use this method instead of using the constructor to create a new sandbox.
|
|
347
|
+
"""
|
|
348
|
+
if sandbox_id and (metadata is not None or template is not None):
|
|
349
|
+
raise SandboxException(
|
|
350
|
+
"Cannot set metadata or timeout when connecting to an existing sandbox. "
|
|
351
|
+
"Use Sandbox.connect method instead.",
|
|
352
|
+
)
|
|
353
|
+
connection_headers = {"Authorization": "Bearer root", }
|
|
354
|
+
if debug:
|
|
355
|
+
sandbox_id = "debug_sandbox_id"
|
|
356
|
+
sandbox_domain = None
|
|
357
|
+
envd_version = None
|
|
358
|
+
envd_access_token = "123456789"
|
|
359
|
+
elif sandbox_id is not None:
|
|
360
|
+
response = SandboxApi._cls_get_info(
|
|
361
|
+
sandbox_id,
|
|
362
|
+
api_key=api_key,
|
|
363
|
+
domain=domain,
|
|
364
|
+
debug=debug,
|
|
365
|
+
request_timeout=request_timeout,
|
|
366
|
+
proxy=proxy,
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
sandbox_domain = response.sandbox_domain
|
|
370
|
+
envd_version = response.envd_version
|
|
371
|
+
envd_access_token = response._envd_access_token
|
|
372
|
+
|
|
373
|
+
if response._envd_access_token is not None and not isinstance(
|
|
374
|
+
response._envd_access_token, Unset
|
|
375
|
+
):
|
|
376
|
+
connection_headers["X-Access-Token"] = response._envd_access_token
|
|
377
|
+
else:
|
|
378
|
+
response = SandboxApi._create_sandbox(
|
|
379
|
+
template=template or cls.default_template,
|
|
380
|
+
api_key=api_key,
|
|
381
|
+
timeout=timeout or cls.default_sandbox_timeout,
|
|
382
|
+
metadata=metadata,
|
|
383
|
+
domain=domain,
|
|
384
|
+
debug=debug,
|
|
385
|
+
request_timeout=request_timeout,
|
|
386
|
+
env_vars=envs,
|
|
387
|
+
secure=secure,
|
|
388
|
+
proxy=proxy,
|
|
389
|
+
allow_internet_access=allow_internet_access,
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
sandbox_id = response.sandbox_id
|
|
393
|
+
sandbox_domain = response.sandbox_domain
|
|
394
|
+
envd_version = response.envd_version
|
|
395
|
+
envd_access_token = response.envd_access_token
|
|
396
|
+
|
|
397
|
+
if envd_access_token is not None and not isinstance(
|
|
398
|
+
envd_access_token, Unset
|
|
399
|
+
):
|
|
400
|
+
connection_headers["X-Access-Token"] = envd_access_token
|
|
401
|
+
|
|
402
|
+
connection_config = ConnectionConfig(
|
|
403
|
+
api_key=api_key,
|
|
404
|
+
domain=domain,
|
|
405
|
+
debug=debug,
|
|
406
|
+
request_timeout=request_timeout,
|
|
407
|
+
headers=connection_headers,
|
|
408
|
+
proxy=proxy,
|
|
409
|
+
)
|
|
410
|
+
print("connection_config" + str(connection_config.__dict__))
|
|
411
|
+
sanbox= cls(
|
|
412
|
+
sandbox_id=sandbox_id,
|
|
413
|
+
sandbox_domain=sandbox_domain,
|
|
414
|
+
envd_version=envd_version,
|
|
415
|
+
envd_access_token=envd_access_token,
|
|
416
|
+
connection_config=connection_config,
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
timeout = 5.0
|
|
420
|
+
interval = 0.3
|
|
421
|
+
elapsed = 0.0
|
|
422
|
+
while elapsed <= timeout:
|
|
423
|
+
try:
|
|
424
|
+
isRunning = sanbox.is_running(request_timeout=1)
|
|
425
|
+
if isRunning:
|
|
426
|
+
break
|
|
427
|
+
except Exception:
|
|
428
|
+
pass
|
|
429
|
+
time.sleep(interval)
|
|
430
|
+
elapsed += interval
|
|
431
|
+
else:
|
|
432
|
+
print("connect "+sandbox_domain+ENVD_API_HEALTH_ROUTE +" timeout 5s")
|
|
433
|
+
return sanbox
|
|
434
|
+
|
|
435
|
+
def is_running(self, request_timeout: Optional[float] = None) -> bool:
|
|
436
|
+
"""
|
|
437
|
+
Check if the sandbox is running.
|
|
438
|
+
|
|
439
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
440
|
+
|
|
441
|
+
:return: `True` if the sandbox is running, `False` otherwise
|
|
442
|
+
|
|
443
|
+
Example
|
|
444
|
+
```python
|
|
445
|
+
sandbox = Sandbox()
|
|
446
|
+
sandbox.is_running() # Returns True
|
|
447
|
+
|
|
448
|
+
sandbox.kill()
|
|
449
|
+
sandbox.is_running() # Returns False
|
|
450
|
+
```
|
|
451
|
+
"""
|
|
452
|
+
try:
|
|
453
|
+
r = self._envd_api.get(
|
|
454
|
+
ENVD_API_HEALTH_ROUTE,
|
|
455
|
+
timeout=self.connection_config.get_request_timeout(request_timeout),
|
|
456
|
+
)
|
|
457
|
+
print(r)
|
|
458
|
+
if r.status_code == 502:
|
|
459
|
+
return False
|
|
460
|
+
|
|
461
|
+
err = handle_envd_api_exception(r)
|
|
462
|
+
|
|
463
|
+
if err:
|
|
464
|
+
raise err
|
|
465
|
+
|
|
466
|
+
except httpx.TimeoutException:
|
|
467
|
+
raise request_timeout_error()
|
|
468
|
+
|
|
469
|
+
return True
|
|
470
|
+
|
|
471
|
+
@classmethod
|
|
472
|
+
def connect(
|
|
473
|
+
cls,
|
|
474
|
+
sandbox_id: str,
|
|
475
|
+
api_key: Optional[str] = None,
|
|
476
|
+
domain: Optional[str] = None,
|
|
477
|
+
debug: Optional[bool] = None,
|
|
478
|
+
proxy: Optional[ProxyTypes] = None,
|
|
479
|
+
):
|
|
480
|
+
"""
|
|
481
|
+
Connects to an existing Sandbox.
|
|
482
|
+
With sandbox ID you can connect to the same sandbox from different places or environments (serverless functions, etc).
|
|
483
|
+
|
|
484
|
+
:param sandbox_id: Sandbox ID
|
|
485
|
+
:param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
|
|
486
|
+
:param proxy: Proxy to use for the request and for the **requests made to the returned sandbox**
|
|
487
|
+
|
|
488
|
+
:return: sandbox instance for the existing sandbox
|
|
489
|
+
|
|
490
|
+
@example
|
|
491
|
+
```python
|
|
492
|
+
sandbox = Sandbox()
|
|
493
|
+
sandbox_id = sandbox.sandbox_id
|
|
494
|
+
|
|
495
|
+
# Another code block
|
|
496
|
+
same_sandbox = Sandbox.connect(sandbox_id)
|
|
497
|
+
```
|
|
498
|
+
"""
|
|
499
|
+
connection_headers = {"Authorization": "Bearer root"}
|
|
500
|
+
|
|
501
|
+
response = SandboxApi._cls_get_info(
|
|
502
|
+
sandbox_id,
|
|
503
|
+
api_key=api_key,
|
|
504
|
+
domain=domain,
|
|
505
|
+
debug=debug,
|
|
506
|
+
proxy=proxy,
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
if response._envd_access_token is not None and not isinstance(
|
|
510
|
+
response._envd_access_token, Unset
|
|
511
|
+
):
|
|
512
|
+
connection_headers["X-Access-Token"] = response._envd_access_token
|
|
513
|
+
connection_config = ConnectionConfig(
|
|
514
|
+
api_key=api_key,
|
|
515
|
+
domain=domain,
|
|
516
|
+
debug=debug,
|
|
517
|
+
headers=connection_headers,
|
|
518
|
+
proxy=proxy,
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
return cls(
|
|
522
|
+
sandbox_id=sandbox_id,
|
|
523
|
+
sandbox_domain=response.sandbox_domain,
|
|
524
|
+
envd_version=response.envd_version,
|
|
525
|
+
envd_access_token=response._envd_access_token,
|
|
526
|
+
connection_config=connection_config,
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
def __enter__(self):
|
|
530
|
+
return self
|
|
531
|
+
|
|
532
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
533
|
+
self.kill()
|
|
534
|
+
|
|
535
|
+
@overload
|
|
536
|
+
def kill(self, request_timeout: Optional[float] = None) -> bool:
|
|
537
|
+
"""
|
|
538
|
+
Kill the sandbox.
|
|
539
|
+
|
|
540
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
541
|
+
|
|
542
|
+
:return: `True` if the sandbox was killed, `False` if the sandbox was not found
|
|
543
|
+
"""
|
|
544
|
+
...
|
|
545
|
+
|
|
546
|
+
@overload
|
|
547
|
+
@staticmethod
|
|
548
|
+
def kill(
|
|
549
|
+
sandbox_id: str,
|
|
550
|
+
api_key: Optional[str] = None,
|
|
551
|
+
domain: Optional[str] = None,
|
|
552
|
+
debug: Optional[bool] = None,
|
|
553
|
+
request_timeout: Optional[float] = None,
|
|
554
|
+
proxy: Optional[ProxyTypes] = None,
|
|
555
|
+
) -> bool:
|
|
556
|
+
"""
|
|
557
|
+
Kill the sandbox specified by sandbox ID.
|
|
558
|
+
|
|
559
|
+
:param sandbox_id: Sandbox ID
|
|
560
|
+
:param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
|
|
561
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
562
|
+
:param proxy: Proxy to use for the request
|
|
563
|
+
|
|
564
|
+
:return: `True` if the sandbox was killed, `False` if the sandbox was not found
|
|
565
|
+
"""
|
|
566
|
+
...
|
|
567
|
+
|
|
568
|
+
@class_method_variant("_cls_kill")
|
|
569
|
+
def kill(self, request_timeout: Optional[float] = None) -> bool: # type: ignore
|
|
570
|
+
"""
|
|
571
|
+
Kill the sandbox.
|
|
572
|
+
|
|
573
|
+
:param request_timeout: Timeout for the request
|
|
574
|
+
:return: `True` if the sandbox was killed, `False` if the sandbox was not found
|
|
575
|
+
"""
|
|
576
|
+
config_dict = self.connection_config.__dict__
|
|
577
|
+
config_dict.pop("access_token", None)
|
|
578
|
+
config_dict.pop("api_url", None)
|
|
579
|
+
|
|
580
|
+
if request_timeout:
|
|
581
|
+
config_dict["request_timeout"] = request_timeout
|
|
582
|
+
|
|
583
|
+
SandboxApi._cls_kill(
|
|
584
|
+
sandbox_id=self.sandbox_id,
|
|
585
|
+
**config_dict,
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
@overload
|
|
589
|
+
def set_timeout(
|
|
590
|
+
self,
|
|
591
|
+
timeout: int,
|
|
592
|
+
request_timeout: Optional[float] = None,
|
|
593
|
+
) -> None:
|
|
594
|
+
"""
|
|
595
|
+
Set the timeout of the sandbox.
|
|
596
|
+
After the timeout expires the sandbox will be automatically killed.
|
|
597
|
+
This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
|
|
598
|
+
|
|
599
|
+
Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
|
|
600
|
+
|
|
601
|
+
:param timeout: Timeout for the sandbox in **seconds**
|
|
602
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
603
|
+
"""
|
|
604
|
+
...
|
|
605
|
+
|
|
606
|
+
@overload
|
|
607
|
+
@staticmethod
|
|
608
|
+
def set_timeout(
|
|
609
|
+
sandbox_id: str,
|
|
610
|
+
timeout: int,
|
|
611
|
+
api_key: Optional[str] = None,
|
|
612
|
+
domain: Optional[str] = None,
|
|
613
|
+
debug: Optional[bool] = None,
|
|
614
|
+
request_timeout: Optional[float] = None,
|
|
615
|
+
proxy: Optional[ProxyTypes] = None,
|
|
616
|
+
) -> None:
|
|
617
|
+
"""
|
|
618
|
+
Set the timeout of the sandbox specified by sandbox ID.
|
|
619
|
+
After the timeout expires the sandbox will be automatically killed.
|
|
620
|
+
This method can extend or reduce the sandbox timeout set when creating the sandbox or from the last call to `.set_timeout`.
|
|
621
|
+
|
|
622
|
+
Maximum time a sandbox can be kept alive is 24 hours (86_400 seconds) for Pro users and 1 hour (3_600 seconds) for Hobby users.
|
|
623
|
+
|
|
624
|
+
:param sandbox_id: Sandbox ID
|
|
625
|
+
:param timeout: Timeout for the sandbox in **seconds**
|
|
626
|
+
:param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
|
|
627
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
628
|
+
:param proxy: Proxy to use for the request
|
|
629
|
+
"""
|
|
630
|
+
...
|
|
631
|
+
|
|
632
|
+
@class_method_variant("_cls_set_timeout")
|
|
633
|
+
def set_timeout( # type: ignore
|
|
634
|
+
self,
|
|
635
|
+
timeout: int,
|
|
636
|
+
request_timeout: Optional[float] = None,
|
|
637
|
+
) -> None:
|
|
638
|
+
config_dict = self.connection_config.__dict__
|
|
639
|
+
config_dict.pop("access_token", None)
|
|
640
|
+
config_dict.pop("api_url", None)
|
|
641
|
+
|
|
642
|
+
if request_timeout:
|
|
643
|
+
config_dict["request_timeout"] = request_timeout
|
|
644
|
+
|
|
645
|
+
SandboxApi._cls_set_timeout(
|
|
646
|
+
sandbox_id=self.sandbox_id,
|
|
647
|
+
timeout=timeout,
|
|
648
|
+
**config_dict,
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
@overload
|
|
652
|
+
def get_info(
|
|
653
|
+
self,
|
|
654
|
+
request_timeout: Optional[float] = None,
|
|
655
|
+
) -> SandboxInfo:
|
|
656
|
+
"""
|
|
657
|
+
Get sandbox information like sandbox ID, template, metadata, started at/end at date.
|
|
658
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
659
|
+
:return: Sandbox info
|
|
660
|
+
"""
|
|
661
|
+
...
|
|
662
|
+
|
|
663
|
+
@overload
|
|
664
|
+
@staticmethod
|
|
665
|
+
def get_info(
|
|
666
|
+
sandbox_id: str,
|
|
667
|
+
api_key: Optional[str] = None,
|
|
668
|
+
domain: Optional[str] = None,
|
|
669
|
+
debug: Optional[bool] = None,
|
|
670
|
+
request_timeout: Optional[float] = None,
|
|
671
|
+
headers: Optional[Dict[str, str]] = None,
|
|
672
|
+
proxy: Optional[ProxyTypes] = None,
|
|
673
|
+
) -> SandboxInfo:
|
|
674
|
+
"""
|
|
675
|
+
Get sandbox information like sandbox ID, template, metadata, started at/end at date.
|
|
676
|
+
:param sandbox_id: Sandbox ID
|
|
677
|
+
:param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
|
|
678
|
+
:param domain: E2B domain to use for authentication, defaults to `E2B_DOMAIN` environment variable
|
|
679
|
+
:param debug: Whether to use debug mode, defaults to `E2B_DEBUG` environment variable
|
|
680
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
681
|
+
:param headers: Custom headers to use for the request
|
|
682
|
+
:param proxy: Proxy to use for the request
|
|
683
|
+
:return: Sandbox info
|
|
684
|
+
"""
|
|
685
|
+
...
|
|
686
|
+
|
|
687
|
+
@class_method_variant("_cls_get_info")
|
|
688
|
+
def get_info( # type: ignore
|
|
689
|
+
self,
|
|
690
|
+
request_timeout: Optional[float] = None,
|
|
691
|
+
) -> SandboxInfo:
|
|
692
|
+
"""
|
|
693
|
+
Get sandbox information like sandbox ID, template, metadata, started at/end at date.
|
|
694
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
695
|
+
:return: Sandbox info
|
|
696
|
+
"""
|
|
697
|
+
config_dict = self.connection_config.__dict__
|
|
698
|
+
config_dict.pop("access_token", None)
|
|
699
|
+
config_dict.pop("api_url", None)
|
|
700
|
+
|
|
701
|
+
if request_timeout:
|
|
702
|
+
config_dict["request_timeout"] = request_timeout
|
|
703
|
+
|
|
704
|
+
return SandboxApi._cls_get_info(
|
|
705
|
+
sandbox_id=self.sandbox_id,
|
|
706
|
+
**config_dict,
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
@overload
|
|
710
|
+
def get_metrics( # type: ignore
|
|
711
|
+
self,
|
|
712
|
+
start: Optional[datetime.datetime] = None,
|
|
713
|
+
end: Optional[datetime.datetime] = None,
|
|
714
|
+
request_timeout: Optional[float] = None,
|
|
715
|
+
) -> List[SandboxMetrics]:
|
|
716
|
+
"""
|
|
717
|
+
Get the metrics of the current sandbox.
|
|
718
|
+
|
|
719
|
+
:param start: Start time for the metrics, defaults to the start of the sandbox
|
|
720
|
+
:param end: End time for the metrics, defaults to current time
|
|
721
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
722
|
+
|
|
723
|
+
:return: List of sandbox metrics containing CPU, memory and disk usage information
|
|
724
|
+
"""
|
|
725
|
+
...
|
|
726
|
+
|
|
727
|
+
@overload
|
|
728
|
+
@staticmethod
|
|
729
|
+
def get_metrics(
|
|
730
|
+
sandbox_id: str,
|
|
731
|
+
start: Optional[datetime.datetime] = None,
|
|
732
|
+
end: Optional[datetime.datetime] = None,
|
|
733
|
+
api_key: Optional[str] = None,
|
|
734
|
+
domain: Optional[str] = None,
|
|
735
|
+
debug: Optional[bool] = None,
|
|
736
|
+
request_timeout: Optional[float] = None,
|
|
737
|
+
) -> List[SandboxMetrics]:
|
|
738
|
+
"""
|
|
739
|
+
Get the metrics of the sandbox specified by sandbox ID.
|
|
740
|
+
|
|
741
|
+
:param sandbox_id: Sandbox ID
|
|
742
|
+
:param start: Start time for the metrics, defaults to the start of the sandbox
|
|
743
|
+
:param end: End time for the metrics, defaults to current time
|
|
744
|
+
:param api_key: E2B API Key to use for authentication, defaults to `E2B_API_KEY` environment variable
|
|
745
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
746
|
+
|
|
747
|
+
:return: List of sandbox metrics containing CPU, memory and disk usage information
|
|
748
|
+
"""
|
|
749
|
+
...
|
|
750
|
+
|
|
751
|
+
@class_method_variant("_cls_get_metrics")
|
|
752
|
+
def get_metrics( # type: ignore
|
|
753
|
+
self,
|
|
754
|
+
start: Optional[datetime.datetime] = None,
|
|
755
|
+
end: Optional[datetime.datetime] = None,
|
|
756
|
+
request_timeout: Optional[float] = None,
|
|
757
|
+
) -> List[SandboxMetrics]:
|
|
758
|
+
"""
|
|
759
|
+
Get the metrics of the current sandbox.
|
|
760
|
+
|
|
761
|
+
:param start: Start time for the metrics, defaults to the start of the sandbox
|
|
762
|
+
:param end: End time for the metrics, defaults to current time
|
|
763
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
764
|
+
|
|
765
|
+
:return: List of sandbox metrics containing CPU, memory and disk usage information
|
|
766
|
+
"""
|
|
767
|
+
if self._envd_version:
|
|
768
|
+
if Version(self._envd_version) < Version("0.1.5"):
|
|
769
|
+
raise SandboxException(
|
|
770
|
+
"Metrics are not supported in this version of the sandbox, please rebuild your template."
|
|
771
|
+
)
|
|
772
|
+
|
|
773
|
+
if Version(self._envd_version) < Version("0.2.4"):
|
|
774
|
+
logger.warning(
|
|
775
|
+
"Disk metrics are not supported in this version of the sandbox, please rebuild the template to get disk metrics."
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
config_dict = self.connection_config.__dict__
|
|
779
|
+
config_dict.pop("access_token", None)
|
|
780
|
+
config_dict.pop("api_url", None)
|
|
781
|
+
if request_timeout:
|
|
782
|
+
config_dict["request_timeout"] = request_timeout
|
|
783
|
+
|
|
784
|
+
return self._cls_get_metrics(
|
|
785
|
+
sandbox_id=self.sandbox_id,
|
|
786
|
+
start=start,
|
|
787
|
+
end=end,
|
|
788
|
+
**config_dict,
|
|
789
|
+
)
|