skypilot-nightly 1.0.0.dev20250806__py3-none-any.whl → 1.0.0.dev20250807__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 (123) hide show
  1. sky/__init__.py +2 -2
  2. sky/backends/cloud_vm_ray_backend.py +33 -4
  3. sky/check.py +11 -1
  4. sky/client/cli/command.py +208 -93
  5. sky/client/sdk.py +14 -1
  6. sky/client/sdk_async.py +4 -0
  7. sky/dashboard/out/404.html +1 -1
  8. sky/dashboard/out/_next/static/YAirOGsV1z6B2RJ0VIUmD/_buildManifest.js +1 -0
  9. sky/dashboard/out/_next/static/chunks/1141-a8a8f1adba34c892.js +11 -0
  10. sky/dashboard/out/_next/static/chunks/1871-980a395e92633a5c.js +6 -0
  11. sky/dashboard/out/_next/static/chunks/3785.6003d293cb83eab4.js +1 -0
  12. sky/dashboard/out/_next/static/chunks/3850-ff4a9a69d978632b.js +1 -0
  13. sky/dashboard/out/_next/static/chunks/4725.29550342bd53afd8.js +1 -0
  14. sky/dashboard/out/_next/static/chunks/{4937.d6bf67771e353356.js → 4937.a2baa2df5572a276.js} +1 -1
  15. sky/dashboard/out/_next/static/chunks/6130-2be46d70a38f1e82.js +1 -0
  16. sky/dashboard/out/_next/static/chunks/6601-3e21152fe16da09c.js +1 -0
  17. sky/dashboard/out/_next/static/chunks/{691.6d99cbfba347cebf.js → 691.5eeedf82cc243343.js} +1 -1
  18. sky/dashboard/out/_next/static/chunks/6989-6129c1cfbcf51063.js +1 -0
  19. sky/dashboard/out/_next/static/chunks/6990-0f886f16e0d55ff8.js +1 -0
  20. sky/dashboard/out/_next/static/chunks/8056-019615038d6ce427.js +1 -0
  21. sky/dashboard/out/_next/static/chunks/8252.62b0d23aed618bb2.js +16 -0
  22. sky/dashboard/out/_next/static/chunks/8969-318c3dca725e8e5d.js +1 -0
  23. sky/dashboard/out/_next/static/chunks/9025.a1bef12d672bb66d.js +6 -0
  24. sky/dashboard/out/_next/static/chunks/9159-11421c0f2909236f.js +1 -0
  25. sky/dashboard/out/_next/static/chunks/9360.85b0b1b4054574dd.js +31 -0
  26. sky/dashboard/out/_next/static/chunks/9666.cd4273f2a5c5802c.js +1 -0
  27. sky/dashboard/out/_next/static/chunks/{9847.4c46c5e229c78704.js → 9847.757720f3b40c0aa5.js} +1 -1
  28. sky/dashboard/out/_next/static/chunks/pages/{_app-2a43ea3241bbdacd.js → _app-1e6de35d15a8d432.js} +1 -1
  29. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-6fd1d2d8441aa54b.js +11 -0
  30. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-155d477a6c3e04e2.js +1 -0
  31. sky/dashboard/out/_next/static/chunks/pages/{clusters-47f1ddae13a2f8e4.js → clusters-b30460f683e6ba96.js} +1 -1
  32. sky/dashboard/out/_next/static/chunks/pages/config-dfb9bf07b13045f4.js +1 -0
  33. sky/dashboard/out/_next/static/chunks/pages/infra/{[context]-2a44e70b500b6b70.js → [context]-13d53fffc03ccb52.js} +1 -1
  34. sky/dashboard/out/_next/static/chunks/pages/{infra-22faac9325016d83.js → infra-fc9222e26c8e2f0d.js} +1 -1
  35. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-154f55cf8af55be5.js +11 -0
  36. sky/dashboard/out/_next/static/chunks/pages/jobs/pools/[pool]-f5ccf5d39d87aebe.js +21 -0
  37. sky/dashboard/out/_next/static/chunks/pages/jobs-cdc60fb5d371e16a.js +1 -0
  38. sky/dashboard/out/_next/static/chunks/pages/{users-b90c865a690bfe84.js → users-7ed36e44e779d5c7.js} +1 -1
  39. sky/dashboard/out/_next/static/chunks/pages/{volumes-7af733f5d7b6ed1c.js → volumes-c9695d657f78b5dc.js} +1 -1
  40. sky/dashboard/out/_next/static/chunks/pages/workspace/new-3f88a1c7e86a3f86.js +1 -0
  41. sky/dashboard/out/_next/static/chunks/pages/workspaces/[name]-f72f73bcef9541dc.js +1 -0
  42. sky/dashboard/out/_next/static/chunks/pages/workspaces-8f67be60165724cc.js +1 -0
  43. sky/dashboard/out/_next/static/chunks/webpack-76efbdad99742559.js +1 -0
  44. sky/dashboard/out/_next/static/css/4614e06482d7309e.css +3 -0
  45. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  46. sky/dashboard/out/clusters/[cluster].html +1 -1
  47. sky/dashboard/out/clusters.html +1 -1
  48. sky/dashboard/out/config.html +1 -1
  49. sky/dashboard/out/index.html +1 -1
  50. sky/dashboard/out/infra/[context].html +1 -1
  51. sky/dashboard/out/infra.html +1 -1
  52. sky/dashboard/out/jobs/[job].html +1 -1
  53. sky/dashboard/out/jobs/pools/[pool].html +1 -0
  54. sky/dashboard/out/jobs.html +1 -1
  55. sky/dashboard/out/users.html +1 -1
  56. sky/dashboard/out/volumes.html +1 -1
  57. sky/dashboard/out/workspace/new.html +1 -1
  58. sky/dashboard/out/workspaces/[name].html +1 -1
  59. sky/dashboard/out/workspaces.html +1 -1
  60. sky/global_user_state.py +14 -2
  61. sky/jobs/__init__.py +2 -0
  62. sky/jobs/client/sdk.py +43 -2
  63. sky/jobs/server/core.py +48 -1
  64. sky/jobs/server/server.py +52 -3
  65. sky/jobs/state.py +5 -1
  66. sky/schemas/db/global_user_state/002_add_workspace_to_cluster_history.py +35 -0
  67. sky/schemas/db/spot_jobs/003_pool_hash.py +34 -0
  68. sky/serve/client/impl.py +85 -1
  69. sky/serve/client/sdk.py +16 -47
  70. sky/serve/constants.py +2 -1
  71. sky/serve/controller.py +4 -2
  72. sky/serve/serve_state.py +28 -5
  73. sky/serve/serve_utils.py +77 -46
  74. sky/serve/server/core.py +13 -197
  75. sky/serve/server/impl.py +239 -2
  76. sky/serve/service.py +8 -3
  77. sky/server/common.py +11 -4
  78. sky/server/constants.py +1 -1
  79. sky/server/requests/executor.py +5 -3
  80. sky/server/requests/payloads.py +19 -0
  81. sky/task.py +18 -11
  82. sky/templates/kubernetes-ray.yml.j2 +5 -0
  83. sky/templates/sky-serve-controller.yaml.j2 +1 -0
  84. sky/usage/usage_lib.py +8 -6
  85. sky/utils/annotations.py +8 -3
  86. sky/utils/common_utils.py +11 -1
  87. sky/utils/db/migration_utils.py +2 -2
  88. {skypilot_nightly-1.0.0.dev20250806.dist-info → skypilot_nightly-1.0.0.dev20250807.dist-info}/METADATA +18 -13
  89. {skypilot_nightly-1.0.0.dev20250806.dist-info → skypilot_nightly-1.0.0.dev20250807.dist-info}/RECORD +95 -92
  90. sky/client/sdk.pyi +0 -301
  91. sky/dashboard/out/_next/static/Gelsd19kVxXcX7aQQGsGu/_buildManifest.js +0 -1
  92. sky/dashboard/out/_next/static/chunks/1043-75af48ca5d5aaf57.js +0 -1
  93. sky/dashboard/out/_next/static/chunks/1141-8678a9102cc5f67e.js +0 -11
  94. sky/dashboard/out/_next/static/chunks/1664-22b00e32c9ff96a4.js +0 -1
  95. sky/dashboard/out/_next/static/chunks/1871-ced1c14230cad6e1.js +0 -6
  96. sky/dashboard/out/_next/static/chunks/2003.f90b06bb1f914295.js +0 -1
  97. sky/dashboard/out/_next/static/chunks/2350.fab69e61bac57b23.js +0 -1
  98. sky/dashboard/out/_next/static/chunks/2622-951867535095b0eb.js +0 -1
  99. sky/dashboard/out/_next/static/chunks/3785.0a173cd4393f0fef.js +0 -1
  100. sky/dashboard/out/_next/static/chunks/4725.42f21f250f91f65b.js +0 -1
  101. sky/dashboard/out/_next/static/chunks/4869.18e6a4361a380763.js +0 -16
  102. sky/dashboard/out/_next/static/chunks/5230-f3bb2663e442e86c.js +0 -1
  103. sky/dashboard/out/_next/static/chunks/6601-2109d22e7861861c.js +0 -1
  104. sky/dashboard/out/_next/static/chunks/6990-08b2a1cae076a943.js +0 -1
  105. sky/dashboard/out/_next/static/chunks/8969-9a8cca241b30db83.js +0 -1
  106. sky/dashboard/out/_next/static/chunks/9025.99f29acb7617963e.js +0 -6
  107. sky/dashboard/out/_next/static/chunks/938-bda2685db5eae6cf.js +0 -1
  108. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-7cb24da04ca00956.js +0 -11
  109. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-1e95993124dbfc57.js +0 -1
  110. sky/dashboard/out/_next/static/chunks/pages/config-d56e64f30db7b42e.js +0 -1
  111. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-90693cb88b5599a7.js +0 -11
  112. sky/dashboard/out/_next/static/chunks/pages/jobs-ab318e52eb4424a7.js +0 -1
  113. sky/dashboard/out/_next/static/chunks/pages/workspace/new-92f741084a89e27b.js +0 -1
  114. sky/dashboard/out/_next/static/chunks/pages/workspaces/[name]-35e0de5bca55e594.js +0 -1
  115. sky/dashboard/out/_next/static/chunks/pages/workspaces-062525fb5462acb6.js +0 -1
  116. sky/dashboard/out/_next/static/chunks/webpack-387626669badf82e.js +0 -1
  117. sky/dashboard/out/_next/static/css/b3227360726f12eb.css +0 -3
  118. /sky/dashboard/out/_next/static/{Gelsd19kVxXcX7aQQGsGu → YAirOGsV1z6B2RJ0VIUmD}/_ssgManifest.js +0 -0
  119. /sky/dashboard/out/_next/static/chunks/{6135-2d7ed3350659d073.js → 6135-85426374db04811e.js} +0 -0
  120. {skypilot_nightly-1.0.0.dev20250806.dist-info → skypilot_nightly-1.0.0.dev20250807.dist-info}/WHEEL +0 -0
  121. {skypilot_nightly-1.0.0.dev20250806.dist-info → skypilot_nightly-1.0.0.dev20250807.dist-info}/entry_points.txt +0 -0
  122. {skypilot_nightly-1.0.0.dev20250806.dist-info → skypilot_nightly-1.0.0.dev20250807.dist-info}/licenses/LICENSE +0 -0
  123. {skypilot_nightly-1.0.0.dev20250806.dist-info → skypilot_nightly-1.0.0.dev20250807.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/b3227360726f12eb.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/b3227360726f12eb.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-387626669badf82e.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-2a43ea3241bbdacd.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-3d59f75e2ccf9321.js" defer=""></script><script src="/dashboard/_next/static/chunks/5230-f3bb2663e442e86c.js" defer=""></script><script src="/dashboard/_next/static/chunks/5739-d67458fcb1386c92.js" defer=""></script><script src="/dashboard/_next/static/chunks/1664-22b00e32c9ff96a4.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/6212-7bd06f60ba693125.js" defer=""></script><script src="/dashboard/_next/static/chunks/2622-951867535095b0eb.js" defer=""></script><script src="/dashboard/_next/static/chunks/6135-2d7ed3350659d073.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-9a8cca241b30db83.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs/%5Bjob%5D-90693cb88b5599a7.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs/[job]","query":{},"buildId":"Gelsd19kVxXcX7aQQGsGu","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-76efbdad99742559.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-1e6de35d15a8d432.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/6212-7bd06f60ba693125.js" defer=""></script><script src="/dashboard/_next/static/chunks/6989-6129c1cfbcf51063.js" defer=""></script><script src="/dashboard/_next/static/chunks/3850-ff4a9a69d978632b.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-318c3dca725e8e5d.js" defer=""></script><script src="/dashboard/_next/static/chunks/6135-85426374db04811e.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs/%5Bjob%5D-154f55cf8af55be5.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs/[job]","query":{},"buildId":"YAirOGsV1z6B2RJ0VIUmD","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
@@ -0,0 +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-76efbdad99742559.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-1e6de35d15a8d432.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/1272-1ef0bf0237faccdb.js" defer=""></script><script src="/dashboard/_next/static/chunks/6212-7bd06f60ba693125.js" defer=""></script><script src="/dashboard/_next/static/chunks/6989-6129c1cfbcf51063.js" defer=""></script><script src="/dashboard/_next/static/chunks/3850-ff4a9a69d978632b.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-318c3dca725e8e5d.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs/pools/%5Bpool%5D-f5ccf5d39d87aebe.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs/pools/[pool]","query":{},"buildId":"YAirOGsV1z6B2RJ0VIUmD","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/b3227360726f12eb.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/b3227360726f12eb.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-387626669badf82e.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-2a43ea3241bbdacd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs-ab318e52eb4424a7.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs","query":{},"buildId":"Gelsd19kVxXcX7aQQGsGu","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-76efbdad99742559.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-1e6de35d15a8d432.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs-cdc60fb5d371e16a.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs","query":{},"buildId":"YAirOGsV1z6B2RJ0VIUmD","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/b3227360726f12eb.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/b3227360726f12eb.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-387626669badf82e.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-2a43ea3241bbdacd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/users-b90c865a690bfe84.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/users","query":{},"buildId":"Gelsd19kVxXcX7aQQGsGu","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-76efbdad99742559.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-1e6de35d15a8d432.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/users-7ed36e44e779d5c7.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/users","query":{},"buildId":"YAirOGsV1z6B2RJ0VIUmD","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/b3227360726f12eb.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/b3227360726f12eb.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-387626669badf82e.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-2a43ea3241bbdacd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/volumes-7af733f5d7b6ed1c.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/volumes","query":{},"buildId":"Gelsd19kVxXcX7aQQGsGu","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-76efbdad99742559.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-1e6de35d15a8d432.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/volumes-c9695d657f78b5dc.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/volumes","query":{},"buildId":"YAirOGsV1z6B2RJ0VIUmD","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/b3227360726f12eb.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/b3227360726f12eb.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-387626669badf82e.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-2a43ea3241bbdacd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspace/new-92f741084a89e27b.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspace/new","query":{},"buildId":"Gelsd19kVxXcX7aQQGsGu","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-76efbdad99742559.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-1e6de35d15a8d432.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspace/new-3f88a1c7e86a3f86.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspace/new","query":{},"buildId":"YAirOGsV1z6B2RJ0VIUmD","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/b3227360726f12eb.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/b3227360726f12eb.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-387626669badf82e.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-2a43ea3241bbdacd.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-3d59f75e2ccf9321.js" defer=""></script><script src="/dashboard/_next/static/chunks/5230-f3bb2663e442e86c.js" defer=""></script><script src="/dashboard/_next/static/chunks/5739-d67458fcb1386c92.js" defer=""></script><script src="/dashboard/_next/static/chunks/1664-22b00e32c9ff96a4.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/1559-6c00e20454194859.js" defer=""></script><script src="/dashboard/_next/static/chunks/2622-951867535095b0eb.js" defer=""></script><script src="/dashboard/_next/static/chunks/6135-2d7ed3350659d073.js" defer=""></script><script src="/dashboard/_next/static/chunks/6990-08b2a1cae076a943.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-9a8cca241b30db83.js" defer=""></script><script src="/dashboard/_next/static/chunks/1043-75af48ca5d5aaf57.js" defer=""></script><script src="/dashboard/_next/static/chunks/6601-2109d22e7861861c.js" defer=""></script><script src="/dashboard/_next/static/chunks/938-bda2685db5eae6cf.js" defer=""></script><script src="/dashboard/_next/static/chunks/1141-8678a9102cc5f67e.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces/%5Bname%5D-35e0de5bca55e594.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"Gelsd19kVxXcX7aQQGsGu","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-76efbdad99742559.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-1e6de35d15a8d432.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/1559-6c00e20454194859.js" defer=""></script><script src="/dashboard/_next/static/chunks/6989-6129c1cfbcf51063.js" defer=""></script><script src="/dashboard/_next/static/chunks/3850-ff4a9a69d978632b.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-318c3dca725e8e5d.js" defer=""></script><script src="/dashboard/_next/static/chunks/6990-0f886f16e0d55ff8.js" defer=""></script><script src="/dashboard/_next/static/chunks/8056-019615038d6ce427.js" defer=""></script><script src="/dashboard/_next/static/chunks/6135-85426374db04811e.js" defer=""></script><script src="/dashboard/_next/static/chunks/6601-3e21152fe16da09c.js" defer=""></script><script src="/dashboard/_next/static/chunks/9159-11421c0f2909236f.js" defer=""></script><script src="/dashboard/_next/static/chunks/1141-a8a8f1adba34c892.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces/%5Bname%5D-f72f73bcef9541dc.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"YAirOGsV1z6B2RJ0VIUmD","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/b3227360726f12eb.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/b3227360726f12eb.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-387626669badf82e.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-2a43ea3241bbdacd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces-062525fb5462acb6.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/Gelsd19kVxXcX7aQQGsGu/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"Gelsd19kVxXcX7aQQGsGu","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-76efbdad99742559.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-1e6de35d15a8d432.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces-8f67be60165724cc.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/YAirOGsV1z6B2RJ0VIUmD/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"YAirOGsV1z6B2RJ0VIUmD","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
sky/global_user_state.py CHANGED
@@ -158,6 +158,7 @@ cluster_history_table = sqlalchemy.Table(
158
158
  sqlalchemy.Column('last_creation_command',
159
159
  sqlalchemy.Text,
160
160
  server_default=None),
161
+ sqlalchemy.Column('workspace', sqlalchemy.Text, server_default=None),
161
162
  )
162
163
 
163
164
  ssh_key_table = sqlalchemy.Table(
@@ -476,6 +477,8 @@ def add_or_update_cluster(cluster_name: str,
476
477
 
477
478
  user_hash = common_utils.get_current_user().id
478
479
  active_workspace = skypilot_config.get_active_workspace()
480
+ history_workspace = active_workspace
481
+ history_hash = user_hash
479
482
 
480
483
  conditional_values = {}
481
484
  if is_launch:
@@ -560,6 +563,10 @@ def add_or_update_cluster(cluster_name: str,
560
563
  # Modify cluster history table
561
564
  launched_nodes = getattr(cluster_handle, 'launched_nodes', None)
562
565
  launched_resources = getattr(cluster_handle, 'launched_resources', None)
566
+ if cluster_row and cluster_row.workspace:
567
+ history_workspace = cluster_row.workspace
568
+ if cluster_row and cluster_row.user_hash:
569
+ history_hash = cluster_row.user_hash
563
570
  creation_info = {}
564
571
  if conditional_values.get('last_creation_yaml') is not None:
565
572
  creation_info = {
@@ -577,6 +584,7 @@ def add_or_update_cluster(cluster_name: str,
577
584
  launched_resources=pickle.dumps(launched_resources),
578
585
  usage_intervals=pickle.dumps(usage_intervals),
579
586
  user_hash=user_hash,
587
+ workspace=history_workspace,
580
588
  **creation_info,
581
589
  )
582
590
  do_update_stmt = insert_stmnt.on_conflict_do_update(
@@ -590,7 +598,8 @@ def add_or_update_cluster(cluster_name: str,
590
598
  pickle.dumps(launched_resources),
591
599
  cluster_history_table.c.usage_intervals:
592
600
  pickle.dumps(usage_intervals),
593
- cluster_history_table.c.user_hash: user_hash,
601
+ cluster_history_table.c.user_hash: history_hash,
602
+ cluster_history_table.c.workspace: history_workspace,
594
603
  **creation_info,
595
604
  })
596
605
  session.execute(do_update_stmt)
@@ -1026,6 +1035,7 @@ def get_clusters_from_history(
1026
1035
  cluster_history_table.c.user_hash,
1027
1036
  cluster_history_table.c.last_creation_yaml,
1028
1037
  cluster_history_table.c.last_creation_command,
1038
+ cluster_history_table.c.workspace.label('history_workspace'),
1029
1039
  cluster_table.c.status, cluster_table.c.workspace,
1030
1040
  cluster_table.c.status_updated_at).select_from(
1031
1041
  cluster_history_table.join(cluster_table,
@@ -1096,6 +1106,8 @@ def get_clusters_from_history(
1096
1106
  # Get user name from user hash
1097
1107
  user = get_user(user_hash)
1098
1108
  user_name = user.name if user is not None else None
1109
+ workspace = (row.history_workspace
1110
+ if row.history_workspace else row.workspace)
1099
1111
 
1100
1112
  record = {
1101
1113
  'name': row.name,
@@ -1108,7 +1120,7 @@ def get_clusters_from_history(
1108
1120
  'status': status,
1109
1121
  'user_hash': user_hash,
1110
1122
  'user_name': user_name,
1111
- 'workspace': row.workspace,
1123
+ 'workspace': workspace,
1112
1124
  'last_creation_yaml': row.last_creation_yaml,
1113
1125
  'last_creation_command': row.last_creation_command,
1114
1126
  }
sky/jobs/__init__.py CHANGED
@@ -8,6 +8,8 @@ from sky.jobs.client.sdk import launch
8
8
  from sky.jobs.client.sdk import pool_apply
9
9
  from sky.jobs.client.sdk import pool_down
10
10
  from sky.jobs.client.sdk import pool_status
11
+ from sky.jobs.client.sdk import pool_sync_down_logs
12
+ from sky.jobs.client.sdk import pool_tail_logs
11
13
  from sky.jobs.client.sdk import queue
12
14
  from sky.jobs.client.sdk import tail_logs
13
15
  from sky.jobs.constants import JOBS_CLUSTER_NAME_PREFIX_LENGTH
sky/jobs/client/sdk.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """SDK functions for managed jobs."""
2
2
  import json
3
3
  import typing
4
- from typing import Dict, List, Optional, Union
4
+ from typing import Dict, List, Optional, Sequence, Union
5
5
 
6
6
  import click
7
7
 
@@ -186,7 +186,7 @@ def queue(refresh: bool,
186
186
  @server_common.check_server_healthy_or_start
187
187
  def cancel(
188
188
  name: Optional[str] = None,
189
- job_ids: Optional[List[int]] = None,
189
+ job_ids: Optional[Sequence[int]] = None,
190
190
  all: bool = False, # pylint: disable=redefined-builtin
191
191
  all_users: bool = False,
192
192
  pool: Optional[str] = None,
@@ -408,3 +408,44 @@ def pool_status(
408
408
  pool_names: Optional[Union[str, List[str]]],) -> server_common.RequestId:
409
409
  """Query a pool."""
410
410
  return impl.status(pool_names, pool=True)
411
+
412
+
413
+ @usage_lib.entrypoint
414
+ @server_common.check_server_healthy_or_start
415
+ @rest.retry_transient_errors()
416
+ @versions.minimal_api_version(13)
417
+ def pool_tail_logs(pool_name: str,
418
+ target: Union[str, 'serve_utils.ServiceComponent'],
419
+ worker_id: Optional[int] = None,
420
+ follow: bool = True,
421
+ output_stream: Optional['io.TextIOBase'] = None,
422
+ tail: Optional[int] = None) -> None:
423
+ """Tails logs of a pool."""
424
+ return impl.tail_logs(pool_name,
425
+ target,
426
+ worker_id,
427
+ follow,
428
+ output_stream,
429
+ tail,
430
+ pool=True)
431
+
432
+
433
+ @usage_lib.entrypoint
434
+ @server_common.check_server_healthy_or_start
435
+ @rest.retry_transient_errors()
436
+ @versions.minimal_api_version(13)
437
+ def pool_sync_down_logs(pool_name: str,
438
+ local_dir: str,
439
+ *,
440
+ targets: Optional[Union[
441
+ str, 'serve_utils.ServiceComponent', Sequence[Union[
442
+ str, 'serve_utils.ServiceComponent']]]] = None,
443
+ worker_ids: Optional[List[int]] = None,
444
+ tail: Optional[int] = None) -> None:
445
+ """Sync down logs of a pool."""
446
+ return impl.sync_down_logs(pool_name,
447
+ local_dir,
448
+ targets=targets,
449
+ replica_ids=worker_ids,
450
+ tail=tail,
451
+ pool=True)
sky/jobs/server/core.py CHANGED
@@ -24,6 +24,7 @@ from sky.jobs import constants as managed_job_constants
24
24
  from sky.jobs import state as managed_job_state
25
25
  from sky.jobs import utils as managed_job_utils
26
26
  from sky.provision import common as provision_common
27
+ from sky.serve import serve_state
27
28
  from sky.serve import serve_utils
28
29
  from sky.serve.server import impl
29
30
  from sky.skylet import constants as skylet_constants
@@ -108,6 +109,11 @@ def _maybe_submit_job_locally(prefix: str, dag: 'sky.Dag', pool: Optional[str],
108
109
  # Create local directory for the managed job.
109
110
  pathlib.Path(prefix).expanduser().mkdir(parents=True, exist_ok=True)
110
111
  job_ids = []
112
+ pool_hash = None
113
+ if pool is not None:
114
+ pool_hash = serve_state.get_service_hash(pool)
115
+ # Already checked in the sdk.
116
+ assert pool_hash is not None, f'Pool {pool} not found'
111
117
  for _ in range(num_jobs if num_jobs is not None else 1):
112
118
  # TODO(tian): We should have a separate name for each job when
113
119
  # submitting multiple jobs. Current blocker is that we are sharing
@@ -121,7 +127,8 @@ def _maybe_submit_job_locally(prefix: str, dag: 'sky.Dag', pool: Optional[str],
121
127
  workspace=skypilot_config.get_active_workspace(
122
128
  force_user_workspace=True),
123
129
  entrypoint=common_utils.get_current_command(),
124
- pool=pool))
130
+ pool=pool,
131
+ pool_hash=pool_hash))
125
132
  for task_id, task in enumerate(dag.tasks):
126
133
  resources_str = backend_utils.get_task_resources_str(
127
134
  task, is_managed_job=True)
@@ -843,3 +850,43 @@ def pool_status(
843
850
  List[str]]] = None,) -> List[Dict[str, Any]]:
844
851
  """Query a pool."""
845
852
  return impl.status(pool_names, pool=True)
853
+
854
+
855
+ ServiceComponentOrStr = Union[str, serve_utils.ServiceComponent]
856
+
857
+
858
+ @usage_lib.entrypoint
859
+ def pool_tail_logs(
860
+ pool_name: str,
861
+ *,
862
+ target: ServiceComponentOrStr,
863
+ worker_id: Optional[int] = None,
864
+ follow: bool = True,
865
+ tail: Optional[int] = None,
866
+ ) -> None:
867
+ """Tail logs of a pool."""
868
+ return impl.tail_logs(pool_name,
869
+ target=target,
870
+ replica_id=worker_id,
871
+ follow=follow,
872
+ tail=tail,
873
+ pool=True)
874
+
875
+
876
+ @usage_lib.entrypoint
877
+ def pool_sync_down_logs(
878
+ pool_name: str,
879
+ *,
880
+ local_dir: str,
881
+ targets: Union[ServiceComponentOrStr, List[ServiceComponentOrStr],
882
+ None] = None,
883
+ worker_ids: Optional[List[int]] = None,
884
+ tail: Optional[int] = None,
885
+ ) -> str:
886
+ """Sync down logs of a pool."""
887
+ return impl.sync_down_logs(pool_name,
888
+ local_dir=local_dir,
889
+ targets=targets,
890
+ replica_ids=worker_ids,
891
+ tail=tail,
892
+ pool=True)
sky/jobs/server/server.py CHANGED
@@ -1,5 +1,7 @@
1
1
  """REST API for managed jobs."""
2
2
 
3
+ import pathlib
4
+
3
5
  import fastapi
4
6
 
5
7
  from sky import sky_logging
@@ -117,7 +119,7 @@ async def pool_apply(request: fastapi.Request,
117
119
  request_body=jobs_pool_apply_body,
118
120
  func=core.pool_apply,
119
121
  schedule_type=api_requests.ScheduleType.LONG,
120
- request_cluster_name=common.SKY_SERVE_CONTROLLER_NAME,
122
+ request_cluster_name=common.JOB_CONTROLLER_NAME,
121
123
  )
122
124
 
123
125
 
@@ -130,7 +132,7 @@ async def pool_down(request: fastapi.Request,
130
132
  request_body=jobs_pool_down_body,
131
133
  func=core.pool_down,
132
134
  schedule_type=api_requests.ScheduleType.SHORT,
133
- request_cluster_name=common.SKY_SERVE_CONTROLLER_NAME,
135
+ request_cluster_name=common.JOB_CONTROLLER_NAME,
134
136
  )
135
137
 
136
138
 
@@ -144,5 +146,52 @@ async def pool_status(
144
146
  request_body=jobs_pool_status_body,
145
147
  func=core.pool_status,
146
148
  schedule_type=api_requests.ScheduleType.SHORT,
147
- request_cluster_name=common.SKY_SERVE_CONTROLLER_NAME,
149
+ request_cluster_name=common.JOB_CONTROLLER_NAME,
150
+ )
151
+
152
+
153
+ @router.post('/pool_logs')
154
+ async def pool_tail_logs(
155
+ request: fastapi.Request, log_body: payloads.JobsPoolLogsBody,
156
+ background_tasks: fastapi.BackgroundTasks
157
+ ) -> fastapi.responses.StreamingResponse:
158
+ executor.schedule_request(
159
+ request_id=request.state.request_id,
160
+ request_name='jobs.pool_logs',
161
+ request_body=log_body,
162
+ func=core.pool_tail_logs,
163
+ schedule_type=api_requests.ScheduleType.SHORT,
164
+ request_cluster_name=common.JOB_CONTROLLER_NAME,
165
+ )
166
+
167
+ request_task = api_requests.get_request(request.state.request_id)
168
+
169
+ return stream_utils.stream_response(
170
+ request_id=request_task.request_id,
171
+ logs_path=request_task.log_path,
172
+ background_tasks=background_tasks,
173
+ )
174
+
175
+
176
+ @router.post('/pool_sync-down-logs')
177
+ async def pool_download_logs(
178
+ request: fastapi.Request,
179
+ download_logs_body: payloads.JobsPoolDownloadLogsBody,
180
+ ) -> None:
181
+ user_hash = download_logs_body.env_vars[constants.USER_ID_ENV_VAR]
182
+ timestamp = sky_logging.get_run_timestamp()
183
+ logs_dir_on_api_server = (
184
+ pathlib.Path(server_common.api_server_user_logs_dir_prefix(user_hash)) /
185
+ 'pool' / f'{download_logs_body.pool_name}_{timestamp}')
186
+ logs_dir_on_api_server.mkdir(parents=True, exist_ok=True)
187
+ # We should reuse the original request body, so that the env vars, such as
188
+ # user hash, are kept the same.
189
+ download_logs_body.local_dir = str(logs_dir_on_api_server)
190
+ executor.schedule_request(
191
+ request_id=request.state.request_id,
192
+ request_name='jobs.pool_sync_down_logs',
193
+ request_body=download_logs_body,
194
+ func=core.pool_sync_down_logs,
195
+ schedule_type=api_requests.ScheduleType.SHORT,
196
+ request_cluster_name=common.JOB_CONTROLLER_NAME,
148
197
  )
sky/jobs/state.py CHANGED
@@ -107,6 +107,7 @@ job_info_table = sqlalchemy.Table(
107
107
  sqlalchemy.Column('job_id_on_pool_cluster',
108
108
  sqlalchemy.Integer,
109
109
  server_default=None),
110
+ sqlalchemy.Column('pool_hash', sqlalchemy.Text, server_default=None),
110
111
  )
111
112
 
112
113
  ha_recovery_script_table = sqlalchemy.Table(
@@ -225,6 +226,7 @@ def _get_jobs_dict(r: 'row.RowMapping') -> Dict[str, Any]:
225
226
  'pool': r['pool'],
226
227
  'current_cluster_name': r['current_cluster_name'],
227
228
  'job_id_on_pool_cluster': r['job_id_on_pool_cluster'],
229
+ 'pool_hash': r['pool_hash'],
228
230
  }
229
231
 
230
232
 
@@ -462,7 +464,8 @@ def set_job_info(job_id: int, name: str, workspace: str, entrypoint: str):
462
464
 
463
465
  @_init_db
464
466
  def set_job_info_without_job_id(name: str, workspace: str, entrypoint: str,
465
- pool: Optional[str]) -> int:
467
+ pool: Optional[str],
468
+ pool_hash: Optional[str]) -> int:
466
469
  assert _SQLALCHEMY_ENGINE is not None
467
470
  with orm.Session(_SQLALCHEMY_ENGINE) as session:
468
471
  if (_SQLALCHEMY_ENGINE.dialect.name ==
@@ -480,6 +483,7 @@ def set_job_info_without_job_id(name: str, workspace: str, entrypoint: str,
480
483
  workspace=workspace,
481
484
  entrypoint=entrypoint,
482
485
  pool=pool,
486
+ pool_hash=pool_hash,
483
487
  )
484
488
 
485
489
  if (_SQLALCHEMY_ENGINE.dialect.name ==
@@ -0,0 +1,35 @@
1
+ """add workspace column to cluster_history table
2
+
3
+ Revision ID: 002
4
+ Revises: 001
5
+ Create Date: 2025-08-06
6
+
7
+ """
8
+ # pylint: disable=invalid-name
9
+ from typing import Sequence, Union
10
+
11
+ from alembic import op
12
+ import sqlalchemy as sa
13
+
14
+ from sky.utils.db import db_utils
15
+
16
+ # revision identifiers, used by Alembic.
17
+ revision: str = '002'
18
+ down_revision: Union[str, Sequence[str], None] = '001'
19
+ branch_labels: Union[str, Sequence[str], None] = None
20
+ depends_on: Union[str, Sequence[str], None] = None
21
+
22
+
23
+ def upgrade() -> None:
24
+ """Upgrade schema."""
25
+ with op.get_context().autocommit_block():
26
+ db_utils.add_column_to_table_alembic('cluster_history',
27
+ 'workspace',
28
+ sa.Text(),
29
+ server_default=None)
30
+ pass
31
+
32
+
33
+ def downgrade() -> None:
34
+ """Downgrade schema."""
35
+ pass
@@ -0,0 +1,34 @@
1
+ """Adding a hash column for pool.
2
+
3
+ Revision ID: 003
4
+ Revises: 002
5
+ Create Date: 2025-07-18
6
+
7
+ """
8
+ # pylint: disable=invalid-name
9
+ from typing import Sequence, Union
10
+
11
+ from alembic import op
12
+ import sqlalchemy as sa
13
+
14
+ from sky.utils.db import db_utils
15
+
16
+ # revision identifiers, used by Alembic.
17
+ revision: str = '003'
18
+ down_revision: Union[str, Sequence[str], None] = '002'
19
+ branch_labels: Union[str, Sequence[str], None] = None
20
+ depends_on: Union[str, Sequence[str], None] = None
21
+
22
+
23
+ def upgrade():
24
+ """Add columns for pool hash."""
25
+ with op.get_context().autocommit_block():
26
+ db_utils.add_column_to_table_alembic('job_info',
27
+ 'pool_hash',
28
+ sa.Text(),
29
+ server_default=None)
30
+
31
+
32
+ def downgrade():
33
+ """Remove columns for pool hash."""
34
+ pass
sky/serve/client/impl.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Implementation of SDK for SkyServe."""
2
2
  import json
3
3
  import typing
4
- from typing import List, Optional, Union
4
+ from typing import List, Optional, Sequence, Union
5
5
 
6
6
  import click
7
7
 
@@ -12,6 +12,8 @@ from sky.utils import admin_policy_utils
12
12
  from sky.utils import dag_utils
13
13
 
14
14
  if typing.TYPE_CHECKING:
15
+ import io
16
+
15
17
  import sky
16
18
  from sky.serve import serve_utils
17
19
 
@@ -186,3 +188,85 @@ def status(
186
188
  json=json.loads(body.model_dump_json()),
187
189
  timeout=(5, None))
188
190
  return server_common.get_request_id(response)
191
+
192
+
193
+ def tail_logs(service_name: str,
194
+ target: Union[str, 'serve_utils.ServiceComponent'],
195
+ replica_id: Optional[int] = None,
196
+ follow: bool = True,
197
+ output_stream: Optional['io.TextIOBase'] = None,
198
+ tail: Optional[int] = None,
199
+ pool: bool = False) -> None:
200
+ # Avoid circular import.
201
+ from sky.client import sdk # pylint: disable=import-outside-toplevel
202
+
203
+ if pool:
204
+ body = payloads.JobsPoolLogsBody(
205
+ pool_name=service_name,
206
+ target=target,
207
+ worker_id=replica_id,
208
+ follow=follow,
209
+ tail=tail,
210
+ )
211
+ else:
212
+ body = payloads.ServeLogsBody(
213
+ service_name=service_name,
214
+ target=target,
215
+ replica_id=replica_id,
216
+ follow=follow,
217
+ tail=tail,
218
+ )
219
+ response = server_common.make_authenticated_request(
220
+ 'POST',
221
+ '/jobs/pool_logs' if pool else '/serve/logs',
222
+ json=json.loads(body.model_dump_json()),
223
+ timeout=(5, None),
224
+ stream=True)
225
+ request_id = server_common.get_request_id(response)
226
+ return sdk.stream_response(request_id=request_id,
227
+ response=response,
228
+ output_stream=output_stream,
229
+ resumable=True)
230
+
231
+
232
+ def sync_down_logs(service_name: str,
233
+ local_dir: str,
234
+ *,
235
+ targets: Optional[Union[
236
+ str, 'serve_utils.ServiceComponent',
237
+ Sequence[Union[str,
238
+ 'serve_utils.ServiceComponent']]]] = None,
239
+ replica_ids: Optional[List[int]] = None,
240
+ tail: Optional[int] = None,
241
+ pool: bool = False) -> None:
242
+ # Avoid circular import.
243
+ from sky.client import sdk # pylint: disable=import-outside-toplevel
244
+
245
+ if pool:
246
+ body = payloads.JobsPoolDownloadLogsBody(
247
+ pool_name=service_name,
248
+ local_dir=local_dir,
249
+ targets=targets,
250
+ worker_ids=replica_ids,
251
+ tail=tail,
252
+ )
253
+ else:
254
+ body = payloads.ServeDownloadLogsBody(
255
+ service_name=service_name,
256
+ # No need to set here, since the server will override it
257
+ # to a directory on the API server.
258
+ local_dir=local_dir,
259
+ targets=targets,
260
+ replica_ids=replica_ids,
261
+ tail=tail,
262
+ )
263
+ response = server_common.make_authenticated_request(
264
+ 'POST',
265
+ '/jobs/pool_sync-down-logs' if pool else '/serve/sync-down-logs',
266
+ json=json.loads(body.model_dump_json()),
267
+ timeout=(5, None))
268
+ remote_dir = sdk.stream_and_get(server_common.get_request_id(response))
269
+
270
+ # Download from API server paths to the client's local_dir
271
+ client_common.download_logs_from_api_server([remote_dir], remote_dir,
272
+ local_dir)