skypilot-nightly 1.0.0.dev20250829__py3-none-any.whl → 1.0.0.dev20250831__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.

Files changed (47) hide show
  1. sky/__init__.py +2 -2
  2. sky/adaptors/nebius.py +24 -2
  3. sky/backends/backend_utils.py +39 -36
  4. sky/backends/cloud_vm_ray_backend.py +37 -0
  5. sky/client/cli/command.py +17 -6
  6. sky/client/common.py +5 -4
  7. sky/client/sdk.py +5 -0
  8. sky/client/sdk_async.py +8 -2
  9. sky/core.py +8 -3
  10. sky/dashboard/out/404.html +1 -1
  11. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  12. sky/dashboard/out/clusters/[cluster].html +1 -1
  13. sky/dashboard/out/clusters.html +1 -1
  14. sky/dashboard/out/config.html +1 -1
  15. sky/dashboard/out/index.html +1 -1
  16. sky/dashboard/out/infra/[context].html +1 -1
  17. sky/dashboard/out/infra.html +1 -1
  18. sky/dashboard/out/jobs/[job].html +1 -1
  19. sky/dashboard/out/jobs/pools/[pool].html +1 -1
  20. sky/dashboard/out/jobs.html +1 -1
  21. sky/dashboard/out/users.html +1 -1
  22. sky/dashboard/out/volumes.html +1 -1
  23. sky/dashboard/out/workspace/new.html +1 -1
  24. sky/dashboard/out/workspaces/[name].html +1 -1
  25. sky/dashboard/out/workspaces.html +1 -1
  26. sky/jobs/server/server.py +1 -2
  27. sky/provision/docker_utils.py +1 -1
  28. sky/provision/kubernetes/utils.py +39 -26
  29. sky/serve/server/server.py +1 -2
  30. sky/server/requests/executor.py +1 -1
  31. sky/server/requests/payloads.py +1 -0
  32. sky/server/requests/preconditions.py +2 -3
  33. sky/server/requests/requests.py +29 -110
  34. sky/server/server.py +4 -4
  35. sky/server/stream_utils.py +5 -7
  36. sky/setup_files/dependencies.py +24 -12
  37. sky/setup_files/setup.py +2 -0
  38. sky/utils/db/db_utils.py +0 -11
  39. sky/utils/schemas.py +6 -0
  40. {skypilot_nightly-1.0.0.dev20250829.dist-info → skypilot_nightly-1.0.0.dev20250831.dist-info}/METADATA +35 -53
  41. {skypilot_nightly-1.0.0.dev20250829.dist-info → skypilot_nightly-1.0.0.dev20250831.dist-info}/RECORD +47 -47
  42. /sky/dashboard/out/_next/static/{hYJYFIxp_ZFONR4wTIJqZ → FtHzmn6BMJ5PzqHhEY51g}/_buildManifest.js +0 -0
  43. /sky/dashboard/out/_next/static/{hYJYFIxp_ZFONR4wTIJqZ → FtHzmn6BMJ5PzqHhEY51g}/_ssgManifest.js +0 -0
  44. {skypilot_nightly-1.0.0.dev20250829.dist-info → skypilot_nightly-1.0.0.dev20250831.dist-info}/WHEEL +0 -0
  45. {skypilot_nightly-1.0.0.dev20250829.dist-info → skypilot_nightly-1.0.0.dev20250831.dist-info}/entry_points.txt +0 -0
  46. {skypilot_nightly-1.0.0.dev20250829.dist-info → skypilot_nightly-1.0.0.dev20250831.dist-info}/licenses/LICENSE +0 -0
  47. {skypilot_nightly-1.0.0.dev20250829.dist-info → skypilot_nightly-1.0.0.dev20250831.dist-info}/top_level.txt +0 -0
@@ -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/hYJYFIxp_ZFONR4wTIJqZ/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/hYJYFIxp_ZFONR4wTIJqZ/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/users","query":{},"buildId":"hYJYFIxp_ZFONR4wTIJqZ","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
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/FtHzmn6BMJ5PzqHhEY51g/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/FtHzmn6BMJ5PzqHhEY51g/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/users","query":{},"buildId":"FtHzmn6BMJ5PzqHhEY51g","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/volumes-739726d6b823f532.js" defer=""></script><script src="/dashboard/_next/static/hYJYFIxp_ZFONR4wTIJqZ/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/hYJYFIxp_ZFONR4wTIJqZ/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/volumes","query":{},"buildId":"hYJYFIxp_ZFONR4wTIJqZ","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
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/FtHzmn6BMJ5PzqHhEY51g/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/FtHzmn6BMJ5PzqHhEY51g/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/volumes","query":{},"buildId":"FtHzmn6BMJ5PzqHhEY51g","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/hYJYFIxp_ZFONR4wTIJqZ/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/hYJYFIxp_ZFONR4wTIJqZ/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspace/new","query":{},"buildId":"hYJYFIxp_ZFONR4wTIJqZ","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
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/FtHzmn6BMJ5PzqHhEY51g/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/FtHzmn6BMJ5PzqHhEY51g/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspace/new","query":{},"buildId":"FtHzmn6BMJ5PzqHhEY51g","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/hYJYFIxp_ZFONR4wTIJqZ/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/hYJYFIxp_ZFONR4wTIJqZ/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"hYJYFIxp_ZFONR4wTIJqZ","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
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/FtHzmn6BMJ5PzqHhEY51g/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/FtHzmn6BMJ5PzqHhEY51g/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"FtHzmn6BMJ5PzqHhEY51g","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/hYJYFIxp_ZFONR4wTIJqZ/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/hYJYFIxp_ZFONR4wTIJqZ/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"hYJYFIxp_ZFONR4wTIJqZ","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
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/FtHzmn6BMJ5PzqHhEY51g/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/FtHzmn6BMJ5PzqHhEY51g/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"FtHzmn6BMJ5PzqHhEY51g","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
sky/jobs/server/server.py CHANGED
@@ -79,8 +79,7 @@ async def logs(
79
79
  if jobs_logs_body.refresh else api_requests.ScheduleType.SHORT,
80
80
  request_cluster_name=common.JOB_CONTROLLER_NAME,
81
81
  )
82
- request_task = await api_requests.get_request_async(request.state.request_id
83
- )
82
+ request_task = api_requests.get_request(request.state.request_id)
84
83
 
85
84
  return stream_utils.stream_response(
86
85
  request_id=request_task.request_id,
@@ -371,7 +371,7 @@ class DockerInitializer:
371
371
  'mkdir -p ~/.ssh;'
372
372
  'cat /tmp/host_ssh_authorized_keys >> ~/.ssh/authorized_keys;'
373
373
  'sudo service ssh start;'
374
- 'sudo sed -i "s/mesg n/tty -s \&\& mesg n/" ~/.profile;'
374
+ 'sudo sed -i "s/mesg n/tty -s \\&\\& mesg n/" ~/.profile;'
375
375
  f'{SETUP_ENV_VARS_CMD}',
376
376
  run_env='docker')
377
377
 
@@ -1,4 +1,5 @@
1
1
  """Kubernetes utilities for SkyPilot."""
2
+ import copy
2
3
  import dataclasses
3
4
  import datetime
4
5
  import enum
@@ -2715,11 +2716,11 @@ def get_endpoint_debug_message(context: Optional[str] = None) -> str:
2715
2716
 
2716
2717
 
2717
2718
  def combine_pod_config_fields(
2718
- cluster_yaml_path: str,
2719
+ cluster_yaml_obj: Dict[str, Any],
2719
2720
  cluster_config_overrides: Dict[str, Any],
2720
2721
  cloud: Optional[clouds.Cloud] = None,
2721
2722
  context: Optional[str] = None,
2722
- ) -> None:
2723
+ ) -> Dict[str, Any]:
2723
2724
  """Adds or updates fields in the YAML with fields from the
2724
2725
  ~/.sky/config.yaml's kubernetes.pod_spec dict.
2725
2726
  This can be used to add fields to the YAML that are not supported by
@@ -2758,9 +2759,7 @@ def combine_pod_config_fields(
2758
2759
  - name: my-secret
2759
2760
  ```
2760
2761
  """
2761
- with open(cluster_yaml_path, 'r', encoding='utf-8') as f:
2762
- yaml_content = f.read()
2763
- yaml_obj = yaml_utils.safe_load(yaml_content)
2762
+ merged_cluster_yaml_obj = copy.deepcopy(cluster_yaml_obj)
2764
2763
  # We don't use override_configs in `get_effective_region_config`, as merging
2765
2764
  # the pod config requires special handling.
2766
2765
  if isinstance(cloud, clouds.SSH):
@@ -2787,26 +2786,20 @@ def combine_pod_config_fields(
2787
2786
 
2788
2787
  # Merge the kubernetes config into the YAML for both head and worker nodes.
2789
2788
  config_utils.merge_k8s_configs(
2790
- yaml_obj['available_node_types']['ray_head_default']['node_config'],
2791
- kubernetes_config)
2789
+ merged_cluster_yaml_obj['available_node_types']['ray_head_default']
2790
+ ['node_config'], kubernetes_config)
2791
+ return merged_cluster_yaml_obj
2792
2792
 
2793
- # Write the updated YAML back to the file
2794
- yaml_utils.dump_yaml(cluster_yaml_path, yaml_obj)
2795
2793
 
2796
-
2797
- def combine_metadata_fields(cluster_yaml_path: str,
2794
+ def combine_metadata_fields(cluster_yaml_obj: Dict[str, Any],
2798
2795
  cluster_config_overrides: Dict[str, Any],
2799
- context: Optional[str] = None) -> None:
2796
+ context: Optional[str] = None) -> Dict[str, Any]:
2800
2797
  """Updates the metadata for all Kubernetes objects created by SkyPilot with
2801
2798
  fields from the ~/.sky/config.yaml's kubernetes.custom_metadata dict.
2802
2799
 
2803
2800
  Obeys the same add or update semantics as combine_pod_config_fields().
2804
2801
  """
2805
-
2806
- with open(cluster_yaml_path, 'r', encoding='utf-8') as f:
2807
- yaml_content = f.read()
2808
- yaml_obj = yaml_utils.safe_load(yaml_content)
2809
-
2802
+ merged_cluster_yaml_obj = copy.deepcopy(cluster_yaml_obj)
2810
2803
  # Get custom_metadata from global config
2811
2804
  custom_metadata = skypilot_config.get_effective_region_config(
2812
2805
  cloud='kubernetes',
@@ -2828,22 +2821,42 @@ def combine_metadata_fields(cluster_yaml_path: str,
2828
2821
  # List of objects in the cluster YAML to be updated
2829
2822
  combination_destinations = [
2830
2823
  # Service accounts
2831
- yaml_obj['provider']['autoscaler_service_account']['metadata'],
2832
- yaml_obj['provider']['autoscaler_role']['metadata'],
2833
- yaml_obj['provider']['autoscaler_role_binding']['metadata'],
2834
- yaml_obj['provider']['autoscaler_service_account']['metadata'],
2835
- # Pod spec
2836
- yaml_obj['available_node_types']['ray_head_default']['node_config']
2824
+ merged_cluster_yaml_obj['provider']['autoscaler_service_account']
2837
2825
  ['metadata'],
2826
+ merged_cluster_yaml_obj['provider']['autoscaler_role']['metadata'],
2827
+ merged_cluster_yaml_obj['provider']['autoscaler_role_binding']
2828
+ ['metadata'],
2829
+ merged_cluster_yaml_obj['provider']['autoscaler_service_account']
2830
+ ['metadata'],
2831
+ # Pod spec
2832
+ merged_cluster_yaml_obj['available_node_types']['ray_head_default']
2833
+ ['node_config']['metadata'],
2838
2834
  # Services for pods
2839
- *[svc['metadata'] for svc in yaml_obj['provider']['services']]
2835
+ *[
2836
+ svc['metadata']
2837
+ for svc in merged_cluster_yaml_obj['provider']['services']
2838
+ ]
2840
2839
  ]
2841
2840
 
2842
2841
  for destination in combination_destinations:
2843
2842
  config_utils.merge_k8s_configs(destination, custom_metadata)
2844
2843
 
2845
- # Write the updated YAML back to the file
2846
- yaml_utils.dump_yaml(cluster_yaml_path, yaml_obj)
2844
+ return merged_cluster_yaml_obj
2845
+
2846
+
2847
+ def combine_pod_config_fields_and_metadata(
2848
+ cluster_yaml_obj: Dict[str, Any],
2849
+ cluster_config_overrides: Dict[str, Any],
2850
+ cloud: Optional[clouds.Cloud] = None,
2851
+ context: Optional[str] = None) -> Dict[str, Any]:
2852
+ """Combines pod config fields and metadata fields"""
2853
+ combined_yaml_obj = combine_pod_config_fields(cluster_yaml_obj,
2854
+ cluster_config_overrides,
2855
+ cloud, context)
2856
+ combined_yaml_obj = combine_metadata_fields(combined_yaml_obj,
2857
+ cluster_config_overrides,
2858
+ context)
2859
+ return combined_yaml_obj
2847
2860
 
2848
2861
 
2849
2862
  def merge_custom_metadata(
@@ -107,8 +107,7 @@ async def tail_logs(
107
107
  request_cluster_name=common.SKY_SERVE_CONTROLLER_NAME,
108
108
  )
109
109
 
110
- request_task = await api_requests.get_request_async(request.state.request_id
111
- )
110
+ request_task = api_requests.get_request(request.state.request_id)
112
111
 
113
112
  return stream_utils.stream_response(
114
113
  request_id=request_task.request_id,
@@ -453,7 +453,7 @@ async def execute_request_coroutine(request: api_requests.Request):
453
453
  **request_body.to_kwargs())
454
454
 
455
455
  async def poll_task(request_id: str) -> bool:
456
- request = await api_requests.get_request_async(request_id)
456
+ request = api_requests.get_request(request_id)
457
457
  if request is None:
458
458
  raise RuntimeError('Request not found')
459
459
 
@@ -309,6 +309,7 @@ class StatusBody(RequestBody):
309
309
  cluster_names: Optional[List[str]] = None
310
310
  refresh: common_lib.StatusRefreshMode = common_lib.StatusRefreshMode.NONE
311
311
  all_users: bool = True
312
+ include_credentials: bool = False
312
313
 
313
314
 
314
315
  class StartBody(RequestBody):
@@ -98,7 +98,7 @@ class Precondition(abc.ABC):
98
98
  return False
99
99
 
100
100
  # Check if the request has been cancelled
101
- request = await api_requests.get_request_async(self.request_id)
101
+ request = api_requests.get_request(self.request_id)
102
102
  if request is None:
103
103
  logger.error(f'Request {self.request_id} not found')
104
104
  return False
@@ -112,8 +112,7 @@ class Precondition(abc.ABC):
112
112
  return True
113
113
  if status_msg is not None and status_msg != last_status_msg:
114
114
  # Update the status message if it has changed.
115
- async with api_requests.update_request_async(
116
- self.request_id) as req:
115
+ with api_requests.update_request(self.request_id) as req:
117
116
  assert req is not None, self.request_id
118
117
  req.status_msg = status_msg
119
118
  last_status_msg = status_msg
@@ -13,8 +13,7 @@ import sqlite3
13
13
  import threading
14
14
  import time
15
15
  import traceback
16
- from typing import (Any, AsyncContextManager, Callable, Dict, Generator, List,
17
- Optional, Tuple)
16
+ from typing import Any, Callable, Dict, Generator, List, Optional, Tuple
18
17
 
19
18
  import colorama
20
19
  import filelock
@@ -403,46 +402,26 @@ _DB = None
403
402
  _init_db_lock = threading.Lock()
404
403
 
405
404
 
406
- def _init_db_within_lock():
407
- global _DB
408
- if _DB is None:
409
- db_path = os.path.expanduser(
410
- server_constants.API_SERVER_REQUEST_DB_PATH)
411
- pathlib.Path(db_path).parents[0].mkdir(parents=True, exist_ok=True)
412
- _DB = db_utils.SQLiteConn(db_path, create_table)
413
-
414
-
415
405
  def init_db(func):
416
406
  """Initialize the database."""
417
407
 
418
408
  @functools.wraps(func)
419
409
  def wrapper(*args, **kwargs):
410
+ global _DB
420
411
  if _DB is not None:
421
412
  return func(*args, **kwargs)
422
413
  with _init_db_lock:
423
- _init_db_within_lock()
414
+ if _DB is None:
415
+ db_path = os.path.expanduser(
416
+ server_constants.API_SERVER_REQUEST_DB_PATH)
417
+ pathlib.Path(db_path).parents[0].mkdir(parents=True,
418
+ exist_ok=True)
419
+ _DB = db_utils.SQLiteConn(db_path, create_table)
424
420
  return func(*args, **kwargs)
425
421
 
426
422
  return wrapper
427
423
 
428
424
 
429
- def init_db_async(func):
430
- """Async version of init_db."""
431
-
432
- @functools.wraps(func)
433
- async def wrapper(*args, **kwargs):
434
- if _DB is not None:
435
- return await func(*args, **kwargs)
436
- # If _DB is not initialized, init_db_async will be blocked if there
437
- # is a thread initializing _DB, this is fine since it occurs on process
438
- # startup.
439
- with _init_db_lock:
440
- _init_db_within_lock()
441
- return await func(*args, **kwargs)
442
-
443
- return wrapper
444
-
445
-
446
425
  def reset_db_and_logs():
447
426
  """Create the database."""
448
427
  server_common.clear_local_api_server_database()
@@ -461,61 +440,28 @@ def request_lock_path(request_id: str) -> str:
461
440
  @contextlib.contextmanager
462
441
  @init_db
463
442
  def update_request(request_id: str) -> Generator[Optional[Request], None, None]:
464
- """Get and update a SkyPilot API request."""
443
+ """Get a SkyPilot API request."""
465
444
  request = _get_request_no_lock(request_id)
466
445
  yield request
467
446
  if request is not None:
468
447
  _add_or_update_request_no_lock(request)
469
448
 
470
449
 
471
- @init_db
472
- def update_request_async(
473
- request_id: str) -> AsyncContextManager[Optional[Request]]:
474
- """Async version of update_request.
475
-
476
- Returns an async context manager that yields the request record and
477
- persists any in-place updates upon exit.
478
- """
479
-
480
- @contextlib.asynccontextmanager
481
- async def _cm():
482
- request = await _get_request_no_lock_async(request_id)
483
- try:
484
- yield request
485
- finally:
486
- if request is not None:
487
- await _add_or_update_request_no_lock_async(request)
488
-
489
- return _cm()
490
-
491
-
492
- _get_request_sql = (f'SELECT {", ".join(REQUEST_COLUMNS)} FROM {REQUEST_TABLE} '
493
- 'WHERE request_id LIKE ?')
494
-
495
-
496
450
  def _get_request_no_lock(request_id: str) -> Optional[Request]:
497
451
  """Get a SkyPilot API request."""
498
452
  assert _DB is not None
453
+ columns_str = ', '.join(REQUEST_COLUMNS)
499
454
  with _DB.conn:
500
455
  cursor = _DB.conn.cursor()
501
- cursor.execute(_get_request_sql, (request_id + '%',))
456
+ cursor.execute(
457
+ f'SELECT {columns_str} FROM {REQUEST_TABLE} '
458
+ 'WHERE request_id LIKE ?', (request_id + '%',))
502
459
  row = cursor.fetchone()
503
460
  if row is None:
504
461
  return None
505
462
  return Request.from_row(row)
506
463
 
507
464
 
508
- async def _get_request_no_lock_async(request_id: str) -> Optional[Request]:
509
- """Async version of _get_request_no_lock."""
510
- assert _DB is not None
511
- conn = await _DB.async_conn()
512
- async with conn.execute(_get_request_sql, (request_id + '%',)) as cursor:
513
- row = await cursor.fetchone()
514
- if row is None:
515
- return None
516
- return Request.from_row(row)
517
-
518
-
519
465
  @init_db
520
466
  def get_latest_request_id() -> Optional[str]:
521
467
  """Get the latest request ID."""
@@ -535,13 +481,6 @@ def get_request(request_id: str) -> Optional[Request]:
535
481
  return _get_request_no_lock(request_id)
536
482
 
537
483
 
538
- @init_db_async
539
- async def get_request_async(request_id: str) -> Optional[Request]:
540
- """Async version of get_request."""
541
- async with filelock.AsyncFileLock(request_lock_path(request_id)):
542
- return await _get_request_no_lock_async(request_id)
543
-
544
-
545
484
  @init_db
546
485
  def create_if_not_exists(request: Request) -> bool:
547
486
  """Create a SkyPilot API request if it does not exist."""
@@ -552,16 +491,6 @@ def create_if_not_exists(request: Request) -> bool:
552
491
  return True
553
492
 
554
493
 
555
- @init_db_async
556
- async def create_if_not_exists_async(request: Request) -> bool:
557
- """Async version of create_if_not_exists."""
558
- async with filelock.AsyncFileLock(request_lock_path(request.request_id)):
559
- if await _get_request_no_lock_async(request.request_id) is not None:
560
- return False
561
- await _add_or_update_request_no_lock_async(request)
562
- return True
563
-
564
-
565
494
  @init_db
566
495
  def get_request_tasks(
567
496
  status: Optional[List[RequestStatus]] = None,
@@ -636,15 +565,16 @@ def get_request_tasks(
636
565
  return requests
637
566
 
638
567
 
639
- @init_db_async
640
- async def get_api_request_ids_start_with(incomplete: str) -> List[str]:
568
+ @init_db
569
+ def get_api_request_ids_start_with(incomplete: str) -> List[str]:
641
570
  """Get a list of API request ids for shell completion."""
642
571
  assert _DB is not None
643
- conn = await _DB.async_conn()
644
- # Prioritize alive requests (PENDING, RUNNING) over finished ones,
645
- # then order by creation time (newest first) within each category.
646
- async with conn.execute(
647
- f"""SELECT request_id FROM {REQUEST_TABLE}
572
+ with _DB.conn:
573
+ cursor = _DB.conn.cursor()
574
+ # Prioritize alive requests (PENDING, RUNNING) over finished ones,
575
+ # then order by creation time (newest first) within each category.
576
+ cursor.execute(
577
+ f"""SELECT request_id FROM {REQUEST_TABLE}
648
578
  WHERE request_id LIKE ?
649
579
  ORDER BY
650
580
  CASE
@@ -652,32 +582,21 @@ async def get_api_request_ids_start_with(incomplete: str) -> List[str]:
652
582
  ELSE 1
653
583
  END,
654
584
  created_at DESC
655
- LIMIT 1000""", (f'{incomplete}%',)) as cursor:
656
- rows = await cursor.fetchall()
657
- if rows is None:
658
- return []
659
- return [row[0] for row in rows]
660
-
661
-
662
- _add_or_update_request_sql = (f'INSERT OR REPLACE INTO {REQUEST_TABLE} '
663
- f'({", ".join(REQUEST_COLUMNS)}) VALUES '
664
- f'({", ".join(["?"] * len(REQUEST_COLUMNS))})')
585
+ LIMIT 1000""", (f'{incomplete}%',))
586
+ return [row[0] for row in cursor.fetchall()]
665
587
 
666
588
 
667
589
  def _add_or_update_request_no_lock(request: Request):
668
590
  """Add or update a REST request into the database."""
591
+ row = request.to_row()
592
+ key_str = ', '.join(REQUEST_COLUMNS)
593
+ fill_str = ', '.join(['?'] * len(row))
669
594
  assert _DB is not None
670
595
  with _DB.conn:
671
596
  cursor = _DB.conn.cursor()
672
- cursor.execute(_add_or_update_request_sql, request.to_row())
673
-
674
-
675
- async def _add_or_update_request_no_lock_async(request: Request):
676
- """Async version of _add_or_update_request_no_lock."""
677
- assert _DB is not None
678
- conn = await _DB.async_conn()
679
- await conn.execute(_add_or_update_request_sql, request.to_row())
680
- await conn.commit()
597
+ cursor.execute(
598
+ f'INSERT OR REPLACE INTO {REQUEST_TABLE} ({key_str}) '
599
+ f'VALUES ({fill_str})', row)
681
600
 
682
601
 
683
602
  def set_request_failed(request_id: str, e: BaseException) -> None:
sky/server/server.py CHANGED
@@ -1397,7 +1397,7 @@ async def local_down(request: fastapi.Request) -> None:
1397
1397
  async def api_get(request_id: str) -> payloads.RequestPayload:
1398
1398
  """Gets a request with a given request ID prefix."""
1399
1399
  while True:
1400
- request_task = await requests_lib.get_request_async(request_id)
1400
+ request_task = requests_lib.get_request(request_id)
1401
1401
  if request_task is None:
1402
1402
  print(f'No task with request ID {request_id}', flush=True)
1403
1403
  raise fastapi.HTTPException(
@@ -1486,7 +1486,7 @@ async def stream(
1486
1486
 
1487
1487
  # Original plain text streaming logic
1488
1488
  if request_id is not None:
1489
- request_task = await requests_lib.get_request_async(request_id)
1489
+ request_task = requests_lib.get_request(request_id)
1490
1490
  if request_task is None:
1491
1491
  print(f'No task with request ID {request_id}')
1492
1492
  raise fastapi.HTTPException(
@@ -1581,7 +1581,7 @@ async def api_status(
1581
1581
  else:
1582
1582
  encoded_request_tasks = []
1583
1583
  for request_id in request_ids:
1584
- request_task = await requests_lib.get_request_async(request_id)
1584
+ request_task = requests_lib.get_request(request_id)
1585
1585
  if request_task is None:
1586
1586
  continue
1587
1587
  encoded_request_tasks.append(request_task.readable_encode())
@@ -1791,7 +1791,7 @@ async def complete_volume_name(incomplete: str,) -> List[str]:
1791
1791
 
1792
1792
  @app.get('/api/completion/api_request')
1793
1793
  async def complete_api_request(incomplete: str,) -> List[str]:
1794
- return await requests_lib.get_api_request_ids_start_with(incomplete)
1794
+ return requests_lib.get_api_request_ids_start_with(incomplete)
1795
1795
 
1796
1796
 
1797
1797
  @app.get('/dashboard/{full_path:path}')
@@ -56,7 +56,7 @@ async def log_streamer(request_id: Optional[str],
56
56
  if request_id is not None:
57
57
  status_msg = rich_utils.EncodedStatusMessage(
58
58
  f'[dim]Checking request: {request_id}[/dim]')
59
- request_task = await requests_lib.get_request_async(request_id)
59
+ request_task = requests_lib.get_request(request_id)
60
60
 
61
61
  if request_task is None:
62
62
  raise fastapi.HTTPException(
@@ -86,12 +86,10 @@ async def log_streamer(request_id: Optional[str],
86
86
  # Use smaller padding (1024 bytes) to force browser rendering
87
87
  yield f'{waiting_msg}' + ' ' * 4096 + '\n'
88
88
  # Sleep shortly to avoid storming the DB and CPU and allow other
89
- # coroutines to run.
90
- # TODO(aylei): we should use a better mechanism to avoid busy
91
- # polling the DB, which can be a bottleneck for high-concurrency
92
- # requests.
89
+ # coroutines to run. This busy waiting loop is performance critical
90
+ # for short-running requests, so we do not want to yield too long.
93
91
  await asyncio.sleep(0.1)
94
- request_task = await requests_lib.get_request_async(request_id)
92
+ request_task = requests_lib.get_request(request_id)
95
93
  if not follow:
96
94
  break
97
95
  if show_request_waiting_spinner:
@@ -153,7 +151,7 @@ async def _tail_log_file(f: aiofiles.threadpool.binary.AsyncBufferedReader,
153
151
  line: Optional[bytes] = await f.readline()
154
152
  if not line:
155
153
  if request_id is not None:
156
- request_task = await requests_lib.get_request_async(request_id)
154
+ request_task = requests_lib.get_request(request_id)
157
155
  if request_task.status > requests_lib.RequestStatus.RUNNING:
158
156
  if (request_task.status ==
159
157
  requests_lib.RequestStatus.CANCELLED):
@@ -8,8 +8,12 @@ This file is imported by setup.py, so:
8
8
  import sys
9
9
  from typing import Dict, List
10
10
 
11
+ clouds_with_ray = ['ibm', 'docker', 'scp']
12
+
11
13
  install_requires = [
12
14
  'wheel<0.46.0', # https://github.com/skypilot-org/skypilot/issues/5153
15
+ 'setuptools', # TODO: match version to pyproject.toml once #5153 is fixed
16
+ 'pip',
13
17
  'cachetools',
14
18
  # NOTE: ray requires click>=7.0.
15
19
  # click 8.2.0 has a bug in parsing the command line arguments:
@@ -35,8 +39,7 @@ install_requires = [
35
39
  # Light weight requirement, can be replaced with "typing" once
36
40
  # we deprecate Python 3.7 (this will take a while).
37
41
  'typing_extensions',
38
- # filelock 3.15.0 or higher is required for async file locking.
39
- 'filelock >= 3.15.0',
42
+ 'filelock >= 3.6.0',
40
43
  'packaging',
41
44
  'psutil',
42
45
  'pulp',
@@ -72,7 +75,6 @@ install_requires = [
72
75
  'types-paramiko',
73
76
  'alembic',
74
77
  'aiohttp',
75
- 'aiosqlite',
76
78
  'anyio',
77
79
  ]
78
80
 
@@ -98,7 +100,6 @@ server_dependencies = [
98
100
  'anyio',
99
101
  GRPC,
100
102
  PROTOBUF,
101
- 'aiosqlite',
102
103
  ]
103
104
 
104
105
  local_ray = [
@@ -148,7 +149,7 @@ extras_require: Dict[str, List[str]] = {
148
149
  'azure-storage-blob>=12.23.1',
149
150
  'msgraph-sdk',
150
151
  'msrestazure',
151
- ] + local_ray,
152
+ ],
152
153
  # We need google-api-python-client>=2.69.0 to enable 'discardLocalSsd'
153
154
  # parameter for stopping instances. Reference:
154
155
  # https://github.com/googleapis/google-api-python-client/commit/f6e9d3869ed605b06f7cbf2e8cf2db25108506e6
@@ -169,7 +170,7 @@ extras_require: Dict[str, List[str]] = {
169
170
  'lambda': [], # No dependencies needed for lambda
170
171
  'cloudflare': aws_dependencies,
171
172
  'scp': local_ray,
172
- 'oci': ['oci'] + local_ray,
173
+ 'oci': ['oci'],
173
174
  # Kubernetes 32.0.0 has an authentication bug: https://github.com/kubernetes-client/python/issues/2333 # pylint: disable=line-too-long
174
175
  'kubernetes': [
175
176
  'kubernetes>=20.0.0,!=32.0.0', 'websockets', 'python-dateutil'
@@ -200,10 +201,21 @@ extras_require: Dict[str, List[str]] = {
200
201
  'server': server_dependencies,
201
202
  }
202
203
 
203
- # Nebius needs python3.10. If python 3.9 [all] will not install nebius
204
+ # Calculate which clouds should be included in the [all] installation.
205
+ clouds_for_all = set(extras_require)
206
+ clouds_for_all.remove('remote')
207
+
204
208
  if sys.version_info < (3, 10):
205
- filtered_keys = [k for k in extras_require if k != 'nebius']
206
- extras_require['all'] = sum(
207
- [v for k, v in extras_require.items() if k != 'nebius'], [])
208
- else:
209
- extras_require['all'] = sum(extras_require.values(), [])
209
+ # Nebius needs python3.10. If python 3.9 [all] will not install nebius
210
+ clouds_for_all.remove('nebius')
211
+
212
+ if sys.version_info >= (3, 12):
213
+ # The version of ray we use does not work with >= 3.12, so avoid clouds
214
+ # that require ray.
215
+ clouds_for_all -= set(clouds_with_ray)
216
+ # vast requires setuptools==51.1.1 which will not work with python >= 3.12
217
+ # TODO: Remove once https://github.com/vast-ai/vast-sdk/pull/6 is released
218
+ clouds_for_all.remove('vast')
219
+
220
+ extras_require['all'] = list(
221
+ set().union(*[extras_require[cloud] for cloud in clouds_for_all]))