skypilot-nightly 1.0.0.dev20250826__py3-none-any.whl → 1.0.0.dev20250827__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.
Potentially problematic release.
This version of skypilot-nightly might be problematic. Click here for more details.
- sky/__init__.py +2 -2
- sky/authentication.py +3 -9
- sky/backends/backend_utils.py +30 -43
- sky/backends/cloud_vm_ray_backend.py +2 -2
- sky/client/cli/command.py +2 -1
- sky/client/common.py +41 -14
- sky/client/sdk.py +1 -1
- sky/clouds/aws.py +1 -1
- sky/clouds/cloud.py +15 -0
- sky/clouds/kubernetes.py +27 -0
- sky/clouds/ssh.py +2 -3
- sky/dashboard/out/404.html +1 -1
- sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
- sky/dashboard/out/clusters/[cluster].html +1 -1
- sky/dashboard/out/clusters.html +1 -1
- sky/dashboard/out/config.html +1 -1
- sky/dashboard/out/index.html +1 -1
- sky/dashboard/out/infra/[context].html +1 -1
- sky/dashboard/out/infra.html +1 -1
- sky/dashboard/out/jobs/[job].html +1 -1
- sky/dashboard/out/jobs/pools/[pool].html +1 -1
- sky/dashboard/out/jobs.html +1 -1
- sky/dashboard/out/users.html +1 -1
- sky/dashboard/out/volumes.html +1 -1
- sky/dashboard/out/workspace/new.html +1 -1
- sky/dashboard/out/workspaces/[name].html +1 -1
- sky/dashboard/out/workspaces.html +1 -1
- sky/global_user_state.py +103 -11
- sky/provision/kubernetes/config.py +2 -8
- sky/provision/kubernetes/instance.py +6 -0
- sky/provision/kubernetes/network_utils.py +3 -4
- sky/provision/kubernetes/utils.py +6 -5
- sky/provision/nebius/utils.py +15 -7
- sky/provision/vsphere/vsphere_utils.py +2 -8
- sky/schemas/api/responses.py +7 -0
- sky/serve/serve_utils.py +2 -2
- sky/serve/service_spec.py +2 -8
- sky/server/auth/authn.py +4 -0
- sky/server/common.py +7 -1
- sky/server/requests/executor.py +4 -0
- sky/server/server.py +18 -33
- sky/server/uvicorn.py +33 -0
- sky/setup_files/dependencies.py +1 -0
- sky/sky_logging.py +4 -1
- sky/skylet/events.py +2 -2
- sky/skypilot_config.py +4 -2
- sky/ssh_node_pools/core.py +3 -1
- sky/task.py +3 -9
- sky/users/server.py +6 -6
- sky/utils/common_utils.py +3 -2
- sky/utils/yaml_utils.py +35 -0
- sky/volumes/volume.py +8 -3
- {skypilot_nightly-1.0.0.dev20250826.dist-info → skypilot_nightly-1.0.0.dev20250827.dist-info}/METADATA +2 -1
- {skypilot_nightly-1.0.0.dev20250826.dist-info → skypilot_nightly-1.0.0.dev20250827.dist-info}/RECORD +60 -59
- /sky/dashboard/out/_next/static/{TPMkEeuj85tHTmIW7Gu3S → -eL7Ky3bxVivzeLHNB9U6}/_buildManifest.js +0 -0
- /sky/dashboard/out/_next/static/{TPMkEeuj85tHTmIW7Gu3S → -eL7Ky3bxVivzeLHNB9U6}/_ssgManifest.js +0 -0
- {skypilot_nightly-1.0.0.dev20250826.dist-info → skypilot_nightly-1.0.0.dev20250827.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20250826.dist-info → skypilot_nightly-1.0.0.dev20250827.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250826.dist-info → skypilot_nightly-1.0.0.dev20250827.dist-info}/licenses/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250826.dist-info → skypilot_nightly-1.0.0.dev20250827.dist-info}/top_level.txt +0 -0
sky/dashboard/out/users.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/users-018bf31cda52e11b.js" defer=""></script><script src="/dashboard/_next/static/
|
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/users-018bf31cda52e11b.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/users","query":{},"buildId":"-eL7Ky3bxVivzeLHNB9U6","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
sky/dashboard/out/volumes.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/volumes-739726d6b823f532.js" defer=""></script><script src="/dashboard/_next/static/
|
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/volumes-739726d6b823f532.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/volumes","query":{},"buildId":"-eL7Ky3bxVivzeLHNB9U6","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspace/new-3f88a1c7e86a3f86.js" defer=""></script><script src="/dashboard/_next/static/
|
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspace/new-3f88a1c7e86a3f86.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspace/new","query":{},"buildId":"-eL7Ky3bxVivzeLHNB9U6","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-3d59f75e2ccf9321.js" defer=""></script><script src="/dashboard/_next/static/chunks/6130-2be46d70a38f1e82.js" defer=""></script><script src="/dashboard/_next/static/chunks/5739-d67458fcb1386c92.js" defer=""></script><script src="/dashboard/_next/static/chunks/7411-b15471acd2cba716.js" defer=""></script><script src="/dashboard/_next/static/chunks/1272-1ef0bf0237faccdb.js" defer=""></script><script src="/dashboard/_next/static/chunks/7205-88191679e7988c57.js" defer=""></script><script src="/dashboard/_next/static/chunks/6989-01359c57e018caa4.js" defer=""></script><script src="/dashboard/_next/static/chunks/3850-ff4a9a69d978632b.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-4a6f1a928fb6d370.js" defer=""></script><script src="/dashboard/_next/static/chunks/6990-08b2a1cae076a943.js" defer=""></script><script src="/dashboard/_next/static/chunks/6135-4b4d5e824b7f9d3c.js" defer=""></script><script src="/dashboard/_next/static/chunks/1121-8afcf719ea87debc.js" defer=""></script><script src="/dashboard/_next/static/chunks/6601-06114c982db410b6.js" defer=""></script><script src="/dashboard/_next/static/chunks/3015-6c9c09593b1e67b6.js" defer=""></script><script src="/dashboard/_next/static/chunks/1141-943efc7aff0f0c06.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces/%5Bname%5D-de06e613e20bc977.js" defer=""></script><script src="/dashboard/_next/static/
|
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-3d59f75e2ccf9321.js" defer=""></script><script src="/dashboard/_next/static/chunks/6130-2be46d70a38f1e82.js" defer=""></script><script src="/dashboard/_next/static/chunks/5739-d67458fcb1386c92.js" defer=""></script><script src="/dashboard/_next/static/chunks/7411-b15471acd2cba716.js" defer=""></script><script src="/dashboard/_next/static/chunks/1272-1ef0bf0237faccdb.js" defer=""></script><script src="/dashboard/_next/static/chunks/7205-88191679e7988c57.js" defer=""></script><script src="/dashboard/_next/static/chunks/6989-01359c57e018caa4.js" defer=""></script><script src="/dashboard/_next/static/chunks/3850-ff4a9a69d978632b.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-4a6f1a928fb6d370.js" defer=""></script><script src="/dashboard/_next/static/chunks/6990-08b2a1cae076a943.js" defer=""></script><script src="/dashboard/_next/static/chunks/6135-4b4d5e824b7f9d3c.js" defer=""></script><script src="/dashboard/_next/static/chunks/1121-8afcf719ea87debc.js" defer=""></script><script src="/dashboard/_next/static/chunks/6601-06114c982db410b6.js" defer=""></script><script src="/dashboard/_next/static/chunks/3015-6c9c09593b1e67b6.js" defer=""></script><script src="/dashboard/_next/static/chunks/1141-943efc7aff0f0c06.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces/%5Bname%5D-de06e613e20bc977.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"-eL7Ky3bxVivzeLHNB9U6","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces-be35b22e2046564c.js" defer=""></script><script src="/dashboard/_next/static/
|
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-6e76f636a048e145.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces-be35b22e2046564c.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/-eL7Ky3bxVivzeLHNB9U6/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"-eL7Ky3bxVivzeLHNB9U6","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
sky/global_user_state.py
CHANGED
|
@@ -25,7 +25,6 @@ from sqlalchemy import orm
|
|
|
25
25
|
from sqlalchemy.dialects import postgresql
|
|
26
26
|
from sqlalchemy.dialects import sqlite
|
|
27
27
|
from sqlalchemy.ext import declarative
|
|
28
|
-
import yaml
|
|
29
28
|
|
|
30
29
|
from sky import models
|
|
31
30
|
from sky import sky_logging
|
|
@@ -35,6 +34,7 @@ from sky.utils import common_utils
|
|
|
35
34
|
from sky.utils import context_utils
|
|
36
35
|
from sky.utils import registry
|
|
37
36
|
from sky.utils import status_lib
|
|
37
|
+
from sky.utils import yaml_utils
|
|
38
38
|
from sky.utils.db import db_utils
|
|
39
39
|
from sky.utils.db import migration_utils
|
|
40
40
|
|
|
@@ -433,6 +433,20 @@ def get_user(user_id: str) -> Optional[models.User]:
|
|
|
433
433
|
created_at=row.created_at)
|
|
434
434
|
|
|
435
435
|
|
|
436
|
+
@_init_db
|
|
437
|
+
def _get_users(user_ids: Set[str]) -> Dict[str, models.User]:
|
|
438
|
+
assert _SQLALCHEMY_ENGINE is not None
|
|
439
|
+
with orm.Session(_SQLALCHEMY_ENGINE) as session:
|
|
440
|
+
rows = session.query(user_table).filter(
|
|
441
|
+
user_table.c.id.in_(user_ids)).all()
|
|
442
|
+
return {
|
|
443
|
+
row.id: models.User(id=row.id,
|
|
444
|
+
name=row.name,
|
|
445
|
+
password=row.password,
|
|
446
|
+
created_at=row.created_at) for row in rows
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
|
|
436
450
|
@_init_db
|
|
437
451
|
def get_user_by_name(username: str) -> List[models.User]:
|
|
438
452
|
with orm.Session(_SQLALCHEMY_ENGINE) as session:
|
|
@@ -767,6 +781,32 @@ def get_last_cluster_event(cluster_hash: str,
|
|
|
767
781
|
return row.reason
|
|
768
782
|
|
|
769
783
|
|
|
784
|
+
def _get_last_cluster_event_multiple(
|
|
785
|
+
cluster_hashes: Set[str],
|
|
786
|
+
event_type: ClusterEventType) -> Dict[str, str]:
|
|
787
|
+
assert _SQLALCHEMY_ENGINE is not None
|
|
788
|
+
with orm.Session(_SQLALCHEMY_ENGINE) as session:
|
|
789
|
+
# Use a subquery to get the latest event for each cluster_hash
|
|
790
|
+
latest_events = session.query(
|
|
791
|
+
cluster_event_table.c.cluster_hash,
|
|
792
|
+
sqlalchemy.func.max(cluster_event_table.c.transitioned_at).label(
|
|
793
|
+
'max_time')).filter(
|
|
794
|
+
cluster_event_table.c.cluster_hash.in_(cluster_hashes),
|
|
795
|
+
cluster_event_table.c.type == event_type.value).group_by(
|
|
796
|
+
cluster_event_table.c.cluster_hash).subquery()
|
|
797
|
+
|
|
798
|
+
# Join with original table to get the full event details
|
|
799
|
+
rows = session.query(cluster_event_table).join(
|
|
800
|
+
latest_events,
|
|
801
|
+
sqlalchemy.and_(
|
|
802
|
+
cluster_event_table.c.cluster_hash ==
|
|
803
|
+
latest_events.c.cluster_hash,
|
|
804
|
+
cluster_event_table.c.transitioned_at ==
|
|
805
|
+
latest_events.c.max_time)).all()
|
|
806
|
+
|
|
807
|
+
return {row.cluster_hash: row.reason for row in rows}
|
|
808
|
+
|
|
809
|
+
|
|
770
810
|
def cleanup_cluster_events_with_retention(retention_hours: float) -> None:
|
|
771
811
|
assert _SQLALCHEMY_ENGINE is not None
|
|
772
812
|
with orm.Session(_SQLALCHEMY_ENGINE) as session:
|
|
@@ -1266,18 +1306,70 @@ def get_cluster_from_name(
|
|
|
1266
1306
|
|
|
1267
1307
|
|
|
1268
1308
|
@_init_db
|
|
1269
|
-
def get_clusters(
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1309
|
+
def get_clusters(
|
|
1310
|
+
*, # keyword only separator
|
|
1311
|
+
exclude_managed_clusters: bool = False,
|
|
1312
|
+
workspaces_filter: Optional[Set[str]] = None,
|
|
1313
|
+
user_hashes_filter: Optional[Set[str]] = None,
|
|
1314
|
+
) -> List[Dict[str, Any]]:
|
|
1315
|
+
"""Get clusters from the database.
|
|
1316
|
+
|
|
1317
|
+
Args:
|
|
1318
|
+
exclude_managed_clusters: If True, exclude clusters that have
|
|
1319
|
+
is_managed field set to True.
|
|
1320
|
+
workspaces_filter: If specified, only include clusters
|
|
1321
|
+
that has workspace field set to one of the values.
|
|
1322
|
+
user_hashes_filter: If specified, only include clusters
|
|
1323
|
+
that has user_hash field set to one of the values.
|
|
1324
|
+
"""
|
|
1325
|
+
# is a cluster has a null user_hash,
|
|
1326
|
+
# we treat it as belonging to the current user.
|
|
1327
|
+
current_user_hash = common_utils.get_user_hash()
|
|
1328
|
+
assert _SQLALCHEMY_ENGINE is not None
|
|
1329
|
+
with orm.Session(_SQLALCHEMY_ENGINE) as session:
|
|
1330
|
+
query = session.query(cluster_table)
|
|
1331
|
+
if exclude_managed_clusters:
|
|
1332
|
+
query = query.filter(cluster_table.c.is_managed == int(False))
|
|
1333
|
+
if workspaces_filter is not None:
|
|
1334
|
+
query = query.filter(
|
|
1335
|
+
cluster_table.c.workspace.in_(workspaces_filter))
|
|
1336
|
+
if user_hashes_filter is not None:
|
|
1337
|
+
if current_user_hash in user_hashes_filter:
|
|
1338
|
+
# backwards compatibility for old clusters.
|
|
1339
|
+
# If current_user_hash is in user_hashes_filter, we include
|
|
1340
|
+
# clusters that have a null user_hash.
|
|
1341
|
+
query = query.filter(
|
|
1342
|
+
cluster_table.c.user_hash.in_(user_hashes_filter) |
|
|
1343
|
+
(cluster_table.c.user_hash is None))
|
|
1344
|
+
else:
|
|
1345
|
+
query = query.filter(
|
|
1346
|
+
cluster_table.c.user_hash.in_(user_hashes_filter))
|
|
1347
|
+
query = query.order_by(sqlalchemy.desc(cluster_table.c.launched_at))
|
|
1348
|
+
rows = query.all()
|
|
1274
1349
|
records = []
|
|
1350
|
+
|
|
1351
|
+
# get user hash for each row
|
|
1352
|
+
row_to_user_hash = {}
|
|
1275
1353
|
for row in rows:
|
|
1276
|
-
user_hash =
|
|
1277
|
-
|
|
1354
|
+
user_hash = (row.user_hash
|
|
1355
|
+
if row.user_hash is not None else current_user_hash)
|
|
1356
|
+
row_to_user_hash[row.cluster_hash] = user_hash
|
|
1357
|
+
|
|
1358
|
+
# get all users needed for the rows at once
|
|
1359
|
+
user_hashes = set(row_to_user_hash.values())
|
|
1360
|
+
user_hash_to_user = _get_users(user_hashes)
|
|
1361
|
+
|
|
1362
|
+
# get last cluster event for each row
|
|
1363
|
+
cluster_hashes = set(row_to_user_hash.keys())
|
|
1364
|
+
last_cluster_event_dict = _get_last_cluster_event_multiple(
|
|
1365
|
+
cluster_hashes, ClusterEventType.STATUS_CHANGE)
|
|
1366
|
+
|
|
1367
|
+
# get user for each row
|
|
1368
|
+
for row in rows:
|
|
1369
|
+
user_hash = row_to_user_hash[row.cluster_hash]
|
|
1370
|
+
user = user_hash_to_user.get(user_hash, None)
|
|
1278
1371
|
user_name = user.name if user is not None else None
|
|
1279
|
-
last_event =
|
|
1280
|
-
row.cluster_hash, event_type=ClusterEventType.STATUS_CHANGE)
|
|
1372
|
+
last_event = last_cluster_event_dict.get(row.cluster_hash, None)
|
|
1281
1373
|
# TODO: use namedtuple instead of dict
|
|
1282
1374
|
record = {
|
|
1283
1375
|
'name': row.name,
|
|
@@ -1999,7 +2091,7 @@ def get_cluster_yaml_dict(cluster_yaml_path: Optional[str]) -> Dict[str, Any]:
|
|
|
1999
2091
|
yaml_str = get_cluster_yaml_str(cluster_yaml_path)
|
|
2000
2092
|
if yaml_str is None:
|
|
2001
2093
|
raise ValueError(f'Cluster yaml {cluster_yaml_path} not found.')
|
|
2002
|
-
return
|
|
2094
|
+
return yaml_utils.safe_load(yaml_str)
|
|
2003
2095
|
|
|
2004
2096
|
|
|
2005
2097
|
@_init_db
|
|
@@ -3,20 +3,14 @@ import copy
|
|
|
3
3
|
import logging
|
|
4
4
|
import math
|
|
5
5
|
import os
|
|
6
|
-
import typing
|
|
7
6
|
from typing import Any, Dict, Optional, Union
|
|
8
7
|
|
|
9
|
-
from sky.adaptors import common as adaptors_common
|
|
10
8
|
from sky.adaptors import kubernetes
|
|
11
9
|
from sky.provision import common
|
|
12
10
|
from sky.provision.kubernetes import network_utils
|
|
13
11
|
from sky.provision.kubernetes import utils as kubernetes_utils
|
|
14
12
|
from sky.utils import kubernetes_enums
|
|
15
|
-
|
|
16
|
-
if typing.TYPE_CHECKING:
|
|
17
|
-
import yaml
|
|
18
|
-
else:
|
|
19
|
-
yaml = adaptors_common.LazyImport('yaml')
|
|
13
|
+
from sky.utils import yaml_utils
|
|
20
14
|
|
|
21
15
|
logger = logging.getLogger(__name__)
|
|
22
16
|
|
|
@@ -592,7 +586,7 @@ def _configure_fuse_mounting(provider_config: Dict[str, Any]) -> None:
|
|
|
592
586
|
daemonset_path = os.path.join(
|
|
593
587
|
root_dir, 'kubernetes/manifests/fusermount-server-daemonset.yaml')
|
|
594
588
|
with open(daemonset_path, 'r', encoding='utf-8') as file:
|
|
595
|
-
daemonset =
|
|
589
|
+
daemonset = yaml_utils.safe_load(file)
|
|
596
590
|
kubernetes_utils.merge_custom_metadata(daemonset['metadata'])
|
|
597
591
|
try:
|
|
598
592
|
kubernetes.apps_api(context).create_namespaced_daemon_set(
|
|
@@ -1441,6 +1441,12 @@ def query_instances(
|
|
|
1441
1441
|
phase = pod.status.phase
|
|
1442
1442
|
pod_status = status_map[phase]
|
|
1443
1443
|
if non_terminated_only and pod_status is None:
|
|
1444
|
+
logger.debug(f'Pod {pod.metadata.name} is terminated, but '
|
|
1445
|
+
'query_instances is called with '
|
|
1446
|
+
f'non_terminated_only=True. Phase: {phase}')
|
|
1447
|
+
if phase == 'Failed':
|
|
1448
|
+
reason_for_debug = _get_pod_termination_reason(pod)
|
|
1449
|
+
logger.debug(f'Termination reason: {reason_for_debug}')
|
|
1444
1450
|
continue
|
|
1445
1451
|
reason = None
|
|
1446
1452
|
if phase == 'Failed':
|
|
@@ -13,13 +13,12 @@ from sky.provision.kubernetes import utils as kubernetes_utils
|
|
|
13
13
|
from sky.utils import directory_utils
|
|
14
14
|
from sky.utils import kubernetes_enums
|
|
15
15
|
from sky.utils import ux_utils
|
|
16
|
+
from sky.utils import yaml_utils
|
|
16
17
|
|
|
17
18
|
if typing.TYPE_CHECKING:
|
|
18
19
|
import jinja2
|
|
19
|
-
import yaml
|
|
20
20
|
else:
|
|
21
21
|
jinja2 = adaptors_common.LazyImport('jinja2')
|
|
22
|
-
yaml = adaptors_common.LazyImport('yaml')
|
|
23
22
|
|
|
24
23
|
logger = sky_logging.init_logger(__name__)
|
|
25
24
|
|
|
@@ -108,7 +107,7 @@ def fill_loadbalancer_template(namespace: str, context: Optional[str],
|
|
|
108
107
|
annotations=annotations,
|
|
109
108
|
labels=labels,
|
|
110
109
|
)
|
|
111
|
-
content =
|
|
110
|
+
content = yaml_utils.safe_load(cont)
|
|
112
111
|
return content
|
|
113
112
|
|
|
114
113
|
|
|
@@ -147,7 +146,7 @@ def fill_ingress_template(namespace: str, context: Optional[str],
|
|
|
147
146
|
annotations=annotations,
|
|
148
147
|
labels=labels,
|
|
149
148
|
)
|
|
150
|
-
content =
|
|
149
|
+
content = yaml_utils.safe_load(cont)
|
|
151
150
|
|
|
152
151
|
# Return a dictionary containing both specs
|
|
153
152
|
return {
|
|
@@ -38,6 +38,7 @@ from sky.utils import schemas
|
|
|
38
38
|
from sky.utils import status_lib
|
|
39
39
|
from sky.utils import timeline
|
|
40
40
|
from sky.utils import ux_utils
|
|
41
|
+
from sky.utils import yaml_utils
|
|
41
42
|
|
|
42
43
|
if typing.TYPE_CHECKING:
|
|
43
44
|
import jinja2
|
|
@@ -1898,7 +1899,7 @@ def is_kubeconfig_exec_auth(
|
|
|
1898
1899
|
|
|
1899
1900
|
# Load the kubeconfig for the context
|
|
1900
1901
|
kubeconfig_text = _get_kubeconfig_text_for_context(context)
|
|
1901
|
-
kubeconfig =
|
|
1902
|
+
kubeconfig = yaml_utils.safe_load(kubeconfig_text)
|
|
1902
1903
|
|
|
1903
1904
|
# Get the user details
|
|
1904
1905
|
user_details = kubeconfig['users']
|
|
@@ -2601,7 +2602,7 @@ def fill_ssh_jump_template(ssh_key_secret: str, ssh_jump_image: str,
|
|
|
2601
2602
|
image=ssh_jump_image,
|
|
2602
2603
|
secret=ssh_key_secret,
|
|
2603
2604
|
service_type=service_type)
|
|
2604
|
-
content =
|
|
2605
|
+
content = yaml_utils.safe_load(cont)
|
|
2605
2606
|
return content
|
|
2606
2607
|
|
|
2607
2608
|
|
|
@@ -2750,7 +2751,7 @@ def combine_pod_config_fields(
|
|
|
2750
2751
|
"""
|
|
2751
2752
|
with open(cluster_yaml_path, 'r', encoding='utf-8') as f:
|
|
2752
2753
|
yaml_content = f.read()
|
|
2753
|
-
yaml_obj =
|
|
2754
|
+
yaml_obj = yaml_utils.safe_load(yaml_content)
|
|
2754
2755
|
# We don't use override_configs in `get_effective_region_config`, as merging
|
|
2755
2756
|
# the pod config requires special handling.
|
|
2756
2757
|
if isinstance(cloud, clouds.SSH):
|
|
@@ -2795,7 +2796,7 @@ def combine_metadata_fields(cluster_yaml_path: str,
|
|
|
2795
2796
|
|
|
2796
2797
|
with open(cluster_yaml_path, 'r', encoding='utf-8') as f:
|
|
2797
2798
|
yaml_content = f.read()
|
|
2798
|
-
yaml_obj =
|
|
2799
|
+
yaml_obj = yaml_utils.safe_load(yaml_content)
|
|
2799
2800
|
|
|
2800
2801
|
# Get custom_metadata from global config
|
|
2801
2802
|
custom_metadata = skypilot_config.get_effective_region_config(
|
|
@@ -3689,7 +3690,7 @@ def format_kubeconfig_exec_auth_with_cache(kubeconfig_path: str) -> str:
|
|
|
3689
3690
|
"""
|
|
3690
3691
|
# TODO(kyuds): GC cache files
|
|
3691
3692
|
with open(kubeconfig_path, 'r', encoding='utf-8') as file:
|
|
3692
|
-
config =
|
|
3693
|
+
config = yaml_utils.safe_load(file)
|
|
3693
3694
|
normalized = yaml.dump(config, sort_keys=True)
|
|
3694
3695
|
hashed = hashlib.sha1(normalized.encode('utf-8')).hexdigest()
|
|
3695
3696
|
path = os.path.expanduser(
|
sky/provision/nebius/utils.py
CHANGED
|
@@ -100,15 +100,23 @@ def delete_cluster(name: str, region: str) -> None:
|
|
|
100
100
|
def list_instances(project_id: str) -> Dict[str, Dict[str, Any]]:
|
|
101
101
|
"""Lists instances associated with API key."""
|
|
102
102
|
service = nebius.compute().InstanceServiceClient(nebius.sdk())
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
page_token = ''
|
|
104
|
+
instances = []
|
|
105
|
+
while True:
|
|
106
|
+
result = nebius.sync_call(
|
|
107
|
+
service.list(nebius.compute().ListInstancesRequest(
|
|
108
|
+
parent_id=project_id,
|
|
109
|
+
page_size=100,
|
|
110
|
+
page_token=page_token,
|
|
111
|
+
),
|
|
112
|
+
timeout=nebius.READ_TIMEOUT))
|
|
113
|
+
instances.extend(result.items)
|
|
114
|
+
if not result.next_page_token: # "" means no more pages
|
|
115
|
+
break
|
|
116
|
+
page_token = result.next_page_token
|
|
109
117
|
|
|
110
118
|
instance_dict: Dict[str, Dict[str, Any]] = {}
|
|
111
|
-
for instance in instances
|
|
119
|
+
for instance in instances:
|
|
112
120
|
info = {}
|
|
113
121
|
info['status'] = instance.status.state.name
|
|
114
122
|
info['name'] = instance.metadata.name
|
|
@@ -3,12 +3,10 @@
|
|
|
3
3
|
import http.cookies as http_cookies
|
|
4
4
|
import os
|
|
5
5
|
import ssl
|
|
6
|
-
import typing
|
|
7
6
|
from typing import Any, Dict, List, Optional
|
|
8
7
|
|
|
9
8
|
from sky import exceptions
|
|
10
9
|
from sky import sky_logging
|
|
11
|
-
from sky.adaptors import common as adaptors_common
|
|
12
10
|
from sky.adaptors import vsphere as vsphere_adaptor
|
|
13
11
|
from sky.catalog import vsphere_catalog
|
|
14
12
|
from sky.catalog.common import get_catalog_path
|
|
@@ -28,11 +26,7 @@ from sky.provision.vsphere.common.vim_utils import create_spec_with_script
|
|
|
28
26
|
from sky.provision.vsphere.common.vim_utils import poweron_vm
|
|
29
27
|
from sky.provision.vsphere.common.vim_utils import wait_for_tasks
|
|
30
28
|
from sky.provision.vsphere.common.vim_utils import wait_internal_ip_ready
|
|
31
|
-
|
|
32
|
-
if typing.TYPE_CHECKING:
|
|
33
|
-
import yaml
|
|
34
|
-
else:
|
|
35
|
-
yaml = adaptors_common.LazyImport('yaml')
|
|
29
|
+
from sky.utils import yaml_utils
|
|
36
30
|
|
|
37
31
|
logger = sky_logging.init_logger(__name__)
|
|
38
32
|
|
|
@@ -323,7 +317,7 @@ def get_vsphere_credentials(name=None):
|
|
|
323
317
|
assert os.path.exists(
|
|
324
318
|
credential_path), f'Missing credential file at {credential_path}.'
|
|
325
319
|
with open(credential_path, 'r', encoding='utf-8') as file:
|
|
326
|
-
credential =
|
|
320
|
+
credential = yaml_utils.safe_load(file)
|
|
327
321
|
vcenters = credential['vcenters']
|
|
328
322
|
if name is None:
|
|
329
323
|
return vcenters
|
sky/schemas/api/responses.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Responses for the API server."""
|
|
2
2
|
|
|
3
|
+
import enum
|
|
3
4
|
from typing import Any, Dict, List, Optional
|
|
4
5
|
|
|
5
6
|
import pydantic
|
|
@@ -117,3 +118,9 @@ class StatusResponse(ResponseBaseModel):
|
|
|
117
118
|
cpus: Optional[str] = None
|
|
118
119
|
memory: Optional[str] = None
|
|
119
120
|
accelerators: Optional[str] = None
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class UploadStatus(enum.Enum):
|
|
124
|
+
"""Status of the upload."""
|
|
125
|
+
UPLOADING = 'uploading'
|
|
126
|
+
COMPLETED = 'completed'
|
sky/serve/serve_utils.py
CHANGED
|
@@ -20,7 +20,6 @@ import uuid
|
|
|
20
20
|
|
|
21
21
|
import colorama
|
|
22
22
|
import filelock
|
|
23
|
-
import yaml
|
|
24
23
|
|
|
25
24
|
from sky import backends
|
|
26
25
|
from sky import exceptions
|
|
@@ -43,6 +42,7 @@ from sky.utils import message_utils
|
|
|
43
42
|
from sky.utils import resources_utils
|
|
44
43
|
from sky.utils import status_lib
|
|
45
44
|
from sky.utils import ux_utils
|
|
45
|
+
from sky.utils import yaml_utils
|
|
46
46
|
|
|
47
47
|
if typing.TYPE_CHECKING:
|
|
48
48
|
import fastapi
|
|
@@ -710,7 +710,7 @@ def _get_service_status(
|
|
|
710
710
|
svc.pop('pool', None) # Remove pool from service config
|
|
711
711
|
original_config['pool'] = svc # Add pool to root config
|
|
712
712
|
else:
|
|
713
|
-
original_config =
|
|
713
|
+
original_config = yaml_utils.safe_load(original_config)
|
|
714
714
|
record['pool_yaml'] = common_utils.dump_yaml_str(original_config)
|
|
715
715
|
|
|
716
716
|
record['target_num_replicas'] = 0
|
sky/serve/service_spec.py
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
import json
|
|
3
3
|
import os
|
|
4
4
|
import textwrap
|
|
5
|
-
import typing
|
|
6
5
|
from typing import Any, Dict, List, Optional, Union
|
|
7
6
|
|
|
8
7
|
from sky import serve
|
|
9
|
-
from sky.adaptors import common as adaptors_common
|
|
10
8
|
from sky.serve import constants
|
|
11
9
|
from sky.serve import load_balancing_policies as lb_policies
|
|
12
10
|
from sky.serve import serve_utils
|
|
@@ -14,11 +12,7 @@ from sky.serve import spot_placer as spot_placer_lib
|
|
|
14
12
|
from sky.utils import common_utils
|
|
15
13
|
from sky.utils import schemas
|
|
16
14
|
from sky.utils import ux_utils
|
|
17
|
-
|
|
18
|
-
if typing.TYPE_CHECKING:
|
|
19
|
-
import yaml
|
|
20
|
-
else:
|
|
21
|
-
yaml = adaptors_common.LazyImport('yaml')
|
|
15
|
+
from sky.utils import yaml_utils
|
|
22
16
|
|
|
23
17
|
|
|
24
18
|
class SkyServiceSpec:
|
|
@@ -274,7 +268,7 @@ class SkyServiceSpec:
|
|
|
274
268
|
@staticmethod
|
|
275
269
|
def from_yaml(yaml_path: str) -> 'SkyServiceSpec':
|
|
276
270
|
with open(os.path.expanduser(yaml_path), 'r', encoding='utf-8') as f:
|
|
277
|
-
config =
|
|
271
|
+
config = yaml_utils.safe_load(f)
|
|
278
272
|
|
|
279
273
|
if isinstance(config, str):
|
|
280
274
|
with ux_utils.print_exception_no_traceback():
|
sky/server/auth/authn.py
CHANGED
|
@@ -14,6 +14,10 @@ logger = sky_logging.init_logger(__name__)
|
|
|
14
14
|
# TODO(hailong): Remove this function and use request.state.auth_user instead.
|
|
15
15
|
async def override_user_info_in_request_body(request: fastapi.Request,
|
|
16
16
|
auth_user: Optional[models.User]):
|
|
17
|
+
# Skip for upload requests to avoid consuming the body prematurely, which
|
|
18
|
+
# will break the streaming upload.
|
|
19
|
+
if request.url.path.startswith('/upload'):
|
|
20
|
+
return
|
|
17
21
|
if auth_user is None:
|
|
18
22
|
return
|
|
19
23
|
|
sky/server/common.py
CHANGED
|
@@ -23,6 +23,7 @@ import uuid
|
|
|
23
23
|
import cachetools
|
|
24
24
|
import colorama
|
|
25
25
|
import filelock
|
|
26
|
+
from passlib import context as passlib_context
|
|
26
27
|
from typing_extensions import ParamSpec
|
|
27
28
|
|
|
28
29
|
from sky import exceptions
|
|
@@ -61,7 +62,7 @@ AVAILABLE_LOCAL_API_SERVER_URLS = [
|
|
|
61
62
|
|
|
62
63
|
API_SERVER_CMD = '-m sky.server.server'
|
|
63
64
|
# The client dir on the API server for storing user-specific data, such as file
|
|
64
|
-
# mounts, logs, etc. This dir is
|
|
65
|
+
# mounts, logs, etc. This dir is ephemeral and will be cleaned up when the API
|
|
65
66
|
# server is restarted.
|
|
66
67
|
API_SERVER_CLIENT_DIR = pathlib.Path('~/.sky/api_server/clients')
|
|
67
68
|
RETRY_COUNT_ON_TIMEOUT = 3
|
|
@@ -102,6 +103,11 @@ logger = sky_logging.init_logger(__name__)
|
|
|
102
103
|
|
|
103
104
|
hinted_for_server_install_version_mismatch = False
|
|
104
105
|
|
|
106
|
+
crypt_ctx = passlib_context.CryptContext([
|
|
107
|
+
'bcrypt', 'sha256_crypt', 'sha512_crypt', 'des_crypt', 'apr_md5_crypt',
|
|
108
|
+
'ldap_sha1'
|
|
109
|
+
])
|
|
110
|
+
|
|
105
111
|
|
|
106
112
|
class ApiServerStatus(enum.Enum):
|
|
107
113
|
HEALTHY = 'healthy'
|
sky/server/requests/executor.py
CHANGED
|
@@ -275,6 +275,10 @@ def override_request_env_and_config(
|
|
|
275
275
|
request_id: str) -> Generator[None, None, None]:
|
|
276
276
|
"""Override the environment and SkyPilot config for a request."""
|
|
277
277
|
original_env = os.environ.copy()
|
|
278
|
+
# Unset SKYPILOT_DEBUG by default, to avoid the value set on the API server
|
|
279
|
+
# affecting client requests. If set on the client side, it will be
|
|
280
|
+
# overridden by the request body.
|
|
281
|
+
os.environ.pop('SKYPILOT_DEBUG', None)
|
|
278
282
|
os.environ.update(request_body.env_vars)
|
|
279
283
|
# Note: may be overridden by AuthProxyMiddleware.
|
|
280
284
|
# TODO(zhwu): we need to make the entire request a context available to the
|