skypilot-nightly 1.0.0.dev20250709__py3-none-any.whl → 1.0.0.dev20250711__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. sky/__init__.py +2 -2
  2. sky/backends/cloud_vm_ray_backend.py +6 -4
  3. sky/clouds/kubernetes.py +137 -23
  4. sky/core.py +3 -1
  5. sky/dashboard/out/404.html +1 -1
  6. sky/dashboard/out/_next/static/chunks/1871-3a0f047988be65cd.js +6 -0
  7. sky/dashboard/out/_next/static/chunks/8969-13bb52ce3cffa4e3.js +1 -0
  8. sky/dashboard/out/_next/static/chunks/{webpack-9a81ea998672c303.js → webpack-60070a62f55486a6.js} +1 -1
  9. sky/dashboard/out/_next/static/css/6cbd41a88d2e9e1c.css +3 -0
  10. sky/dashboard/out/_next/static/{EqELoF4IXcALfWVihInou → ldZFQWCiYX_vZnIfB_o8S}/_buildManifest.js +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.html +1 -1
  20. sky/dashboard/out/users.html +1 -1
  21. sky/dashboard/out/volumes.html +1 -1
  22. sky/dashboard/out/workspace/new.html +1 -1
  23. sky/dashboard/out/workspaces/[name].html +1 -1
  24. sky/dashboard/out/workspaces.html +1 -1
  25. sky/global_user_state.py +10 -11
  26. sky/jobs/constants.py +1 -1
  27. sky/jobs/controller.py +7 -0
  28. sky/jobs/server/core.py +2 -1
  29. sky/jobs/server/utils.py +81 -0
  30. sky/jobs/state.py +58 -40
  31. sky/jobs/utils.py +45 -6
  32. sky/provision/kubernetes/instance.py +17 -0
  33. sky/provision/kubernetes/utils.py +134 -0
  34. sky/provision/provisioner.py +20 -0
  35. sky/skylet/constants.py +1 -6
  36. sky/skylet/job_lib.py +30 -8
  37. sky/skypilot_config.py +8 -3
  38. sky/task.py +17 -0
  39. sky/templates/kubernetes-ray.yml.j2 +298 -10
  40. sky/users/permission.py +18 -1
  41. sky/users/token_service.py +25 -3
  42. sky/utils/common_utils.py +13 -0
  43. sky/utils/db_utils.py +16 -0
  44. sky/utils/schemas.py +6 -0
  45. sky/utils/ux_utils.py +2 -4
  46. {skypilot_nightly-1.0.0.dev20250709.dist-info → skypilot_nightly-1.0.0.dev20250711.dist-info}/METADATA +1 -1
  47. {skypilot_nightly-1.0.0.dev20250709.dist-info → skypilot_nightly-1.0.0.dev20250711.dist-info}/RECORD +55 -54
  48. sky/dashboard/out/_next/static/chunks/1871-80dea41717729fa5.js +0 -6
  49. sky/dashboard/out/_next/static/chunks/8969-909d53833da080cb.js +0 -1
  50. sky/dashboard/out/_next/static/css/0da6afe66176678a.css +0 -3
  51. /sky/dashboard/out/_next/static/chunks/pages/{_app-a37b06ddb64521fd.js → _app-e6e82dc8abb50c4f.js} +0 -0
  52. /sky/dashboard/out/_next/static/chunks/pages/clusters/{[cluster]-1159f362b960e2b8.js → [cluster]-0fbfb1dd0b08c90c.js} +0 -0
  53. /sky/dashboard/out/_next/static/chunks/pages/{clusters-9744c271a1642f76.js → clusters-102d169e87913ba1.js} +0 -0
  54. /sky/dashboard/out/_next/static/{EqELoF4IXcALfWVihInou → ldZFQWCiYX_vZnIfB_o8S}/_ssgManifest.js +0 -0
  55. {skypilot_nightly-1.0.0.dev20250709.dist-info → skypilot_nightly-1.0.0.dev20250711.dist-info}/WHEEL +0 -0
  56. {skypilot_nightly-1.0.0.dev20250709.dist-info → skypilot_nightly-1.0.0.dev20250711.dist-info}/entry_points.txt +0 -0
  57. {skypilot_nightly-1.0.0.dev20250709.dist-info → skypilot_nightly-1.0.0.dev20250711.dist-info}/licenses/LICENSE +0 -0
  58. {skypilot_nightly-1.0.0.dev20250709.dist-info → skypilot_nightly-1.0.0.dev20250711.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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters-9744c271a1642f76.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters-102d169e87913ba1.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/config-a2673b256b6d416f.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/config","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/config-a2673b256b6d416f.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/config","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/index-927ddeebe57a8ac3.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/index-927ddeebe57a8ac3.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/infra/%5Bcontext%5D-8b0809f59034d509.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/infra/[context]","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/infra/%5Bcontext%5D-8b0809f59034d509.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/infra/[context]","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/infra-ae9d2f705ce582c9.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/infra","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/infra-ae9d2f705ce582c9.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/infra","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-162f3033ffcd3d31.js" defer=""></script><script src="/dashboard/_next/static/chunks/5230-df791914b54d91d9.js" defer=""></script><script src="/dashboard/_next/static/chunks/5739-5ea3ffa10fc884f2.js" defer=""></script><script src="/dashboard/_next/static/chunks/1664-d65361e92b85e786.js" defer=""></script><script src="/dashboard/_next/static/chunks/804-9f5e98ce84d46bdd.js" defer=""></script><script src="/dashboard/_next/static/chunks/1272-1ef0bf0237faccdb.js" defer=""></script><script src="/dashboard/_next/static/chunks/6989-6ff4e45dfb49d11d.js" defer=""></script><script src="/dashboard/_next/static/chunks/3698-52ad1ca228faa776.js" defer=""></script><script src="/dashboard/_next/static/chunks/9470-21d059a1dfa03f61.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-909d53833da080cb.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs/%5Bjob%5D-c4d5cfac7fbc0668.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs/[job]","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-162f3033ffcd3d31.js" defer=""></script><script src="/dashboard/_next/static/chunks/5230-df791914b54d91d9.js" defer=""></script><script src="/dashboard/_next/static/chunks/5739-5ea3ffa10fc884f2.js" defer=""></script><script src="/dashboard/_next/static/chunks/1664-d65361e92b85e786.js" defer=""></script><script src="/dashboard/_next/static/chunks/804-9f5e98ce84d46bdd.js" defer=""></script><script src="/dashboard/_next/static/chunks/1272-1ef0bf0237faccdb.js" defer=""></script><script src="/dashboard/_next/static/chunks/6989-6ff4e45dfb49d11d.js" defer=""></script><script src="/dashboard/_next/static/chunks/3698-52ad1ca228faa776.js" defer=""></script><script src="/dashboard/_next/static/chunks/9470-21d059a1dfa03f61.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-13bb52ce3cffa4e3.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs/%5Bjob%5D-c4d5cfac7fbc0668.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs/[job]","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs-5bbdc71878f0a068.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs-5bbdc71878f0a068.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/users-cd43fb3c122eedde.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/users","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/users-cd43fb3c122eedde.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/users","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/volumes-4ebf6484f7216387.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/volumes","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/volumes-4ebf6484f7216387.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/volumes","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspace/new-5629d4e551dba1ee.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspace/new","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspace/new-5629d4e551dba1ee.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspace/new","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-162f3033ffcd3d31.js" defer=""></script><script src="/dashboard/_next/static/chunks/5230-df791914b54d91d9.js" defer=""></script><script src="/dashboard/_next/static/chunks/5739-5ea3ffa10fc884f2.js" defer=""></script><script src="/dashboard/_next/static/chunks/1664-d65361e92b85e786.js" defer=""></script><script src="/dashboard/_next/static/chunks/804-9f5e98ce84d46bdd.js" defer=""></script><script src="/dashboard/_next/static/chunks/1272-1ef0bf0237faccdb.js" defer=""></script><script src="/dashboard/_next/static/chunks/3947-b059261d6fa88a1f.js" defer=""></script><script src="/dashboard/_next/static/chunks/6989-6ff4e45dfb49d11d.js" defer=""></script><script src="/dashboard/_next/static/chunks/3698-52ad1ca228faa776.js" defer=""></script><script src="/dashboard/_next/static/chunks/9470-21d059a1dfa03f61.js" defer=""></script><script src="/dashboard/_next/static/chunks/6990-d0dc765474fa0eca.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-909d53833da080cb.js" defer=""></script><script src="/dashboard/_next/static/chunks/1043-1b39779691bb4030.js" defer=""></script><script src="/dashboard/_next/static/chunks/6601-fcfad0ddf92ec7ab.js" defer=""></script><script src="/dashboard/_next/static/chunks/938-044ad21de8b4626b.js" defer=""></script><script src="/dashboard/_next/static/chunks/1141-726e5a3f00b67185.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces/%5Bname%5D-7c0187f43757a548.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-162f3033ffcd3d31.js" defer=""></script><script src="/dashboard/_next/static/chunks/5230-df791914b54d91d9.js" defer=""></script><script src="/dashboard/_next/static/chunks/5739-5ea3ffa10fc884f2.js" defer=""></script><script src="/dashboard/_next/static/chunks/1664-d65361e92b85e786.js" defer=""></script><script src="/dashboard/_next/static/chunks/804-9f5e98ce84d46bdd.js" defer=""></script><script src="/dashboard/_next/static/chunks/1272-1ef0bf0237faccdb.js" defer=""></script><script src="/dashboard/_next/static/chunks/3947-b059261d6fa88a1f.js" defer=""></script><script src="/dashboard/_next/static/chunks/6989-6ff4e45dfb49d11d.js" defer=""></script><script src="/dashboard/_next/static/chunks/3698-52ad1ca228faa776.js" defer=""></script><script src="/dashboard/_next/static/chunks/9470-21d059a1dfa03f61.js" defer=""></script><script src="/dashboard/_next/static/chunks/6990-d0dc765474fa0eca.js" defer=""></script><script src="/dashboard/_next/static/chunks/8969-13bb52ce3cffa4e3.js" defer=""></script><script src="/dashboard/_next/static/chunks/1043-1b39779691bb4030.js" defer=""></script><script src="/dashboard/_next/static/chunks/6601-fcfad0ddf92ec7ab.js" defer=""></script><script src="/dashboard/_next/static/chunks/938-044ad21de8b4626b.js" defer=""></script><script src="/dashboard/_next/static/chunks/1141-726e5a3f00b67185.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces/%5Bname%5D-7c0187f43757a548.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","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/0da6afe66176678a.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/0da6afe66176678a.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-9a81ea998672c303.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a37b06ddb64521fd.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces-06bde99155fa6292.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/EqELoF4IXcALfWVihInou/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"EqELoF4IXcALfWVihInou","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/6cbd41a88d2e9e1c.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6cbd41a88d2e9e1c.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-60070a62f55486a6.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-efc06c2733009cd3.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-c0a4f1ea606d48d2.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-e6e82dc8abb50c4f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces-06bde99155fa6292.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ldZFQWCiYX_vZnIfB_o8S/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"ldZFQWCiYX_vZnIfB_o8S","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
sky/global_user_state.py CHANGED
@@ -220,17 +220,16 @@ def _glob_to_similar(glob_pattern):
220
220
  return like_pattern
221
221
 
222
222
 
223
- def create_table():
223
+ def create_table(engine: sqlalchemy.engine.Engine):
224
224
  # Enable WAL mode to avoid locking issues.
225
225
  # See: issue #1441 and PR #1509
226
226
  # https://github.com/microsoft/WSL/issues/2395
227
227
  # TODO(romilb): We do not enable WAL for WSL because of known issue in WSL.
228
228
  # This may cause the database locked problem from WSL issue #1441.
229
- if (_SQLALCHEMY_ENGINE.dialect.name
230
- == db_utils.SQLAlchemyDialect.SQLITE.value and
229
+ if (engine.dialect.name == db_utils.SQLAlchemyDialect.SQLITE.value and
231
230
  not common_utils.is_wsl()):
232
231
  try:
233
- with orm.Session(_SQLALCHEMY_ENGINE) as session:
232
+ with orm.Session(engine) as session:
234
233
  session.execute(sqlalchemy.text('PRAGMA journal_mode=WAL'))
235
234
  session.commit()
236
235
  except sqlalchemy_exc.OperationalError as e:
@@ -240,12 +239,12 @@ def create_table():
240
239
  # is not critical and is likely to be enabled by other processes.
241
240
 
242
241
  # Create tables if they don't exist
243
- Base.metadata.create_all(bind=_SQLALCHEMY_ENGINE)
242
+ db_utils.add_tables_to_db_sqlalchemy(Base.metadata, engine)
244
243
 
245
244
  # For backward compatibility.
246
245
  # TODO(zhwu): Remove this function after all users have migrated to
247
246
  # the latest version of SkyPilot.
248
- with orm.Session(_SQLALCHEMY_ENGINE) as session:
247
+ with orm.Session(engine) as session:
249
248
  # Add autostop column to clusters table
250
249
  db_utils.add_column_to_table_sqlalchemy(session,
251
250
  'clusters',
@@ -391,15 +390,15 @@ def initialize_and_get_db() -> sqlalchemy.engine.Engine:
391
390
  conn_string = skypilot_config.get_nested(('db',), None)
392
391
  if conn_string:
393
392
  logger.debug(f'using db URI from {conn_string}')
394
- _SQLALCHEMY_ENGINE = sqlalchemy.create_engine(
395
- conn_string, poolclass=sqlalchemy.NullPool)
393
+ engine = sqlalchemy.create_engine(conn_string,
394
+ poolclass=sqlalchemy.NullPool)
396
395
  else:
397
396
  db_path = os.path.expanduser('~/.sky/state.db')
398
397
  pathlib.Path(db_path).parents[0].mkdir(parents=True,
399
398
  exist_ok=True)
400
- _SQLALCHEMY_ENGINE = sqlalchemy.create_engine('sqlite:///' +
401
- db_path)
402
- create_table()
399
+ engine = sqlalchemy.create_engine('sqlite:///' + db_path)
400
+ create_table(engine)
401
+ _SQLALCHEMY_ENGINE = engine
403
402
  return _SQLALCHEMY_ENGINE
404
403
 
405
404
 
sky/jobs/constants.py CHANGED
@@ -47,7 +47,7 @@ JOBS_CLUSTER_NAME_PREFIX_LENGTH = 25
47
47
  # The version of the lib files that jobs/utils use. Whenever there is an API
48
48
  # change for the jobs/utils, we need to bump this version and update
49
49
  # job.utils.ManagedJobCodeGen to handle the version update.
50
- MANAGED_JOBS_VERSION = 6
50
+ MANAGED_JOBS_VERSION = 7
51
51
 
52
52
  # The command for setting up the jobs dashboard on the controller. It firstly
53
53
  # checks if the systemd services are available, and if not (e.g., Kubernetes
sky/jobs/controller.py CHANGED
@@ -14,6 +14,13 @@ from typing import Optional, Tuple
14
14
 
15
15
  import filelock
16
16
 
17
+ # This import ensures backward compatibility. Controller processes may not have
18
+ # imported this module initially, but will attempt to import it during job
19
+ # termination on the fly. If a job was launched with an old SkyPilot runtime
20
+ # and a new job is launched with a newer runtime, the old job's termination
21
+ # will try to import code from a different SkyPilot runtime, causing exceptions.
22
+ # pylint: disable=unused-import
23
+ from sky import core
17
24
  from sky import exceptions
18
25
  from sky import sky_logging
19
26
  from sky.backends import backend_utils
sky/jobs/server/core.py CHANGED
@@ -110,7 +110,8 @@ def _maybe_submit_job_locally(prefix: str, dag: 'sky.Dag') -> Optional[int]:
110
110
  resources_str = backend_utils.get_task_resources_str(
111
111
  task, is_managed_job=True)
112
112
  managed_job_state.set_pending(consolidation_mode_job_id, task_id,
113
- task.name, resources_str)
113
+ task.name, resources_str,
114
+ task.metadata_json)
114
115
  return consolidation_mode_job_id
115
116
 
116
117
 
@@ -0,0 +1,81 @@
1
+ """Utility functions for managed jobs."""
2
+ from sky import backends
3
+ from sky import sky_logging
4
+ from sky.backends import backend_utils
5
+ from sky.jobs import utils as managed_job_utils
6
+ from sky.skylet import constants as skylet_constants
7
+ from sky.utils import controller_utils
8
+
9
+ logger = sky_logging.init_logger(__name__)
10
+
11
+
12
+ def check_version_mismatch_and_non_terminal_jobs() -> None:
13
+ """Check if controller has version mismatch and non-terminal jobs exist.
14
+
15
+ Raises:
16
+ ValueError: If there's a version mismatch and non-terminal jobs exist.
17
+ sky.exceptions.ClusterNotUpError: If the controller is not accessible.
18
+ """
19
+ # Get the current local SKYLET_VERSION
20
+ local_version = skylet_constants.SKYLET_VERSION
21
+
22
+ # Get controller handle (works the same in both normal and
23
+ # consolidation mode)
24
+ jobs_controller_type = controller_utils.Controllers.JOBS_CONTROLLER
25
+ handle = backend_utils.is_controller_accessible(
26
+ controller=jobs_controller_type,
27
+ stopped_message='Jobs controller is not running.')
28
+
29
+ backend = backend_utils.get_backend_from_handle(handle)
30
+ assert isinstance(backend, backends.CloudVmRayBackend)
31
+
32
+ # Get controller version and raw job table
33
+ code = managed_job_utils.ManagedJobCodeGen.get_version_and_job_table()
34
+
35
+ returncode, output, stderr = backend.run_on_head(handle,
36
+ code,
37
+ require_outputs=True,
38
+ stream_logs=False,
39
+ separate_stderr=True)
40
+
41
+ if returncode != 0:
42
+ logger.error(output + stderr)
43
+ raise ValueError('Failed to check controller version and jobs with '
44
+ f'returncode: {returncode}.\n{output + stderr}')
45
+
46
+ # Parse the output to extract controller version (split only on first
47
+ # newline)
48
+ output_parts = output.strip().split('\n', 1)
49
+
50
+ # Extract controller version from first line
51
+ if len(output_parts) < 2 or not output_parts[0].startswith(
52
+ 'controller_version:'):
53
+ raise ValueError(
54
+ f'Expected controller version in first line, got: {output}')
55
+
56
+ controller_version = output_parts[0].split(':', 1)[1]
57
+
58
+ # Rest is job table payload (preserving any newlines within it)
59
+ job_table_payload = output_parts[1]
60
+
61
+ # Process locally: check version match and filter non-terminal jobs
62
+ version_matches = controller_version == local_version
63
+
64
+ # Load and filter jobs locally using existing method
65
+ jobs = managed_job_utils.load_managed_job_queue(job_table_payload)
66
+ non_terminal_jobs = [job for job in jobs if not job['status'].is_terminal()]
67
+ has_non_terminal_jobs = len(non_terminal_jobs) > 0
68
+
69
+ if not version_matches and has_non_terminal_jobs:
70
+ # Format job table locally using the same method as queue()
71
+ formatted_job_table = managed_job_utils.format_job_table(
72
+ non_terminal_jobs, show_all=False, show_user=False)
73
+
74
+ error_msg = (
75
+ f'Controller SKYLET_VERSION ({controller_version}) does not match '
76
+ f'current version ({local_version}), and there are non-terminal '
77
+ 'jobs on the controller. Please wait for all jobs to complete or '
78
+ 'cancel them before launching new jobs with the updated version.'
79
+ f'\n\nCurrent non-terminal jobs:\n{formatted_job_table}')
80
+
81
+ raise ValueError(error_msg)
sky/jobs/state.py CHANGED
@@ -77,6 +77,7 @@ spot_table = sqlalchemy.Table(
77
77
  sqlalchemy.Column('task_name', sqlalchemy.Text),
78
78
  sqlalchemy.Column('specs', sqlalchemy.Text),
79
79
  sqlalchemy.Column('local_log_file', sqlalchemy.Text, server_default=None),
80
+ sqlalchemy.Column('metadata', sqlalchemy.Text, server_default='{}'),
80
81
  )
81
82
 
82
83
  job_info_table = sqlalchemy.Table(
@@ -111,17 +112,16 @@ ha_recovery_script_table = sqlalchemy.Table(
111
112
  )
112
113
 
113
114
 
114
- def create_table():
115
+ def create_table(engine: sqlalchemy.engine.Engine):
115
116
  # Enable WAL mode to avoid locking issues.
116
117
  # See: issue #3863, #1441 and PR #1509
117
118
  # https://github.com/microsoft/WSL/issues/2395
118
119
  # TODO(romilb): We do not enable WAL for WSL because of known issue in WSL.
119
120
  # This may cause the database locked problem from WSL issue #1441.
120
- if (_SQLALCHEMY_ENGINE.dialect.name
121
- == db_utils.SQLAlchemyDialect.SQLITE.value and
121
+ if (engine.dialect.name == db_utils.SQLAlchemyDialect.SQLITE.value and
122
122
  not common_utils.is_wsl()):
123
123
  try:
124
- with orm.Session(_SQLALCHEMY_ENGINE) as session:
124
+ with orm.Session(engine) as session:
125
125
  session.execute(sqlalchemy.text('PRAGMA journal_mode=WAL'))
126
126
  session.commit()
127
127
  except sqlalchemy_exc.OperationalError as e:
@@ -131,10 +131,10 @@ def create_table():
131
131
  # is not critical and is likely to be enabled by other processes.
132
132
 
133
133
  # Create tables if they don't exist
134
- Base.metadata.create_all(bind=_SQLALCHEMY_ENGINE)
134
+ db_utils.add_tables_to_db_sqlalchemy(Base.metadata, engine)
135
135
 
136
136
  # Backward compatibility: add columns that not exist in older databases
137
- with orm.Session(_SQLALCHEMY_ENGINE) as session:
137
+ with orm.Session(engine) as session:
138
138
  db_utils.add_column_to_table_sqlalchemy(session, 'spot',
139
139
  'failure_reason',
140
140
  sqlalchemy.Text())
@@ -170,6 +170,14 @@ def create_table():
170
170
  sqlalchemy.Text(),
171
171
  default_statement='DEFAULT NULL')
172
172
 
173
+ db_utils.add_column_to_table_sqlalchemy(
174
+ session,
175
+ 'spot',
176
+ 'metadata',
177
+ sqlalchemy.Text(),
178
+ default_statement='DEFAULT \'{}\'',
179
+ value_to_replace_existing_entries='{}')
180
+
173
181
  db_utils.add_column_to_table_sqlalchemy(session, 'job_info',
174
182
  'schedule_state',
175
183
  sqlalchemy.Text())
@@ -219,15 +227,15 @@ def initialize_and_get_db() -> sqlalchemy.engine.Engine:
219
227
  conn_string = skypilot_config.get_nested(('db',), None)
220
228
  if conn_string:
221
229
  logger.debug(f'using db URI from {conn_string}')
222
- _SQLALCHEMY_ENGINE = sqlalchemy.create_engine(
223
- conn_string, poolclass=sqlalchemy.NullPool)
230
+ engine = sqlalchemy.create_engine(conn_string,
231
+ poolclass=sqlalchemy.NullPool)
224
232
  else:
225
233
  db_path = os.path.expanduser('~/.sky/spot_jobs.db')
226
234
  pathlib.Path(db_path).parents[0].mkdir(parents=True,
227
235
  exist_ok=True)
228
- _SQLALCHEMY_ENGINE = sqlalchemy.create_engine('sqlite:///' +
229
- db_path)
230
- create_table()
236
+ engine = sqlalchemy.create_engine('sqlite:///' + db_path)
237
+ create_table(engine)
238
+ _SQLALCHEMY_ENGINE = engine
231
239
  return _SQLALCHEMY_ENGINE
232
240
 
233
241
 
@@ -273,6 +281,7 @@ def _get_jobs_dict(r: 'row.RowMapping') -> Dict[str, Any]:
273
281
  'task_name': r['task_name'],
274
282
  'specs': r['specs'],
275
283
  'local_log_file': r['local_log_file'],
284
+ 'metadata': r['metadata'],
276
285
  # columns from job_info table (some may be None for legacy jobs)
277
286
  '_job_info_job_id': r[job_info_table.c.spot_job_id
278
287
  ], # ambiguous, use table.column
@@ -560,7 +569,13 @@ def set_job_info_without_job_id(name: str, workspace: str,
560
569
 
561
570
 
562
571
  @_init_db
563
- def set_pending(job_id: int, task_id: int, task_name: str, resources_str: str):
572
+ def set_pending(
573
+ job_id: int,
574
+ task_id: int,
575
+ task_name: str,
576
+ resources_str: str,
577
+ metadata: str,
578
+ ):
564
579
  """Set the task to pending state."""
565
580
  assert _SQLALCHEMY_ENGINE is not None
566
581
  with orm.Session(_SQLALCHEMY_ENGINE) as session:
@@ -570,6 +585,7 @@ def set_pending(job_id: int, task_id: int, task_name: str, resources_str: str):
570
585
  task_id=task_id,
571
586
  task_name=task_name,
572
587
  resources=resources_str,
588
+ metadata=metadata,
573
589
  status=ManagedJobStatus.PENDING.value,
574
590
  ))
575
591
  session.commit()
@@ -1195,38 +1211,40 @@ def get_managed_jobs(job_id: Optional[int] = None) -> List[Dict[str, Any]]:
1195
1211
  # Note: we will get the user_hash here, but don't try to call
1196
1212
  # global_user_state.get_user() on it. This runs on the controller, which may
1197
1213
  # not have the user info. Prefer to do it on the API server side.
1214
+ query = sqlalchemy.select(spot_table, job_info_table).select_from(
1215
+ spot_table.outerjoin(
1216
+ job_info_table,
1217
+ spot_table.c.spot_job_id == job_info_table.c.spot_job_id))
1218
+ if job_id is not None:
1219
+ query = query.where(spot_table.c.spot_job_id == job_id)
1220
+ query = query.order_by(spot_table.c.spot_job_id.desc(),
1221
+ spot_table.c.task_id.asc())
1222
+ rows = None
1198
1223
  with orm.Session(_SQLALCHEMY_ENGINE) as session:
1199
- query = sqlalchemy.select(spot_table, job_info_table).select_from(
1200
- spot_table.outerjoin(
1201
- job_info_table,
1202
- spot_table.c.spot_job_id == job_info_table.c.spot_job_id))
1203
- if job_id is not None:
1204
- query = query.where(spot_table.c.spot_job_id == job_id)
1205
- query = query.order_by(spot_table.c.spot_job_id.desc(),
1206
- spot_table.c.task_id.asc())
1207
1224
  rows = session.execute(query).fetchall()
1208
- jobs = []
1209
- for row in rows:
1210
- job_dict = _get_jobs_dict(row._mapping) # pylint: disable=protected-access
1211
- job_dict['status'] = ManagedJobStatus(job_dict['status'])
1212
- job_dict['schedule_state'] = ManagedJobScheduleState(
1213
- job_dict['schedule_state'])
1214
- if job_dict['job_name'] is None:
1215
- job_dict['job_name'] = job_dict['task_name']
1216
-
1217
- # Add user YAML content for managed jobs.
1218
- yaml_path = job_dict.get('original_user_yaml_path')
1219
- if yaml_path:
1220
- try:
1221
- with open(yaml_path, 'r', encoding='utf-8') as f:
1222
- job_dict['user_yaml'] = f.read()
1223
- except (FileNotFoundError, IOError, OSError):
1224
- job_dict['user_yaml'] = None
1225
- else:
1225
+ jobs = []
1226
+ for row in rows:
1227
+ job_dict = _get_jobs_dict(row._mapping) # pylint: disable=protected-access
1228
+ job_dict['status'] = ManagedJobStatus(job_dict['status'])
1229
+ job_dict['schedule_state'] = ManagedJobScheduleState(
1230
+ job_dict['schedule_state'])
1231
+ if job_dict['job_name'] is None:
1232
+ job_dict['job_name'] = job_dict['task_name']
1233
+ job_dict['metadata'] = json.loads(job_dict['metadata'])
1234
+
1235
+ # Add user YAML content for managed jobs.
1236
+ yaml_path = job_dict.get('original_user_yaml_path')
1237
+ if yaml_path:
1238
+ try:
1239
+ with open(yaml_path, 'r', encoding='utf-8') as f:
1240
+ job_dict['user_yaml'] = f.read()
1241
+ except (FileNotFoundError, IOError, OSError):
1226
1242
  job_dict['user_yaml'] = None
1243
+ else:
1244
+ job_dict['user_yaml'] = None
1227
1245
 
1228
- jobs.append(job_dict)
1229
- return jobs
1246
+ jobs.append(job_dict)
1247
+ return jobs
1230
1248
 
1231
1249
 
1232
1250
  @_init_db