skypilot-nightly 1.0.0.dev20250905__py3-none-any.whl → 1.0.0.dev20251203__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 (397) hide show
  1. sky/__init__.py +10 -2
  2. sky/adaptors/aws.py +81 -16
  3. sky/adaptors/common.py +25 -2
  4. sky/adaptors/coreweave.py +278 -0
  5. sky/adaptors/do.py +8 -2
  6. sky/adaptors/gcp.py +11 -0
  7. sky/adaptors/ibm.py +5 -2
  8. sky/adaptors/kubernetes.py +64 -0
  9. sky/adaptors/nebius.py +3 -1
  10. sky/adaptors/primeintellect.py +1 -0
  11. sky/adaptors/seeweb.py +183 -0
  12. sky/adaptors/shadeform.py +89 -0
  13. sky/admin_policy.py +20 -0
  14. sky/authentication.py +157 -263
  15. sky/backends/__init__.py +3 -2
  16. sky/backends/backend.py +11 -3
  17. sky/backends/backend_utils.py +588 -184
  18. sky/backends/cloud_vm_ray_backend.py +1088 -904
  19. sky/backends/local_docker_backend.py +9 -5
  20. sky/backends/task_codegen.py +633 -0
  21. sky/backends/wheel_utils.py +18 -0
  22. sky/catalog/__init__.py +8 -0
  23. sky/catalog/aws_catalog.py +4 -0
  24. sky/catalog/common.py +19 -1
  25. sky/catalog/data_fetchers/fetch_aws.py +102 -80
  26. sky/catalog/data_fetchers/fetch_gcp.py +30 -3
  27. sky/catalog/data_fetchers/fetch_nebius.py +9 -6
  28. sky/catalog/data_fetchers/fetch_runpod.py +698 -0
  29. sky/catalog/data_fetchers/fetch_seeweb.py +329 -0
  30. sky/catalog/data_fetchers/fetch_shadeform.py +142 -0
  31. sky/catalog/kubernetes_catalog.py +24 -28
  32. sky/catalog/primeintellect_catalog.py +95 -0
  33. sky/catalog/runpod_catalog.py +5 -1
  34. sky/catalog/seeweb_catalog.py +184 -0
  35. sky/catalog/shadeform_catalog.py +165 -0
  36. sky/check.py +73 -43
  37. sky/client/cli/command.py +675 -412
  38. sky/client/cli/flags.py +4 -2
  39. sky/{volumes/utils.py → client/cli/table_utils.py} +111 -13
  40. sky/client/cli/utils.py +79 -0
  41. sky/client/common.py +12 -2
  42. sky/client/sdk.py +132 -63
  43. sky/client/sdk_async.py +34 -33
  44. sky/cloud_stores.py +82 -3
  45. sky/clouds/__init__.py +6 -0
  46. sky/clouds/aws.py +337 -129
  47. sky/clouds/azure.py +24 -18
  48. sky/clouds/cloud.py +40 -13
  49. sky/clouds/cudo.py +16 -13
  50. sky/clouds/do.py +9 -7
  51. sky/clouds/fluidstack.py +12 -5
  52. sky/clouds/gcp.py +14 -7
  53. sky/clouds/hyperbolic.py +12 -5
  54. sky/clouds/ibm.py +12 -5
  55. sky/clouds/kubernetes.py +80 -45
  56. sky/clouds/lambda_cloud.py +12 -5
  57. sky/clouds/nebius.py +23 -9
  58. sky/clouds/oci.py +19 -12
  59. sky/clouds/paperspace.py +4 -1
  60. sky/clouds/primeintellect.py +317 -0
  61. sky/clouds/runpod.py +85 -24
  62. sky/clouds/scp.py +12 -8
  63. sky/clouds/seeweb.py +477 -0
  64. sky/clouds/shadeform.py +400 -0
  65. sky/clouds/ssh.py +4 -2
  66. sky/clouds/utils/scp_utils.py +61 -50
  67. sky/clouds/vast.py +33 -27
  68. sky/clouds/vsphere.py +14 -16
  69. sky/core.py +174 -165
  70. sky/dashboard/out/404.html +1 -1
  71. sky/dashboard/out/_next/static/96_E2yl3QAiIJGOYCkSpB/_buildManifest.js +1 -0
  72. sky/dashboard/out/_next/static/chunks/1141-e6aa9ab418717c59.js +11 -0
  73. sky/dashboard/out/_next/static/chunks/1871-7e202677c42f43fe.js +6 -0
  74. sky/dashboard/out/_next/static/chunks/2260-7703229c33c5ebd5.js +1 -0
  75. sky/dashboard/out/_next/static/chunks/2369.fc20f0c2c8ed9fe7.js +15 -0
  76. sky/dashboard/out/_next/static/chunks/2755.edd818326d489a1d.js +26 -0
  77. sky/dashboard/out/_next/static/chunks/3294.20a8540fe697d5ee.js +1 -0
  78. sky/dashboard/out/_next/static/chunks/3785.7e245f318f9d1121.js +1 -0
  79. sky/dashboard/out/_next/static/chunks/{6601-06114c982db410b6.js → 3800-7b45f9fbb6308557.js} +1 -1
  80. sky/dashboard/out/_next/static/chunks/4725.172ede95d1b21022.js +1 -0
  81. sky/dashboard/out/_next/static/chunks/4937.a2baa2df5572a276.js +15 -0
  82. sky/dashboard/out/_next/static/chunks/6212-7bd06f60ba693125.js +13 -0
  83. sky/dashboard/out/_next/static/chunks/6856-8f27d1c10c98def8.js +1 -0
  84. sky/dashboard/out/_next/static/chunks/6990-9146207c4567fdfd.js +1 -0
  85. sky/dashboard/out/_next/static/chunks/7359-c8d04e06886000b3.js +30 -0
  86. sky/dashboard/out/_next/static/chunks/7615-019513abc55b3b47.js +1 -0
  87. sky/dashboard/out/_next/static/chunks/8640.5b9475a2d18c5416.js +16 -0
  88. sky/dashboard/out/_next/static/chunks/8969-452f9d5cbdd2dc73.js +1 -0
  89. sky/dashboard/out/_next/static/chunks/9025.fa408f3242e9028d.js +6 -0
  90. sky/dashboard/out/_next/static/chunks/9353-cff34f7e773b2e2b.js +1 -0
  91. sky/dashboard/out/_next/static/chunks/9360.a536cf6b1fa42355.js +31 -0
  92. sky/dashboard/out/_next/static/chunks/9847.3aaca6bb33455140.js +30 -0
  93. sky/dashboard/out/_next/static/chunks/pages/{_app-ce361c6959bc2001.js → _app-bde01e4a2beec258.js} +1 -1
  94. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-792db96d918c98c9.js +16 -0
  95. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-abfcac9c137aa543.js +1 -0
  96. sky/dashboard/out/_next/static/chunks/pages/clusters-ee39056f9851a3ff.js +1 -0
  97. sky/dashboard/out/_next/static/chunks/pages/infra/{[context]-6563820e094f68ca.js → [context]-c0b5935149902e6f.js} +1 -1
  98. sky/dashboard/out/_next/static/chunks/pages/{infra-aabba60d57826e0f.js → infra-aed0ea19df7cf961.js} +1 -1
  99. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-d66997e2bfc837cf.js +16 -0
  100. sky/dashboard/out/_next/static/chunks/pages/jobs/pools/[pool]-9faf940b253e3e06.js +21 -0
  101. sky/dashboard/out/_next/static/chunks/pages/jobs-2072b48b617989c9.js +1 -0
  102. sky/dashboard/out/_next/static/chunks/pages/users-f42674164aa73423.js +1 -0
  103. sky/dashboard/out/_next/static/chunks/pages/volumes-b84b948ff357c43e.js +1 -0
  104. sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-af76bb06dbb3954f.js → [name]-84a40f8c7c627fe4.js} +1 -1
  105. sky/dashboard/out/_next/static/chunks/pages/{workspaces-7598c33a746cdc91.js → workspaces-531b2f8c4bf89f82.js} +1 -1
  106. sky/dashboard/out/_next/static/chunks/webpack-64e05f17bf2cf8ce.js +1 -0
  107. sky/dashboard/out/_next/static/css/0748ce22df867032.css +3 -0
  108. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  109. sky/dashboard/out/clusters/[cluster].html +1 -1
  110. sky/dashboard/out/clusters.html +1 -1
  111. sky/dashboard/out/config.html +1 -1
  112. sky/dashboard/out/index.html +1 -1
  113. sky/dashboard/out/infra/[context].html +1 -1
  114. sky/dashboard/out/infra.html +1 -1
  115. sky/dashboard/out/jobs/[job].html +1 -1
  116. sky/dashboard/out/jobs/pools/[pool].html +1 -1
  117. sky/dashboard/out/jobs.html +1 -1
  118. sky/dashboard/out/users.html +1 -1
  119. sky/dashboard/out/volumes.html +1 -1
  120. sky/dashboard/out/workspace/new.html +1 -1
  121. sky/dashboard/out/workspaces/[name].html +1 -1
  122. sky/dashboard/out/workspaces.html +1 -1
  123. sky/data/data_utils.py +92 -1
  124. sky/data/mounting_utils.py +162 -29
  125. sky/data/storage.py +200 -19
  126. sky/data/storage_utils.py +10 -45
  127. sky/exceptions.py +18 -7
  128. sky/execution.py +74 -31
  129. sky/global_user_state.py +605 -191
  130. sky/jobs/__init__.py +2 -0
  131. sky/jobs/client/sdk.py +101 -4
  132. sky/jobs/client/sdk_async.py +31 -5
  133. sky/jobs/constants.py +15 -8
  134. sky/jobs/controller.py +726 -284
  135. sky/jobs/file_content_utils.py +128 -0
  136. sky/jobs/log_gc.py +193 -0
  137. sky/jobs/recovery_strategy.py +250 -100
  138. sky/jobs/scheduler.py +271 -173
  139. sky/jobs/server/core.py +367 -114
  140. sky/jobs/server/server.py +81 -35
  141. sky/jobs/server/utils.py +89 -35
  142. sky/jobs/state.py +1498 -620
  143. sky/jobs/utils.py +771 -306
  144. sky/logs/agent.py +40 -5
  145. sky/logs/aws.py +9 -19
  146. sky/metrics/utils.py +282 -39
  147. sky/optimizer.py +1 -1
  148. sky/provision/__init__.py +37 -1
  149. sky/provision/aws/config.py +34 -13
  150. sky/provision/aws/instance.py +5 -2
  151. sky/provision/azure/instance.py +5 -3
  152. sky/provision/common.py +2 -0
  153. sky/provision/cudo/instance.py +4 -3
  154. sky/provision/do/instance.py +4 -3
  155. sky/provision/docker_utils.py +97 -26
  156. sky/provision/fluidstack/instance.py +6 -5
  157. sky/provision/gcp/config.py +6 -1
  158. sky/provision/gcp/instance.py +4 -2
  159. sky/provision/hyperbolic/instance.py +4 -2
  160. sky/provision/instance_setup.py +66 -20
  161. sky/provision/kubernetes/__init__.py +2 -0
  162. sky/provision/kubernetes/config.py +7 -44
  163. sky/provision/kubernetes/constants.py +0 -1
  164. sky/provision/kubernetes/instance.py +609 -213
  165. sky/provision/kubernetes/manifests/fusermount-server-daemonset.yaml +1 -2
  166. sky/provision/kubernetes/network.py +12 -8
  167. sky/provision/kubernetes/network_utils.py +8 -25
  168. sky/provision/kubernetes/utils.py +382 -418
  169. sky/provision/kubernetes/volume.py +150 -18
  170. sky/provision/lambda_cloud/instance.py +16 -13
  171. sky/provision/nebius/instance.py +6 -2
  172. sky/provision/nebius/utils.py +103 -86
  173. sky/provision/oci/instance.py +4 -2
  174. sky/provision/paperspace/instance.py +4 -3
  175. sky/provision/primeintellect/__init__.py +10 -0
  176. sky/provision/primeintellect/config.py +11 -0
  177. sky/provision/primeintellect/instance.py +454 -0
  178. sky/provision/primeintellect/utils.py +398 -0
  179. sky/provision/provisioner.py +30 -9
  180. sky/provision/runpod/__init__.py +2 -0
  181. sky/provision/runpod/instance.py +4 -3
  182. sky/provision/runpod/volume.py +69 -13
  183. sky/provision/scp/instance.py +307 -130
  184. sky/provision/seeweb/__init__.py +11 -0
  185. sky/provision/seeweb/config.py +13 -0
  186. sky/provision/seeweb/instance.py +812 -0
  187. sky/provision/shadeform/__init__.py +11 -0
  188. sky/provision/shadeform/config.py +12 -0
  189. sky/provision/shadeform/instance.py +351 -0
  190. sky/provision/shadeform/shadeform_utils.py +83 -0
  191. sky/provision/vast/instance.py +5 -3
  192. sky/provision/volume.py +164 -0
  193. sky/provision/vsphere/common/ssl_helper.py +1 -1
  194. sky/provision/vsphere/common/vapiconnect.py +2 -1
  195. sky/provision/vsphere/common/vim_utils.py +3 -2
  196. sky/provision/vsphere/instance.py +8 -6
  197. sky/provision/vsphere/vsphere_utils.py +8 -1
  198. sky/resources.py +11 -3
  199. sky/schemas/api/responses.py +107 -6
  200. sky/schemas/db/global_user_state/008_skylet_ssh_tunnel_metadata.py +34 -0
  201. sky/schemas/db/global_user_state/009_last_activity_and_launched_at.py +89 -0
  202. sky/schemas/db/global_user_state/010_save_ssh_key.py +66 -0
  203. sky/schemas/db/global_user_state/011_is_ephemeral.py +34 -0
  204. sky/schemas/db/kv_cache/001_initial_schema.py +29 -0
  205. sky/schemas/db/serve_state/002_yaml_content.py +34 -0
  206. sky/schemas/db/skypilot_config/001_initial_schema.py +30 -0
  207. sky/schemas/db/spot_jobs/002_cluster_pool.py +3 -3
  208. sky/schemas/db/spot_jobs/004_job_file_contents.py +42 -0
  209. sky/schemas/db/spot_jobs/005_logs_gc.py +38 -0
  210. sky/schemas/db/spot_jobs/006_controller_pid_started_at.py +34 -0
  211. sky/schemas/db/spot_jobs/007_config_file_content.py +34 -0
  212. sky/schemas/generated/jobsv1_pb2.py +86 -0
  213. sky/schemas/generated/jobsv1_pb2.pyi +254 -0
  214. sky/schemas/generated/jobsv1_pb2_grpc.py +542 -0
  215. sky/schemas/generated/managed_jobsv1_pb2.py +76 -0
  216. sky/schemas/generated/managed_jobsv1_pb2.pyi +278 -0
  217. sky/schemas/generated/managed_jobsv1_pb2_grpc.py +278 -0
  218. sky/schemas/generated/servev1_pb2.py +58 -0
  219. sky/schemas/generated/servev1_pb2.pyi +115 -0
  220. sky/schemas/generated/servev1_pb2_grpc.py +322 -0
  221. sky/serve/autoscalers.py +2 -0
  222. sky/serve/client/impl.py +55 -21
  223. sky/serve/constants.py +4 -3
  224. sky/serve/controller.py +17 -11
  225. sky/serve/load_balancing_policies.py +1 -1
  226. sky/serve/replica_managers.py +219 -142
  227. sky/serve/serve_rpc_utils.py +179 -0
  228. sky/serve/serve_state.py +63 -54
  229. sky/serve/serve_utils.py +145 -109
  230. sky/serve/server/core.py +46 -25
  231. sky/serve/server/impl.py +311 -162
  232. sky/serve/server/server.py +21 -19
  233. sky/serve/service.py +84 -68
  234. sky/serve/service_spec.py +45 -7
  235. sky/server/auth/loopback.py +38 -0
  236. sky/server/auth/oauth2_proxy.py +12 -7
  237. sky/server/common.py +47 -24
  238. sky/server/config.py +62 -28
  239. sky/server/constants.py +9 -1
  240. sky/server/daemons.py +109 -38
  241. sky/server/metrics.py +76 -96
  242. sky/server/middleware_utils.py +166 -0
  243. sky/server/requests/executor.py +381 -145
  244. sky/server/requests/payloads.py +71 -18
  245. sky/server/requests/preconditions.py +15 -13
  246. sky/server/requests/request_names.py +121 -0
  247. sky/server/requests/requests.py +507 -157
  248. sky/server/requests/serializers/decoders.py +48 -17
  249. sky/server/requests/serializers/encoders.py +85 -20
  250. sky/server/requests/threads.py +117 -0
  251. sky/server/rest.py +116 -24
  252. sky/server/server.py +420 -172
  253. sky/server/stream_utils.py +219 -45
  254. sky/server/uvicorn.py +30 -19
  255. sky/setup_files/MANIFEST.in +6 -1
  256. sky/setup_files/alembic.ini +8 -0
  257. sky/setup_files/dependencies.py +62 -19
  258. sky/setup_files/setup.py +44 -44
  259. sky/sky_logging.py +13 -5
  260. sky/skylet/attempt_skylet.py +106 -24
  261. sky/skylet/configs.py +3 -1
  262. sky/skylet/constants.py +111 -26
  263. sky/skylet/events.py +64 -10
  264. sky/skylet/job_lib.py +141 -104
  265. sky/skylet/log_lib.py +233 -5
  266. sky/skylet/log_lib.pyi +40 -2
  267. sky/skylet/providers/ibm/node_provider.py +12 -8
  268. sky/skylet/providers/ibm/vpc_provider.py +13 -12
  269. sky/skylet/runtime_utils.py +21 -0
  270. sky/skylet/services.py +524 -0
  271. sky/skylet/skylet.py +22 -1
  272. sky/skylet/subprocess_daemon.py +104 -29
  273. sky/skypilot_config.py +99 -79
  274. sky/ssh_node_pools/server.py +9 -8
  275. sky/task.py +221 -104
  276. sky/templates/aws-ray.yml.j2 +1 -0
  277. sky/templates/azure-ray.yml.j2 +1 -0
  278. sky/templates/cudo-ray.yml.j2 +1 -0
  279. sky/templates/do-ray.yml.j2 +1 -0
  280. sky/templates/fluidstack-ray.yml.j2 +1 -0
  281. sky/templates/gcp-ray.yml.j2 +1 -0
  282. sky/templates/hyperbolic-ray.yml.j2 +1 -0
  283. sky/templates/ibm-ray.yml.j2 +2 -1
  284. sky/templates/jobs-controller.yaml.j2 +3 -0
  285. sky/templates/kubernetes-ray.yml.j2 +196 -55
  286. sky/templates/lambda-ray.yml.j2 +1 -0
  287. sky/templates/nebius-ray.yml.j2 +3 -0
  288. sky/templates/oci-ray.yml.j2 +1 -0
  289. sky/templates/paperspace-ray.yml.j2 +1 -0
  290. sky/templates/primeintellect-ray.yml.j2 +72 -0
  291. sky/templates/runpod-ray.yml.j2 +1 -0
  292. sky/templates/scp-ray.yml.j2 +1 -0
  293. sky/templates/seeweb-ray.yml.j2 +171 -0
  294. sky/templates/shadeform-ray.yml.j2 +73 -0
  295. sky/templates/vast-ray.yml.j2 +1 -0
  296. sky/templates/vsphere-ray.yml.j2 +1 -0
  297. sky/templates/websocket_proxy.py +188 -43
  298. sky/usage/usage_lib.py +16 -4
  299. sky/users/permission.py +60 -43
  300. sky/utils/accelerator_registry.py +6 -3
  301. sky/utils/admin_policy_utils.py +18 -5
  302. sky/utils/annotations.py +22 -0
  303. sky/utils/asyncio_utils.py +78 -0
  304. sky/utils/atomic.py +1 -1
  305. sky/utils/auth_utils.py +153 -0
  306. sky/utils/cli_utils/status_utils.py +12 -7
  307. sky/utils/cluster_utils.py +28 -6
  308. sky/utils/command_runner.py +88 -27
  309. sky/utils/command_runner.pyi +36 -3
  310. sky/utils/common.py +3 -1
  311. sky/utils/common_utils.py +37 -4
  312. sky/utils/config_utils.py +1 -14
  313. sky/utils/context.py +127 -40
  314. sky/utils/context_utils.py +73 -18
  315. sky/utils/controller_utils.py +229 -70
  316. sky/utils/db/db_utils.py +95 -18
  317. sky/utils/db/kv_cache.py +149 -0
  318. sky/utils/db/migration_utils.py +24 -7
  319. sky/utils/env_options.py +4 -0
  320. sky/utils/git.py +559 -1
  321. sky/utils/kubernetes/create_cluster.sh +15 -30
  322. sky/utils/kubernetes/delete_cluster.sh +10 -7
  323. sky/utils/kubernetes/{deploy_remote_cluster.py → deploy_ssh_node_pools.py} +258 -380
  324. sky/utils/kubernetes/generate_kind_config.py +6 -66
  325. sky/utils/kubernetes/gpu_labeler.py +13 -3
  326. sky/utils/kubernetes/k8s_gpu_labeler_job.yaml +2 -1
  327. sky/utils/kubernetes/k8s_gpu_labeler_setup.yaml +16 -16
  328. sky/utils/kubernetes/kubernetes_deploy_utils.py +213 -194
  329. sky/utils/kubernetes/rsync_helper.sh +11 -3
  330. sky/utils/kubernetes_enums.py +7 -15
  331. sky/utils/lock_events.py +4 -4
  332. sky/utils/locks.py +128 -31
  333. sky/utils/log_utils.py +0 -319
  334. sky/utils/resource_checker.py +13 -10
  335. sky/utils/resources_utils.py +53 -29
  336. sky/utils/rich_utils.py +8 -4
  337. sky/utils/schemas.py +107 -52
  338. sky/utils/subprocess_utils.py +17 -4
  339. sky/utils/thread_utils.py +91 -0
  340. sky/utils/timeline.py +2 -1
  341. sky/utils/ux_utils.py +35 -1
  342. sky/utils/volume.py +88 -4
  343. sky/utils/yaml_utils.py +9 -0
  344. sky/volumes/client/sdk.py +48 -10
  345. sky/volumes/server/core.py +59 -22
  346. sky/volumes/server/server.py +46 -17
  347. sky/volumes/volume.py +54 -42
  348. sky/workspaces/core.py +57 -21
  349. sky/workspaces/server.py +13 -12
  350. sky_templates/README.md +3 -0
  351. sky_templates/__init__.py +3 -0
  352. sky_templates/ray/__init__.py +0 -0
  353. sky_templates/ray/start_cluster +183 -0
  354. sky_templates/ray/stop_cluster +75 -0
  355. {skypilot_nightly-1.0.0.dev20250905.dist-info → skypilot_nightly-1.0.0.dev20251203.dist-info}/METADATA +331 -65
  356. skypilot_nightly-1.0.0.dev20251203.dist-info/RECORD +611 -0
  357. skypilot_nightly-1.0.0.dev20251203.dist-info/top_level.txt +2 -0
  358. sky/client/cli/git.py +0 -549
  359. sky/dashboard/out/_next/static/chunks/1121-408ed10b2f9fce17.js +0 -1
  360. sky/dashboard/out/_next/static/chunks/1141-943efc7aff0f0c06.js +0 -1
  361. sky/dashboard/out/_next/static/chunks/1836-37fede578e2da5f8.js +0 -40
  362. sky/dashboard/out/_next/static/chunks/3015-86cabed5d4669ad0.js +0 -1
  363. sky/dashboard/out/_next/static/chunks/3294.c80326aec9bfed40.js +0 -6
  364. sky/dashboard/out/_next/static/chunks/3785.4872a2f3aa489880.js +0 -1
  365. sky/dashboard/out/_next/static/chunks/4045.b30465273dc5e468.js +0 -21
  366. sky/dashboard/out/_next/static/chunks/4676-9da7fdbde90b5549.js +0 -10
  367. sky/dashboard/out/_next/static/chunks/4725.10f7a9a5d3ea8208.js +0 -1
  368. sky/dashboard/out/_next/static/chunks/5339.3fda4a4010ff4e06.js +0 -51
  369. sky/dashboard/out/_next/static/chunks/6135-4b4d5e824b7f9d3c.js +0 -1
  370. sky/dashboard/out/_next/static/chunks/649.b9d7f7d10c1b8c53.js +0 -45
  371. sky/dashboard/out/_next/static/chunks/6856-dca7962af4814e1b.js +0 -1
  372. sky/dashboard/out/_next/static/chunks/6990-08b2a1cae076a943.js +0 -1
  373. sky/dashboard/out/_next/static/chunks/7325.b4bc99ce0892dcd5.js +0 -6
  374. sky/dashboard/out/_next/static/chunks/754-d0da8ab45f9509e9.js +0 -18
  375. sky/dashboard/out/_next/static/chunks/7669.1f5d9a402bf5cc42.js +0 -36
  376. sky/dashboard/out/_next/static/chunks/8969-0be3036bf86f8256.js +0 -1
  377. sky/dashboard/out/_next/static/chunks/9025.c12318fb6a1a9093.js +0 -6
  378. sky/dashboard/out/_next/static/chunks/9037-fa1737818d0a0969.js +0 -6
  379. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-1cbba24bd1bd35f8.js +0 -16
  380. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-0b4b35dc1dfe046c.js +0 -16
  381. sky/dashboard/out/_next/static/chunks/pages/clusters-469814d711d63b1b.js +0 -1
  382. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-dd64309c3fe67ed2.js +0 -11
  383. sky/dashboard/out/_next/static/chunks/pages/jobs/pools/[pool]-07349868f7905d37.js +0 -16
  384. sky/dashboard/out/_next/static/chunks/pages/jobs-1f70d9faa564804f.js +0 -1
  385. sky/dashboard/out/_next/static/chunks/pages/users-018bf31cda52e11b.js +0 -1
  386. sky/dashboard/out/_next/static/chunks/pages/volumes-739726d6b823f532.js +0 -1
  387. sky/dashboard/out/_next/static/chunks/webpack-4fe903277b57b523.js +0 -1
  388. sky/dashboard/out/_next/static/css/4614e06482d7309e.css +0 -3
  389. sky/dashboard/out/_next/static/mS-4qZPSkRuA1u-g2wQhg/_buildManifest.js +0 -1
  390. sky/templates/kubernetes-ssh-jump.yml.j2 +0 -94
  391. sky/utils/kubernetes/ssh_jump_lifecycle_manager.py +0 -191
  392. skypilot_nightly-1.0.0.dev20250905.dist-info/RECORD +0 -547
  393. skypilot_nightly-1.0.0.dev20250905.dist-info/top_level.txt +0 -1
  394. /sky/dashboard/out/_next/static/{mS-4qZPSkRuA1u-g2wQhg → 96_E2yl3QAiIJGOYCkSpB}/_ssgManifest.js +0 -0
  395. {skypilot_nightly-1.0.0.dev20250905.dist-info → skypilot_nightly-1.0.0.dev20251203.dist-info}/WHEEL +0 -0
  396. {skypilot_nightly-1.0.0.dev20250905.dist-info → skypilot_nightly-1.0.0.dev20251203.dist-info}/entry_points.txt +0 -0
  397. {skypilot_nightly-1.0.0.dev20250905.dist-info → skypilot_nightly-1.0.0.dev20251203.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,5 @@
1
1
  """Kubernetes adaptors"""
2
+ import functools
2
3
  import logging
3
4
  import os
4
5
  import platform
@@ -162,8 +163,61 @@ def list_kube_config_contexts():
162
163
  return kubernetes.config.list_kube_config_contexts(_get_config_file())
163
164
 
164
165
 
166
+ class ClientWrapper:
167
+ """Wrapper around the kubernetes API clients.
168
+
169
+ This is needed because we cache kubernetes.client.ApiClient and other typed
170
+ clients (e.g. kubernetes.client.CoreV1Api) and lru_cache.cache_clear() does
171
+ not call close() on the client to cleanup external resources like
172
+ semaphores. This decorator wraps the client with __del__ to ensure the
173
+ external state of kubernetes clients are properly cleaned up on GC.
174
+ """
175
+
176
+ def __init__(self, client):
177
+ self._client = client
178
+
179
+ def __getattr__(self, name):
180
+ """Delegate to the underlying client"""
181
+ return getattr(self._client, name)
182
+
183
+ def __del__(self):
184
+ """Clean up the underlying client"""
185
+ try:
186
+ real_client = None
187
+ if isinstance(self._client, kubernetes.client.ApiClient):
188
+ real_client = self._client
189
+ elif isinstance(self._client, kubernetes.watch.Watch):
190
+ real_client = getattr(self._client, '_api_client', None)
191
+ else:
192
+ # Otherwise, the client is a typed client, the typed client
193
+ # is generated by codegen and all of them should have an
194
+ # 'api_client' attribute referring to the real client.
195
+ real_client = getattr(self._client, 'api_client', None)
196
+ if real_client is not None:
197
+ real_client.close()
198
+ else:
199
+ # logger may already be cleaned up during __del__ at shutdown
200
+ if logger is not None:
201
+ logger.debug(f'No client found for {self._client}')
202
+ except Exception as e: # pylint: disable=broad-except
203
+ if logger is not None:
204
+ logger.debug(f'Error closing Kubernetes client: {e}')
205
+
206
+
207
+ def wrap_kubernetes_client(func):
208
+ """Wraps kubernetes API clients for proper cleanup."""
209
+
210
+ @functools.wraps(func)
211
+ def wrapper(*args, **kwargs):
212
+ obj = func(*args, **kwargs)
213
+ return ClientWrapper(obj)
214
+
215
+ return wrapper
216
+
217
+
165
218
  @_api_logging_decorator('urllib3', logging.ERROR)
166
219
  @annotations.lru_cache(scope='request')
220
+ @wrap_kubernetes_client
167
221
  def core_api(context: Optional[str] = None):
168
222
  _load_config(context)
169
223
  return kubernetes.client.CoreV1Api()
@@ -171,6 +225,7 @@ def core_api(context: Optional[str] = None):
171
225
 
172
226
  @_api_logging_decorator('urllib3', logging.ERROR)
173
227
  @annotations.lru_cache(scope='request')
228
+ @wrap_kubernetes_client
174
229
  def storage_api(context: Optional[str] = None):
175
230
  _load_config(context)
176
231
  return kubernetes.client.StorageV1Api()
@@ -178,6 +233,7 @@ def storage_api(context: Optional[str] = None):
178
233
 
179
234
  @_api_logging_decorator('urllib3', logging.ERROR)
180
235
  @annotations.lru_cache(scope='request')
236
+ @wrap_kubernetes_client
181
237
  def auth_api(context: Optional[str] = None):
182
238
  _load_config(context)
183
239
  return kubernetes.client.RbacAuthorizationV1Api()
@@ -185,6 +241,7 @@ def auth_api(context: Optional[str] = None):
185
241
 
186
242
  @_api_logging_decorator('urllib3', logging.ERROR)
187
243
  @annotations.lru_cache(scope='request')
244
+ @wrap_kubernetes_client
188
245
  def networking_api(context: Optional[str] = None):
189
246
  _load_config(context)
190
247
  return kubernetes.client.NetworkingV1Api()
@@ -192,6 +249,7 @@ def networking_api(context: Optional[str] = None):
192
249
 
193
250
  @_api_logging_decorator('urllib3', logging.ERROR)
194
251
  @annotations.lru_cache(scope='request')
252
+ @wrap_kubernetes_client
195
253
  def custom_objects_api(context: Optional[str] = None):
196
254
  _load_config(context)
197
255
  return kubernetes.client.CustomObjectsApi()
@@ -199,6 +257,7 @@ def custom_objects_api(context: Optional[str] = None):
199
257
 
200
258
  @_api_logging_decorator('urllib3', logging.ERROR)
201
259
  @annotations.lru_cache(scope='global')
260
+ @wrap_kubernetes_client
202
261
  def node_api(context: Optional[str] = None):
203
262
  _load_config(context)
204
263
  return kubernetes.client.NodeV1Api()
@@ -206,6 +265,7 @@ def node_api(context: Optional[str] = None):
206
265
 
207
266
  @_api_logging_decorator('urllib3', logging.ERROR)
208
267
  @annotations.lru_cache(scope='request')
268
+ @wrap_kubernetes_client
209
269
  def apps_api(context: Optional[str] = None):
210
270
  _load_config(context)
211
271
  return kubernetes.client.AppsV1Api()
@@ -213,6 +273,7 @@ def apps_api(context: Optional[str] = None):
213
273
 
214
274
  @_api_logging_decorator('urllib3', logging.ERROR)
215
275
  @annotations.lru_cache(scope='request')
276
+ @wrap_kubernetes_client
216
277
  def batch_api(context: Optional[str] = None):
217
278
  _load_config(context)
218
279
  return kubernetes.client.BatchV1Api()
@@ -220,6 +281,7 @@ def batch_api(context: Optional[str] = None):
220
281
 
221
282
  @_api_logging_decorator('urllib3', logging.ERROR)
222
283
  @annotations.lru_cache(scope='request')
284
+ @wrap_kubernetes_client
223
285
  def api_client(context: Optional[str] = None):
224
286
  _load_config(context)
225
287
  return kubernetes.client.ApiClient()
@@ -227,6 +289,7 @@ def api_client(context: Optional[str] = None):
227
289
 
228
290
  @_api_logging_decorator('urllib3', logging.ERROR)
229
291
  @annotations.lru_cache(scope='request')
292
+ @wrap_kubernetes_client
230
293
  def custom_resources_api(context: Optional[str] = None):
231
294
  _load_config(context)
232
295
  return kubernetes.client.CustomObjectsApi()
@@ -234,6 +297,7 @@ def custom_resources_api(context: Optional[str] = None):
234
297
 
235
298
  @_api_logging_decorator('urllib3', logging.ERROR)
236
299
  @annotations.lru_cache(scope='request')
300
+ @wrap_kubernetes_client
237
301
  def watch(context: Optional[str] = None):
238
302
  _load_config(context)
239
303
  return kubernetes.watch.Watch()
sky/adaptors/nebius.py CHANGED
@@ -136,7 +136,9 @@ SKY_CHECK_NAME = 'Nebius (for Nebius Object Storae)'
136
136
 
137
137
 
138
138
  def request_error():
139
- return nebius.aio.service_error.RequestError
139
+ # pylint: disable=import-outside-toplevel
140
+ from nebius.aio import service_error
141
+ return service_error.RequestError
140
142
 
141
143
 
142
144
  def compute():
@@ -0,0 +1 @@
1
+ """Prime Intellect cloud adaptor."""
sky/adaptors/seeweb.py ADDED
@@ -0,0 +1,183 @@
1
+ """ Seeweb Adaptor """
2
+ import configparser
3
+ import pathlib
4
+ from typing import Optional
5
+
6
+ import pydantic
7
+ import requests # type: ignore
8
+
9
+ from sky.adaptors import common
10
+ from sky.utils import annotations
11
+
12
+
13
+ class SeewebError(Exception):
14
+ """Base exception for Seeweb adaptor errors."""
15
+
16
+
17
+ class SeewebCredentialsFileNotFound(SeewebError):
18
+ """Raised when the Seeweb credentials file is missing."""
19
+
20
+
21
+ class SeewebApiKeyMissing(SeewebError):
22
+ """Raised when the Seeweb API key is missing or empty."""
23
+
24
+
25
+ class SeewebAuthenticationError(SeewebError):
26
+ """Raised when authenticating with Seeweb API fails."""
27
+
28
+
29
+ _IMPORT_ERROR_MESSAGE = ('Failed to import dependencies for Seeweb.'
30
+ 'Try pip install "skypilot[seeweb]"')
31
+
32
+ ecsapi = common.LazyImport(
33
+ 'ecsapi',
34
+ import_error_message=_IMPORT_ERROR_MESSAGE,
35
+ )
36
+ boto3 = common.LazyImport('boto3', import_error_message=_IMPORT_ERROR_MESSAGE)
37
+ botocore = common.LazyImport('botocore',
38
+ import_error_message=_IMPORT_ERROR_MESSAGE)
39
+
40
+ _LAZY_MODULES = (ecsapi, boto3, botocore)
41
+
42
+
43
+ @common.load_lazy_modules(_LAZY_MODULES)
44
+ def check_compute_credentials() -> bool:
45
+ """Checks if the user has access credentials to Seeweb's compute service.
46
+
47
+ Returns True if credentials are valid; otherwise raises a SeewebError.
48
+ """
49
+ # Read API key from standard Seeweb configuration file
50
+ key_path = pathlib.Path('~/.seeweb_cloud/seeweb_keys').expanduser()
51
+ if not key_path.exists():
52
+ raise SeewebCredentialsFileNotFound(
53
+ 'Missing Seeweb API key file ~/.seeweb_cloud/seeweb_keys')
54
+
55
+ parser = configparser.ConfigParser()
56
+ parser.read(key_path)
57
+ try:
58
+ api_key = parser['DEFAULT']['api_key'].strip()
59
+ except KeyError as e:
60
+ raise SeewebApiKeyMissing(
61
+ 'Missing api_key in ~/.seeweb_cloud/seeweb_keys') from e
62
+ if not api_key:
63
+ raise SeewebApiKeyMissing(
64
+ 'Empty api_key in ~/.seeweb_cloud/seeweb_keys')
65
+
66
+ # Test connection by fetching servers list to validate the key
67
+ try:
68
+ seeweb_client = ecsapi.Api(token=api_key)
69
+ try:
70
+ seeweb_client.fetch_servers()
71
+ except pydantic.ValidationError:
72
+ # Fallback: fetch raw JSON to validate authentication
73
+ # pylint: disable=protected-access
74
+ base_url = seeweb_client._Api__generate_base_url() # type: ignore
75
+ headers = seeweb_client._Api__generate_authentication_headers(
76
+ ) # type: ignore
77
+ url = f'{base_url}/servers'
78
+ resp = requests.get(url, headers=headers, timeout=15)
79
+ resp.raise_for_status()
80
+ # If we get here, authentication worked even if schema mismatches
81
+ except Exception as e: # pylint: disable=broad-except
82
+ raise SeewebAuthenticationError(
83
+ f'Unable to authenticate with Seeweb API: {e}') from e
84
+
85
+ return True
86
+
87
+
88
+ @common.load_lazy_modules(_LAZY_MODULES)
89
+ def check_storage_credentials() -> bool:
90
+ """Checks if the user has access credentials to Seeweb's storage service.
91
+
92
+ Mirrors compute credentials validation.
93
+ """
94
+ return check_compute_credentials()
95
+
96
+
97
+ @common.load_lazy_modules(_LAZY_MODULES)
98
+ @annotations.lru_cache(scope='global', maxsize=1)
99
+ def client():
100
+ """Returns an authenticated ecsapi.Api object."""
101
+ # Create authenticated client using the same credential pattern
102
+ key_path = pathlib.Path('~/.seeweb_cloud/seeweb_keys').expanduser()
103
+ if not key_path.exists():
104
+ raise SeewebCredentialsFileNotFound(
105
+ 'Missing Seeweb API key file ~/.seeweb_cloud/seeweb_keys')
106
+
107
+ parser = configparser.ConfigParser()
108
+ parser.read(key_path)
109
+ try:
110
+ api_key = parser['DEFAULT']['api_key'].strip()
111
+ except KeyError as e:
112
+ raise SeewebApiKeyMissing(
113
+ 'Missing api_key in ~/.seeweb_cloud/seeweb_keys') from e
114
+ if not api_key:
115
+ raise SeewebApiKeyMissing(
116
+ 'Empty api_key in ~/.seeweb_cloud/seeweb_keys')
117
+
118
+ api = ecsapi.Api(token=api_key)
119
+
120
+ # Monkey-patch fetch_servers to be tolerant to API schema mismatches.
121
+ orig_fetch_servers = api.fetch_servers
122
+ orig_delete_server = api.delete_server
123
+
124
+ def _tolerant_fetch_servers(
125
+ timeout: Optional[int] = None): # type: ignore[override]
126
+ try:
127
+ return orig_fetch_servers(timeout=timeout)
128
+ except pydantic.ValidationError:
129
+ # Fallback path: fetch raw JSON, drop snapshot fields, then validate
130
+ # pylint: disable=protected-access
131
+ base_url = api._Api__generate_base_url() # type: ignore
132
+ headers = api._Api__generate_authentication_headers(
133
+ ) # type: ignore
134
+ url = f'{base_url}/servers'
135
+ resp = requests.get(url, headers=headers, timeout=timeout or 15)
136
+ resp.raise_for_status()
137
+ data = resp.json()
138
+ try:
139
+ servers = data.get('server', [])
140
+ for s in servers:
141
+ s.pop('last_restored_snapshot', None)
142
+ group = s.get('group')
143
+ if isinstance(group, dict):
144
+ group_name = group.get('name')
145
+ s['group'] = group_name if isinstance(
146
+ group_name, str) else str(group_name)
147
+ except (KeyError, TypeError, ValueError):
148
+ pass
149
+ server_list_response_cls = ecsapi._server._ServerListResponse
150
+ servers_response = server_list_response_cls.model_validate(data)
151
+ return servers_response.server
152
+
153
+ api.fetch_servers = _tolerant_fetch_servers # type: ignore[assignment]
154
+
155
+ def _tolerant_delete_server(server_name: str,
156
+ timeout: Optional[int] = None):
157
+ try:
158
+ return orig_delete_server(server_name, timeout=timeout)
159
+ except pydantic.ValidationError:
160
+ # Fallback: perform raw DELETE and interpret not_found as success
161
+ # pylint: disable=protected-access
162
+ base_url = api._Api__generate_base_url() # type: ignore
163
+ headers = api._Api__generate_authentication_headers(
164
+ ) # type: ignore
165
+ url = f'{base_url}/servers/{server_name}'
166
+ resp = requests.delete(url, headers=headers, timeout=timeout or 15)
167
+ # Treat 404 as idempotent success
168
+ if resp.status_code == 404:
169
+ return None
170
+ # Some APIs return {status: 'not_found', message: ...}
171
+ try:
172
+ data = resp.json()
173
+ if isinstance(data, dict) and data.get('status') == 'not_found':
174
+ return None
175
+ except (ValueError, TypeError):
176
+ pass
177
+ # If not clearly not_found, re-raise original behavior
178
+ resp.raise_for_status()
179
+ # Best-effort: return None to indicate deletion requested
180
+ return None
181
+
182
+ api.delete_server = _tolerant_delete_server # type: ignore[assignment]
183
+ return api
@@ -0,0 +1,89 @@
1
+ """Shadeform cloud adaptor."""
2
+
3
+ import functools
4
+ import socket
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ import requests
8
+
9
+ from sky import sky_logging
10
+ from sky.provision.shadeform import shadeform_utils
11
+ from sky.utils import common_utils
12
+
13
+ logger = sky_logging.init_logger(__name__)
14
+
15
+ _shadeform_sdk = None
16
+
17
+
18
+ def import_package(func):
19
+
20
+ @functools.wraps(func)
21
+ def wrapper(*args, **kwargs):
22
+ global _shadeform_sdk
23
+ if _shadeform_sdk is None:
24
+ try:
25
+ import shadeform as _shadeform # pylint: disable=import-outside-toplevel
26
+ _shadeform_sdk = _shadeform
27
+ except ImportError:
28
+ raise ImportError(
29
+ 'Failed to import dependencies for Shadeform. '
30
+ 'Try pip install "skypilot[shadeform]"') from None
31
+ return func(*args, **kwargs)
32
+
33
+ return wrapper
34
+
35
+
36
+ @import_package
37
+ def shadeform():
38
+ """Return the shadeform package."""
39
+ return _shadeform_sdk
40
+
41
+
42
+ def list_ssh_keys() -> List[Dict[str, Any]]:
43
+ """List all SSH keys in Shadeform account."""
44
+ try:
45
+ response = shadeform_utils.get_ssh_keys()
46
+ return response.get('ssh_keys', [])
47
+ except (ValueError, KeyError, requests.exceptions.RequestException) as e:
48
+ logger.warning(f'Failed to list SSH keys from Shadeform: {e}')
49
+ return []
50
+
51
+
52
+ def add_ssh_key_to_shadeform(public_key: str) -> Optional[str]:
53
+ """Add SSH key to Shadeform if it doesn't already exist.
54
+
55
+ Args:
56
+ public_key: The SSH public key string.
57
+
58
+ Returns:
59
+ The name of the key if added successfully, None otherwise.
60
+ """
61
+ try:
62
+ # Check if key already exists
63
+ existing_keys = list_ssh_keys()
64
+ key_exists = False
65
+ key_id = None
66
+ for key in existing_keys:
67
+ if key.get('public_key') == public_key:
68
+ key_exists = True
69
+ key_id = key.get('id')
70
+ break
71
+
72
+ if key_exists:
73
+ logger.info('SSH key already exists in Shadeform account')
74
+ return key_id
75
+
76
+ # Generate a unique key name
77
+ hostname = socket.gethostname()
78
+ key_name = f'skypilot-{hostname}-{common_utils.get_user_hash()[:8]}'
79
+
80
+ # Add the key
81
+ response = shadeform_utils.add_ssh_key(name=key_name,
82
+ public_key=public_key)
83
+ key_id = response['id']
84
+ logger.info(f'Added SSH key to Shadeform: {key_name, key_id}')
85
+ return key_id
86
+
87
+ except (ValueError, KeyError, requests.exceptions.RequestException) as e:
88
+ logger.warning(f'Failed to add SSH key to Shadeform: {e}')
89
+ return None
sky/admin_policy.py CHANGED
@@ -9,7 +9,9 @@ import pydantic
9
9
 
10
10
  import sky
11
11
  from sky import exceptions
12
+ from sky import models
12
13
  from sky.adaptors import common as adaptors_common
14
+ from sky.server.requests import request_names
13
15
  from sky.utils import common_utils
14
16
  from sky.utils import config_utils
15
17
  from sky.utils import ux_utils
@@ -49,8 +51,10 @@ class _UserRequestBody(pydantic.BaseModel):
49
51
  # will be converted to JSON string, which will lose the None key.
50
52
  task: str
51
53
  skypilot_config: str
54
+ request_name: str
52
55
  request_options: Optional[RequestOptions] = None
53
56
  at_client_side: bool = False
57
+ user: str
54
58
 
55
59
 
56
60
  @dataclasses.dataclass
@@ -73,32 +77,48 @@ class UserRequest:
73
77
  skypilot_config: Global skypilot config to be used in this request.
74
78
  request_options: Request options. It is None for jobs and services.
75
79
  at_client_side: Is the request intercepted by the policy at client-side?
80
+ user: User who made the request.
81
+ Only available on the server side.
82
+ This value is None if at_client_side is True.
76
83
  """
77
84
  task: 'sky.Task'
78
85
  skypilot_config: 'sky.Config'
86
+ request_name: request_names.AdminPolicyRequestName
79
87
  request_options: Optional['RequestOptions'] = None
80
88
  at_client_side: bool = False
89
+ user: Optional['models.User'] = None
81
90
 
82
91
  def encode(self) -> str:
83
92
  return _UserRequestBody(
84
93
  task=yaml_utils.dump_yaml_str(self.task.to_yaml_config()),
85
94
  skypilot_config=yaml_utils.dump_yaml_str(dict(
86
95
  self.skypilot_config)),
96
+ request_name=self.request_name.value,
87
97
  request_options=self.request_options,
88
98
  at_client_side=self.at_client_side,
99
+ user=(yaml_utils.dump_yaml_str(self.user.to_dict())
100
+ if self.user is not None else ''),
89
101
  ).model_dump_json()
90
102
 
91
103
  @classmethod
92
104
  def decode(cls, body: str) -> 'UserRequest':
93
105
  user_request_body = _UserRequestBody.model_validate_json(body)
106
+ user_dict = yaml_utils.read_yaml_str(
107
+ user_request_body.user) if user_request_body.user != '' else None
108
+ user = models.User(
109
+ id=user_dict['id'],
110
+ name=user_dict['name']) if user_dict is not None else None
94
111
  return cls(
95
112
  task=sky.Task.from_yaml_config(
96
113
  yaml_utils.read_yaml_all_str(user_request_body.task)[0]),
97
114
  skypilot_config=config_utils.Config.from_dict(
98
115
  yaml_utils.read_yaml_all_str(
99
116
  user_request_body.skypilot_config)[0]),
117
+ request_name=request_names.AdminPolicyRequestName(
118
+ user_request_body.request_name),
100
119
  request_options=user_request_body.request_options,
101
120
  at_client_side=user_request_body.at_client_side,
121
+ user=user,
102
122
  )
103
123
 
104
124