skypilot-nightly 1.0.0.dev20250903__py3-none-any.whl → 1.0.0.dev20250905__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.
Files changed (74) hide show
  1. sky/__init__.py +2 -2
  2. sky/backends/cloud_vm_ray_backend.py +18 -2
  3. sky/client/cli/command.py +18 -1
  4. sky/client/sdk.py +42 -17
  5. sky/clouds/nebius.py +4 -2
  6. sky/dashboard/out/404.html +1 -1
  7. sky/dashboard/out/_next/static/chunks/{1121-ec35954c8cbea535.js → 1121-408ed10b2f9fce17.js} +1 -1
  8. sky/dashboard/out/_next/static/chunks/{7205-88191679e7988c57.js → 1836-37fede578e2da5f8.js} +4 -9
  9. sky/dashboard/out/_next/static/chunks/3015-86cabed5d4669ad0.js +1 -0
  10. sky/dashboard/out/_next/static/chunks/3294.c80326aec9bfed40.js +6 -0
  11. sky/dashboard/out/_next/static/chunks/{3785.d5b86f6ebc88e6e6.js → 3785.4872a2f3aa489880.js} +1 -1
  12. sky/dashboard/out/_next/static/chunks/{4783.c485f48348349f47.js → 5339.3fda4a4010ff4e06.js} +4 -9
  13. sky/dashboard/out/_next/static/chunks/{9946.3b7b43c217ff70ec.js → 649.b9d7f7d10c1b8c53.js} +4 -9
  14. sky/dashboard/out/_next/static/chunks/6856-dca7962af4814e1b.js +1 -0
  15. sky/dashboard/out/_next/static/chunks/{8969-4a6f1a928fb6d370.js → 8969-0be3036bf86f8256.js} +1 -1
  16. sky/dashboard/out/_next/static/chunks/9025.c12318fb6a1a9093.js +6 -0
  17. sky/dashboard/out/_next/static/chunks/{9037-89a84fd7fa31362d.js → 9037-fa1737818d0a0969.js} +2 -2
  18. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-1cbba24bd1bd35f8.js +16 -0
  19. sky/dashboard/out/_next/static/chunks/pages/clusters/{[cluster]-a0527109c2fab467.js → [cluster]-0b4b35dc1dfe046c.js} +2 -7
  20. sky/dashboard/out/_next/static/chunks/pages/infra/{[context]-81351f95f3bec08e.js → [context]-6563820e094f68ca.js} +1 -1
  21. sky/dashboard/out/_next/static/chunks/pages/{infra-c320641c2bcbbea6.js → infra-aabba60d57826e0f.js} +1 -1
  22. sky/dashboard/out/_next/static/chunks/pages/jobs-1f70d9faa564804f.js +1 -0
  23. sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-de06e613e20bc977.js → [name]-af76bb06dbb3954f.js} +1 -1
  24. sky/dashboard/out/_next/static/chunks/pages/{workspaces-be35b22e2046564c.js → workspaces-7598c33a746cdc91.js} +1 -1
  25. sky/dashboard/out/_next/static/chunks/webpack-4fe903277b57b523.js +1 -0
  26. sky/dashboard/out/_next/static/mS-4qZPSkRuA1u-g2wQhg/_buildManifest.js +1 -0
  27. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  28. sky/dashboard/out/clusters/[cluster].html +1 -1
  29. sky/dashboard/out/clusters.html +1 -1
  30. sky/dashboard/out/config.html +1 -1
  31. sky/dashboard/out/index.html +1 -1
  32. sky/dashboard/out/infra/[context].html +1 -1
  33. sky/dashboard/out/infra.html +1 -1
  34. sky/dashboard/out/jobs/[job].html +1 -1
  35. sky/dashboard/out/jobs/pools/[pool].html +1 -1
  36. sky/dashboard/out/jobs.html +1 -1
  37. sky/dashboard/out/users.html +1 -1
  38. sky/dashboard/out/volumes.html +1 -1
  39. sky/dashboard/out/workspace/new.html +1 -1
  40. sky/dashboard/out/workspaces/[name].html +1 -1
  41. sky/dashboard/out/workspaces.html +1 -1
  42. sky/data/mounting_utils.py +29 -38
  43. sky/global_user_state.py +17 -5
  44. sky/jobs/state.py +1 -1
  45. sky/models.py +24 -1
  46. sky/provision/kubernetes/instance.py +10 -3
  47. sky/serve/serve_state.py +1 -1
  48. sky/server/config.py +31 -3
  49. sky/server/requests/executor.py +9 -3
  50. sky/server/requests/requests.py +24 -14
  51. sky/server/server.py +24 -21
  52. sky/server/uvicorn.py +9 -3
  53. sky/skylet/constants.py +1 -1
  54. sky/skypilot_config.py +21 -9
  55. sky/ssh_node_pools/server.py +5 -5
  56. sky/users/permission.py +6 -0
  57. sky/users/server.py +26 -17
  58. sky/utils/db/db_utils.py +61 -1
  59. sky/utils/db/migration_utils.py +0 -32
  60. {skypilot_nightly-1.0.0.dev20250903.dist-info → skypilot_nightly-1.0.0.dev20250905.dist-info}/METADATA +35 -35
  61. {skypilot_nightly-1.0.0.dev20250903.dist-info → skypilot_nightly-1.0.0.dev20250905.dist-info}/RECORD +66 -66
  62. sky/dashboard/out/_next/static/chunks/3015-8089ed1e0b7e37fd.js +0 -1
  63. sky/dashboard/out/_next/static/chunks/6856-049014c6d43d127b.js +0 -1
  64. sky/dashboard/out/_next/static/chunks/9025.a1bef12d672bb66d.js +0 -6
  65. sky/dashboard/out/_next/static/chunks/9984.7eb6cc51fb460cae.js +0 -6
  66. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-b77360a343d48902.js +0 -16
  67. sky/dashboard/out/_next/static/chunks/pages/jobs-7421e63ac35f8fce.js +0 -1
  68. sky/dashboard/out/_next/static/chunks/webpack-60556df644cd5d71.js +0 -1
  69. sky/dashboard/out/_next/static/yLz6EPhW_XXmnNs1I6dmS/_buildManifest.js +0 -1
  70. /sky/dashboard/out/_next/static/{yLz6EPhW_XXmnNs1I6dmS → mS-4qZPSkRuA1u-g2wQhg}/_ssgManifest.js +0 -0
  71. {skypilot_nightly-1.0.0.dev20250903.dist-info → skypilot_nightly-1.0.0.dev20250905.dist-info}/WHEEL +0 -0
  72. {skypilot_nightly-1.0.0.dev20250903.dist-info → skypilot_nightly-1.0.0.dev20250905.dist-info}/entry_points.txt +0 -0
  73. {skypilot_nightly-1.0.0.dev20250903.dist-info → skypilot_nightly-1.0.0.dev20250905.dist-info}/licenses/LICENSE +0 -0
  74. {skypilot_nightly-1.0.0.dev20250903.dist-info → skypilot_nightly-1.0.0.dev20250905.dist-info}/top_level.txt +0 -0
sky/users/server.py CHANGED
@@ -33,28 +33,38 @@ USER_LOCK_TIMEOUT_SECONDS = 20
33
33
  router = fastapi.APIRouter()
34
34
 
35
35
 
36
+ # All handlers in user handler are sync to get fastAPI run it in a
37
+ # ThreadPoolExecutor to avoid blocking the async event loop.
38
+ # TODO(aylei): make these async once we have the global_user_state async
39
+ # support.
36
40
  @router.get('')
37
- async def users() -> List[Dict[str, Any]]:
41
+ def users() -> List[Dict[str, Any]]:
38
42
  """Gets all users."""
39
43
  all_users = []
40
44
  user_list = global_user_state.get_all_users()
45
+
46
+ users_to_role = {}
47
+ for role in rbac.get_supported_roles():
48
+ user_ids = permission.permission_service.get_users_for_role(role)
49
+ for user_id in user_ids:
50
+ users_to_role[user_id] = role
51
+
41
52
  for user in user_list:
42
53
  # Filter out service accounts - they have IDs starting with "sa-"
43
54
  if user.is_service_account():
44
55
  continue
45
56
 
46
- user_roles = permission.permission_service.get_user_roles(user.id)
47
57
  all_users.append({
48
58
  'id': user.id,
49
59
  'name': user.name,
50
60
  'created_at': user.created_at,
51
- 'role': user_roles[0] if user_roles else ''
61
+ 'role': users_to_role.get(user.id, '')
52
62
  })
53
63
  return all_users
54
64
 
55
65
 
56
66
  @router.get('/role')
57
- async def get_current_user_role(request: fastapi.Request):
67
+ def get_current_user_role(request: fastapi.Request):
58
68
  """Get current user's role."""
59
69
  # TODO(hailong): is there a reliable way to get the user
60
70
  # hash for the request without 'X-Auth-Request-Email' header?
@@ -70,7 +80,7 @@ async def get_current_user_role(request: fastapi.Request):
70
80
 
71
81
 
72
82
  @router.post('/create')
73
- async def user_create(user_create_body: payloads.UserCreateBody) -> None:
83
+ def user_create(user_create_body: payloads.UserCreateBody) -> None:
74
84
  username = user_create_body.username
75
85
  password = user_create_body.password
76
86
  role = user_create_body.role
@@ -100,8 +110,8 @@ async def user_create(user_create_body: payloads.UserCreateBody) -> None:
100
110
 
101
111
 
102
112
  @router.post('/update')
103
- async def user_update(request: fastapi.Request,
104
- user_update_body: payloads.UserUpdateBody) -> None:
113
+ def user_update(request: fastapi.Request,
114
+ user_update_body: payloads.UserUpdateBody) -> None:
105
115
  """Updates the user role."""
106
116
  user_id = user_update_body.user_id
107
117
  role = user_update_body.role
@@ -181,14 +191,13 @@ def _delete_user(user_id: str) -> None:
181
191
 
182
192
 
183
193
  @router.post('/delete')
184
- async def user_delete(user_delete_body: payloads.UserDeleteBody) -> None:
194
+ def user_delete(user_delete_body: payloads.UserDeleteBody) -> None:
185
195
  user_id = user_delete_body.user_id
186
196
  _delete_user(user_id)
187
197
 
188
198
 
189
199
  @router.post('/import')
190
- async def user_import(
191
- user_import_body: payloads.UserImportBody) -> Dict[str, Any]:
200
+ def user_import(user_import_body: payloads.UserImportBody) -> Dict[str, Any]:
192
201
  """Import users from CSV content."""
193
202
  csv_content = user_import_body.csv_content
194
203
 
@@ -305,7 +314,7 @@ async def user_import(
305
314
 
306
315
 
307
316
  @router.get('/export')
308
- async def user_export() -> Dict[str, Any]:
317
+ def user_export() -> Dict[str, Any]:
309
318
  """Export all users as CSV content."""
310
319
  try:
311
320
  # Get all users
@@ -369,7 +378,7 @@ def _user_lock(user_id: str) -> Generator[None, None, None]:
369
378
 
370
379
 
371
380
  @router.get('/service-account-tokens')
372
- async def get_service_account_tokens(
381
+ def get_service_account_tokens(
373
382
  request: fastapi.Request) -> List[Dict[str, Any]]:
374
383
  """Get service account tokens. All users can see all tokens."""
375
384
  auth_user = request.state.auth_user
@@ -420,7 +429,7 @@ def _generate_service_account_user_id() -> str:
420
429
 
421
430
 
422
431
  @router.post('/service-account-tokens')
423
- async def create_service_account_token(
432
+ def create_service_account_token(
424
433
  request: fastapi.Request,
425
434
  token_body: payloads.ServiceAccountTokenCreateBody) -> Dict[str, Any]:
426
435
  """Create a new service account token."""
@@ -508,7 +517,7 @@ async def create_service_account_token(
508
517
 
509
518
 
510
519
  @router.post('/service-account-tokens/delete')
511
- async def delete_service_account_token(
520
+ def delete_service_account_token(
512
521
  request: fastapi.Request,
513
522
  token_body: payloads.ServiceAccountTokenDeleteBody) -> Dict[str, str]:
514
523
  """Delete a service account token.
@@ -549,7 +558,7 @@ async def delete_service_account_token(
549
558
 
550
559
 
551
560
  @router.post('/service-account-tokens/get-role')
552
- async def get_service_account_role(
561
+ def get_service_account_role(
553
562
  request: fastapi.Request,
554
563
  role_body: payloads.ServiceAccountTokenRoleBody) -> Dict[str, Any]:
555
564
  """Get the role of a service account."""
@@ -585,7 +594,7 @@ async def get_service_account_role(
585
594
 
586
595
 
587
596
  @router.post('/service-account-tokens/update-role')
588
- async def update_service_account_role(
597
+ def update_service_account_role(
589
598
  request: fastapi.Request,
590
599
  role_body: payloads.ServiceAccountTokenUpdateRoleBody
591
600
  ) -> Dict[str, str]:
@@ -628,7 +637,7 @@ async def update_service_account_role(
628
637
 
629
638
 
630
639
  @router.post('/service-account-tokens/rotate')
631
- async def rotate_service_account_token(
640
+ def rotate_service_account_token(
632
641
  request: fastapi.Request,
633
642
  token_body: payloads.ServiceAccountTokenRotateBody) -> Dict[str, Any]:
634
643
  """Rotate a service account token.
sky/utils/db/db_utils.py CHANGED
@@ -2,10 +2,12 @@
2
2
  import asyncio
3
3
  import contextlib
4
4
  import enum
5
+ import os
6
+ import pathlib
5
7
  import sqlite3
6
8
  import threading
7
9
  import typing
8
- from typing import Any, Callable, Iterable, Optional
10
+ from typing import Any, Callable, Dict, Iterable, Optional
9
11
 
10
12
  import aiosqlite
11
13
  import aiosqlite.context
@@ -13,6 +15,7 @@ import sqlalchemy
13
15
  from sqlalchemy import exc as sqlalchemy_exc
14
16
 
15
17
  from sky import sky_logging
18
+ from sky.skylet import constants
16
19
 
17
20
  logger = sky_logging.init_logger(__name__)
18
21
  if typing.TYPE_CHECKING:
@@ -331,6 +334,9 @@ class SQLiteConn(threading.local):
331
334
  """Execute the sql and commit the transaction in a sync block."""
332
335
  conn = await self._get_async_conn()
333
336
 
337
+ if parameters is None:
338
+ parameters = []
339
+
334
340
  def exec_and_commit(sql: str, parameters: Optional[Iterable[Any]]):
335
341
  # pylint: disable=protected-access
336
342
  conn._conn.execute(sql, parameters)
@@ -346,3 +352,57 @@ class SQLiteConn(threading.local):
346
352
  ) -> Iterable[sqlite3.Row]:
347
353
  conn = await self._get_async_conn()
348
354
  return await conn.execute_fetchall(sql, parameters)
355
+
356
+ async def close(self):
357
+ if self._async_conn is not None:
358
+ await self._async_conn.close()
359
+ self.conn.close()
360
+
361
+
362
+ _max_connections = 0
363
+ _postgres_engine_cache: Dict[str, sqlalchemy.engine.Engine] = {}
364
+ _sqlite_engine_cache: Dict[str, sqlalchemy.engine.Engine] = {}
365
+
366
+ _db_creation_lock = threading.Lock()
367
+
368
+
369
+ def set_max_connections(max_connections: int):
370
+ global _max_connections
371
+ _max_connections = max_connections
372
+
373
+
374
+ def get_max_connections():
375
+ return _max_connections
376
+
377
+
378
+ def get_engine(db_name: str):
379
+ conn_string = None
380
+ if os.environ.get(constants.ENV_VAR_IS_SKYPILOT_SERVER) is not None:
381
+ conn_string = os.environ.get(constants.ENV_VAR_DB_CONNECTION_URI)
382
+ if conn_string:
383
+ with _db_creation_lock:
384
+ if conn_string not in _postgres_engine_cache:
385
+ if _max_connections == 0:
386
+ _postgres_engine_cache[conn_string] = (
387
+ sqlalchemy.create_engine(
388
+ conn_string, poolclass=sqlalchemy.pool.NullPool))
389
+ elif _max_connections == 1:
390
+ _postgres_engine_cache[conn_string] = (
391
+ sqlalchemy.create_engine(
392
+ conn_string, poolclass=sqlalchemy.pool.StaticPool))
393
+ else:
394
+ _postgres_engine_cache[conn_string] = (
395
+ sqlalchemy.create_engine(
396
+ conn_string,
397
+ poolclass=sqlalchemy.pool.QueuePool,
398
+ size=_max_connections,
399
+ max_overflow=0))
400
+ engine = _postgres_engine_cache[conn_string]
401
+ else:
402
+ db_path = os.path.expanduser(f'~/.sky/{db_name}.db')
403
+ pathlib.Path(db_path).parents[0].mkdir(parents=True, exist_ok=True)
404
+ if db_path not in _sqlite_engine_cache:
405
+ _sqlite_engine_cache[db_path] = sqlalchemy.create_engine(
406
+ 'sqlite:///' + db_path)
407
+ engine = _sqlite_engine_cache[db_path]
408
+ return engine
@@ -3,9 +3,6 @@
3
3
  import contextlib
4
4
  import logging
5
5
  import os
6
- import pathlib
7
- import threading
8
- from typing import Dict, Optional
9
6
 
10
7
  from alembic import command as alembic_command
11
8
  from alembic.config import Config
@@ -14,7 +11,6 @@ import filelock
14
11
  import sqlalchemy
15
12
 
16
13
  from sky import sky_logging
17
- from sky.skylet import constants
18
14
 
19
15
  logger = sky_logging.init_logger(__name__)
20
16
 
@@ -32,34 +28,6 @@ SERVE_DB_NAME = 'serve_db'
32
28
  SERVE_VERSION = '001'
33
29
  SERVE_LOCK_PATH = '~/.sky/locks/.serve_db.lock'
34
30
 
35
- _postgres_engine_cache: Dict[str, sqlalchemy.engine.Engine] = {}
36
- _sqlite_engine_cache: Dict[str, sqlalchemy.engine.Engine] = {}
37
-
38
- _db_creation_lock = threading.Lock()
39
-
40
-
41
- def get_engine(db_name: str,
42
- pg_pool_class: Optional[sqlalchemy.pool.Pool] = None):
43
- conn_string = None
44
- if os.environ.get(constants.ENV_VAR_IS_SKYPILOT_SERVER) is not None:
45
- conn_string = os.environ.get(constants.ENV_VAR_DB_CONNECTION_URI)
46
- if conn_string:
47
- if pg_pool_class is None:
48
- pg_pool_class = sqlalchemy.NullPool
49
- with _db_creation_lock:
50
- if conn_string not in _postgres_engine_cache:
51
- _postgres_engine_cache[conn_string] = sqlalchemy.create_engine(
52
- conn_string, poolclass=pg_pool_class)
53
- engine = _postgres_engine_cache[conn_string]
54
- else:
55
- db_path = os.path.expanduser(f'~/.sky/{db_name}.db')
56
- pathlib.Path(db_path).parents[0].mkdir(parents=True, exist_ok=True)
57
- if db_path not in _sqlite_engine_cache:
58
- _sqlite_engine_cache[db_path] = sqlalchemy.create_engine(
59
- 'sqlite:///' + db_path)
60
- engine = _sqlite_engine_cache[db_path]
61
- return engine
62
-
63
31
 
64
32
  @contextlib.contextmanager
65
33
  def db_lock(db_name: str):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skypilot-nightly
3
- Version: 1.0.0.dev20250903
3
+ Version: 1.0.0.dev20250905
4
4
  Summary: SkyPilot: Run AI on Any Infra — Unified, Faster, Cheaper.
5
5
  Author: SkyPilot Team
6
6
  License: Apache 2.0
@@ -145,48 +145,48 @@ Requires-Dist: grpcio>=1.63.0; extra == "server"
145
145
  Requires-Dist: protobuf<7.0.0,>=5.26.1; extra == "server"
146
146
  Requires-Dist: aiosqlite; extra == "server"
147
147
  Provides-Extra: all
148
- Requires-Dist: ibm-cos-sdk; extra == "all"
149
- Requires-Dist: ray[default]!=2.6.0,>=2.2.0; extra == "all"
150
- Requires-Dist: vastai-sdk>=0.1.12; extra == "all"
151
- Requires-Dist: aiohttp; extra == "all"
152
- Requires-Dist: google-cloud-storage; extra == "all"
153
- Requires-Dist: websockets; extra == "all"
154
- Requires-Dist: azure-mgmt-compute>=33.0.0; extra == "all"
155
148
  Requires-Dist: kubernetes!=32.0.0,>=20.0.0; extra == "all"
156
- Requires-Dist: msgraph-sdk; extra == "all"
157
149
  Requires-Dist: azure-storage-blob>=12.23.1; extra == "all"
158
- Requires-Dist: anyio; extra == "all"
159
- Requires-Dist: boto3>=1.26.1; extra == "all"
150
+ Requires-Dist: grpcio>=1.63.0; extra == "all"
160
151
  Requires-Dist: google-api-python-client>=2.69.0; extra == "all"
152
+ Requires-Dist: colorama<0.4.5; extra == "all"
153
+ Requires-Dist: azure-mgmt-network>=27.0.0; extra == "all"
154
+ Requires-Dist: sqlalchemy_adapter; extra == "all"
155
+ Requires-Dist: aiosqlite; extra == "all"
156
+ Requires-Dist: ibm-cos-sdk; extra == "all"
161
157
  Requires-Dist: pyopenssl<24.3.0,>=23.2.0; extra == "all"
158
+ Requires-Dist: websockets; extra == "all"
159
+ Requires-Dist: awscli>=1.27.10; extra == "all"
160
+ Requires-Dist: boto3>=1.26.1; extra == "all"
161
+ Requires-Dist: pydo>=0.3.0; extra == "all"
162
+ Requires-Dist: google-cloud-storage; extra == "all"
162
163
  Requires-Dist: cudo-compute>=0.1.10; extra == "all"
163
- Requires-Dist: azure-mgmt-network>=27.0.0; extra == "all"
164
+ Requires-Dist: azure-core>=1.24.0; extra == "all"
164
165
  Requires-Dist: pyvmomi==8.0.1.0.2; extra == "all"
166
+ Requires-Dist: casbin; extra == "all"
167
+ Requires-Dist: docker; extra == "all"
165
168
  Requires-Dist: passlib; extra == "all"
169
+ Requires-Dist: ibm-vpc; extra == "all"
170
+ Requires-Dist: oci; extra == "all"
171
+ Requires-Dist: azure-cli>=2.65.0; extra == "all"
172
+ Requires-Dist: nebius>=0.2.47; extra == "all"
173
+ Requires-Dist: azure-core>=1.31.0; extra == "all"
174
+ Requires-Dist: azure-mgmt-compute>=33.0.0; extra == "all"
166
175
  Requires-Dist: azure-identity>=1.19.0; extra == "all"
167
176
  Requires-Dist: botocore>=1.29.10; extra == "all"
168
- Requires-Dist: awscli>=1.27.10; extra == "all"
169
177
  Requires-Dist: python-dateutil; extra == "all"
170
- Requires-Dist: pyjwt; extra == "all"
171
- Requires-Dist: oci; extra == "all"
172
178
  Requires-Dist: ibm-cloud-sdk-core; extra == "all"
173
- Requires-Dist: azure-cli>=2.65.0; extra == "all"
174
- Requires-Dist: aiosqlite; extra == "all"
175
- Requires-Dist: pydo>=0.3.0; extra == "all"
176
- Requires-Dist: docker; extra == "all"
177
- Requires-Dist: azure-common; extra == "all"
178
- Requires-Dist: colorama<0.4.5; extra == "all"
179
- Requires-Dist: msrestazure; extra == "all"
180
- Requires-Dist: ibm-vpc; extra == "all"
181
- Requires-Dist: ibm-platform-services>=0.48.0; extra == "all"
182
- Requires-Dist: azure-core>=1.24.0; extra == "all"
183
- Requires-Dist: sqlalchemy_adapter; extra == "all"
184
- Requires-Dist: azure-core>=1.31.0; extra == "all"
185
- Requires-Dist: nebius>=0.2.47; extra == "all"
186
- Requires-Dist: casbin; extra == "all"
179
+ Requires-Dist: ray[default]!=2.6.0,>=2.2.0; extra == "all"
187
180
  Requires-Dist: protobuf<7.0.0,>=5.26.1; extra == "all"
188
- Requires-Dist: grpcio>=1.63.0; extra == "all"
181
+ Requires-Dist: ibm-platform-services>=0.48.0; extra == "all"
182
+ Requires-Dist: msgraph-sdk; extra == "all"
183
+ Requires-Dist: msrestazure; extra == "all"
184
+ Requires-Dist: pyjwt; extra == "all"
185
+ Requires-Dist: aiohttp; extra == "all"
189
186
  Requires-Dist: runpod>=1.6.1; extra == "all"
187
+ Requires-Dist: azure-common; extra == "all"
188
+ Requires-Dist: vastai-sdk>=0.1.12; extra == "all"
189
+ Requires-Dist: anyio; extra == "all"
190
190
  Dynamic: author
191
191
  Dynamic: classifier
192
192
  Dynamic: description
@@ -284,21 +284,21 @@ SkyPilot supports your existing GPU, TPU, and CPU workloads, with no code change
284
284
  Install with pip:
285
285
  ```bash
286
286
  # Choose your clouds:
287
- pip install -U "skypilot[kubernetes,aws,gcp,azure,oci,lambda,runpod,fluidstack,paperspace,cudo,ibm,scp,nebius]"
287
+ pip install -U "skypilot[kubernetes,aws,gcp,azure,oci,nebius,lambda,runpod,fluidstack,paperspace,cudo,ibm,scp]"
288
288
  ```
289
289
  To get the latest features and fixes, use the nightly build or [install from source](https://docs.skypilot.co/en/latest/getting-started/installation.html):
290
290
  ```bash
291
291
  # Choose your clouds:
292
- pip install "skypilot-nightly[kubernetes,aws,gcp,azure,oci,lambda,runpod,fluidstack,paperspace,cudo,ibm,scp,nebius]"
292
+ pip install "skypilot-nightly[kubernetes,aws,gcp,azure,oci,nebius,lambda,runpod,fluidstack,paperspace,cudo,ibm,scp]"
293
293
  ```
294
294
 
295
295
  <p align="center">
296
296
  <img src="docs/source/_static/intro.gif" alt="SkyPilot">
297
297
  </p>
298
298
 
299
- Current supported infra: Kubernetes, AWS, GCP, Azure, OCI, Lambda Cloud, Fluidstack,
300
- RunPod, Cudo, Digital Ocean, Paperspace, Cloudflare, Samsung, IBM, Vast.ai,
301
- VMware vSphere, Nebius.
299
+ Current supported infra: Kubernetes, AWS, GCP, Azure, OCI, Nebius, Lambda Cloud, RunPod, Fluidstack,
300
+ Cudo, Digital Ocean, Paperspace, Cloudflare, Samsung, IBM, Vast.ai,
301
+ VMware vSphere.
302
302
  <p align="center">
303
303
  <img alt="SkyPilot" src="https://raw.githubusercontent.com/skypilot-org/skypilot/master/docs/source/images/cloud-logos-light.png" width=85%>
304
304
  </p>