skypilot-nightly 1.0.0.dev20250626__py3-none-any.whl → 1.0.0.dev20250628__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 (106) hide show
  1. sky/__init__.py +2 -2
  2. sky/adaptors/kubernetes.py +7 -0
  3. sky/adaptors/nebius.py +2 -2
  4. sky/admin_policy.py +27 -17
  5. sky/authentication.py +12 -5
  6. sky/backends/backend_utils.py +92 -26
  7. sky/check.py +5 -2
  8. sky/client/cli/command.py +38 -6
  9. sky/client/sdk.py +217 -167
  10. sky/client/service_account_auth.py +47 -0
  11. sky/clouds/aws.py +10 -4
  12. sky/clouds/azure.py +5 -2
  13. sky/clouds/cloud.py +5 -2
  14. sky/clouds/gcp.py +31 -18
  15. sky/clouds/kubernetes.py +54 -34
  16. sky/clouds/nebius.py +8 -2
  17. sky/clouds/ssh.py +5 -2
  18. sky/clouds/utils/aws_utils.py +10 -4
  19. sky/clouds/utils/gcp_utils.py +22 -7
  20. sky/clouds/utils/oci_utils.py +62 -14
  21. sky/dashboard/out/404.html +1 -1
  22. sky/dashboard/out/_next/static/{bs6UB9V4Jq10TIZ5x-kBK → ZYLkkWSYZjJhLVsObh20y}/_buildManifest.js +1 -1
  23. sky/dashboard/out/_next/static/chunks/43-f38a531f6692f281.js +1 -0
  24. sky/dashboard/out/_next/static/chunks/601-111d06d9ded11d00.js +1 -0
  25. sky/dashboard/out/_next/static/chunks/{616-d6128fa9e7cae6e6.js → 616-50a620ac4a23deb4.js} +1 -1
  26. sky/dashboard/out/_next/static/chunks/691.fd9292250ab089af.js +21 -0
  27. sky/dashboard/out/_next/static/chunks/{785.dc2686c3c1235554.js → 785.3446c12ffdf3d188.js} +1 -1
  28. sky/dashboard/out/_next/static/chunks/871-e547295e7e21399c.js +6 -0
  29. sky/dashboard/out/_next/static/chunks/937.72796f7afe54075b.js +1 -0
  30. sky/dashboard/out/_next/static/chunks/938-0a770415b5ce4649.js +1 -0
  31. sky/dashboard/out/_next/static/chunks/982.d7bd80ed18cad4cc.js +1 -0
  32. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-21080826c6095f21.js +6 -0
  33. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-77d4816945b04793.js +6 -0
  34. sky/dashboard/out/_next/static/chunks/pages/{clusters-f119a5630a1efd61.js → clusters-65b2c90320b8afb8.js} +1 -1
  35. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-64bdc0b2d3a44709.js +16 -0
  36. sky/dashboard/out/_next/static/chunks/pages/{jobs-0a5695ff3075d94a.js → jobs-df7407b5e37d3750.js} +1 -1
  37. sky/dashboard/out/_next/static/chunks/pages/{users-4978cbb093e141e7.js → users-d7684eaa04c4f58f.js} +1 -1
  38. sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-cb7e720b739de53a.js → [name]-04e1b3ad4207b1e9.js} +1 -1
  39. sky/dashboard/out/_next/static/chunks/pages/{workspaces-50e230828730cfb3.js → workspaces-c470366a6179f16e.js} +1 -1
  40. sky/dashboard/out/_next/static/chunks/{webpack-08fdb9e6070127fc.js → webpack-75a3310ef922a299.js} +1 -1
  41. sky/dashboard/out/_next/static/css/605ac87514049058.css +3 -0
  42. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  43. sky/dashboard/out/clusters/[cluster].html +1 -1
  44. sky/dashboard/out/clusters.html +1 -1
  45. sky/dashboard/out/config.html +1 -1
  46. sky/dashboard/out/index.html +1 -1
  47. sky/dashboard/out/infra/[context].html +1 -1
  48. sky/dashboard/out/infra.html +1 -1
  49. sky/dashboard/out/jobs/[job].html +1 -1
  50. sky/dashboard/out/jobs.html +1 -1
  51. sky/dashboard/out/users.html +1 -1
  52. sky/dashboard/out/volumes.html +1 -1
  53. sky/dashboard/out/workspace/new.html +1 -1
  54. sky/dashboard/out/workspaces/[name].html +1 -1
  55. sky/dashboard/out/workspaces.html +1 -1
  56. sky/data/storage.py +8 -3
  57. sky/global_user_state.py +257 -9
  58. sky/jobs/client/sdk.py +20 -25
  59. sky/models.py +16 -0
  60. sky/provision/kubernetes/config.py +1 -1
  61. sky/provision/kubernetes/instance.py +7 -4
  62. sky/provision/kubernetes/network.py +15 -9
  63. sky/provision/kubernetes/network_utils.py +42 -23
  64. sky/provision/kubernetes/utils.py +73 -35
  65. sky/provision/nebius/utils.py +10 -4
  66. sky/resources.py +10 -4
  67. sky/serve/client/sdk.py +28 -34
  68. sky/server/common.py +51 -3
  69. sky/server/constants.py +3 -0
  70. sky/server/requests/executor.py +4 -0
  71. sky/server/requests/payloads.py +33 -0
  72. sky/server/requests/requests.py +19 -0
  73. sky/server/rest.py +6 -15
  74. sky/server/server.py +121 -6
  75. sky/skylet/constants.py +6 -0
  76. sky/skypilot_config.py +32 -4
  77. sky/users/permission.py +29 -0
  78. sky/users/server.py +384 -5
  79. sky/users/token_service.py +196 -0
  80. sky/utils/common_utils.py +4 -5
  81. sky/utils/config_utils.py +41 -0
  82. sky/utils/controller_utils.py +5 -1
  83. sky/utils/resource_checker.py +153 -0
  84. sky/utils/resources_utils.py +12 -4
  85. sky/utils/schemas.py +87 -60
  86. sky/utils/subprocess_utils.py +2 -6
  87. sky/workspaces/core.py +9 -117
  88. {skypilot_nightly-1.0.0.dev20250626.dist-info → skypilot_nightly-1.0.0.dev20250628.dist-info}/METADATA +1 -1
  89. {skypilot_nightly-1.0.0.dev20250626.dist-info → skypilot_nightly-1.0.0.dev20250628.dist-info}/RECORD +95 -92
  90. sky/dashboard/out/_next/static/chunks/43-36177d00f6956ab2.js +0 -1
  91. sky/dashboard/out/_next/static/chunks/690.55f9eed3be903f56.js +0 -16
  92. sky/dashboard/out/_next/static/chunks/871-3db673be3ee3750b.js +0 -6
  93. sky/dashboard/out/_next/static/chunks/937.3759f538f11a0953.js +0 -1
  94. sky/dashboard/out/_next/static/chunks/938-068520cc11738deb.js +0 -1
  95. sky/dashboard/out/_next/static/chunks/973-81b2d057178adb76.js +0 -1
  96. sky/dashboard/out/_next/static/chunks/982.1b61658204416b0f.js +0 -1
  97. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-aff040d7bc5d0086.js +0 -6
  98. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-8040f2483897ed0c.js +0 -6
  99. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-e4b23128db0774cd.js +0 -16
  100. sky/dashboard/out/_next/static/css/52082cf558ec9705.css +0 -3
  101. /sky/dashboard/out/_next/static/{bs6UB9V4Jq10TIZ5x-kBK → ZYLkkWSYZjJhLVsObh20y}/_ssgManifest.js +0 -0
  102. /sky/dashboard/out/_next/static/chunks/pages/{_app-9a3ce3170d2edcec.js → _app-050a9e637b057b24.js} +0 -0
  103. {skypilot_nightly-1.0.0.dev20250626.dist-info → skypilot_nightly-1.0.0.dev20250628.dist-info}/WHEEL +0 -0
  104. {skypilot_nightly-1.0.0.dev20250626.dist-info → skypilot_nightly-1.0.0.dev20250628.dist-info}/entry_points.txt +0 -0
  105. {skypilot_nightly-1.0.0.dev20250626.dist-info → skypilot_nightly-1.0.0.dev20250628.dist-info}/licenses/LICENSE +0 -0
  106. {skypilot_nightly-1.0.0.dev20250626.dist-info → skypilot_nightly-1.0.0.dev20250628.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,47 @@
1
+ """Service account token authentication for SkyPilot client."""
2
+
3
+ import os
4
+ from typing import Optional
5
+
6
+ from sky import skypilot_config
7
+ from sky.skylet import constants
8
+
9
+
10
+ def _get_service_account_token() -> Optional[str]:
11
+ """Get service account token from environment variable or config file.
12
+
13
+ Priority order:
14
+ 1. SKYPILOT_SERVICE_ACCOUNT_TOKEN environment variable
15
+ 2. ~/.sky/config.yaml service_account_token field
16
+
17
+ Returns:
18
+ The service account token if found, None otherwise.
19
+ """
20
+ # Check environment variable first
21
+ token = os.environ.get(constants.SERVICE_ACCOUNT_TOKEN_ENV_VAR)
22
+ if token:
23
+ if not token.startswith('sky_'):
24
+ raise ValueError('Invalid service account token format. '
25
+ 'Token must start with "sky_"')
26
+ return token
27
+
28
+ # Check config file
29
+ token = skypilot_config.get_nested(('api_server', 'service_account_token'),
30
+ default_value=None)
31
+ if token and not token.startswith('sky_'):
32
+ raise ValueError('Invalid service account token format in config. '
33
+ 'Token must start with "sky_"')
34
+ return token
35
+
36
+
37
+ def get_service_account_headers() -> dict:
38
+ """Get headers for service account authentication.
39
+
40
+ Returns:
41
+ Dictionary with Authorization header if token is available,
42
+ empty dict otherwise.
43
+ """
44
+ token = _get_service_account_token()
45
+ if token:
46
+ return {'Authorization': f'Bearer {token}'}
47
+ return {}
sky/clouds/aws.py CHANGED
@@ -458,10 +458,16 @@ class AWS(clouds.Cloud):
458
458
  image_id = self._get_image_id(image_id_to_use, region_name,
459
459
  resources.instance_type)
460
460
 
461
- disk_encrypted = skypilot_config.get_nested(('aws', 'disk_encrypted'),
462
- False)
463
- user_security_group_config = skypilot_config.get_nested(
464
- ('aws', 'security_group_name'), None)
461
+ disk_encrypted = skypilot_config.get_effective_region_config(
462
+ cloud='aws',
463
+ region=region_name,
464
+ keys=('disk_encrypted',),
465
+ default_value=False)
466
+ user_security_group_config = skypilot_config.get_effective_region_config(
467
+ cloud='aws',
468
+ region=region_name,
469
+ keys=('security_group_name',),
470
+ default_value=None)
465
471
  user_security_group = None
466
472
  if isinstance(user_security_group_config, str):
467
473
  user_security_group = user_security_group_config
sky/clouds/azure.py CHANGED
@@ -380,8 +380,11 @@ class Azure(clouds.Cloud):
380
380
  }
381
381
 
382
382
  # Determine resource group for deploying the instance.
383
- resource_group_name = skypilot_config.get_nested(
384
- ('azure', 'resource_group_vm'), None)
383
+ resource_group_name = skypilot_config.get_effective_region_config(
384
+ cloud='azure',
385
+ region=region_name,
386
+ keys=('resource_group_vm',),
387
+ default_value=None)
385
388
  use_external_resource_group = resource_group_name is not None
386
389
  if resource_group_name is None:
387
390
  resource_group_name = f'{cluster_name.name_on_cloud}-{region_name}'
sky/clouds/cloud.py CHANGED
@@ -669,8 +669,11 @@ class Cloud:
669
669
  resources)
670
670
 
671
671
  # Docker image is not compatible with ssh proxy command.
672
- if skypilot_config.get_nested(
673
- (str(cls._REPR).lower(), 'ssh_proxy_command'), None) is not None:
672
+ if skypilot_config.get_effective_region_config(
673
+ cloud=str(cls).lower(),
674
+ region=None,
675
+ keys=('ssh_proxy_command',),
676
+ default_value=None) is not None:
674
677
  unsupported_features2reason.update({
675
678
  CloudImplementationFeatures.DOCKER_IMAGE: (
676
679
  f'Docker image is currently not supported on {cls._REPR} '
sky/clouds/gcp.py CHANGED
@@ -229,9 +229,10 @@ class GCP(clouds.Cloud):
229
229
  # TODO(zhwu): We probably need to store the MIG requirement in resources
230
230
  # because `skypilot_config` may change for an existing cluster.
231
231
  # Clusters created with MIG (only GPU clusters) cannot be stopped.
232
- if (skypilot_config.get_nested(
233
- ('gcp', 'managed_instance_group'),
234
- None,
232
+ if (skypilot_config.get_effective_region_config(
233
+ cloud='gcp',
234
+ region=resources.region,
235
+ keys=('managed_instance_group',),
235
236
  override_configs=resources.cluster_config_overrides) is not None
236
237
  and resources.accelerators):
237
238
  unsupported[clouds.CloudImplementationFeatures.STOP] = (
@@ -504,9 +505,11 @@ class GCP(clouds.Cloud):
504
505
  r.instance_type,
505
506
  GCP.failover_disk_tier(r.instance_type, r.disk_tier)),
506
507
  }
507
- enable_gpu_direct = skypilot_config.get_nested(
508
- ('gcp', 'enable_gpu_direct'),
509
- False,
508
+ enable_gpu_direct = skypilot_config.get_effective_region_config(
509
+ cloud='gcp',
510
+ region=region_name,
511
+ keys=('enable_gpu_direct',),
512
+ default_value=False,
510
513
  override_configs=resources.cluster_config_overrides)
511
514
  resources_vars['enable_gpu_direct'] = enable_gpu_direct
512
515
  network_tier = r.network_tier
@@ -591,9 +594,11 @@ class GCP(clouds.Cloud):
591
594
 
592
595
  resources_vars['tpu_node_name'] = tpu_node_name
593
596
 
594
- managed_instance_group_config = skypilot_config.get_nested(
595
- ('gcp', 'managed_instance_group'),
596
- None,
597
+ managed_instance_group_config = skypilot_config.get_effective_region_config(
598
+ cloud='gcp',
599
+ region=region_name,
600
+ keys=('managed_instance_group',),
601
+ default_value=None,
597
602
  override_configs=resources.cluster_config_overrides)
598
603
  use_mig = managed_instance_group_config is not None
599
604
  resources_vars['gcp_use_managed_instance_group'] = use_mig
@@ -604,8 +609,11 @@ class GCP(clouds.Cloud):
604
609
  if use_mig:
605
610
  resources_vars.update(managed_instance_group_config)
606
611
  resources_vars[
607
- 'force_enable_external_ips'] = skypilot_config.get_nested(
608
- ('gcp', 'force_enable_external_ips'), False)
612
+ 'force_enable_external_ips'] = skypilot_config.get_effective_region_config(
613
+ cloud='gcp',
614
+ region=region_name,
615
+ keys=('force_enable_external_ips',),
616
+ default_value=False)
609
617
 
610
618
  volumes, device_mount_points = GCP._get_volumes_specs(
611
619
  region, zones, r.instance_type, r.volumes, use_mig,
@@ -629,13 +637,18 @@ class GCP(clouds.Cloud):
629
637
  device_mounts=device_mounts_str)
630
638
 
631
639
  # Add gVNIC from config
632
- resources_vars['enable_gvnic'] = skypilot_config.get_nested(
633
- ('gcp', 'enable_gvnic'),
634
- False,
635
- override_configs=resources.cluster_config_overrides)
636
- placement_policy = skypilot_config.get_nested(
637
- ('gcp', 'placement_policy'),
638
- None,
640
+ resources_vars[
641
+ 'enable_gvnic'] = skypilot_config.get_effective_region_config(
642
+ cloud='gcp',
643
+ region=region_name,
644
+ keys=('enable_gvnic',),
645
+ default_value=False,
646
+ override_configs=resources.cluster_config_overrides)
647
+ placement_policy = skypilot_config.get_effective_region_config(
648
+ cloud='gcp',
649
+ region=region_name,
650
+ keys=('placement_policy',),
651
+ default_value=None,
639
652
  override_configs=resources.cluster_config_overrides)
640
653
  if enable_gpu_direct or network_tier == resources_utils.NetworkTier.BEST:
641
654
  user_data += constants.GPU_DIRECT_TCPX_USER_DATA
sky/clouds/kubernetes.py CHANGED
@@ -168,8 +168,11 @@ class Kubernetes(clouds.Cloud):
168
168
  allowed_contexts = skypilot_config.get_workspace_cloud(
169
169
  'kubernetes').get('allowed_contexts', None)
170
170
  if allowed_contexts is None:
171
- allowed_contexts = skypilot_config.get_nested(
172
- ('kubernetes', 'allowed_contexts'), None)
171
+ allowed_contexts = skypilot_config.get_effective_region_config(
172
+ cloud='kubernetes',
173
+ region=None,
174
+ keys=('allowed_contexts',),
175
+ default_value=None)
173
176
 
174
177
  # Exclude contexts starting with `ssh-`
175
178
  # TODO(romilb): Remove when SSH Node Pools use a separate kubeconfig.
@@ -254,22 +257,6 @@ class Kubernetes(clouds.Cloud):
254
257
  if instance_type is None:
255
258
  return regions
256
259
 
257
- autoscaler_type = kubernetes_utils.get_autoscaler_type()
258
- if (autoscaler_type is not None and not kubernetes_utils.get_autoscaler(
259
- autoscaler_type).can_query_backend):
260
- # Unsupported autoscaler type. Rely on the autoscaler to
261
- # provision the right instance type without running checks.
262
- # Worst case, if autoscaling fails, the pod will be stuck in
263
- # pending state until provision_timeout, after which failover
264
- # will be triggered.
265
- #
266
- # Removing this if statement produces the same behavior,
267
- # because can_create_new_instance_of_type() always returns True
268
- # for unsupported autoscaler types.
269
- # This check is here as a performance optimization to avoid
270
- # further code executions that is known to return this result.
271
- return regions
272
-
273
260
  regions_to_return = []
274
261
  for r in regions:
275
262
  context = r.name
@@ -286,6 +273,29 @@ class Kubernetes(clouds.Cloud):
286
273
  'not fit in the existing Kubernetes cluster '
287
274
  'with context: '
288
275
  f'{context}. Reason: {reason}')
276
+
277
+ autoscaler_type = skypilot_config.get_effective_region_config(
278
+ cloud='kubernetes',
279
+ region=context,
280
+ keys=('autoscaler',),
281
+ default_value=None)
282
+ if (autoscaler_type is not None and
283
+ not kubernetes_utils.get_autoscaler(
284
+ autoscaler_type).can_query_backend):
285
+ # Unsupported autoscaler type. Rely on the autoscaler to
286
+ # provision the right instance type without running checks.
287
+ # Worst case, if autoscaling fails, the pod will be stuck in
288
+ # pending state until provision_timeout, after which failover
289
+ # will be triggered.
290
+ #
291
+ # Removing this if statement produces the same behavior,
292
+ # because can_create_new_instance_of_type() always returns True
293
+ # for unsupported autoscaler types.
294
+ # This check is here as a performance optimization to avoid
295
+ # further code executions that is known to return this result.
296
+ regions_to_return.append(r)
297
+ continue
298
+
289
299
  if autoscaler_type is None:
290
300
  continue
291
301
  autoscaler = kubernetes_utils.get_autoscaler(autoscaler_type)
@@ -532,11 +542,13 @@ class Kubernetes(clouds.Cloud):
532
542
  context)
533
543
  if len(avoid_label_keys) == 0:
534
544
  avoid_label_keys = None
535
- port_mode = network_utils.get_port_mode(None)
545
+ port_mode = network_utils.get_port_mode(None, context)
536
546
 
537
- remote_identity = skypilot_config.get_nested(
538
- ('kubernetes', 'remote_identity'),
539
- schemas.get_default_remote_identity('kubernetes'))
547
+ remote_identity = skypilot_config.get_effective_region_config(
548
+ cloud='kubernetes',
549
+ region=context,
550
+ keys=('remote_identity',),
551
+ default_value=schemas.get_default_remote_identity('kubernetes'))
540
552
 
541
553
  if isinstance(remote_identity, dict):
542
554
  # If remote_identity is a dict, use the service account for the
@@ -580,9 +592,11 @@ class Kubernetes(clouds.Cloud):
580
592
  # number of nodes.
581
593
 
582
594
  timeout = self._calculate_provision_timeout(num_nodes, volume_mounts)
583
- timeout = skypilot_config.get_nested(
584
- ('kubernetes', 'provision_timeout'),
585
- timeout,
595
+ timeout = skypilot_config.get_effective_region_config(
596
+ cloud='kubernetes',
597
+ region=context,
598
+ keys=('provision_timeout',),
599
+ default_value=timeout,
586
600
  override_configs=resources.cluster_config_overrides)
587
601
 
588
602
  # Check if this cluster supports high performance networking and
@@ -614,15 +628,20 @@ class Kubernetes(clouds.Cloud):
614
628
  }
615
629
 
616
630
  # Get the storage class name for high availability controller's PVC
617
- k8s_ha_storage_class_name = skypilot_config.get_nested(
618
- ('kubernetes', 'high_availability', 'storage_class_name'),
619
- None,
620
- override_configs=resources.cluster_config_overrides)
631
+ k8s_ha_storage_class_name = (
632
+ skypilot_config.get_effective_region_config(
633
+ cloud='kubernetes',
634
+ region=context,
635
+ keys=('high_availability', 'storage_class_name'),
636
+ default_value=None))
637
+
638
+ k8s_kueue_local_queue_name = (
639
+ skypilot_config.get_effective_region_config(
640
+ cloud='kubernetes',
641
+ region=context,
642
+ keys=('kueue', 'local_queue_name'),
643
+ default_value=None))
621
644
 
622
- k8s_kueue_local_queue_name = skypilot_config.get_nested(
623
- ('kubernetes', 'kueue', 'local_queue_name'),
624
- None,
625
- override_configs=resources.cluster_config_overrides)
626
645
  deploy_vars = {
627
646
  'instance_type': resources.instance_type,
628
647
  'custom_resources': custom_resources,
@@ -631,7 +650,8 @@ class Kubernetes(clouds.Cloud):
631
650
  'accelerator_count': str(acc_count),
632
651
  'timeout': str(timeout),
633
652
  'k8s_port_mode': port_mode.value,
634
- 'k8s_networking_mode': network_utils.get_networking_mode().value,
653
+ 'k8s_networking_mode': network_utils.get_networking_mode(
654
+ None, context=context).value,
635
655
  'k8s_ssh_key_secret_name': self.SKY_SSH_KEY_SECRET_NAME,
636
656
  'k8s_acc_label_key': k8s_acc_label_key,
637
657
  'k8s_acc_label_values': k8s_acc_label_values,
sky/clouds/nebius.py CHANGED
@@ -224,8 +224,14 @@ class Nebius(clouds.Cloud):
224
224
  raise RuntimeError('Unsupported instance type for Nebius cloud:'
225
225
  f' {resources.instance_type}')
226
226
 
227
- config_fs = skypilot_config.get_nested(
228
- ('nebius', region.name, 'filesystems'), [])
227
+ config_fs = skypilot_config.get_effective_region_config(
228
+ cloud='nebius',
229
+ region=None,
230
+ keys=(
231
+ region.name,
232
+ 'filesystems',
233
+ ),
234
+ default_value=[])
229
235
  resources_vars_fs = []
230
236
  for i, fs in enumerate(config_fs):
231
237
  resources_vars_fs.append({
sky/clouds/ssh.py CHANGED
@@ -143,8 +143,11 @@ class SSH(kubernetes.Kubernetes):
143
143
  allowed_node_pools = skypilot_config.get_workspace_cloud('ssh').get(
144
144
  'allowed_node_pools', None)
145
145
  if allowed_node_pools is None:
146
- allowed_node_pools = skypilot_config.get_nested(
147
- ('ssh', 'allowed_node_pools'), None)
146
+ allowed_node_pools = skypilot_config.get_effective_region_config(
147
+ cloud='ssh',
148
+ region=None,
149
+ keys=('allowed_node_pools',),
150
+ default_value=None)
148
151
 
149
152
  # Filter for SSH contexts (those starting with 'ssh-')
150
153
  ssh_contexts = [
@@ -28,10 +28,16 @@ class AWSReservation:
28
28
 
29
29
 
30
30
  def use_reservations() -> bool:
31
- prioritize_reservations = skypilot_config.get_nested(
32
- ('aws', 'prioritize_reservations'), False)
33
- specific_reservations = skypilot_config.get_nested(
34
- ('aws', 'specific_reservations'), set())
31
+ prioritize_reservations = skypilot_config.get_effective_region_config(
32
+ cloud='aws',
33
+ region=None,
34
+ keys=('prioritize_reservations',),
35
+ default_value=False)
36
+ specific_reservations = skypilot_config.get_effective_region_config(
37
+ cloud='aws',
38
+ region=None,
39
+ keys=('specific_reservations',),
40
+ default_value=set())
35
41
  return prioritize_reservations or specific_reservations
36
42
 
37
43
 
@@ -137,10 +137,16 @@ def _list_reservations_for_instance_type(
137
137
  For example, if we have a specific reservation with n1-highmem-8
138
138
  in us-central1-c. `sky launch --gpus V100` will fail.
139
139
  """
140
- prioritize_reservations = skypilot_config.get_nested(
141
- ('gcp', 'prioritize_reservations'), False)
142
- specific_reservations = skypilot_config.get_nested(
143
- ('gcp', 'specific_reservations'), [])
140
+ prioritize_reservations = skypilot_config.get_effective_region_config(
141
+ cloud='gcp',
142
+ region=None,
143
+ keys=('prioritize_reservations',),
144
+ default_value=False)
145
+ specific_reservations = skypilot_config.get_effective_region_config(
146
+ cloud='gcp',
147
+ region=None,
148
+ keys=('specific_reservations',),
149
+ default_value=[])
144
150
  if not prioritize_reservations and not specific_reservations:
145
151
  return []
146
152
  logger.debug(f'Querying GCP reservations for instance {instance_type!r}')
@@ -170,14 +176,23 @@ def _list_reservations_for_instance_type(
170
176
 
171
177
  def get_minimal_compute_permissions() -> List[str]:
172
178
  permissions = copy.copy(constants.VM_MINIMAL_PERMISSIONS)
173
- if skypilot_config.get_nested(('gcp', 'vpc_name'), None) is None:
179
+ if skypilot_config.get_effective_region_config(
180
+ cloud='gcp', region=None, keys=('vpc_name',),
181
+ default_value=None) is None:
174
182
  # If custom VPC is not specified, permissions to modify network are
175
183
  # required to ensure SkyPilot to be able to setup the network, and
176
184
  # allow opening ports (e.g., via `resources.ports`).
177
185
  permissions += constants.FIREWALL_PERMISSIONS
178
186
 
179
- if (skypilot_config.get_nested(('gcp', 'prioritize_reservations'), False) or
180
- skypilot_config.get_nested(('gcp', 'specific_reservations'), [])):
187
+ if (skypilot_config.get_effective_region_config(
188
+ cloud='gcp',
189
+ region=None,
190
+ keys=('prioritize_reservations',),
191
+ default_value=False) or skypilot_config.get_effective_region_config(
192
+ cloud='gcp',
193
+ region=None,
194
+ keys=('specific_reservations',),
195
+ default_value=[])):
181
196
  permissions += constants.RESERVATION_PERMISSIONS
182
197
 
183
198
  permissions += constants.GCP_MINIMAL_PERMISSIONS
@@ -105,22 +105,46 @@ class OCIConfig:
105
105
  @classmethod
106
106
  def get_compartment(cls, region):
107
107
  # Allow task(cluster)-specific compartment/VCN parameters.
108
- default_compartment_ocid = skypilot_config.get_nested(
109
- ('oci', 'default', 'compartment_ocid'), None)
110
- compartment = skypilot_config.get_nested(
111
- ('oci', region, 'compartment_ocid'), default_compartment_ocid)
108
+ default_compartment_ocid = skypilot_config.get_effective_region_config(
109
+ cloud='oci',
110
+ region=None,
111
+ keys=(
112
+ 'default',
113
+ 'compartment_ocid',
114
+ ),
115
+ default_value=None)
116
+ compartment = skypilot_config.get_effective_region_config(
117
+ cloud='oci',
118
+ region=None,
119
+ keys=(
120
+ region,
121
+ 'compartment_ocid',
122
+ ),
123
+ default_value=default_compartment_ocid)
112
124
  return compartment
113
125
 
114
126
  @classmethod
115
127
  def get_vcn_ocid(cls, region):
116
128
  # Will reuse the regional VCN if specified.
117
- vcn = skypilot_config.get_nested(('oci', region, 'vcn_ocid'), None)
129
+ vcn = skypilot_config.get_effective_region_config(cloud='oci',
130
+ region=None,
131
+ keys=(
132
+ region,
133
+ 'vcn_ocid',
134
+ ),
135
+ default_value=None)
118
136
  return vcn
119
137
 
120
138
  @classmethod
121
139
  def get_vcn_subnet(cls, region):
122
140
  # Will reuse the subnet if specified.
123
- vcn = skypilot_config.get_nested(('oci', region, 'vcn_subnet'), None)
141
+ vcn = skypilot_config.get_effective_region_config(cloud='oci',
142
+ region=None,
143
+ keys=(
144
+ region,
145
+ 'vcn_subnet',
146
+ ),
147
+ default_value=None)
124
148
  return vcn
125
149
 
126
150
  @classmethod
@@ -129,16 +153,28 @@ class OCIConfig:
129
153
  # we give a choice to set the default image tag (for gpu instances) in
130
154
  # the sky's user-config file (if not specified, use the hardcode one at
131
155
  # last)
132
- return skypilot_config.get_nested(('oci', 'default', 'image_tag_gpu'),
133
- 'skypilot:gpu-ubuntu-2204')
156
+ return skypilot_config.get_effective_region_config(
157
+ cloud='oci',
158
+ region=None,
159
+ keys=(
160
+ 'default',
161
+ 'image_tag_gpu',
162
+ ),
163
+ default_value='skypilot:gpu-ubuntu-2204')
134
164
 
135
165
  @classmethod
136
166
  def get_default_image_tag(cls) -> str:
137
167
  # Get the default image tag. Instead of hardcoding, we give a choice to
138
168
  # set the default image tag in the sky's user-config file. (if not
139
169
  # specified, use the hardcode one at last)
140
- return skypilot_config.get_nested(
141
- ('oci', 'default', 'image_tag_general'), 'skypilot:cpu-ubuntu-2204')
170
+ return skypilot_config.get_effective_region_config(
171
+ cloud='oci',
172
+ region=None,
173
+ keys=(
174
+ 'default',
175
+ 'image_tag_general',
176
+ ),
177
+ default_value='skypilot:cpu-ubuntu-2204')
142
178
 
143
179
  @classmethod
144
180
  def get_sky_user_config_file(cls) -> str:
@@ -152,16 +188,28 @@ class OCIConfig:
152
188
 
153
189
  @classmethod
154
190
  def get_profile(cls) -> str:
155
- return skypilot_config.get_nested(
156
- ('oci', 'default', 'oci_config_profile'), 'DEFAULT')
191
+ return skypilot_config.get_effective_region_config(
192
+ cloud='oci',
193
+ region=None,
194
+ keys=(
195
+ 'default',
196
+ 'oci_config_profile',
197
+ ),
198
+ default_value='DEFAULT')
157
199
 
158
200
  @classmethod
159
201
  def get_default_image_os(cls) -> str:
160
202
  # Get the default image OS. Instead of hardcoding, we give a choice to
161
203
  # set the default image OS type in the sky's user-config file. (if not
162
204
  # specified, use the hardcode one at last)
163
- return skypilot_config.get_nested(('oci', 'default', 'image_os_type'),
164
- 'ubuntu')
205
+ return skypilot_config.get_effective_region_config(
206
+ cloud='oci',
207
+ region=None,
208
+ keys=(
209
+ 'default',
210
+ 'image_os_type',
211
+ ),
212
+ default_value='ubuntu')
165
213
 
166
214
 
167
215
  oci_config = OCIConfig()
@@ -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/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/_error-1be831200e60c5c0.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":{"statusCode":404}},"page":"/_error","query":{},"buildId":"bs6UB9V4Jq10TIZ5x-kBK","assetPrefix":"/dashboard","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/605ac87514049058.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/605ac87514049058.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-75a3310ef922a299.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-050a9e637b057b24.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_error-1be831200e60c5c0.js" defer=""></script><script src="/dashboard/_next/static/ZYLkkWSYZjJhLVsObh20y/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ZYLkkWSYZjJhLVsObh20y/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"ZYLkkWSYZjJhLVsObh20y","assetPrefix":"/dashboard","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
@@ -1 +1 @@
1
- self.__BUILD_MANIFEST=function(s,c,e,a,t,u,n,r,b,i,j,k,f,o){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":["static/chunks/pages/index-6b0d9e5031b70c58.js"],"/_error":["static/chunks/pages/_error-1be831200e60c5c0.js"],"/clusters":["static/chunks/pages/clusters-f119a5630a1efd61.js"],"/clusters/[cluster]":[s,c,e,a,t,r,i,u,n,j,b,k,f,o,"static/chunks/871-3db673be3ee3750b.js","static/chunks/pages/clusters/[cluster]-8040f2483897ed0c.js"],"/clusters/[cluster]/[job]":[s,c,e,a,t,u,n,"static/chunks/pages/clusters/[cluster]/[job]-aff040d7bc5d0086.js"],"/config":["static/chunks/pages/config-6b255eae088da6a3.js"],"/infra":["static/chunks/pages/infra-ee8cc4d449945d19.js"],"/infra/[context]":["static/chunks/pages/infra/[context]-b302aea4d65766bf.js"],"/jobs":["static/chunks/pages/jobs-0a5695ff3075d94a.js"],"/jobs/[job]":[s,c,e,a,t,r,u,n,b,"static/chunks/pages/jobs/[job]-e4b23128db0774cd.js"],"/users":["static/chunks/pages/users-4978cbb093e141e7.js"],"/volumes":["static/chunks/pages/volumes-476b670ef33d1ecd.js"],"/workspace/new":["static/chunks/pages/workspace/new-5b59bce9eb208d84.js"],"/workspaces":["static/chunks/pages/workspaces-50e230828730cfb3.js"],"/workspaces/[name]":[s,c,e,a,t,r,i,u,n,j,b,k,f,o,"static/chunks/141-fa5a20cbf401b351.js","static/chunks/pages/workspaces/[name]-cb7e720b739de53a.js"],sortedPages:["/","/_app","/_error","/clusters","/clusters/[cluster]","/clusters/[cluster]/[job]","/config","/infra","/infra/[context]","/jobs","/jobs/[job]","/users","/volumes","/workspace/new","/workspaces","/workspaces/[name]"]}}("static/chunks/616-d6128fa9e7cae6e6.js","static/chunks/230-d6e363362017ff3a.js","static/chunks/799-3625946b2ec2eb30.js","static/chunks/664-047bc03493fda379.js","static/chunks/804-4c9fc53aa74bc191.js","static/chunks/989-db34c16ad7ea6155.js","static/chunks/470-92dd1614396389be.js","static/chunks/798-c0525dc3f21e488d.js","static/chunks/969-d3a0b53f728d280a.js","static/chunks/947-6620842ef80ae879.js","static/chunks/990-0ad5ea1699e03ee8.js","static/chunks/43-36177d00f6956ab2.js","static/chunks/973-81b2d057178adb76.js","static/chunks/938-068520cc11738deb.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
1
+ self.__BUILD_MANIFEST=function(s,c,e,a,t,u,n,r,i,b,j,k,f,o){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":["static/chunks/pages/index-6b0d9e5031b70c58.js"],"/_error":["static/chunks/pages/_error-1be831200e60c5c0.js"],"/clusters":["static/chunks/pages/clusters-65b2c90320b8afb8.js"],"/clusters/[cluster]":[s,c,e,a,t,r,b,u,n,j,i,k,f,o,"static/chunks/871-e547295e7e21399c.js","static/chunks/pages/clusters/[cluster]-77d4816945b04793.js"],"/clusters/[cluster]/[job]":[s,c,e,a,t,u,n,"static/chunks/pages/clusters/[cluster]/[job]-21080826c6095f21.js"],"/config":["static/chunks/pages/config-6b255eae088da6a3.js"],"/infra":["static/chunks/pages/infra-ee8cc4d449945d19.js"],"/infra/[context]":["static/chunks/pages/infra/[context]-b302aea4d65766bf.js"],"/jobs":["static/chunks/pages/jobs-df7407b5e37d3750.js"],"/jobs/[job]":[s,c,e,a,t,r,u,n,i,"static/chunks/pages/jobs/[job]-64bdc0b2d3a44709.js"],"/users":["static/chunks/pages/users-d7684eaa04c4f58f.js"],"/volumes":["static/chunks/pages/volumes-476b670ef33d1ecd.js"],"/workspace/new":["static/chunks/pages/workspace/new-5b59bce9eb208d84.js"],"/workspaces":["static/chunks/pages/workspaces-c470366a6179f16e.js"],"/workspaces/[name]":[s,c,e,a,t,r,b,u,n,j,i,k,f,o,"static/chunks/141-fa5a20cbf401b351.js","static/chunks/pages/workspaces/[name]-04e1b3ad4207b1e9.js"],sortedPages:["/","/_app","/_error","/clusters","/clusters/[cluster]","/clusters/[cluster]/[job]","/config","/infra","/infra/[context]","/jobs","/jobs/[job]","/users","/volumes","/workspace/new","/workspaces","/workspaces/[name]"]}}("static/chunks/616-50a620ac4a23deb4.js","static/chunks/230-d6e363362017ff3a.js","static/chunks/799-3625946b2ec2eb30.js","static/chunks/664-047bc03493fda379.js","static/chunks/804-4c9fc53aa74bc191.js","static/chunks/989-db34c16ad7ea6155.js","static/chunks/470-92dd1614396389be.js","static/chunks/798-c0525dc3f21e488d.js","static/chunks/969-d3a0b53f728d280a.js","static/chunks/947-6620842ef80ae879.js","static/chunks/990-0ad5ea1699e03ee8.js","static/chunks/43-f38a531f6692f281.js","static/chunks/601-111d06d9ded11d00.js","static/chunks/938-0a770415b5ce4649.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[43],{326:function(e,t,a){a.d(t,{$N:function(){return p},Be:function(){return _},Vq:function(){return c},cN:function(){return f},cZ:function(){return d},fK:function(){return g}});var r=a(5893),s=a(7294),o=a(6327),n=a(2350),l=a(3767);let c=o.fC;o.xz;let u=o.h_;o.x8;let i=s.forwardRef((e,t)=>{let{className:a,...s}=e;return(0,r.jsx)(o.aV,{ref:t,className:(0,n.cn)("fixed inset-0 z-50 bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",a),...s})});i.displayName=o.aV.displayName;let d=s.forwardRef((e,t)=>{let{className:a,children:s,...c}=e;return(0,r.jsxs)(u,{children:[(0,r.jsx)(i,{}),(0,r.jsxs)(o.VY,{ref:t,className:(0,n.cn)("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-gray-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",a),...c,children:[s,(0,r.jsxs)(o.x8,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 data-[state=open]:text-gray-500",children:[(0,r.jsx)(l.Z,{className:"h-4 w-4"}),(0,r.jsx)("span",{className:"sr-only",children:"Close"})]})]})]})});d.displayName=o.VY.displayName;let g=e=>{let{className:t,...a}=e;return(0,r.jsx)("div",{className:(0,n.cn)("flex flex-col space-y-1.5 text-center sm:text-left",t),...a})};g.displayName="DialogHeader";let f=e=>{let{className:t,...a}=e;return(0,r.jsx)("div",{className:(0,n.cn)("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",t),...a})};f.displayName="DialogFooter";let p=s.forwardRef((e,t)=>{let{className:a,...s}=e;return(0,r.jsx)(o.Dx,{ref:t,className:(0,n.cn)("text-lg font-semibold leading-none tracking-tight",a),...s})});p.displayName=o.Dx.displayName;let _=s.forwardRef((e,t)=>{let{className:a,...s}=e;return(0,r.jsx)(o.dk,{ref:t,className:(0,n.cn)("text-sm text-gray-500",a),...s})});_.displayName=o.dk.displayName},3266:function(e,t,a){a.d(t,{QL:function(){return g},Sl:function(){return i},getClusters:function(){return c},uR:function(){return u}});var r=a(7294),s=a(5821),o=a(7145),n=a(6378);let l={UP:"RUNNING",STOPPED:"STOPPED",INIT:"LAUNCHING",null:"TERMINATED"};async function c(){let{clusterNames:e=null}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};try{return(await o.x.fetch("/status",{cluster_names:e,all_users:!0})).map(e=>{let t="",a=t=e.zone?e.zone:e.region;return t&&t.length>25&&(t=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:15;if(!e||e.length<=t)return e;if(t<=3)return"...";let a=Math.floor((t-3)/2),r=a+(t-3)%2;return 0===a?e.substring(0,r)+"...":e.substring(0,r)+"..."+e.substring(e.length-a)}(t,25)),{status:l[e.status],cluster:e.name,user:e.user_name,user_hash:e.user_hash,cloud:e.cloud,region:e.region,infra:t?e.cloud+" ("+t+")":e.cloud,full_infra:a?"".concat(e.cloud," (").concat(a,")"):e.cloud,cpus:e.cpus,mem:e.memory,gpus:e.accelerators,resources_str:e.resources_str,resources_str_full:e.resources_str_full,time:new Date(1e3*e.launched_at),num_nodes:e.nodes,workspace:e.workspace,autostop:e.autostop,to_down:e.to_down,jobs:[],command:e.last_creation_command||e.last_use,task_yaml:e.last_creation_yaml||"{}",events:[{time:new Date(1e3*e.launched_at),event:"Cluster created."}]}})}catch(e){return console.error("Error fetching clusters:",e),[]}}async function u(){try{let e=await o.x.fetch("/cost_report",{days:30});console.log("Raw cluster history data:",e);let t=e.map(e=>{let t="Unknown";e.cloud?t=e.cloud:e.resources&&e.resources.cloud&&(t=e.resources.cloud);let a=e.user_name||"-";return{status:e.status?l[e.status]:"TERMINATED",cluster:e.name,user:a,user_hash:e.user_hash,cloud:t,region:"",infra:t,full_infra:t,resources_str:e.resources_str,resources_str_full:e.resources_str_full,time:e.launched_at?new Date(1e3*e.launched_at):null,num_nodes:e.num_nodes||1,duration:e.duration,total_cost:e.total_cost,workspace:e.workspace||"default",autostop:-1,to_down:!1,cluster_hash:e.cluster_hash,usage_intervals:e.usage_intervals,command:e.last_creation_command||"",task_yaml:e.last_creation_yaml||"{}",events:[{time:e.launched_at?new Date(1e3*e.launched_at):new Date,event:"Cluster created."}]}});return console.log("Processed cluster history data:",t),t}catch(e){return console.error("Error fetching cluster history:",e),[]}}async function i(e){let{clusterName:t,jobId:a,onNewLog:r,workspace:n}=e;try{await o.x.stream("/logs",{follow:!1,cluster_name:t,job_id:a,override_skypilot_config:{active_workspace:n||"default"}},r)}catch(e){console.error("Error in streamClusterJobLogs:",e),(0,s.C)("Error in streamClusterJobLogs: ".concat(e.message),"error")}}async function d(e){let{clusterName:t,workspace:a}=e;try{return(await o.x.fetch("/queue",{cluster_name:t,all_users:!0,override_skypilot_config:{active_workspace:a}})).map(e=>{let r=e.end_at?e.end_at:Date.now()/1e3,s=0,o=0;return e.submitted_at&&(s=r-e.submitted_at),e.start_at&&(o=r-e.start_at),{id:e.job_id,status:e.status,job:e.job_name,user:e.username,user_hash:e.user_hash,gpus:e.accelerators||{},submitted_at:e.submitted_at?new Date(1e3*e.submitted_at):null,resources:e.resources,cluster:t,total_duration:s,job_duration:o,infra:"",logs:"",workspace:a||"default"}})}catch(e){return console.error("Error fetching cluster jobs:",e),[]}}function g(e){let{cluster:t,job:a=null}=e,[s,o]=(0,r.useState)(null),[l,u]=(0,r.useState)(null),[i,g]=(0,r.useState)(!0),[f,p]=(0,r.useState)(!0),_=(0,r.useCallback)(async()=>{if(t)try{g(!0);let e=await n.default.get(c,[{clusterNames:[t]}]);return o(e[0]),e[0]}catch(e){console.error("Error fetching cluster data:",e)}finally{g(!1)}return null},[t]),h=(0,r.useCallback)(async e=>{if(t)try{p(!0);let a=await n.default.get(d,[{clusterName:t,workspace:e||"default"}]);u(a)}catch(e){console.error("Error fetching cluster job data:",e)}finally{p(!1)}},[t]),m=(0,r.useCallback)(async()=>{n.default.invalidate(c,[{clusterNames:[t]}]);let e=await _();e&&(n.default.invalidate(d,[{clusterName:t,workspace:e.workspace||"default"}]),await h(e.workspace))},[_,h,t]),b=(0,r.useCallback)(async()=>{s&&(n.default.invalidate(d,[{clusterName:t,workspace:s.workspace||"default"}]),await h(s.workspace))},[h,s,t]);return(0,r.useEffect)(()=>{(async()=>{let e=await _();e&&h(e.workspace)})()},[t,a,_,h]),{clusterData:s,clusterJobData:l,loading:i,clusterDetailsLoading:i,clusterJobsLoading:f,refreshData:m,refreshClusterJobsOnly:b}}},2045:function(e,t,a){a.d(t,{l4:function(){return n}});var r=a(3225),s=a(7145);async function o(e,t){try{let a=[];try{let e=await s.x.get("/enabled_clouds"),t=e.headers.get("X-Skypilot-Request-ID")||e.headers.get("X-Request-ID"),r=await s.x.get("/api/get?request_id=".concat(t)),o=await r.json();a=o.return_value?JSON.parse(o.return_value):[],console.log("Enabled clouds:",a)}catch(e){console.error("Error fetching enabled clouds:",e),a=[]}let o={};r.$m.forEach(e=>{let t=a.includes(e.toLowerCase());o[e]={name:e,clusters:0,jobs:0,enabled:t}}),e.forEach(e=>{if(e.cloud){let t=e.cloud;o[t]&&(o[t].clusters+=1,o[t].enabled=!0)}}),t.forEach(e=>{if(e.cloud){let t=e.cloud;o[t]&&(o[t].jobs+=1,o[t].enabled=!0)}});let n=r.$m.length,l=Object.values(o).filter(e=>e.enabled).length;return{clouds:Object.values(o).filter(e=>e.enabled).sort((e,t)=>t.clusters-e.clusters||t.jobs-e.jobs),totalClouds:n,enabledClouds:l}}catch(e){return console.error("Error fetching cloud infrastructure:",e),{clouds:[],totalClouds:r.$m.length,enabledClouds:0}}}async function n(){let{getClusters:e}=await Promise.resolve().then(a.bind(a,3266)),{getManagedJobs:t}=await Promise.resolve().then(a.bind(a,8969)),r=(await Promise.resolve().then(a.bind(a,6378))).default,[s,n]=await Promise.all([r.get(e),r.get(t,[{allUsers:!0}])]),c=s||[],u=(null==n?void 0:n.jobs)||[],[i,d]=await Promise.all([l(c,u),o(c,u)]);return{gpuData:i,cloudData:d}}async function l(e,t){return await g({clusters:e||[],jobs:t||[]})}async function c(){try{let e=await s.x.post("/realtime_kubernetes_gpu_availability",{context:null,name_filter:null,quantity_filter:null});if(!e.ok)return console.error("Error fetching Kubernetes context GPUs (in getKubernetesContextGPUs): ".concat(e.status," ").concat(e.statusText)),[];let t=e.headers.get("X-Skypilot-Request-ID")||e.headers.get("x-request-id");if(!t)return console.error("No request ID returned for Kubernetes GPU availability (in getKubernetesContextGPUs)"),[];let a=await s.x.get("/api/get?request_id=".concat(t)),r=await a.text();if(500===a.status){try{let e=JSON.parse(r);if(e.detail&&e.detail.error)try{let t=JSON.parse(e.detail.error);console.error("[infra.jsx] getKubernetesContextGPUs: Server error detail:",t.message)}catch(t){console.error("[infra.jsx] getKubernetesContextGPUs: Error parsing server error JSON:",t,"Original error text:",e.detail.error)}}catch(e){console.error("[infra.jsx] getKubernetesContextGPUs: Error parsing 500 error response JSON:",e,"Raw text was:",r)}return[]}let o=JSON.parse(r);return o.return_value?JSON.parse(o.return_value):[]}catch(e){return console.error("[infra.jsx] Outer error in getKubernetesContextGPUs:",e),[]}}async function u(){try{let e=await s.x.get("/all_contexts");if(!e.ok)return console.error("Error fetching all contexts: ".concat(e.status," ").concat(e.statusText)),[];let t=e.headers.get("X-Skypilot-Request-ID")||e.headers.get("x-request-id");if(!t)return console.error("No request ID returned for /all_contexts"),[];let a=await s.x.get("/api/get?request_id=".concat(t)),r=await a.json();return r.return_value?JSON.parse(r.return_value):[]}catch(e){return console.error("[infra.jsx] Error in getAllContexts:",e),[]}}async function i(e){try{let t=await s.x.post("/kubernetes_node_info",{context:e}),a=t.headers.get("X-Skypilot-Request-ID")||t.headers.get("x-request-id"),r=await s.x.get("/api/get?request_id=".concat(a));if(500===r.status){try{let e=await r.json();if(e.detail&&e.detail.error)try{let t=JSON.parse(e.detail.error);console.error("Error fetching Kubernetes per node GPUs:",t.message)}catch(e){console.error("Error parsing JSON:",e)}}catch(e){console.error("Error parsing JSON:",e)}return{}}let o=await r.json();return(o.return_value?JSON.parse(o.return_value):{}).node_info_dict||{}}catch(t){return console.error("[infra.jsx] Error in getKubernetesPerNodeGPUs for context",e,":",t),{}}}async function d(e){try{let t=e.clusters,a=e.jobs,r={};return t.forEach(e=>{let t=null;if("Kubernetes"===e.cloud)(t=e.region)&&(t="kubernetes/".concat(t));else if("SSH"===e.cloud&&(t=e.region)){let e=t.startsWith("ssh-")?t.substring(4):t;t="ssh/".concat(e)}t&&(r[t]||(r[t]={clusters:0,jobs:0}),r[t].clusters+=1)}),a.forEach(e=>{let t=null;if("Kubernetes"===e.cloud)(t=e.region)&&(t="kubernetes/".concat(t));else if("SSH"===e.cloud&&(t=e.region)){let e=t.startsWith("ssh-")?t.substring(4):t;t="ssh/".concat(e)}t&&(r[t]||(r[t]={clusters:0,jobs:0}),r[t].jobs+=1)}),r}catch(e){return console.error("=== Error in getContextClustersAndJobs ===",e),{}}}async function g(e){try{let o=await u();if(!o||0===o.length)return console.log("No contexts found from /all_contexts endpoint."),{allContextNames:[],allGPUs:[],perContextGPUs:[],perNodeGPUs:[],contextStats:{}};let n=await d(e),l=await c(),g=new Map;l&&l.forEach(e=>{g.set(e[0],e[1])});let f={},p={},_={};for(let e of o){p[e]||(p[e]=[]);let o=g.get(e);if(o&&o.length>0)for(let t of o){let a=t[0],r=t[1].join(", "),s=t[2],o=t[3];a in f?(f[a].gpu_total+=s,f[a].gpu_free+=o):f[a]={gpu_total:s,gpu_free:o,gpu_name:a},p[e].push({gpu_name:a,gpu_requestable_qty_per_node:r,gpu_total:s,gpu_free:o,context:e})}let n=await i(e);if(n&&Object.keys(n).length>0)for(let o in n){var t,a,r,s;let l=n[o],c=l.accelerator_type||"-",u=null!==(r=null===(t=l.total)||void 0===t?void 0:t.accelerator_count)&&void 0!==r?r:0,i=null!==(s=null===(a=l.free)||void 0===a?void 0:a.accelerators_available)&&void 0!==s?s:0;_["".concat(e,"/").concat(o)]={node_name:l.name,gpu_name:c,gpu_total:u,gpu_free:i,ip_address:l.ip_address||null,context:e},"-"===c||p[e].some(e=>e.gpu_name===c)||(c in f||(f[c]={gpu_total:0,gpu_free:0,gpu_name:c}),p[e].find(e=>e.gpu_name===c)||p[e].push({gpu_name:c,gpu_requestable_qty_per_node:"-",gpu_total:0,gpu_free:0,context:e}))}0===p[e].length&&n&&Object.keys(n).length}return{allContextNames:o.sort(),allGPUs:Object.values(f).sort((e,t)=>e.gpu_name.localeCompare(t.gpu_name)),perContextGPUs:Object.values(p).flat().sort((e,t)=>e.context.localeCompare(t.context)||e.gpu_name.localeCompare(t.gpu_name)),perNodeGPUs:Object.values(_).sort((e,t)=>e.context.localeCompare(t.context)||e.node_name.localeCompare(t.node_name)||e.gpu_name.localeCompare(t.gpu_name)),contextStats:n}}catch(e){return console.error("[infra.jsx] Outer error in getKubernetesGPUs:",e),{allContextNames:[],allGPUs:[],perContextGPUs:[],perNodeGPUs:[],contextStats:{}}}}},3081:function(e,t,a){a.d(t,{R:function(){return s}}),a(3266),a(8969);var r=a(7145);async function s(){try{let e=await r.x.get("/users");if(!e.ok)throw Error("HTTP error! status: ".concat(e.status));return(await e.json()).map(e=>({userId:e.id,username:e.name,role:e.role}))||[]}catch(e){return console.error("Failed to fetch users:",e),[]}}},6856:function(e,t,a){var r=a(6378),s=a(3266),o=a(8969),n=a(7324),l=a(3081),c=a(2045);let u={base:{getClusters:{fn:s.getClusters,args:[]},getClusterHistory:{fn:s.uR,args:[]},getManagedJobs:{fn:o.getManagedJobs,args:[{allUsers:!0}]},getWorkspaces:{fn:n.fX,args:[]},getUsers:{fn:l.R,args:[]},getInfraData:{fn:c.l4,args:[]}},dynamic:{getEnabledClouds:{fn:n.yz,requiresWorkspaces:!0}},pages:{clusters:["getClusters","getClusterHistory","getWorkspaces","getUsers"],jobs:["getManagedJobs","getClusters","getWorkspaces","getUsers"],infra:["getInfraData","getClusters","getManagedJobs"],workspaces:["getWorkspaces","getClusters","getManagedJobs","getEnabledClouds"],users:["getUsers","getClusters","getManagedJobs"]}};class i{async preloadForPage(e,t){let{backgroundPreload:a=!0,force:r=!1}=t||{};if(!u.pages[e]){console.warn("Unknown page: ".concat(e));return}console.log("[CachePreloader] Preloading cache for page: ".concat(e));try{await this._loadPageData(e,r),a&&this._backgroundPreloadOtherPages(e)}catch(t){console.error("[CachePreloader] Error preloading for page ".concat(e,":"),t)}}async _loadPageData(e){let t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],a=u.pages[e],s=[];for(let e of a)if(u.base[e]){let{fn:a,args:o}=u.base[e];t&&r.default.invalidate(a,o),s.push(r.default.get(a,o))}else"getEnabledClouds"===e&&s.push(this._loadEnabledCloudsForAllWorkspaces(t));await Promise.allSettled(s),console.log("[CachePreloader] Loaded data for page: ".concat(e))}async _loadEnabledCloudsForAllWorkspaces(){let e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];try{e&&r.default.invalidate(n.fX);let t=await r.default.get(n.fX),a=Object.keys(t||{}).map(t=>(e&&r.default.invalidate(n.yz,[t]),r.default.get(n.yz,[t])));await Promise.allSettled(a)}catch(e){console.error("[CachePreloader] Error loading enabled clouds:",e)}}_backgroundPreloadOtherPages(e){if(this.isPreloading)return;this.isPreloading=!0;let t=Object.keys(u.pages).filter(t=>t!==e);console.log("[CachePreloader] Background preloading pages: ".concat(t.join(", "))),Promise.allSettled(t.map(async e=>{try{await this._loadPageData(e,!1),console.log("[CachePreloader] Background loaded: ".concat(e))}catch(t){console.error("[CachePreloader] Background load failed for ".concat(e,":"),t)}})).then(()=>{this.isPreloading=!1,console.log("[CachePreloader] Background preloading complete")})}async preloadBaseFunctions(){let e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];console.log("[CachePreloader] Preloading all base functions");let t=Object.entries(u.base).map(t=>{let[a,{fn:s,args:o}]=t;return e&&r.default.invalidate(s,o),r.default.get(s,o).catch(e=>{console.error("[CachePreloader] Failed to preload ".concat(a,":"),e)})});await Promise.allSettled(t),console.log("[CachePreloader] Base functions preloaded")}getCacheStats(){return{...r.default.getStats(),isPreloading:this.isPreloading}}clearCache(){r.default.clear(),this.isPreloading=!1,this.preloadPromises.clear(),console.log("[CachePreloader] Cache cleared")}constructor(){this.isPreloading=!1,this.preloadPromises=new Map}}let d=new i;t.ZP=d}}]);