skypilot-nightly 1.0.0.dev20250522__py3-none-any.whl → 1.0.0.dev20250524__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 (120) hide show
  1. sky/__init__.py +2 -2
  2. sky/adaptors/kubernetes.py +46 -16
  3. sky/backends/backend_utils.py +62 -45
  4. sky/backends/cloud_vm_ray_backend.py +19 -5
  5. sky/check.py +398 -171
  6. sky/cli.py +302 -98
  7. sky/client/cli.py +302 -98
  8. sky/client/sdk.py +104 -12
  9. sky/clouds/__init__.py +3 -0
  10. sky/clouds/aws.py +4 -2
  11. sky/clouds/azure.py +4 -2
  12. sky/clouds/cloud.py +24 -6
  13. sky/clouds/cudo.py +2 -1
  14. sky/clouds/do.py +2 -1
  15. sky/clouds/fluidstack.py +2 -1
  16. sky/clouds/gcp.py +23 -5
  17. sky/clouds/ibm.py +4 -2
  18. sky/clouds/kubernetes.py +66 -22
  19. sky/clouds/lambda_cloud.py +2 -1
  20. sky/clouds/nebius.py +18 -2
  21. sky/clouds/oci.py +4 -2
  22. sky/clouds/paperspace.py +2 -1
  23. sky/clouds/runpod.py +2 -1
  24. sky/clouds/scp.py +2 -1
  25. sky/clouds/service_catalog/constants.py +1 -1
  26. sky/clouds/service_catalog/ssh_catalog.py +167 -0
  27. sky/clouds/ssh.py +203 -0
  28. sky/clouds/vast.py +2 -1
  29. sky/clouds/vsphere.py +2 -1
  30. sky/core.py +58 -11
  31. sky/dashboard/out/404.html +1 -1
  32. sky/dashboard/out/_next/static/aHej19bZyl4hoHgrzPCn7/_buildManifest.js +1 -0
  33. sky/dashboard/out/_next/static/chunks/480-ee58038f1a4afd5c.js +1 -0
  34. sky/dashboard/out/_next/static/chunks/488-50d843fdb5396d32.js +15 -0
  35. sky/dashboard/out/_next/static/chunks/498-d7722313e5e5b4e6.js +21 -0
  36. sky/dashboard/out/_next/static/chunks/573-f17bd89d9f9118b3.js +66 -0
  37. sky/dashboard/out/_next/static/chunks/578-7a4795009a56430c.js +6 -0
  38. sky/dashboard/out/_next/static/chunks/734-5f5ce8f347b7f417.js +1 -0
  39. sky/dashboard/out/_next/static/chunks/937.f97f83652028e944.js +1 -0
  40. sky/dashboard/out/_next/static/chunks/938-f347f6144075b0c8.js +1 -0
  41. sky/dashboard/out/_next/static/chunks/9f96d65d-5a3e4af68c26849e.js +1 -0
  42. sky/dashboard/out/_next/static/chunks/pages/_app-dec800f9ef1b10f4.js +1 -0
  43. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-37c042a356f8e608.js +1 -0
  44. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-9529d9e882a0e75c.js +16 -0
  45. sky/dashboard/out/_next/static/chunks/pages/clusters-9e6d1ec6e1ac5b29.js +1 -0
  46. sky/dashboard/out/_next/static/chunks/pages/infra-e690d864aa00e2ea.js +1 -0
  47. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-db6558a5ec687011.js +1 -0
  48. sky/dashboard/out/_next/static/chunks/pages/jobs-73d5e0c369d00346.js +16 -0
  49. sky/dashboard/out/_next/static/chunks/pages/users-2d319455c3f1c3e2.js +1 -0
  50. sky/dashboard/out/_next/static/chunks/pages/workspaces-02a7b60f2ead275f.js +1 -0
  51. sky/dashboard/out/_next/static/chunks/webpack-deda68c926e8d0bc.js +1 -0
  52. sky/dashboard/out/_next/static/css/d2cdba64c9202dd7.css +3 -0
  53. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  54. sky/dashboard/out/clusters/[cluster].html +1 -1
  55. sky/dashboard/out/clusters.html +1 -1
  56. sky/dashboard/out/index.html +1 -1
  57. sky/dashboard/out/infra.html +1 -1
  58. sky/dashboard/out/jobs/[job].html +1 -1
  59. sky/dashboard/out/jobs.html +1 -1
  60. sky/dashboard/out/users.html +1 -0
  61. sky/dashboard/out/workspaces.html +1 -0
  62. sky/data/storage.py +1 -1
  63. sky/global_user_state.py +42 -19
  64. sky/jobs/constants.py +1 -1
  65. sky/jobs/server/core.py +72 -56
  66. sky/jobs/state.py +26 -5
  67. sky/jobs/utils.py +65 -13
  68. sky/optimizer.py +29 -7
  69. sky/provision/__init__.py +1 -0
  70. sky/provision/aws/instance.py +17 -1
  71. sky/provision/fluidstack/instance.py +1 -0
  72. sky/provision/kubernetes/instance.py +16 -5
  73. sky/provision/kubernetes/utils.py +37 -19
  74. sky/provision/nebius/instance.py +3 -1
  75. sky/provision/nebius/utils.py +14 -2
  76. sky/provision/ssh/__init__.py +18 -0
  77. sky/resources.py +4 -1
  78. sky/serve/server/core.py +9 -6
  79. sky/server/html/token_page.html +6 -1
  80. sky/server/requests/executor.py +1 -0
  81. sky/server/requests/payloads.py +18 -0
  82. sky/server/server.py +108 -5
  83. sky/setup_files/dependencies.py +1 -0
  84. sky/skylet/constants.py +4 -1
  85. sky/skypilot_config.py +83 -9
  86. sky/templates/nebius-ray.yml.j2 +12 -0
  87. sky/utils/cli_utils/status_utils.py +18 -8
  88. sky/utils/infra_utils.py +21 -1
  89. sky/utils/kubernetes/cleanup-tunnel.sh +62 -0
  90. sky/utils/kubernetes/create_cluster.sh +1 -0
  91. sky/utils/kubernetes/deploy_remote_cluster.py +1440 -0
  92. sky/utils/kubernetes/kubernetes_deploy_utils.py +117 -10
  93. sky/utils/kubernetes/ssh-tunnel.sh +387 -0
  94. sky/utils/log_utils.py +218 -1
  95. sky/utils/schemas.py +75 -0
  96. sky/utils/ux_utils.py +2 -1
  97. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250524.dist-info}/METADATA +6 -1
  98. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250524.dist-info}/RECORD +103 -91
  99. sky/dashboard/out/_next/static/CzOVV6JpRQBRt5GhZuhyK/_buildManifest.js +0 -1
  100. sky/dashboard/out/_next/static/chunks/236-1a3a9440417720eb.js +0 -6
  101. sky/dashboard/out/_next/static/chunks/312-c3c8845990db8ffc.js +0 -15
  102. sky/dashboard/out/_next/static/chunks/37-d584022b0da4ac3b.js +0 -6
  103. sky/dashboard/out/_next/static/chunks/393-e1eaa440481337ec.js +0 -1
  104. sky/dashboard/out/_next/static/chunks/480-f28cd152a98997de.js +0 -1
  105. sky/dashboard/out/_next/static/chunks/582-683f4f27b81996dc.js +0 -59
  106. sky/dashboard/out/_next/static/chunks/pages/_app-8cfab319f9fb3ae8.js +0 -1
  107. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-33bc2bec322249b1.js +0 -1
  108. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-e2fc2dd1955e6c36.js +0 -1
  109. sky/dashboard/out/_next/static/chunks/pages/clusters-3a748bd76e5c2984.js +0 -1
  110. sky/dashboard/out/_next/static/chunks/pages/infra-9180cd91cee64b96.js +0 -1
  111. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-70756c2dad850a7e.js +0 -1
  112. sky/dashboard/out/_next/static/chunks/pages/jobs-ecd804b9272f4a7c.js +0 -1
  113. sky/dashboard/out/_next/static/chunks/webpack-830f59b8404e96b8.js +0 -1
  114. sky/dashboard/out/_next/static/css/7e7ce4ff31d3977b.css +0 -3
  115. sky/utils/kubernetes/deploy_remote_cluster.sh +0 -308
  116. /sky/dashboard/out/_next/static/{CzOVV6JpRQBRt5GhZuhyK → aHej19bZyl4hoHgrzPCn7}/_ssgManifest.js +0 -0
  117. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250524.dist-info}/WHEEL +0 -0
  118. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250524.dist-info}/entry_points.txt +0 -0
  119. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250524.dist-info}/licenses/LICENSE +0 -0
  120. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250524.dist-info}/top_level.txt +0 -0
sky/utils/log_utils.py CHANGED
@@ -190,7 +190,7 @@ class SkyLocalUpLineProcessor(LineProcessor):
190
190
 
191
191
 
192
192
  class SkyRemoteUpLineProcessor(LineProcessor):
193
- """A processor for deploy_remote_cluster.sh log lines."""
193
+ """A processor for deploy_remote_cluster.py log lines."""
194
194
 
195
195
  def __init__(self, log_path: str, is_local: bool):
196
196
  self.log_path = log_path
@@ -291,6 +291,223 @@ class SkyRemoteUpLineProcessor(LineProcessor):
291
291
  self.status_display.stop()
292
292
 
293
293
 
294
+ class SkySSHUpLineProcessor(LineProcessor):
295
+ """A processor for deploy_remote_cluster.py log lines for SSH clusters"""
296
+
297
+ def __init__(self, log_path: str, is_local: bool):
298
+ self.log_path = log_path
299
+ self.is_local = is_local
300
+ self.current_cluster: Optional[str] = None
301
+ self.is_cleanup_mode = False
302
+
303
+ def __enter__(self) -> None:
304
+ status = rich_utils.safe_status(
305
+ ux_utils.spinner_message('Preparing to set up SSH Node Pools',
306
+ log_path=self.log_path,
307
+ is_local=self.is_local))
308
+ self.status_display = status
309
+ self.status_display.start()
310
+
311
+ def process_line(self, log_line: str) -> None:
312
+ # Detect cleanup mode
313
+ if 'SKYPILOT_CLEANUP_MODE:' in log_line:
314
+ self.is_cleanup_mode = True
315
+ if self.current_cluster:
316
+ self.status_display.update(
317
+ ux_utils.spinner_message(
318
+ f'Cleaning up Node Pool: \\[{self.current_cluster}]',
319
+ log_path=self.log_path,
320
+ is_local=self.is_local))
321
+
322
+ # Cluster detection message
323
+ if 'SKYPILOT_CLUSTER_INFO:' in log_line:
324
+ clusters_part = log_line.split('SKYPILOT_CLUSTER_INFO:',
325
+ 1)[1].strip()
326
+ if clusters_part.startswith('Found'):
327
+ logger.info(f'{colorama.Style.RESET_ALL}'
328
+ f'{colorama.Fore.CYAN}{clusters_part}'
329
+ f'{colorama.Style.RESET_ALL}')
330
+
331
+ # Current cluster being operated on
332
+ if 'SKYPILOT_CURRENT_CLUSTER:' in log_line:
333
+ self.current_cluster = log_line.split('SKYPILOT_CURRENT_CLUSTER:',
334
+ 1)[1].strip()
335
+
336
+ if self.is_cleanup_mode:
337
+ self.status_display.update(
338
+ ux_utils.spinner_message(
339
+ f'Cleaning up Node Pool: {self.current_cluster}',
340
+ log_path=self.log_path,
341
+ is_local=self.is_local))
342
+ logger.info(f'{colorama.Fore.CYAN}\nCleaning up Node Pool: '
343
+ f'{self.current_cluster}{colorama.Style.RESET_ALL}')
344
+ else:
345
+ self.status_display.update(
346
+ ux_utils.spinner_message(
347
+ f'Deploying SkyPilot \\[{self.current_cluster}]',
348
+ log_path=self.log_path,
349
+ is_local=self.is_local))
350
+ logger.info(f'{colorama.Style.RESET_ALL}'
351
+ f'{colorama.Fore.CYAN}\nSetting up Node Pool: '
352
+ f'{self.current_cluster}{colorama.Style.RESET_ALL}')
353
+
354
+ # Handle cluster completion marker
355
+ if 'SKYPILOT_CLUSTER_COMPLETED:' in log_line:
356
+ if self.is_cleanup_mode:
357
+ logger.info(
358
+ f'{ux_utils.INDENT_LAST_SYMBOL}{colorama.Fore.GREEN}'
359
+ f'✔ Node Pool {self.current_cluster} cleaned up '
360
+ f'successfully.{colorama.Style.RESET_ALL}')
361
+ else:
362
+ logger.info(
363
+ f'{ux_utils.INDENT_LAST_SYMBOL}{colorama.Fore.GREEN}'
364
+ f'✔ Node Pool {self.current_cluster} deployed successfully.'
365
+ f'{colorama.Style.RESET_ALL}')
366
+
367
+ # Pre-flight checks
368
+ if 'Checking SSH connection to head node' in log_line:
369
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Style.DIM}'
370
+ 'Checking SSH connection to head node...'
371
+ f'{colorama.Style.RESET_ALL}')
372
+
373
+ if log_line.startswith('SSH connection successful'):
374
+ node_name = log_line.split('(')[-1].split(')')[0]
375
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.GREEN}'
376
+ '✔ SSH connection established to head node '
377
+ f'{node_name}.{colorama.Style.RESET_ALL}')
378
+
379
+ # Kubernetes installation steps
380
+ if 'Deploying Kubernetes on head node' in log_line:
381
+ current_cluster_str = f' \\[{self.current_cluster}]' if (
382
+ self.current_cluster) else ''
383
+ self.status_display.update(
384
+ ux_utils.spinner_message(
385
+ 'Deploying SkyPilot runtime on head node'
386
+ f'{current_cluster_str}',
387
+ log_path=self.log_path,
388
+ is_local=self.is_local))
389
+
390
+ if 'K3s deployed on head node' in log_line:
391
+ node_name = log_line.split('(')[-1].split(')')[0]
392
+ logger.info(
393
+ f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.GREEN}'
394
+ f'✔ SkyPilot runtime successfully deployed on head node '
395
+ f'{node_name}.{colorama.Style.RESET_ALL}')
396
+
397
+ # Worker nodes
398
+ if 'Deploying Kubernetes on worker node' in log_line:
399
+ self.status_display.update(
400
+ ux_utils.spinner_message(
401
+ 'Deploying SkyPilot runtime on worker nodes' +
402
+ (f' \\[{self.current_cluster}]'
403
+ if self.current_cluster else ''),
404
+ log_path=self.log_path,
405
+ is_local=self.is_local))
406
+
407
+ if 'Kubernetes deployed on worker node' in log_line:
408
+ node_name = log_line.split('(')[-1].split(')')[0]
409
+ logger.info(
410
+ f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.GREEN}'
411
+ '✔ SkyPilot runtime successfully deployed on worker node '
412
+ f'{node_name}.{colorama.Style.RESET_ALL}')
413
+
414
+ if 'Failed to deploy K3s on worker node' in log_line:
415
+ node_name = log_line.split('(')[-1].split(')')[0]
416
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.RED}'
417
+ '✗ Failed to deploy K3s on worker node '
418
+ f'{node_name}.{colorama.Style.RESET_ALL}')
419
+
420
+ # Cluster configuration
421
+ if 'Configuring local kubectl to connect to the cluster...' in log_line:
422
+ self.status_display.update(
423
+ ux_utils.spinner_message('Setting up SkyPilot configuration' +
424
+ (f' \\[{self.current_cluster}]'
425
+ if self.current_cluster else ''),
426
+ log_path=self.log_path,
427
+ is_local=self.is_local))
428
+
429
+ if 'kubectl configured to connect to the cluster.' in log_line:
430
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.GREEN}'
431
+ '✔ SkyPilot configuration complete.'
432
+ f'{colorama.Style.RESET_ALL}')
433
+
434
+ # GPU operator installation
435
+ if 'Installing Nvidia GPU Operator...' in log_line:
436
+ self.status_display.update(
437
+ ux_utils.spinner_message('Configuring Nvidia GPUs' +
438
+ (f' \\[{self.current_cluster}]'
439
+ if self.current_cluster else ''),
440
+ log_path=self.log_path,
441
+ is_local=self.is_local))
442
+
443
+ if 'GPU Operator installed.' in log_line:
444
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.GREEN}'
445
+ '✔ Nvidia GPUs configured successfully.'
446
+ f'{colorama.Style.RESET_ALL}')
447
+
448
+ # Cleanup steps
449
+ if 'Cleaning up head node' in log_line:
450
+ self.status_display.update(
451
+ ux_utils.spinner_message('Cleaning up head node' +
452
+ (f' \\[{self.current_cluster}]'
453
+ if self.current_cluster else ''),
454
+ log_path=self.log_path,
455
+ is_local=self.is_local))
456
+
457
+ if 'Cleaning up worker node' in log_line:
458
+ self.status_display.update(
459
+ ux_utils.spinner_message('Cleaning up worker nodes' +
460
+ (f' \\[{self.current_cluster}]'
461
+ if self.current_cluster else ''),
462
+ log_path=self.log_path,
463
+ is_local=self.is_local))
464
+
465
+ # Handle node cleanup success messages
466
+ if 'Node' in log_line and 'cleaned up successfully' in log_line:
467
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.GREEN}'
468
+ f'{log_line.strip()}{colorama.Style.RESET_ALL}')
469
+
470
+ if 'Node' in log_line and 'Failed to clean up' in log_line:
471
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.RED}'
472
+ f'{log_line.strip()}{colorama.Style.RESET_ALL}')
473
+
474
+ if 'Failed to clean up worker node' in log_line:
475
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.RED}'
476
+ f'{log_line.strip()}{colorama.Style.RESET_ALL}')
477
+
478
+ # Final status for the cluster deployment
479
+ if 'Cluster deployment completed.' in log_line:
480
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.GREEN}'
481
+ '✔ SkyPilot runtime is up.'
482
+ f'{colorama.Style.RESET_ALL}')
483
+
484
+ if 'Failed to deploy Kubernetes on the following nodes:' in log_line:
485
+ logger.info(log_line.strip())
486
+
487
+ if 'already exists in history. ' in log_line:
488
+ node_name = log_line.split('(')[-1].split(')')[0]
489
+ logger.info(f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.YELLOW}'
490
+ '✔ SkyPilot runtime already deployed on worker node '
491
+ f'{node_name}. Skipping.{colorama.Style.RESET_ALL}')
492
+
493
+ if 'Failed to setup TCP forwarding on head node' in log_line:
494
+ node_name = log_line.split('(')[-1].split(')')[0]
495
+ logger.info(
496
+ f'{ux_utils.INDENT_SYMBOL}{colorama.Fore.RED}'
497
+ f'✗ Failed to setup TCP forwarding on head node {node_name}.'
498
+ f'{colorama.Style.RESET_ALL}')
499
+
500
+ if 'Error in deploying SSH Target' in log_line:
501
+ logger.info(f'{ux_utils.INDENT_LAST_SYMBOL}{colorama.Fore.RED}'
502
+ f'{log_line.strip()}{colorama.Style.RESET_ALL}')
503
+
504
+ def __exit__(self, except_type: Optional[Type[BaseException]],
505
+ except_value: Optional[BaseException],
506
+ traceback: Optional[types.TracebackType]) -> None:
507
+ del except_type, except_value, traceback # unused
508
+ self.status_display.stop()
509
+
510
+
294
511
  def create_table(field_names: List[str], **kwargs) -> prettytable.PrettyTable:
295
512
  """Creates table with default style."""
296
513
  border = kwargs.pop('border', False)
sky/utils/schemas.py CHANGED
@@ -1089,6 +1089,27 @@ def get_config_schema():
1089
1089
  'fabric': {
1090
1090
  'type': 'string',
1091
1091
  },
1092
+ 'filesystems': {
1093
+ 'type': 'array',
1094
+ 'items': {
1095
+ 'type': 'object',
1096
+ 'additionalProperties': False,
1097
+ 'properties': {
1098
+ 'filesystem_id': {
1099
+ 'type': 'string',
1100
+ },
1101
+ 'attach_mode': {
1102
+ 'type': 'string',
1103
+ 'case_sensitive_enum': [
1104
+ 'READ_WRITE', 'READ_ONLY'
1105
+ ]
1106
+ },
1107
+ 'mount_path': {
1108
+ 'type': 'string',
1109
+ }
1110
+ }
1111
+ }
1112
+ },
1092
1113
  }
1093
1114
  },
1094
1115
  }
@@ -1152,6 +1173,54 @@ def get_config_schema():
1152
1173
  }
1153
1174
  }
1154
1175
 
1176
+ workspace_schema = {'type': 'string'}
1177
+
1178
+ allowed_workspace_cloud_names = list(
1179
+ service_catalog.ALL_CLOUDS) + ['cloudflare']
1180
+ # Create pattern for non-GCP clouds (all clouds except gcp)
1181
+ non_gcp_clouds = [
1182
+ cloud for cloud in allowed_workspace_cloud_names
1183
+ if cloud.lower() != 'gcp'
1184
+ ]
1185
+ non_gcp_cloud_regex = '|'.join(non_gcp_clouds)
1186
+ workspaces_schema = {
1187
+ 'type': 'object',
1188
+ 'required': [],
1189
+ # each key is a workspace name
1190
+ 'additionalProperties': {
1191
+ 'type': 'object',
1192
+ 'additionalProperties': False,
1193
+ 'patternProperties': {
1194
+ # Pattern for non-GCP clouds - only allows 'disabled' property
1195
+ f'^({non_gcp_cloud_regex})$': {
1196
+ 'type': 'object',
1197
+ 'additionalProperties': False,
1198
+ 'properties': {
1199
+ 'disabled': {
1200
+ 'type': 'boolean'
1201
+ }
1202
+ },
1203
+ },
1204
+ },
1205
+ 'properties': {
1206
+ # Explicit definition for GCP allows both project_id and
1207
+ # disabled
1208
+ 'gcp': {
1209
+ 'type': 'object',
1210
+ 'properties': {
1211
+ 'project_id': {
1212
+ 'type': 'string'
1213
+ },
1214
+ 'disabled': {
1215
+ 'type': 'boolean'
1216
+ }
1217
+ },
1218
+ 'additionalProperties': False,
1219
+ },
1220
+ },
1221
+ },
1222
+ }
1223
+
1155
1224
  provision_configs = {
1156
1225
  'type': 'object',
1157
1226
  'required': [],
@@ -1178,6 +1247,10 @@ def get_config_schema():
1178
1247
  'required': [],
1179
1248
  'additionalProperties': False,
1180
1249
  'properties': {
1250
+ # TODO Replace this with whatever syang cooks up
1251
+ 'workspace': {
1252
+ 'type': 'string',
1253
+ },
1181
1254
  'jobs': controller_resources_schema,
1182
1255
  'serve': controller_resources_schema,
1183
1256
  'allowed_clouds': allowed_clouds,
@@ -1185,6 +1258,8 @@ def get_config_schema():
1185
1258
  'docker': docker_configs,
1186
1259
  'nvidia_gpus': gpu_configs,
1187
1260
  'api_server': api_server,
1261
+ 'active_workspace': workspace_schema,
1262
+ 'workspaces': workspaces_schema,
1188
1263
  'provision': provision_configs,
1189
1264
  **cloud_configs,
1190
1265
  },
sky/utils/ux_utils.py CHANGED
@@ -161,7 +161,8 @@ def finishing_message(message: str,
161
161
  follow_up_message = follow_up_message if (follow_up_message
162
162
  is not None) else ''
163
163
  success_prefix = (f'{colorama.Style.RESET_ALL}{colorama.Fore.GREEN}✓ '
164
- f'{message}{colorama.Style.RESET_ALL}{follow_up_message}')
164
+ f'{message}{colorama.Style.RESET_ALL}{follow_up_message}'
165
+ f'{colorama.Style.RESET_ALL}')
165
166
  if log_path is None:
166
167
  return success_prefix
167
168
  path_hint = log_path_hint(log_path, is_local)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skypilot-nightly
3
- Version: 1.0.0.dev20250522
3
+ Version: 1.0.0.dev20250524
4
4
  Summary: SkyPilot: Run AI on Any Infra — Unified, Faster, Cheaper.
5
5
  Author: SkyPilot Team
6
6
  License: Apache 2.0
@@ -87,6 +87,9 @@ Requires-Dist: ray[default]!=2.6.0,>=2.2.0; extra == "oci"
87
87
  Provides-Extra: kubernetes
88
88
  Requires-Dist: kubernetes!=32.0.0,>=20.0.0; extra == "kubernetes"
89
89
  Requires-Dist: websockets; extra == "kubernetes"
90
+ Provides-Extra: ssh
91
+ Requires-Dist: kubernetes!=32.0.0,>=20.0.0; extra == "ssh"
92
+ Requires-Dist: websockets; extra == "ssh"
90
93
  Provides-Extra: remote
91
94
  Requires-Dist: grpcio!=1.48.0,>=1.32.0; python_version < "3.10" and extra == "remote"
92
95
  Requires-Dist: grpcio!=1.48.0,>=1.42.0; python_version >= "3.10" and extra == "remote"
@@ -142,6 +145,8 @@ Requires-Dist: oci; extra == "all"
142
145
  Requires-Dist: ray[default]!=2.6.0,>=2.2.0; extra == "all"
143
146
  Requires-Dist: kubernetes!=32.0.0,>=20.0.0; extra == "all"
144
147
  Requires-Dist: websockets; extra == "all"
148
+ Requires-Dist: kubernetes!=32.0.0,>=20.0.0; extra == "all"
149
+ Requires-Dist: websockets; extra == "all"
145
150
  Requires-Dist: grpcio!=1.48.0,>=1.32.0; python_version < "3.10" and extra == "all"
146
151
  Requires-Dist: grpcio!=1.48.0,>=1.42.0; python_version >= "3.10" and extra == "all"
147
152
  Requires-Dist: protobuf!=3.19.5,>=3.15.3; extra == "all"