skypilot-nightly 1.0.0.dev20250526__py3-none-any.whl → 1.0.0.dev20250528__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 (86) hide show
  1. sky/__init__.py +2 -2
  2. sky/adaptors/kubernetes.py +13 -1
  3. sky/backends/cloud_vm_ray_backend.py +2 -2
  4. sky/check.py +32 -6
  5. sky/cli.py +5 -22
  6. sky/client/cli.py +5 -22
  7. sky/client/sdk.py +5 -2
  8. sky/clouds/cloud.py +2 -2
  9. sky/clouds/kubernetes.py +12 -7
  10. sky/clouds/service_catalog/kubernetes_catalog.py +4 -0
  11. sky/clouds/ssh.py +24 -8
  12. sky/core.py +20 -2
  13. sky/dashboard/out/404.html +1 -1
  14. sky/dashboard/out/_next/static/Mx1iAbDQn1jMHh3UHmK3R/_buildManifest.js +1 -0
  15. sky/dashboard/out/_next/static/chunks/121-8f55ee3fa6301784.js +20 -0
  16. sky/dashboard/out/_next/static/chunks/{573-f17bd89d9f9118b3.js → 173-7db8607cefc20f70.js} +5 -5
  17. sky/dashboard/out/_next/static/chunks/236-d6900c828331f664.js +6 -0
  18. sky/dashboard/out/_next/static/chunks/293-351268365226d251.js +1 -0
  19. sky/dashboard/out/_next/static/chunks/{498-d7722313e5e5b4e6.js → 320-afea3ddcc5bd1c6c.js} +1 -16
  20. sky/dashboard/out/_next/static/chunks/470-4d003c441839094d.js +1 -0
  21. sky/dashboard/out/_next/static/chunks/578-9146658cead92981.js +6 -0
  22. sky/dashboard/out/_next/static/chunks/843-256ec920f6d5f41f.js +11 -0
  23. sky/dashboard/out/_next/static/chunks/856-62b87c68917b08ed.js +1 -0
  24. sky/dashboard/out/_next/static/chunks/973-1a09cac61cfcc1e1.js +1 -0
  25. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-159bffb2fa34ed54.js +6 -0
  26. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-9506c00257d10dbd.js +1 -0
  27. sky/dashboard/out/_next/static/chunks/pages/{clusters-9e6d1ec6e1ac5b29.js → clusters-943992b84fd6f4ee.js} +1 -1
  28. sky/dashboard/out/_next/static/chunks/pages/config-41738d1896fc02fe.js +6 -0
  29. sky/dashboard/out/_next/static/chunks/pages/infra-881fcd902fbbd0e5.js +6 -0
  30. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-2c29e97a6aa50dd4.js +6 -0
  31. sky/dashboard/out/_next/static/chunks/pages/jobs-a4efc09e61988f8d.js +1 -0
  32. sky/dashboard/out/_next/static/chunks/pages/users-b2634885d67c49a6.js +6 -0
  33. sky/dashboard/out/_next/static/chunks/pages/workspace/{new-bbf436f41381e169.js → new-579b3203c7c19d84.js} +1 -1
  34. sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-7733c960685b4385.js → [name]-9388e38fac73ee8f.js} +1 -1
  35. sky/dashboard/out/_next/static/chunks/pages/workspaces-610c49ae3619ee85.js +1 -0
  36. sky/dashboard/out/_next/static/css/ffd1cd601648c303.css +3 -0
  37. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  38. sky/dashboard/out/clusters/[cluster].html +1 -1
  39. sky/dashboard/out/clusters.html +1 -1
  40. sky/dashboard/out/config.html +1 -0
  41. sky/dashboard/out/index.html +1 -1
  42. sky/dashboard/out/infra.html +1 -1
  43. sky/dashboard/out/jobs/[job].html +1 -1
  44. sky/dashboard/out/jobs.html +1 -1
  45. sky/dashboard/out/users.html +1 -1
  46. sky/dashboard/out/workspace/new.html +1 -1
  47. sky/dashboard/out/workspaces/[name].html +1 -1
  48. sky/dashboard/out/workspaces.html +1 -1
  49. sky/global_user_state.py +181 -134
  50. sky/provision/kubernetes/utils.py +4 -4
  51. sky/server/constants.py +1 -1
  52. sky/server/requests/payloads.py +18 -5
  53. sky/server/requests/serializers/decoders.py +0 -11
  54. sky/server/server.py +25 -14
  55. sky/setup_files/dependencies.py +1 -0
  56. sky/skylet/constants.py +4 -0
  57. sky/skypilot_config.py +4 -0
  58. sky/utils/db_utils.py +34 -46
  59. sky/utils/kubernetes/exec_kubeconfig_converter.py +19 -0
  60. sky/utils/schemas.py +57 -5
  61. sky/utils/subprocess_utils.py +2 -3
  62. sky/workspaces/core.py +186 -50
  63. sky/workspaces/server.py +25 -0
  64. {skypilot_nightly-1.0.0.dev20250526.dist-info → skypilot_nightly-1.0.0.dev20250528.dist-info}/METADATA +2 -1
  65. {skypilot_nightly-1.0.0.dev20250526.dist-info → skypilot_nightly-1.0.0.dev20250528.dist-info}/RECORD +71 -67
  66. {skypilot_nightly-1.0.0.dev20250526.dist-info → skypilot_nightly-1.0.0.dev20250528.dist-info}/WHEEL +1 -1
  67. sky/dashboard/out/_next/static/7GEgRyZKRaSnYZCV1Jwol/_buildManifest.js +0 -1
  68. sky/dashboard/out/_next/static/chunks/25-062253ea41fb8eec.js +0 -6
  69. sky/dashboard/out/_next/static/chunks/480-5a0de8b6570ea105.js +0 -1
  70. sky/dashboard/out/_next/static/chunks/488-50d843fdb5396d32.js +0 -15
  71. sky/dashboard/out/_next/static/chunks/578-d351125af46c293f.js +0 -6
  72. sky/dashboard/out/_next/static/chunks/734-a6e01d7f98904741.js +0 -1
  73. sky/dashboard/out/_next/static/chunks/938-59956af3950b02ed.js +0 -1
  74. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-3b5aad09a25f64b7.js +0 -1
  75. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-9529d9e882a0e75c.js +0 -16
  76. sky/dashboard/out/_next/static/chunks/pages/infra-abb7d744ecf15109.js +0 -1
  77. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-48dc8d67d4b60be1.js +0 -1
  78. sky/dashboard/out/_next/static/chunks/pages/jobs-73d5e0c369d00346.js +0 -16
  79. sky/dashboard/out/_next/static/chunks/pages/users-b8acf6e6735323a2.js +0 -1
  80. sky/dashboard/out/_next/static/chunks/pages/workspaces-5ed48b3201b998c8.js +0 -1
  81. sky/dashboard/out/_next/static/css/28558d57108b05ae.css +0 -3
  82. /sky/dashboard/out/_next/static/{7GEgRyZKRaSnYZCV1Jwol → Mx1iAbDQn1jMHh3UHmK3R}/_ssgManifest.js +0 -0
  83. /sky/dashboard/out/_next/static/chunks/pages/{_app-96a715a6fb01e228.js → _app-a631df412d8172de.js} +0 -0
  84. {skypilot_nightly-1.0.0.dev20250526.dist-info → skypilot_nightly-1.0.0.dev20250528.dist-info}/entry_points.txt +0 -0
  85. {skypilot_nightly-1.0.0.dev20250526.dist-info → skypilot_nightly-1.0.0.dev20250528.dist-info}/licenses/LICENSE +0 -0
  86. {skypilot_nightly-1.0.0.dev20250526.dist-info → skypilot_nightly-1.0.0.dev20250528.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/28558d57108b05ae.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/28558d57108b05ae.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-deda68c926e8d0bc.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-87d061ee6ed71b28.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-e0e2335212e72357.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-96a715a6fb01e228.js" defer=""></script><script src="/dashboard/_next/static/chunks/9f96d65d-5a3e4af68c26849e.js" defer=""></script><script src="/dashboard/_next/static/chunks/573-f17bd89d9f9118b3.js" defer=""></script><script src="/dashboard/_next/static/chunks/488-50d843fdb5396d32.js" defer=""></script><script src="/dashboard/_next/static/chunks/498-d7722313e5e5b4e6.js" defer=""></script><script src="/dashboard/_next/static/chunks/480-5a0de8b6570ea105.js" defer=""></script><script src="/dashboard/_next/static/chunks/734-a6e01d7f98904741.js" defer=""></script><script src="/dashboard/_next/static/chunks/938-59956af3950b02ed.js" defer=""></script><script src="/dashboard/_next/static/chunks/25-062253ea41fb8eec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces/%5Bname%5D-7733c960685b4385.js" defer=""></script><script src="/dashboard/_next/static/7GEgRyZKRaSnYZCV1Jwol/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/7GEgRyZKRaSnYZCV1Jwol/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div>Loading...</div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"7GEgRyZKRaSnYZCV1Jwol","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/ffd1cd601648c303.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/ffd1cd601648c303.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-deda68c926e8d0bc.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-87d061ee6ed71b28.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-e0e2335212e72357.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a631df412d8172de.js" defer=""></script><script src="/dashboard/_next/static/chunks/9f96d65d-5a3e4af68c26849e.js" defer=""></script><script src="/dashboard/_next/static/chunks/173-7db8607cefc20f70.js" defer=""></script><script src="/dashboard/_next/static/chunks/121-8f55ee3fa6301784.js" defer=""></script><script src="/dashboard/_next/static/chunks/320-afea3ddcc5bd1c6c.js" defer=""></script><script src="/dashboard/_next/static/chunks/470-4d003c441839094d.js" defer=""></script><script src="/dashboard/_next/static/chunks/293-351268365226d251.js" defer=""></script><script src="/dashboard/_next/static/chunks/856-62b87c68917b08ed.js" defer=""></script><script src="/dashboard/_next/static/chunks/973-1a09cac61cfcc1e1.js" defer=""></script><script src="/dashboard/_next/static/chunks/236-d6900c828331f664.js" defer=""></script><script src="/dashboard/_next/static/chunks/843-256ec920f6d5f41f.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces/%5Bname%5D-9388e38fac73ee8f.js" defer=""></script><script src="/dashboard/_next/static/Mx1iAbDQn1jMHh3UHmK3R/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/Mx1iAbDQn1jMHh3UHmK3R/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div>Loading...</div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"Mx1iAbDQn1jMHh3UHmK3R","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"/><link rel="preload" href="/dashboard/skypilot.svg" as="image" fetchpriority="high"/><meta name="next-head-count" content="3"/><link rel="preload" href="/dashboard/_next/static/css/28558d57108b05ae.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/28558d57108b05ae.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-deda68c926e8d0bc.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-87d061ee6ed71b28.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-e0e2335212e72357.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-96a715a6fb01e228.js" defer=""></script><script src="/dashboard/_next/static/chunks/9f96d65d-5a3e4af68c26849e.js" defer=""></script><script src="/dashboard/_next/static/chunks/573-f17bd89d9f9118b3.js" defer=""></script><script src="/dashboard/_next/static/chunks/488-50d843fdb5396d32.js" defer=""></script><script src="/dashboard/_next/static/chunks/498-d7722313e5e5b4e6.js" defer=""></script><script src="/dashboard/_next/static/chunks/480-5a0de8b6570ea105.js" defer=""></script><script src="/dashboard/_next/static/chunks/734-a6e01d7f98904741.js" defer=""></script><script src="/dashboard/_next/static/chunks/938-59956af3950b02ed.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces-5ed48b3201b998c8.js" defer=""></script><script src="/dashboard/_next/static/7GEgRyZKRaSnYZCV1Jwol/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/7GEgRyZKRaSnYZCV1Jwol/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div class="min-h-screen bg-gray-50"><div class="fixed top-0 left-0 right-0 z-50 shadow-sm"><div class="fixed top-0 left-0 right-0 bg-white z-30 h-14 px-4 border-b border-gray-200 shadow-sm"><div class="flex items-center h-full"><div class="flex items-center space-x-4 mr-6"><a class="flex items-center px-1 pt-1 h-full" href="/dashboard"><div class="h-20 w-20 flex items-center justify-center"><img alt="SkyPilot Logo" fetchpriority="high" width="80" height="80" decoding="async" data-nimg="1" class="w-full h-full object-contain" style="color:transparent" src="/dashboard/skypilot.svg"/></div></a></div><div class="flex items-center space-x-2 md:space-x-4 mr-6"><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/clusters"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"></rect><rect width="20" height="8" x="2" y="14" rx="2" ry="2"></rect><line x1="6" x2="6.01" y1="6" y2="6"></line><line x1="6" x2="6.01" y1="18" y2="18"></line></svg><span>Clusters</span></a><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/jobs"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"></path><rect width="20" height="14" x="2" y="6" rx="2"></rect></svg><span>Jobs</span></a><div class="border-l border-gray-200 h-6 mx-1"></div><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/infra"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2" ry="2"></rect><rect x="9" y="9" width="6" height="6"></rect><line x1="9" y1="1" x2="9" y2="4"></line><line x1="15" y1="1" x2="15" y2="4"></line><line x1="9" y1="20" x2="9" y2="23"></line><line x1="15" y1="20" x2="15" y2="23"></line><line x1="20" y1="9" x2="23" y2="9"></line><line x1="20" y1="14" x2="23" y2="14"></line><line x1="1" y1="9" x2="4" y2="9"></line><line x1="1" y1="14" x2="4" y2="14"></line></svg><span>Infra</span></a><a class="inline-flex items-center border-b-2 border-transparent text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/workspaces"><svg class="w-4 h-4" stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g><path fill="none" d="M0 0h24v24H0z"></path><path d="M3 18.5V5a3 3 0 0 1 3-3h14a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5A3.5 3.5 0 0 1 3 18.5zM19 20v-3H6.5a1.5 1.5 0 0 0 0 3H19zM10 4H6a1 1 0 0 0-1 1v10.337A3.486 3.486 0 0 1 6.5 15H19V4h-2v8l-3.5-2-3.5 2V4z"></path></g></svg><span>Workspaces</span></a><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/users"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-users w-4 h-4"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M22 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg><span>Users</span></a></div><div class="flex items-center space-x-1 ml-auto"><a href="https://skypilot.readthedocs.io/en/latest/" target="_blank" rel="noopener noreferrer" class="inline-flex items-center px-2 py-1 text-gray-600 hover:text-blue-600 transition-colors duration-150 cursor-pointer" title="Docs" tabindex="0"><span class="mr-1">Docs</span><svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg></a><div class="border-l border-gray-200 h-6 mx-1"></div><a href="https://github.com/skypilot-org/skypilot" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="GitHub" tabindex="0"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"></path></svg></a><a href="https://slack.skypilot.co/" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="Slack" tabindex="0"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path transform="scale(0.85) translate(1.8, 1.8)" d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"></path></svg></a><a href="https://github.com/skypilot-org/skypilot/issues/new" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="Leave Feedback" tabindex="0"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-message-square w-5 h-5"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg></a></div></div></div></div><div class="transition-all duration-200 ease-in-out min-h-screen" style="padding-top:56px"><main class="p-6"><div class="flex justify-center items-center h-64"><style data-emotion="css z01bqi animation-61bdi0">.css-z01bqi{display:inline-block;color:#1976d2;-webkit-animation:animation-61bdi0 1.4s linear infinite;animation:animation-61bdi0 1.4s linear infinite;}@-webkit-keyframes animation-61bdi0{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg);}}@keyframes animation-61bdi0{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg);}}</style><span class="MuiCircularProgress-root MuiCircularProgress-indeterminate MuiCircularProgress-colorPrimary css-z01bqi" style="width:40px;height:40px" role="progressbar"><style data-emotion="css 13o7eu2">.css-13o7eu2{display:block;}</style><svg class="MuiCircularProgress-svg css-13o7eu2" viewBox="22 22 44 44"><style data-emotion="css 14891ef animation-1p2h4ri">.css-14891ef{stroke:currentColor;stroke-dasharray:80px,200px;stroke-dashoffset:0;-webkit-animation:animation-1p2h4ri 1.4s ease-in-out infinite;animation:animation-1p2h4ri 1.4s ease-in-out infinite;}@-webkit-keyframes animation-1p2h4ri{0%{stroke-dasharray:1px,200px;stroke-dashoffset:0;}50%{stroke-dasharray:100px,200px;stroke-dashoffset:-15px;}100%{stroke-dasharray:100px,200px;stroke-dashoffset:-125px;}}@keyframes animation-1p2h4ri{0%{stroke-dasharray:1px,200px;stroke-dashoffset:0;}50%{stroke-dasharray:100px,200px;stroke-dashoffset:-15px;}100%{stroke-dasharray:100px,200px;stroke-dashoffset:-125px;}}</style><circle class="MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate css-14891ef" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></span><span class="ml-2 text-gray-500">Loading workspaces...</span></div></main></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"7GEgRyZKRaSnYZCV1Jwol","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"/><link rel="preload" href="/dashboard/skypilot.svg" as="image" fetchpriority="high"/><meta name="next-head-count" content="3"/><link rel="preload" href="/dashboard/_next/static/css/ffd1cd601648c303.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/ffd1cd601648c303.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-deda68c926e8d0bc.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-87d061ee6ed71b28.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-e0e2335212e72357.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a631df412d8172de.js" defer=""></script><script src="/dashboard/_next/static/chunks/9f96d65d-5a3e4af68c26849e.js" defer=""></script><script src="/dashboard/_next/static/chunks/173-7db8607cefc20f70.js" defer=""></script><script src="/dashboard/_next/static/chunks/121-8f55ee3fa6301784.js" defer=""></script><script src="/dashboard/_next/static/chunks/320-afea3ddcc5bd1c6c.js" defer=""></script><script src="/dashboard/_next/static/chunks/470-4d003c441839094d.js" defer=""></script><script src="/dashboard/_next/static/chunks/293-351268365226d251.js" defer=""></script><script src="/dashboard/_next/static/chunks/856-62b87c68917b08ed.js" defer=""></script><script src="/dashboard/_next/static/chunks/973-1a09cac61cfcc1e1.js" defer=""></script><script src="/dashboard/_next/static/chunks/236-d6900c828331f664.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces-610c49ae3619ee85.js" defer=""></script><script src="/dashboard/_next/static/Mx1iAbDQn1jMHh3UHmK3R/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/Mx1iAbDQn1jMHh3UHmK3R/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div class="min-h-screen bg-gray-50"><div class="fixed top-0 left-0 right-0 z-50 shadow-sm"><div class="fixed top-0 left-0 right-0 bg-white z-30 h-14 px-4 border-b border-gray-200 shadow-sm"><div class="flex items-center h-full"><div class="flex items-center space-x-4 mr-6"><a class="flex items-center px-1 pt-1 h-full" href="/dashboard"><div class="h-20 w-20 flex items-center justify-center"><img alt="SkyPilot Logo" fetchpriority="high" width="80" height="80" decoding="async" data-nimg="1" class="w-full h-full object-contain" style="color:transparent" src="/dashboard/skypilot.svg"/></div></a></div><div class="flex items-center space-x-2 md:space-x-4 mr-6"><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/clusters"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"></rect><rect width="20" height="8" x="2" y="14" rx="2" ry="2"></rect><line x1="6" x2="6.01" y1="6" y2="6"></line><line x1="6" x2="6.01" y1="18" y2="18"></line></svg><span>Clusters</span></a><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/jobs"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"></path><rect width="20" height="14" x="2" y="6" rx="2"></rect></svg><span>Jobs</span></a><div class="border-l border-gray-200 h-6 mx-1"></div><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/infra"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2" ry="2"></rect><rect x="9" y="9" width="6" height="6"></rect><line x1="9" y1="1" x2="9" y2="4"></line><line x1="15" y1="1" x2="15" y2="4"></line><line x1="9" y1="20" x2="9" y2="23"></line><line x1="15" y1="20" x2="15" y2="23"></line><line x1="20" y1="9" x2="23" y2="9"></line><line x1="20" y1="14" x2="23" y2="14"></line><line x1="1" y1="9" x2="4" y2="9"></line><line x1="1" y1="14" x2="4" y2="14"></line></svg><span>Infra</span></a><a class="inline-flex items-center border-b-2 border-transparent text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/workspaces"><svg class="w-4 h-4" stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g><path fill="none" d="M0 0h24v24H0z"></path><path d="M3 18.5V5a3 3 0 0 1 3-3h14a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5A3.5 3.5 0 0 1 3 18.5zM19 20v-3H6.5a1.5 1.5 0 0 0 0 3H19zM10 4H6a1 1 0 0 0-1 1v10.337A3.486 3.486 0 0 1 6.5 15H19V4h-2v8l-3.5-2-3.5 2V4z"></path></g></svg><span>Workspaces</span></a><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/users"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-users w-4 h-4"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M22 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg><span>Users</span></a></div><div class="flex items-center space-x-1 ml-auto"><a href="https://skypilot.readthedocs.io/en/latest/" target="_blank" rel="noopener noreferrer" class="inline-flex items-center px-2 py-1 text-gray-600 hover:text-blue-600 transition-colors duration-150 cursor-pointer" title="Docs" tabindex="0"><span class="mr-1">Docs</span><svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg></a><a href="https://github.com/skypilot-org/skypilot" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="GitHub" tabindex="0"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"></path></svg></a><a href="https://slack.skypilot.co/" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="Slack" tabindex="0"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path transform="scale(0.85) translate(1.8, 1.8)" d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"></path></svg></a><a href="https://github.com/skypilot-org/skypilot/issues/new" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="Leave Feedback" tabindex="0"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-message-square w-5 h-5"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg></a><div class="border-l border-gray-200 h-6"></div><a class="inline-flex items-center justify-center p-2 rounded-full transition-colors duration-150 cursor-pointer text-gray-600 hover:bg-gray-100" title="Configuration" tabindex="0" href="/dashboard/config"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-settings w-5 h-5"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"></path><circle cx="12" cy="12" r="3"></circle></svg></a></div></div></div></div><div class="transition-all duration-200 ease-in-out min-h-screen" style="padding-top:56px"><main class="p-6"><div class="flex justify-center items-center h-64"><style data-emotion="css z01bqi animation-61bdi0">.css-z01bqi{display:inline-block;color:#1976d2;-webkit-animation:animation-61bdi0 1.4s linear infinite;animation:animation-61bdi0 1.4s linear infinite;}@-webkit-keyframes animation-61bdi0{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg);}}@keyframes animation-61bdi0{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg);}}</style><span class="MuiCircularProgress-root MuiCircularProgress-indeterminate MuiCircularProgress-colorPrimary css-z01bqi" style="width:40px;height:40px" role="progressbar"><style data-emotion="css 13o7eu2">.css-13o7eu2{display:block;}</style><svg class="MuiCircularProgress-svg css-13o7eu2" viewBox="22 22 44 44"><style data-emotion="css 14891ef animation-1p2h4ri">.css-14891ef{stroke:currentColor;stroke-dasharray:80px,200px;stroke-dashoffset:0;-webkit-animation:animation-1p2h4ri 1.4s ease-in-out infinite;animation:animation-1p2h4ri 1.4s ease-in-out infinite;}@-webkit-keyframes animation-1p2h4ri{0%{stroke-dasharray:1px,200px;stroke-dashoffset:0;}50%{stroke-dasharray:100px,200px;stroke-dashoffset:-15px;}100%{stroke-dasharray:100px,200px;stroke-dashoffset:-125px;}}@keyframes animation-1p2h4ri{0%{stroke-dasharray:1px,200px;stroke-dashoffset:0;}50%{stroke-dasharray:100px,200px;stroke-dashoffset:-15px;}100%{stroke-dasharray:100px,200px;stroke-dashoffset:-125px;}}</style><circle class="MuiCircularProgress-circle MuiCircularProgress-circleIndeterminate css-14891ef" cx="44" cy="44" r="20.2" fill="none" stroke-width="3.6"></circle></svg></span><span class="ml-2 text-gray-500">Loading workspaces...</span></div></main></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"Mx1iAbDQn1jMHh3UHmK3R","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
sky/global_user_state.py CHANGED
@@ -10,6 +10,7 @@ import json
10
10
  import os
11
11
  import pathlib
12
12
  import pickle
13
+ import re
13
14
  import time
14
15
  import typing
15
16
  from typing import Any, Dict, List, Optional, Set, Tuple
@@ -18,6 +19,7 @@ import uuid
18
19
  import sqlalchemy
19
20
  from sqlalchemy import exc as sqlalchemy_exc
20
21
  from sqlalchemy import orm
22
+ from sqlalchemy.dialects import postgresql
21
23
  from sqlalchemy.dialects import sqlite
22
24
  from sqlalchemy.ext import declarative
23
25
 
@@ -43,7 +45,14 @@ _ENABLED_CLOUDS_KEY_PREFIX = 'enabled_clouds_'
43
45
  _DB_PATH = os.path.expanduser('~/.sky/state.db')
44
46
  pathlib.Path(_DB_PATH).parents[0].mkdir(parents=True, exist_ok=True)
45
47
 
46
- _SQLALCHEMY_ENGINE = sqlalchemy.create_engine(f'sqlite:///{_DB_PATH}')
48
+ if os.environ.get(constants.SKYPILOT_API_SERVER_DB_URL_ENV_VAR):
49
+ # If SKYPILOT_API_SERVER_DB_URL_ENV_VAR is set, use it as the database URI.
50
+ logger.debug(
51
+ f'using db URI from {constants.SKYPILOT_API_SERVER_DB_URL_ENV_VAR}')
52
+ _SQLALCHEMY_ENGINE = sqlalchemy.create_engine(
53
+ os.environ.get(constants.SKYPILOT_API_SERVER_DB_URL_ENV_VAR))
54
+ else:
55
+ _SQLALCHEMY_ENGINE = sqlalchemy.create_engine('sqlite:///' + _DB_PATH)
47
56
 
48
57
  Base = declarative.declarative_base()
49
58
 
@@ -125,6 +134,26 @@ cluster_history_table = sqlalchemy.Table(
125
134
  )
126
135
 
127
136
 
137
+ def _glob_to_similar(glob_pattern):
138
+ """Converts a glob pattern to a PostgreSQL LIKE pattern."""
139
+
140
+ # Escape special LIKE characters that are not special in glob
141
+ glob_pattern = glob_pattern.replace('%', '\\%').replace('_', '\\_')
142
+
143
+ # Convert glob wildcards to LIKE wildcards
144
+ like_pattern = glob_pattern.replace('*', '%').replace('?', '_')
145
+
146
+ # Handle character classes, including negation
147
+ def replace_char_class(match):
148
+ group = match.group(0)
149
+ if group.startswith('[!'):
150
+ return '[^' + group[2:-1] + ']'
151
+ return group
152
+
153
+ like_pattern = re.sub(r'\[(!)?.*?\]', replace_char_class, like_pattern)
154
+ return like_pattern
155
+
156
+
128
157
  def create_table():
129
158
  # Enable WAL mode to avoid locking issues.
130
159
  # See: issue #1441 and PR #1509
@@ -152,31 +181,52 @@ def create_table():
152
181
  # the latest version of SkyPilot.
153
182
  with orm.Session(_SQLALCHEMY_ENGINE) as session:
154
183
  # Add autostop column to clusters table
155
- db_utils.add_column_to_table_sqlalchemy(session, 'clusters', 'autostop',
156
- 'INTEGER DEFAULT -1')
184
+ db_utils.add_column_to_table_sqlalchemy(session,
185
+ 'clusters',
186
+ 'autostop',
187
+ sqlalchemy.Integer(),
188
+ default_statement='DEFAULT -1')
157
189
 
158
- db_utils.add_column_to_table_sqlalchemy(session, 'clusters', 'metadata',
159
- 'TEXT DEFAULT \'{}\'')
190
+ db_utils.add_column_to_table_sqlalchemy(
191
+ session,
192
+ 'clusters',
193
+ 'metadata',
194
+ sqlalchemy.Text(),
195
+ default_statement='DEFAULT \'{}\'')
160
196
 
161
- db_utils.add_column_to_table_sqlalchemy(session, 'clusters', 'to_down',
162
- 'INTEGER DEFAULT 0')
197
+ db_utils.add_column_to_table_sqlalchemy(session,
198
+ 'clusters',
199
+ 'to_down',
200
+ sqlalchemy.Integer(),
201
+ default_statement='DEFAULT 0')
163
202
 
164
203
  # The cloud identity that created the cluster.
165
- db_utils.add_column_to_table_sqlalchemy(session, 'clusters', 'owner',
166
- 'TEXT')
204
+ db_utils.add_column_to_table_sqlalchemy(
205
+ session,
206
+ 'clusters',
207
+ 'owner',
208
+ sqlalchemy.Text(),
209
+ default_statement='DEFAULT NULL')
167
210
 
168
- db_utils.add_column_to_table_sqlalchemy(session, 'clusters',
169
- 'cluster_hash',
170
- 'TEXT DEFAULT null')
211
+ db_utils.add_column_to_table_sqlalchemy(
212
+ session,
213
+ 'clusters',
214
+ 'cluster_hash',
215
+ sqlalchemy.Text(),
216
+ default_statement='DEFAULT NULL')
171
217
 
172
- db_utils.add_column_to_table_sqlalchemy(session, 'clusters',
173
- 'storage_mounts_metadata',
174
- 'BLOB DEFAULT null')
218
+ db_utils.add_column_to_table_sqlalchemy(
219
+ session,
220
+ 'clusters',
221
+ 'storage_mounts_metadata',
222
+ sqlalchemy.LargeBinary(),
223
+ default_statement='DEFAULT NULL')
175
224
  db_utils.add_column_to_table_sqlalchemy(
176
225
  session,
177
226
  'clusters',
178
227
  'cluster_ever_up',
179
- 'INTEGER DEFAULT 0',
228
+ sqlalchemy.Integer(),
229
+ default_statement='DEFAULT 0',
180
230
  # Set the value to 1 so that all the existing clusters before #2977
181
231
  # are considered as ever up, i.e:
182
232
  # existing cluster's default (null) -> 1;
@@ -185,28 +235,39 @@ def create_table():
185
235
  # clusters were never really UP, setting it to 1 means they won't be
186
236
  # auto-deleted during any failover.
187
237
  value_to_replace_existing_entries=1)
188
- db_utils.add_column_to_table_sqlalchemy(session, 'clusters',
189
- 'status_updated_at',
190
- 'INTEGER DEFAULT null')
191
238
  db_utils.add_column_to_table_sqlalchemy(
192
239
  session,
193
240
  'clusters',
194
- 'user_hash',
195
- 'TEXT DEFAULT null',
241
+ 'status_updated_at',
242
+ sqlalchemy.Integer(),
243
+ default_statement='DEFAULT NULL')
244
+ db_utils.add_column_to_table_sqlalchemy(
245
+ session,
246
+ 'clusters',
247
+ 'user_hasha',
248
+ sqlalchemy.Text(),
249
+ default_statement='DEFAULT NULL',
196
250
  value_to_replace_existing_entries=common_utils.get_user_hash())
197
- db_utils.add_column_to_table_sqlalchemy(session, 'clusters',
198
- 'config_hash',
199
- 'TEXT DEFAULT null')
251
+ db_utils.add_column_to_table_sqlalchemy(
252
+ session,
253
+ 'clusters',
254
+ 'config_hash',
255
+ sqlalchemy.Text(),
256
+ default_statement='DEFAULT NULL')
200
257
 
201
- db_utils.add_column_to_table_sqlalchemy(session, 'cluster_history',
202
- 'user_hash',
203
- 'TEXT DEFAULT null')
258
+ db_utils.add_column_to_table_sqlalchemy(
259
+ session,
260
+ 'cluster_history',
261
+ 'user_hash',
262
+ sqlalchemy.Text(),
263
+ default_statement='DEFAULT NULL')
204
264
 
205
265
  db_utils.add_column_to_table_sqlalchemy(
206
266
  session,
207
267
  'clusters',
208
268
  'workspace',
209
- 'TEXT DEFAULT \'default\'',
269
+ sqlalchemy.Text(),
270
+ default_statement='DEFAULT \'default\'',
210
271
  value_to_replace_existing_entries=constants.
211
272
  SKYPILOT_DEFAULT_WORKSPACE)
212
273
  session.commit()
@@ -223,20 +284,18 @@ def add_or_update_user(user: models.User):
223
284
  with orm.Session(_SQLALCHEMY_ENGINE) as session:
224
285
  if (_SQLALCHEMY_ENGINE.dialect.name ==
225
286
  db_utils.SQLAlchemyDialect.SQLITE.value):
226
- insert_stmnt = sqlite.insert(user_table).values(id=user.id,
227
- name=user.name)
228
- do_update_stmt = insert_stmnt.on_conflict_do_update(
229
- index_elements=[user_table.c.id],
230
- set_={user_table.c.name: user.name})
231
- session.execute(do_update_stmt)
287
+ insert_func = sqlite.insert
232
288
  elif (_SQLALCHEMY_ENGINE.dialect.name ==
233
289
  db_utils.SQLAlchemyDialect.POSTGRESQL.value):
234
- # TODO(syang) support postgres dialect
235
- session.rollback()
236
- raise ValueError('Unsupported database dialect')
290
+ insert_func = postgresql.insert
237
291
  else:
238
- session.rollback()
239
292
  raise ValueError('Unsupported database dialect')
293
+ insert_stmnt = insert_func(user_table).values(id=user.id,
294
+ name=user.name)
295
+ do_update_stmt = insert_stmnt.on_conflict_do_update(
296
+ index_elements=[user_table.c.id],
297
+ set_={user_table.c.name: user.name})
298
+ session.execute(do_update_stmt)
240
299
  session.commit()
241
300
 
242
301
 
@@ -348,76 +407,67 @@ def add_or_update_cluster(cluster_name: str,
348
407
 
349
408
  if (_SQLALCHEMY_ENGINE.dialect.name ==
350
409
  db_utils.SQLAlchemyDialect.SQLITE.value):
351
- insert_stmnt = sqlite.insert(cluster_table).values(
352
- name=cluster_name,
353
- **conditional_values,
354
- handle=handle,
355
- status=status.value,
356
- # set metadata to server default ('{}')
357
- # set owner to server default (null)
358
- cluster_hash=cluster_hash,
359
- # set storage_mounts_metadata to server default (null)
360
- status_updated_at=status_updated_at,
361
- )
362
- do_update_stmt = insert_stmnt.on_conflict_do_update(
363
- index_elements=[cluster_table.c.name],
364
- set_={
365
- **conditional_values,
366
- cluster_table.c.handle: handle,
367
- cluster_table.c.status: status.value,
368
- # do not update metadata value
369
- # do not update owner value
370
- cluster_table.c.cluster_hash: cluster_hash,
371
- # do not update storage_mounts_metadata
372
- cluster_table.c.status_updated_at: status_updated_at,
373
- # do not update user_hash
374
- })
375
- session.execute(do_update_stmt)
410
+ insert_func = sqlite.insert
376
411
  elif (_SQLALCHEMY_ENGINE.dialect.name ==
377
412
  db_utils.SQLAlchemyDialect.POSTGRESQL.value):
378
- # TODO(syang) support postgres dialect
379
- session.rollback()
380
- raise ValueError('Unsupported database dialect')
413
+ insert_func = postgresql.insert
381
414
  else:
382
415
  session.rollback()
383
416
  raise ValueError('Unsupported database dialect')
384
417
 
418
+ insert_stmnt = insert_func(cluster_table).values(
419
+ name=cluster_name,
420
+ **conditional_values,
421
+ handle=handle,
422
+ status=status.value,
423
+ # set metadata to server default ('{}')
424
+ # set owner to server default (null)
425
+ cluster_hash=cluster_hash,
426
+ # set storage_mounts_metadata to server default (null)
427
+ status_updated_at=status_updated_at,
428
+ )
429
+ do_update_stmt = insert_stmnt.on_conflict_do_update(
430
+ index_elements=[cluster_table.c.name],
431
+ set_={
432
+ **conditional_values,
433
+ cluster_table.c.handle: handle,
434
+ cluster_table.c.status: status.value,
435
+ # do not update metadata value
436
+ # do not update owner value
437
+ cluster_table.c.cluster_hash: cluster_hash,
438
+ # do not update storage_mounts_metadata
439
+ cluster_table.c.status_updated_at: status_updated_at,
440
+ # do not update user_hash
441
+ })
442
+ session.execute(do_update_stmt)
443
+
385
444
  # Modify cluster history table
386
445
  launched_nodes = getattr(cluster_handle, 'launched_nodes', None)
387
446
  launched_resources = getattr(cluster_handle, 'launched_resources', None)
388
447
 
389
- if (_SQLALCHEMY_ENGINE.dialect.name ==
390
- db_utils.SQLAlchemyDialect.SQLITE.value):
391
- insert_stmnt = sqlite.insert(cluster_history_table).values(
392
- cluster_hash=cluster_hash,
393
- name=cluster_name,
394
- num_nodes=launched_nodes,
395
- requested_resources=pickle.dumps(requested_resources),
396
- launched_resources=pickle.dumps(launched_resources),
397
- usage_intervals=pickle.dumps(usage_intervals),
398
- user_hash=user_hash)
399
- do_update_stmt = insert_stmnt.on_conflict_do_update(
400
- index_elements=[cluster_history_table.c.cluster_hash],
401
- set_={
402
- cluster_history_table.c.name: cluster_name,
403
- cluster_history_table.c.num_nodes: launched_nodes,
404
- cluster_history_table.c.requested_resources:
405
- pickle.dumps(requested_resources),
406
- cluster_history_table.c.launched_resources:
407
- pickle.dumps(launched_resources),
408
- cluster_history_table.c.usage_intervals:
409
- pickle.dumps(usage_intervals),
410
- cluster_history_table.c.user_hash: user_hash
411
- })
412
- session.execute(do_update_stmt)
413
- elif (_SQLALCHEMY_ENGINE.dialect.name ==
414
- db_utils.SQLAlchemyDialect.POSTGRESQL.value):
415
- # TODO(syang) support postgres dialect
416
- session.rollback()
417
- raise ValueError('Unsupported database dialect')
418
- else:
419
- session.rollback()
420
- raise ValueError('Unsupported database dialect')
448
+ insert_stmnt = insert_func(cluster_history_table).values(
449
+ cluster_hash=cluster_hash,
450
+ name=cluster_name,
451
+ num_nodes=launched_nodes,
452
+ requested_resources=pickle.dumps(requested_resources),
453
+ launched_resources=pickle.dumps(launched_resources),
454
+ usage_intervals=pickle.dumps(usage_intervals),
455
+ user_hash=user_hash)
456
+ do_update_stmt = insert_stmnt.on_conflict_do_update(
457
+ index_elements=[cluster_history_table.c.cluster_hash],
458
+ set_={
459
+ cluster_history_table.c.name: cluster_name,
460
+ cluster_history_table.c.num_nodes: launched_nodes,
461
+ cluster_history_table.c.requested_resources:
462
+ pickle.dumps(requested_resources),
463
+ cluster_history_table.c.launched_resources:
464
+ pickle.dumps(launched_resources),
465
+ cluster_history_table.c.usage_intervals:
466
+ pickle.dumps(usage_intervals),
467
+ cluster_history_table.c.user_hash: user_hash
468
+ })
469
+ session.execute(do_update_stmt)
470
+
421
471
  session.commit()
422
472
 
423
473
 
@@ -504,9 +554,9 @@ def get_glob_cluster_names(cluster_name: str) -> List[str]:
504
554
  cluster_table.c.name.op('GLOB')(cluster_name)).all()
505
555
  elif (_SQLALCHEMY_ENGINE.dialect.name ==
506
556
  db_utils.SQLAlchemyDialect.POSTGRESQL.value):
507
- # TODO(syang) support postgres dialect
508
- # postgres does not support GLOB
509
- raise ValueError('Unsupported database dialect')
557
+ rows = session.query(cluster_table).filter(
558
+ cluster_table.c.name.op('SIMILAR TO')(
559
+ _glob_to_similar(cluster_name))).all()
510
560
  else:
511
561
  raise ValueError('Unsupported database dialect')
512
562
  return [row.name for row in rows]
@@ -741,6 +791,7 @@ def get_cluster_from_name(
741
791
  'config_hash': row.config_hash,
742
792
  'workspace': row.workspace,
743
793
  }
794
+
744
795
  return record
745
796
 
746
797
 
@@ -849,21 +900,19 @@ def set_enabled_clouds(enabled_clouds: List[str],
849
900
  with orm.Session(_SQLALCHEMY_ENGINE) as session:
850
901
  if (_SQLALCHEMY_ENGINE.dialect.name ==
851
902
  db_utils.SQLAlchemyDialect.SQLITE.value):
852
- insert_stmnt = sqlite.insert(config_table).values(
853
- key=_get_enabled_clouds_key(cloud_capability, workspace),
854
- value=json.dumps(enabled_clouds))
855
- do_update_stmt = insert_stmnt.on_conflict_do_update(
856
- index_elements=[config_table.c.key],
857
- set_={config_table.c.value: json.dumps(enabled_clouds)})
858
- session.execute(do_update_stmt)
903
+ insert_func = sqlite.insert
859
904
  elif (_SQLALCHEMY_ENGINE.dialect.name ==
860
905
  db_utils.SQLAlchemyDialect.POSTGRESQL.value):
861
- # TODO(syang) support postgres dialect
862
- session.rollback()
863
- raise ValueError('Unsupported database dialect')
906
+ insert_func = postgresql.insert
864
907
  else:
865
- session.rollback()
866
908
  raise ValueError('Unsupported database dialect')
909
+ insert_stmnt = insert_func(config_table).values(
910
+ key=_get_enabled_clouds_key(cloud_capability, workspace),
911
+ value=json.dumps(enabled_clouds))
912
+ do_update_stmt = insert_stmnt.on_conflict_do_update(
913
+ index_elements=[config_table.c.key],
914
+ set_={config_table.c.value: json.dumps(enabled_clouds)})
915
+ session.execute(do_update_stmt)
867
916
  session.commit()
868
917
 
869
918
 
@@ -888,29 +937,27 @@ def add_or_update_storage(storage_name: str,
888
937
  with orm.Session(_SQLALCHEMY_ENGINE) as session:
889
938
  if (_SQLALCHEMY_ENGINE.dialect.name ==
890
939
  db_utils.SQLAlchemyDialect.SQLITE.value):
891
- insert_stmnt = sqlite.insert(storage_table).values(
892
- name=storage_name,
893
- handle=handle,
894
- last_use=last_use,
895
- launched_at=storage_launched_at,
896
- status=storage_status.value)
897
- do_update_stmt = insert_stmnt.on_conflict_do_update(
898
- index_elements=[storage_table.c.name],
899
- set_={
900
- storage_table.c.handle: handle,
901
- storage_table.c.last_use: last_use,
902
- storage_table.c.launched_at: storage_launched_at,
903
- storage_table.c.status: storage_status.value
904
- })
905
- session.execute(do_update_stmt)
940
+ insert_func = sqlite.insert
906
941
  elif (_SQLALCHEMY_ENGINE.dialect.name ==
907
942
  db_utils.SQLAlchemyDialect.POSTGRESQL.value):
908
- # TODO(syang) support postgres dialect
909
- session.rollback()
910
- raise ValueError('Unsupported database dialect')
943
+ insert_func = postgresql.insert
911
944
  else:
912
- session.rollback()
913
945
  raise ValueError('Unsupported database dialect')
946
+ insert_stmnt = insert_func(storage_table).values(
947
+ name=storage_name,
948
+ handle=handle,
949
+ last_use=last_use,
950
+ launched_at=storage_launched_at,
951
+ status=storage_status.value)
952
+ do_update_stmt = insert_stmnt.on_conflict_do_update(
953
+ index_elements=[storage_table.c.name],
954
+ set_={
955
+ storage_table.c.handle: handle,
956
+ storage_table.c.last_use: last_use,
957
+ storage_table.c.launched_at: storage_launched_at,
958
+ storage_table.c.status: storage_status.value
959
+ })
960
+ session.execute(do_update_stmt)
914
961
  session.commit()
915
962
 
916
963
 
@@ -973,9 +1020,9 @@ def get_glob_storage_name(storage_name: str) -> List[str]:
973
1020
  storage_table.c.name.op('GLOB')(storage_name)).all()
974
1021
  elif (_SQLALCHEMY_ENGINE.dialect.name ==
975
1022
  db_utils.SQLAlchemyDialect.POSTGRESQL.value):
976
- # TODO(syang) support postgres dialect
977
- # postgres does not support GLOB
978
- raise ValueError('Unsupported database dialect')
1023
+ rows = session.query(storage_table).filter(
1024
+ storage_table.c.name.op('SIMILAR TO')(
1025
+ _glob_to_similar(storage_name))).all()
979
1026
  else:
980
1027
  raise ValueError('Unsupported database dialect')
981
1028
  return [row.name for row in rows]
@@ -1525,7 +1525,7 @@ def is_kubeconfig_exec_auth(
1525
1525
  return False, None
1526
1526
 
1527
1527
  # Get active context and user from kubeconfig using k8s api
1528
- all_contexts, current_context = k8s.config.list_kube_config_contexts()
1528
+ all_contexts, current_context = kubernetes.list_kube_config_contexts()
1529
1529
  context_obj = current_context
1530
1530
  if context is not None:
1531
1531
  for c in all_contexts:
@@ -1581,7 +1581,7 @@ def get_current_kube_config_context_name() -> Optional[str]:
1581
1581
  """
1582
1582
  k8s = kubernetes.kubernetes
1583
1583
  try:
1584
- _, current_context = k8s.config.list_kube_config_contexts()
1584
+ _, current_context = kubernetes.list_kube_config_contexts()
1585
1585
  return current_context['name']
1586
1586
  except k8s.config.config_exception.ConfigException:
1587
1587
  return None
@@ -1617,7 +1617,7 @@ def get_all_kube_context_names() -> List[str]:
1617
1617
  k8s = kubernetes.kubernetes
1618
1618
  context_names = []
1619
1619
  try:
1620
- all_contexts, _ = k8s.config.list_kube_config_contexts()
1620
+ all_contexts, _ = kubernetes.list_kube_config_contexts()
1621
1621
  # all_contexts will always have at least one context. If kubeconfig
1622
1622
  # does not have any contexts defined, it will raise ConfigException.
1623
1623
  context_names = [context['name'] for context in all_contexts]
@@ -1660,7 +1660,7 @@ def get_kube_config_context_namespace(
1660
1660
  return f.read().strip()
1661
1661
  # If not in-cluster, get the namespace from kubeconfig
1662
1662
  try:
1663
- contexts, current_context = k8s.config.list_kube_config_contexts()
1663
+ contexts, current_context = kubernetes.list_kube_config_contexts()
1664
1664
  if context_name is None:
1665
1665
  context = current_context
1666
1666
  else:
sky/server/constants.py CHANGED
@@ -7,7 +7,7 @@ from sky.skylet import constants
7
7
  # API server version, whenever there is a change in API server that requires a
8
8
  # restart of the local API server or error out when the client does not match
9
9
  # the server version.
10
- API_VERSION = '5'
10
+ API_VERSION = '6'
11
11
 
12
12
  # Prefix for API request names.
13
13
  REQUEST_NAME_PREFIX = 'sky.'
@@ -72,6 +72,8 @@ def request_body_env_vars() -> dict:
72
72
 
73
73
  def get_override_skypilot_config_from_client() -> Dict[str, Any]:
74
74
  """Returns the override configs from the client."""
75
+ if annotations.is_on_api_server:
76
+ return {}
75
77
  config = skypilot_config.to_dict()
76
78
  # Remove the API server config, as we should not specify the SkyPilot
77
79
  # server endpoint on the server side. This avoids the warning at
@@ -134,6 +136,12 @@ class CheckBody(RequestBody):
134
136
  workspace: Optional[str] = None
135
137
 
136
138
 
139
+ class EnabledCloudsBody(RequestBody):
140
+ """The request body for the enabled clouds endpoint."""
141
+ workspace: Optional[str] = None
142
+ expand: bool = False
143
+
144
+
137
145
  class DagRequestBody(RequestBody):
138
146
  """Request body base class for endpoints with a dag."""
139
147
  dag: str
@@ -533,11 +541,6 @@ class UploadZipFileResponse(pydantic.BaseModel):
533
541
  missing_chunks: Optional[List[str]] = None
534
542
 
535
543
 
536
- class EnabledCloudsBody(RequestBody):
537
- """The request body for the enabled clouds endpoint."""
538
- workspace: Optional[str] = None
539
-
540
-
541
544
  class UpdateWorkspaceBody(RequestBody):
542
545
  """The request body for updating a specific workspace configuration."""
543
546
  workspace_name: str = '' # Will be set from path parameter
@@ -553,3 +556,13 @@ class CreateWorkspaceBody(RequestBody):
553
556
  class DeleteWorkspaceBody(RequestBody):
554
557
  """The request body for deleting a workspace."""
555
558
  workspace_name: str
559
+
560
+
561
+ class UpdateConfigBody(RequestBody):
562
+ """The request body for updating the entire SkyPilot configuration."""
563
+ config: Dict[str, Any]
564
+
565
+
566
+ class GetConfigBody(RequestBody):
567
+ """The request body for getting the entire SkyPilot configuration."""
568
+ pass