skypilot-nightly 1.0.0.dev20250625__py3-none-any.whl → 1.0.0.dev20250626__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.
- sky/__init__.py +2 -2
- sky/adaptors/kubernetes.py +1 -6
- sky/client/cli/command.py +10 -5
- sky/client/sdk.py +91 -15
- sky/clouds/ssh.py +36 -0
- sky/core.py +20 -0
- sky/dashboard/out/404.html +1 -1
- sky/dashboard/out/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js +1 -0
- sky/dashboard/out/_next/static/chunks/141-fa5a20cbf401b351.js +11 -0
- sky/dashboard/out/_next/static/chunks/25.76c246239df93d50.js +6 -0
- sky/dashboard/out/_next/static/chunks/43-36177d00f6956ab2.js +1 -0
- sky/dashboard/out/_next/static/chunks/430.ed51037d1a4a438b.js +1 -0
- sky/dashboard/out/_next/static/chunks/690.55f9eed3be903f56.js +16 -0
- sky/dashboard/out/_next/static/chunks/785.dc2686c3c1235554.js +1 -0
- sky/dashboard/out/_next/static/chunks/871-3db673be3ee3750b.js +6 -0
- sky/dashboard/out/_next/static/chunks/875.52c962183328b3f2.js +25 -0
- sky/dashboard/out/_next/static/chunks/973-81b2d057178adb76.js +1 -0
- sky/dashboard/out/_next/static/chunks/982.1b61658204416b0f.js +1 -0
- sky/dashboard/out/_next/static/chunks/984.e8bac186a24e5178.js +1 -0
- sky/dashboard/out/_next/static/chunks/990-0ad5ea1699e03ee8.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/{[cluster]-32ce4f49f2261f55.js → [cluster]-8040f2483897ed0c.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/clusters-f119a5630a1efd61.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/config-6b255eae088da6a3.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/infra/[context]-b302aea4d65766bf.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/infra-ee8cc4d449945d19.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/{jobs-26da173e20af16e4.js → jobs-0a5695ff3075d94a.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/{users-ce29e7420385563d.js → users-4978cbb093e141e7.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/workspace/new-5b59bce9eb208d84.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/workspaces/[name]-cb7e720b739de53a.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/{workspaces-862b120406461b10.js → workspaces-50e230828730cfb3.js} +1 -1
- sky/dashboard/out/_next/static/chunks/webpack-08fdb9e6070127fc.js +1 -0
- sky/dashboard/out/_next/static/css/52082cf558ec9705.css +3 -0
- sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
- sky/dashboard/out/clusters/[cluster].html +1 -1
- sky/dashboard/out/clusters.html +1 -1
- sky/dashboard/out/config.html +1 -1
- sky/dashboard/out/index.html +1 -1
- sky/dashboard/out/infra/[context].html +1 -1
- sky/dashboard/out/infra.html +1 -1
- sky/dashboard/out/jobs/[job].html +1 -1
- sky/dashboard/out/jobs.html +1 -1
- sky/dashboard/out/users.html +1 -1
- sky/dashboard/out/volumes.html +1 -1
- sky/dashboard/out/workspace/new.html +1 -1
- sky/dashboard/out/workspaces/[name].html +1 -1
- sky/dashboard/out/workspaces.html +1 -1
- sky/provision/kubernetes/utils.py +18 -2
- sky/server/rest.py +3 -2
- sky/server/server.py +4 -27
- sky/skylet/constants.py +5 -0
- sky/skypilot_config.py +3 -0
- sky/ssh_node_pools/__init__.py +1 -0
- sky/ssh_node_pools/core.py +133 -0
- sky/ssh_node_pools/server.py +232 -0
- sky/utils/kubernetes/deploy_remote_cluster.py +12 -185
- sky/utils/kubernetes/ssh_utils.py +221 -0
- {skypilot_nightly-1.0.0.dev20250625.dist-info → skypilot_nightly-1.0.0.dev20250626.dist-info}/METADATA +1 -1
- {skypilot_nightly-1.0.0.dev20250625.dist-info → skypilot_nightly-1.0.0.dev20250626.dist-info}/RECORD +64 -59
- sky/dashboard/out/_next/static/ZWdSYkqVe3WjnFR8ocqoG/_buildManifest.js +0 -1
- sky/dashboard/out/_next/static/chunks/211.692afc57e812ae1a.js +0 -1
- sky/dashboard/out/_next/static/chunks/310.2671028c20e892c7.js +0 -16
- sky/dashboard/out/_next/static/chunks/37-1f1e94f5a561202a.js +0 -6
- sky/dashboard/out/_next/static/chunks/42.bc85e5b1a4debf22.js +0 -6
- sky/dashboard/out/_next/static/chunks/443.b2242d0efcdf5f47.js +0 -1
- sky/dashboard/out/_next/static/chunks/513.309df9e18a9ff005.js +0 -1
- sky/dashboard/out/_next/static/chunks/66-66ae330df2d3c1c7.js +0 -1
- sky/dashboard/out/_next/static/chunks/682.00e56a220dd26fe1.js +0 -6
- sky/dashboard/out/_next/static/chunks/843-07d25a7e64462fd8.js +0 -11
- sky/dashboard/out/_next/static/chunks/856-cdf66268ec878d0c.js +0 -1
- sky/dashboard/out/_next/static/chunks/973-5b5019ba333e8d62.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/clusters-4aa031d1f42723d8.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/config-3102d02a188f04b3.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/infra/[context]-6f1e02e31eecb5ce.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/infra-fd5dc8a91bd9169a.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/workspace/new-09ae0f6f972aa871.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/workspaces/[name]-0b4c662a25e4747a.js +0 -1
- sky/dashboard/out/_next/static/chunks/webpack-6133dc1e928bd0b5.js +0 -1
- sky/dashboard/out/_next/static/css/b23cb0257bf96c51.css +0 -3
- /sky/dashboard/out/_next/static/{ZWdSYkqVe3WjnFR8ocqoG → bs6UB9V4Jq10TIZ5x-kBK}/_ssgManifest.js +0 -0
- /sky/dashboard/out/_next/static/chunks/pages/{_app-0ef7418d1a3822f3.js → _app-9a3ce3170d2edcec.js} +0 -0
- {skypilot_nightly-1.0.0.dev20250625.dist-info → skypilot_nightly-1.0.0.dev20250626.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20250625.dist-info → skypilot_nightly-1.0.0.dev20250626.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250625.dist-info → skypilot_nightly-1.0.0.dev20250626.dist-info}/licenses/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250625.dist-info → skypilot_nightly-1.0.0.dev20250626.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/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-d6128fa9e7cae6e6.js" defer=""></script><script src="/dashboard/_next/static/chunks/230-d6e363362017ff3a.js" defer=""></script><script src="/dashboard/_next/static/chunks/799-3625946b2ec2eb30.js" defer=""></script><script src="/dashboard/_next/static/chunks/664-047bc03493fda379.js" defer=""></script><script src="/dashboard/_next/static/chunks/804-4c9fc53aa74bc191.js" defer=""></script><script src="/dashboard/_next/static/chunks/798-c0525dc3f21e488d.js" defer=""></script><script src="/dashboard/_next/static/chunks/947-6620842ef80ae879.js" defer=""></script><script src="/dashboard/_next/static/chunks/989-db34c16ad7ea6155.js" defer=""></script><script src="/dashboard/_next/static/chunks/470-92dd1614396389be.js" defer=""></script><script src="/dashboard/_next/static/chunks/990-0ad5ea1699e03ee8.js" defer=""></script><script src="/dashboard/_next/static/chunks/969-d3a0b53f728d280a.js" defer=""></script><script src="/dashboard/_next/static/chunks/43-36177d00f6956ab2.js" defer=""></script><script src="/dashboard/_next/static/chunks/973-81b2d057178adb76.js" defer=""></script><script src="/dashboard/_next/static/chunks/938-068520cc11738deb.js" defer=""></script><script src="/dashboard/_next/static/chunks/871-3db673be3ee3750b.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters/%5Bcluster%5D-8040f2483897ed0c.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters/[cluster]","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
sky/dashboard/out/clusters.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters-f119a5630a1efd61.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
sky/dashboard/out/config.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/config-6b255eae088da6a3.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/config","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
sky/dashboard/out/index.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/index-6b0d9e5031b70c58.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","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/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/infra/%5Bcontext%5D-b302aea4d65766bf.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/infra/[context]","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
sky/dashboard/out/infra.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/infra-ee8cc4d449945d19.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/infra","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","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/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-d6128fa9e7cae6e6.js" defer=""></script><script src="/dashboard/_next/static/chunks/230-d6e363362017ff3a.js" defer=""></script><script src="/dashboard/_next/static/chunks/799-3625946b2ec2eb30.js" defer=""></script><script src="/dashboard/_next/static/chunks/664-047bc03493fda379.js" defer=""></script><script src="/dashboard/_next/static/chunks/804-4c9fc53aa74bc191.js" defer=""></script><script src="/dashboard/_next/static/chunks/798-c0525dc3f21e488d.js" defer=""></script><script src="/dashboard/_next/static/chunks/989-db34c16ad7ea6155.js" defer=""></script><script src="/dashboard/_next/static/chunks/470-92dd1614396389be.js" defer=""></script><script src="/dashboard/_next/static/chunks/969-d3a0b53f728d280a.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs/%5Bjob%5D-e4b23128db0774cd.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs/[job]","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
sky/dashboard/out/jobs.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/jobs-0a5695ff3075d94a.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/jobs","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
sky/dashboard/out/users.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/users-4978cbb093e141e7.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/users","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
sky/dashboard/out/volumes.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/volumes-476b670ef33d1ecd.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/volumes","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","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/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspace/new-5b59bce9eb208d84.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspace/new","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","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/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/616-d6128fa9e7cae6e6.js" defer=""></script><script src="/dashboard/_next/static/chunks/230-d6e363362017ff3a.js" defer=""></script><script src="/dashboard/_next/static/chunks/799-3625946b2ec2eb30.js" defer=""></script><script src="/dashboard/_next/static/chunks/664-047bc03493fda379.js" defer=""></script><script src="/dashboard/_next/static/chunks/804-4c9fc53aa74bc191.js" defer=""></script><script src="/dashboard/_next/static/chunks/798-c0525dc3f21e488d.js" defer=""></script><script src="/dashboard/_next/static/chunks/947-6620842ef80ae879.js" defer=""></script><script src="/dashboard/_next/static/chunks/989-db34c16ad7ea6155.js" defer=""></script><script src="/dashboard/_next/static/chunks/470-92dd1614396389be.js" defer=""></script><script src="/dashboard/_next/static/chunks/990-0ad5ea1699e03ee8.js" defer=""></script><script src="/dashboard/_next/static/chunks/969-d3a0b53f728d280a.js" defer=""></script><script src="/dashboard/_next/static/chunks/43-36177d00f6956ab2.js" defer=""></script><script src="/dashboard/_next/static/chunks/973-81b2d057178adb76.js" defer=""></script><script src="/dashboard/_next/static/chunks/938-068520cc11738deb.js" defer=""></script><script src="/dashboard/_next/static/chunks/141-fa5a20cbf401b351.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces/%5Bname%5D-cb7e720b739de53a.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces/[name]","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","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/
|
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/52082cf558ec9705.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/52082cf558ec9705.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-08fdb9e6070127fc.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-9a3ce3170d2edcec.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/workspaces-50e230828730cfb3.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bs6UB9V4Jq10TIZ5x-kBK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/workspaces","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|
@@ -1625,9 +1625,15 @@ def _get_kubeconfig_text_for_context(context: Optional[str] = None) -> str:
|
|
1625
1625
|
command = 'kubectl config view --minify'
|
1626
1626
|
if context is not None:
|
1627
1627
|
command += f' --context={context}'
|
1628
|
+
|
1629
|
+
# Ensure subprocess inherits the current environment properly
|
1630
|
+
# This fixes the issue where kubectl can't find ~/.kube/config in API server context
|
1631
|
+
env = os.environ.copy()
|
1632
|
+
|
1628
1633
|
proc = subprocess.run(command,
|
1629
1634
|
shell=True,
|
1630
1635
|
check=False,
|
1636
|
+
env=env,
|
1631
1637
|
stdout=subprocess.PIPE,
|
1632
1638
|
stderr=subprocess.PIPE)
|
1633
1639
|
if proc.returncode != 0:
|
@@ -3295,8 +3301,18 @@ def format_kubeconfig_exec_auth_with_cache(kubeconfig_path: str) -> str:
|
|
3295
3301
|
if os.path.isfile(path):
|
3296
3302
|
return path
|
3297
3303
|
|
3298
|
-
|
3299
|
-
|
3304
|
+
try:
|
3305
|
+
format_kubeconfig_exec_auth(config, path)
|
3306
|
+
return path
|
3307
|
+
except Exception as e: # pylint: disable=broad-except
|
3308
|
+
# There may be problems with kubeconfig, but the user is not actually
|
3309
|
+
# using Kubernetes (or SSH Node Pools)
|
3310
|
+
logger.warning(
|
3311
|
+
f'Failed to format kubeconfig at {kubeconfig_path}. '
|
3312
|
+
'Please check if the kubeconfig is valid. This may cause '
|
3313
|
+
'problems when Kubernetes infra is used. '
|
3314
|
+
f'Reason: {common_utils.format_exception(e)}')
|
3315
|
+
return kubeconfig_path
|
3300
3316
|
|
3301
3317
|
|
3302
3318
|
def delete_k8s_resource_with_retry(delete_func: Callable, resource_type: str,
|
sky/server/rest.py
CHANGED
@@ -64,8 +64,9 @@ def retry_on_server_unavailable(max_wait_seconds: int = 600,
|
|
64
64
|
@functools.wraps(func)
|
65
65
|
def wrapper(*args, **kwargs) -> Any:
|
66
66
|
msg = (
|
67
|
-
f'{colorama.Fore.YELLOW}API server is temporarily:
|
68
|
-
|
67
|
+
f'{colorama.Fore.YELLOW}API server is temporarily unavailable: '
|
68
|
+
'upgrade in progress. Waiting to resume...'
|
69
|
+
f'{colorama.Style.RESET_ALL}')
|
69
70
|
backoff = common_utils.Backoff(
|
70
71
|
initial_backoff=initial_backoff,
|
71
72
|
max_backoff_factor=max_backoff_factor)
|
sky/server/server.py
CHANGED
@@ -52,6 +52,7 @@ from sky.server.requests import payloads
|
|
52
52
|
from sky.server.requests import preconditions
|
53
53
|
from sky.server.requests import requests as requests_lib
|
54
54
|
from sky.skylet import constants
|
55
|
+
from sky.ssh_node_pools import server as ssh_node_pools_rest
|
55
56
|
from sky.usage import usage_lib
|
56
57
|
from sky.users import permission
|
57
58
|
from sky.users import server as users_rest
|
@@ -432,6 +433,9 @@ app.include_router(workspaces_rest.router,
|
|
432
433
|
prefix='/workspaces',
|
433
434
|
tags=['workspaces'])
|
434
435
|
app.include_router(volumes_rest.router, prefix='/volumes', tags=['volumes'])
|
436
|
+
app.include_router(ssh_node_pools_rest.router,
|
437
|
+
prefix='/ssh_node_pools',
|
438
|
+
tags=['ssh_node_pools'])
|
435
439
|
|
436
440
|
|
437
441
|
@app.get('/token')
|
@@ -1141,33 +1145,6 @@ async def local_down(request: fastapi.Request) -> None:
|
|
1141
1145
|
)
|
1142
1146
|
|
1143
1147
|
|
1144
|
-
@app.post('/ssh_up')
|
1145
|
-
async def ssh_up(request: fastapi.Request,
|
1146
|
-
ssh_up_body: payloads.SSHUpBody) -> None:
|
1147
|
-
"""Deploys a Kubernetes cluster on SSH targets."""
|
1148
|
-
executor.schedule_request(
|
1149
|
-
request_id=request.state.request_id,
|
1150
|
-
request_name='ssh_up',
|
1151
|
-
request_body=ssh_up_body,
|
1152
|
-
func=core.ssh_up,
|
1153
|
-
schedule_type=requests_lib.ScheduleType.LONG,
|
1154
|
-
)
|
1155
|
-
|
1156
|
-
|
1157
|
-
@app.post('/ssh_down')
|
1158
|
-
async def ssh_down(request: fastapi.Request,
|
1159
|
-
ssh_up_body: payloads.SSHUpBody) -> None:
|
1160
|
-
"""Tears down a Kubernetes cluster on SSH targets."""
|
1161
|
-
# We still call ssh_up but with cleanup=True
|
1162
|
-
executor.schedule_request(
|
1163
|
-
request_id=request.state.request_id,
|
1164
|
-
request_name='ssh_down',
|
1165
|
-
request_body=ssh_up_body,
|
1166
|
-
func=core.ssh_up, # Reuse ssh_up function with cleanup=True
|
1167
|
-
schedule_type=requests_lib.ScheduleType.LONG,
|
1168
|
-
)
|
1169
|
-
|
1170
|
-
|
1171
1148
|
# === API server related APIs ===
|
1172
1149
|
@app.get('/api/get')
|
1173
1150
|
async def api_get(request_id: str) -> requests_lib.RequestPayload:
|
sky/skylet/constants.py
CHANGED
@@ -415,6 +415,11 @@ ENV_VAR_IS_SKYPILOT_SERVER = 'IS_SKYPILOT_SERVER'
|
|
415
415
|
|
416
416
|
# Environment variable that is set to 'true' if metrics are enabled.
|
417
417
|
ENV_VAR_SERVER_METRICS_ENABLED = 'SKY_API_SERVER_METRICS_ENABLED'
|
418
|
+
|
419
|
+
# Environment variable that is used as the DB connection string for the
|
420
|
+
# skypilot server.
|
421
|
+
ENV_VAR_DB_CONNECTION_URI = (f'{SKYPILOT_ENV_VAR_PREFIX}DB_CONNECTION_URI')
|
422
|
+
|
418
423
|
# Environment variable that is set to 'true' if basic
|
419
424
|
# authentication is enabled in the API server.
|
420
425
|
ENV_VAR_ENABLE_BASIC_AUTH = 'ENABLE_BASIC_AUTH'
|
sky/skypilot_config.py
CHANGED
@@ -564,7 +564,10 @@ def _reload_config_as_server() -> None:
|
|
564
564
|
_set_loaded_config_path(None)
|
565
565
|
|
566
566
|
server_config_path = _resolve_server_config_path()
|
567
|
+
db_url_from_env = os.environ.get(constants.ENV_VAR_DB_CONNECTION_URI)
|
567
568
|
server_config = _get_config_from_path(server_config_path)
|
569
|
+
if db_url_from_env:
|
570
|
+
server_config.set_nested(('db',), db_url_from_env)
|
568
571
|
|
569
572
|
if sky_logging.logging_enabled(logger, sky_logging.DEBUG):
|
570
573
|
logger.debug(f'server config: \n'
|
@@ -0,0 +1 @@
|
|
1
|
+
"""SSH Node Pool management package."""
|
@@ -0,0 +1,133 @@
|
|
1
|
+
"""SSH Node Pool management core functionality."""
|
2
|
+
import os
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Any, Dict, List
|
5
|
+
|
6
|
+
import yaml
|
7
|
+
|
8
|
+
|
9
|
+
class SSHNodePoolManager:
|
10
|
+
"""Manager for SSH Node Pool configurations."""
|
11
|
+
|
12
|
+
def __init__(self):
|
13
|
+
self.config_path = Path.home() / '.sky' / 'ssh_node_pools.yaml'
|
14
|
+
self.keys_dir = Path.home() / '.sky' / 'ssh_keys'
|
15
|
+
self.keys_dir.mkdir(parents=True, exist_ok=True)
|
16
|
+
|
17
|
+
def get_all_pools(self) -> Dict[str, Any]:
|
18
|
+
"""Read all SSH Node Pool configurations from YAML file."""
|
19
|
+
if not self.config_path.exists():
|
20
|
+
return {}
|
21
|
+
|
22
|
+
try:
|
23
|
+
with open(self.config_path, 'r', encoding='utf-8') as f:
|
24
|
+
return yaml.safe_load(f) or {}
|
25
|
+
except Exception as e:
|
26
|
+
raise RuntimeError(
|
27
|
+
f'Failed to read SSH Node Pool config: {e}') from e
|
28
|
+
|
29
|
+
def save_all_pools(self, pools_config: Dict[str, Any]) -> None:
|
30
|
+
"""Write SSH Node Pool configurations to YAML file."""
|
31
|
+
try:
|
32
|
+
self.config_path.parent.mkdir(parents=True, exist_ok=True)
|
33
|
+
with open(self.config_path, 'w', encoding='utf-8') as f:
|
34
|
+
yaml.dump(pools_config, f, default_flow_style=False)
|
35
|
+
except Exception as e:
|
36
|
+
raise RuntimeError(
|
37
|
+
f'Failed to save SSH Node Pool config: {e}') from e
|
38
|
+
|
39
|
+
def update_pools(self, pools_config: Dict[str, Any]) -> None:
|
40
|
+
"""Update SSH Node Pool configurations."""
|
41
|
+
all_pools = self.get_all_pools()
|
42
|
+
all_pools.update(pools_config)
|
43
|
+
self.save_all_pools(all_pools)
|
44
|
+
|
45
|
+
def add_or_update_pool(self, pool_name: str,
|
46
|
+
pool_config: Dict[str, Any]) -> None:
|
47
|
+
"""Add or update a single SSH Node Pool configuration."""
|
48
|
+
# Validate pool configuration
|
49
|
+
self._validate_pool_config(pool_config)
|
50
|
+
|
51
|
+
all_pools = self.get_all_pools()
|
52
|
+
all_pools[pool_name] = pool_config
|
53
|
+
self.save_all_pools(all_pools)
|
54
|
+
|
55
|
+
def delete_pool(self, pool_name: str) -> bool:
|
56
|
+
"""Delete a SSH Node Pool configuration."""
|
57
|
+
all_pools = self.get_all_pools()
|
58
|
+
if pool_name in all_pools:
|
59
|
+
del all_pools[pool_name]
|
60
|
+
self.save_all_pools(all_pools)
|
61
|
+
return True
|
62
|
+
return False
|
63
|
+
|
64
|
+
def save_ssh_key(self, key_name: str, key_content: str) -> str:
|
65
|
+
"""Save SSH private key to ~/.sky/ssh_keys/ directory."""
|
66
|
+
# Validate key name
|
67
|
+
if not key_name or '/' in key_name or key_name.startswith('.'):
|
68
|
+
raise ValueError('Invalid key name')
|
69
|
+
|
70
|
+
key_path = self.keys_dir / key_name
|
71
|
+
try:
|
72
|
+
with open(key_path, 'w', encoding='utf-8') as f:
|
73
|
+
f.write(key_content)
|
74
|
+
os.chmod(key_path, 0o600) # Set secure permissions
|
75
|
+
return str(key_path)
|
76
|
+
except Exception as e:
|
77
|
+
raise RuntimeError(f'Failed to save SSH key: {e}') from e
|
78
|
+
|
79
|
+
def list_ssh_keys(self) -> List[str]:
|
80
|
+
"""List available SSH key files."""
|
81
|
+
if not self.keys_dir.exists():
|
82
|
+
return []
|
83
|
+
try:
|
84
|
+
return [f.name for f in self.keys_dir.iterdir() if f.is_file()]
|
85
|
+
except Exception: # pylint: disable=broad-except
|
86
|
+
return []
|
87
|
+
|
88
|
+
def _validate_pool_config(self, config: Dict[str, Any]) -> None:
|
89
|
+
"""Validate SSH Node Pool configuration."""
|
90
|
+
if 'hosts' not in config:
|
91
|
+
raise ValueError('Pool configuration must include `hosts`')
|
92
|
+
|
93
|
+
if not isinstance(config['hosts'], list) or not config['hosts']:
|
94
|
+
raise ValueError('`hosts` must be a non-empty list')
|
95
|
+
|
96
|
+
# Validate user field
|
97
|
+
if not config.get('user', '').strip():
|
98
|
+
raise ValueError('Pool configuration must include `user`')
|
99
|
+
|
100
|
+
# Validate authentication - must have either identity_file or password
|
101
|
+
if not config.get('identity_file') and not config.get('password'):
|
102
|
+
raise ValueError('Pool configuration must include '
|
103
|
+
'either `identity_file` or `password`')
|
104
|
+
|
105
|
+
|
106
|
+
def get_all_pools() -> Dict[str, Any]:
|
107
|
+
"""Get all SSH Node Pool configurations."""
|
108
|
+
manager = SSHNodePoolManager()
|
109
|
+
return manager.get_all_pools()
|
110
|
+
|
111
|
+
|
112
|
+
def update_pools(pools_config: Dict[str, Any]) -> None:
|
113
|
+
"""Update SSH Node Pool configurations."""
|
114
|
+
manager = SSHNodePoolManager()
|
115
|
+
manager.update_pools(pools_config)
|
116
|
+
|
117
|
+
|
118
|
+
def delete_pool(pool_name: str) -> bool:
|
119
|
+
"""Delete a SSH Node Pool configuration."""
|
120
|
+
manager = SSHNodePoolManager()
|
121
|
+
return manager.delete_pool(pool_name)
|
122
|
+
|
123
|
+
|
124
|
+
def upload_ssh_key(key_name: str, key_content: str) -> str:
|
125
|
+
"""Upload SSH private key."""
|
126
|
+
manager = SSHNodePoolManager()
|
127
|
+
return manager.save_ssh_key(key_name, key_content)
|
128
|
+
|
129
|
+
|
130
|
+
def list_ssh_keys() -> List[str]:
|
131
|
+
"""List available SSH keys."""
|
132
|
+
manager = SSHNodePoolManager()
|
133
|
+
return manager.list_ssh_keys()
|