skypilot-nightly 1.0.0.dev20250522__py3-none-any.whl → 1.0.0.dev20250523__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 (70) hide show
  1. sky/__init__.py +2 -2
  2. sky/adaptors/kubernetes.py +46 -16
  3. sky/backends/cloud_vm_ray_backend.py +16 -4
  4. sky/check.py +109 -44
  5. sky/cli.py +261 -90
  6. sky/client/cli.py +261 -90
  7. sky/client/sdk.py +50 -2
  8. sky/clouds/__init__.py +3 -0
  9. sky/clouds/aws.py +4 -2
  10. sky/clouds/azure.py +4 -2
  11. sky/clouds/cloud.py +24 -6
  12. sky/clouds/cudo.py +2 -1
  13. sky/clouds/do.py +2 -1
  14. sky/clouds/fluidstack.py +2 -1
  15. sky/clouds/gcp.py +4 -2
  16. sky/clouds/ibm.py +4 -2
  17. sky/clouds/kubernetes.py +66 -22
  18. sky/clouds/lambda_cloud.py +2 -1
  19. sky/clouds/nebius.py +18 -2
  20. sky/clouds/oci.py +4 -2
  21. sky/clouds/paperspace.py +2 -1
  22. sky/clouds/runpod.py +2 -1
  23. sky/clouds/scp.py +2 -1
  24. sky/clouds/service_catalog/constants.py +1 -1
  25. sky/clouds/service_catalog/ssh_catalog.py +167 -0
  26. sky/clouds/ssh.py +203 -0
  27. sky/clouds/vast.py +2 -1
  28. sky/clouds/vsphere.py +2 -1
  29. sky/core.py +53 -9
  30. sky/dashboard/out/404.html +1 -1
  31. sky/dashboard/out/_next/static/{CzOVV6JpRQBRt5GhZuhyK → ECKwDNS9v9y3_IKFZ2lpp}/_buildManifest.js +1 -1
  32. sky/dashboard/out/_next/static/chunks/pages/infra-abf08c4384190a39.js +1 -0
  33. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  34. sky/dashboard/out/clusters/[cluster].html +1 -1
  35. sky/dashboard/out/clusters.html +1 -1
  36. sky/dashboard/out/index.html +1 -1
  37. sky/dashboard/out/infra.html +1 -1
  38. sky/dashboard/out/jobs/[job].html +1 -1
  39. sky/dashboard/out/jobs.html +1 -1
  40. sky/optimizer.py +23 -4
  41. sky/provision/__init__.py +1 -0
  42. sky/provision/aws/instance.py +17 -1
  43. sky/provision/kubernetes/instance.py +16 -5
  44. sky/provision/kubernetes/utils.py +37 -19
  45. sky/provision/nebius/instance.py +3 -1
  46. sky/provision/nebius/utils.py +14 -2
  47. sky/provision/ssh/__init__.py +18 -0
  48. sky/resources.py +4 -1
  49. sky/server/requests/payloads.py +7 -0
  50. sky/server/server.py +40 -0
  51. sky/setup_files/dependencies.py +1 -0
  52. sky/templates/nebius-ray.yml.j2 +12 -0
  53. sky/utils/infra_utils.py +21 -1
  54. sky/utils/kubernetes/cleanup-tunnel.sh +62 -0
  55. sky/utils/kubernetes/create_cluster.sh +1 -0
  56. sky/utils/kubernetes/deploy_remote_cluster.py +1437 -0
  57. sky/utils/kubernetes/kubernetes_deploy_utils.py +117 -10
  58. sky/utils/kubernetes/ssh-tunnel.sh +387 -0
  59. sky/utils/log_utils.py +214 -1
  60. sky/utils/schemas.py +21 -0
  61. sky/utils/ux_utils.py +2 -1
  62. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250523.dist-info}/METADATA +6 -1
  63. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250523.dist-info}/RECORD +68 -63
  64. sky/dashboard/out/_next/static/chunks/pages/infra-9180cd91cee64b96.js +0 -1
  65. sky/utils/kubernetes/deploy_remote_cluster.sh +0 -308
  66. /sky/dashboard/out/_next/static/{CzOVV6JpRQBRt5GhZuhyK → ECKwDNS9v9y3_IKFZ2lpp}/_ssgManifest.js +0 -0
  67. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250523.dist-info}/WHEEL +0 -0
  68. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250523.dist-info}/entry_points.txt +0 -0
  69. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250523.dist-info}/licenses/LICENSE +0 -0
  70. {skypilot_nightly-1.0.0.dev20250522.dist-info → skypilot_nightly-1.0.0.dev20250523.dist-info}/top_level.txt +0 -0
sky/clouds/ssh.py ADDED
@@ -0,0 +1,203 @@
1
+ """SSH Node Pools"""
2
+
3
+ import os
4
+ import typing
5
+ from typing import Dict, List, Optional, Set, Tuple, Union
6
+
7
+ import yaml
8
+
9
+ from sky import sky_logging
10
+ from sky.adaptors import kubernetes as kubernetes_adaptor
11
+ from sky.clouds import kubernetes
12
+ from sky.provision.kubernetes import utils as kubernetes_utils
13
+ from sky.utils import annotations
14
+ from sky.utils import registry
15
+
16
+ if typing.TYPE_CHECKING:
17
+ # Renaming to avoid shadowing variables.
18
+ from sky import resources as resources_lib
19
+
20
+ logger = sky_logging.init_logger(__name__)
21
+
22
+ SSH_NODE_POOLS_PATH = os.path.expanduser('~/.sky/ssh_node_pools.yaml')
23
+
24
+
25
+ @registry.CLOUD_REGISTRY.register()
26
+ class SSH(kubernetes.Kubernetes):
27
+ """SSH cloud implementation.
28
+
29
+ This is used by SSH Node Pools in SkyPilot, which use Kubernetes to manage
30
+ the SSH clusters.
31
+
32
+ This cloud is a thin wrapper around Kubernetes that only uses contexts
33
+ starting with 'ssh-', which are managed through `sky ssh up` command.
34
+ """
35
+
36
+ _REPR = 'SSH'
37
+
38
+ # Keep track of contexts that have been logged as unreachable
39
+ logged_unreachable_contexts: Set[str] = set()
40
+
41
+ def __repr__(self):
42
+ return self._REPR
43
+
44
+ @classmethod
45
+ def _unsupported_features_for_resources(
46
+ cls, resources: 'resources_lib.Resources'
47
+ ) -> Dict[kubernetes.clouds.CloudImplementationFeatures, str]:
48
+ # Inherit all Kubernetes unsupported features
49
+ return super()._unsupported_features_for_resources(resources)
50
+
51
+ @classmethod
52
+ def get_ssh_node_pool_contexts(cls) -> List[str]:
53
+ """Get context names from ssh_node_pools.yaml file.
54
+
55
+ Reads the SSH node pools configuration file and returns
56
+ a list of context names by prepending 'ssh-' to each Node Pool name.
57
+
58
+ Returns:
59
+ A list of SSH Kubernetes context names derived from the Node Pools
60
+ in the SSH node pools file.
61
+ """
62
+ contexts = []
63
+
64
+ if os.path.exists(SSH_NODE_POOLS_PATH):
65
+ try:
66
+ with open(SSH_NODE_POOLS_PATH, 'r', encoding='utf-8') as f:
67
+ ssh_config = yaml.safe_load(f)
68
+ if ssh_config:
69
+ # Get cluster names and prepend 'ssh-' to match
70
+ # context naming convention
71
+ contexts = [
72
+ f'ssh-{cluster_name}'
73
+ for cluster_name in ssh_config.keys()
74
+ ]
75
+ except Exception: # pylint: disable=broad-except
76
+ # If there's an error reading the file, return empty list
77
+ pass
78
+
79
+ return contexts
80
+
81
+ def validate_region_zone(self, region: Optional[str], zone: Optional[str]):
82
+ if region == kubernetes_adaptor.in_cluster_context_name():
83
+ # If running incluster, we set region to IN_CLUSTER_REGION
84
+ # since there is no context name available.
85
+ return region, zone
86
+
87
+ all_contexts = self.existing_allowed_contexts()
88
+
89
+ if region is not None and region not in all_contexts:
90
+ region_name = region.lstrip('ssh-')
91
+ available_contexts = [c.lstrip('ssh-') for c in all_contexts]
92
+ err_str = (f'SSH Node Pool {region_name!r} is not set up. '
93
+ 'Run `sky check` for more details. ')
94
+ if available_contexts:
95
+ err_str += f'Available node pools: {available_contexts}'
96
+ raise ValueError(err_str)
97
+ if zone is not None:
98
+ raise ValueError('SSH Node Pools do not support setting zone.')
99
+ return region, zone
100
+
101
+ @classmethod
102
+ @annotations.lru_cache(scope='global', maxsize=1)
103
+ def _ssh_log_skipped_contexts_once(
104
+ cls, skipped_contexts: Tuple[str, ...]) -> None:
105
+ """Log skipped contexts for only once.
106
+
107
+ We don't directly cache the result of _filter_existing_allowed_contexts
108
+ as the admin policy may update the allowed contexts.
109
+ """
110
+ if skipped_contexts:
111
+ count = len(set(skipped_contexts))
112
+ is_singular = count == 1
113
+ logger.warning(
114
+ f'SSH Node {("Pool" if is_singular else "Pools")} '
115
+ f'{set(skipped_contexts)!r} specified in '
116
+ f'{SSH_NODE_POOLS_PATH} {("has" if is_singular else "have")} '
117
+ 'not been set up. Skipping '
118
+ f'{("that pool" if is_singular else "those pools")}. '
119
+ 'Run `sky ssh up` to set up.')
120
+
121
+ @classmethod
122
+ def existing_allowed_contexts(cls, silent: bool = False) -> List[str]:
123
+ """Get existing allowed contexts that start with 'ssh-'.
124
+
125
+ Override the Kubernetes implementation to only return contexts that
126
+ start with 'ssh-', which are created by `sky ssh up`.
127
+
128
+ Returns contexts based on clusters defined in ~/.sky/ssh_node_pools.yaml
129
+ """
130
+ # Get all contexts from the Kubernetes implementation
131
+ all_contexts = kubernetes_utils.get_all_kube_context_names()
132
+ if not all_contexts:
133
+ return []
134
+
135
+ all_contexts = set(all_contexts)
136
+
137
+ # Filter for SSH contexts (those starting with 'ssh-')
138
+ ssh_contexts = [
139
+ context for context in all_contexts if context.startswith('ssh-')
140
+ ]
141
+
142
+ # Get contexts from SSH node pools file
143
+ allowed_contexts = cls.get_ssh_node_pool_contexts()
144
+
145
+ if allowed_contexts:
146
+ # Only include allowed contexts that exist
147
+ existing_contexts = []
148
+ skipped_contexts = []
149
+ for context in allowed_contexts:
150
+ if context in ssh_contexts:
151
+ existing_contexts.append(context)
152
+ else:
153
+ skipped_contexts.append(context)
154
+ if not silent:
155
+ cls._ssh_log_skipped_contexts_once(tuple(skipped_contexts))
156
+ return existing_contexts
157
+
158
+ # If no allowed_contexts found, return all SSH contexts
159
+ return ssh_contexts
160
+
161
+ @classmethod
162
+ def _check_compute_credentials(
163
+ cls) -> Tuple[bool, Optional[Union[str, Dict[str, str]]]]:
164
+ """Check if the user has access credentials to SSH contexts."""
165
+ # Check for port forward dependencies - reuse Kubernetes implementation
166
+ reasons = kubernetes_utils.check_port_forward_mode_dependencies(False)
167
+ if reasons is not None:
168
+ formatted = '\n'.join(
169
+ [reasons[0]] +
170
+ [f'{cls._INDENT_PREFIX}' + r for r in reasons[1:]])
171
+ return (False, formatted)
172
+
173
+ # Get SSH contexts
174
+ try:
175
+ existing_allowed_contexts = cls.existing_allowed_contexts()
176
+ except Exception as e: # pylint: disable=broad-except
177
+ return (False, f'Failed to get SSH contexts: {str(e)}')
178
+
179
+ if not existing_allowed_contexts:
180
+ return (False,
181
+ 'No SSH Node Pools are up. Run `sky ssh up` to set up '
182
+ f'Node Pools from {SSH_NODE_POOLS_PATH}.')
183
+
184
+ # Check credentials for each context
185
+ ctx2text = {}
186
+ success = False
187
+ for context in existing_allowed_contexts:
188
+ suc, text = super()._check_single_context(context)
189
+ success = success or suc
190
+ ctx2text[context] = text
191
+
192
+ return success, ctx2text
193
+
194
+ @classmethod
195
+ def get_infras(cls) -> List[str]:
196
+ return [
197
+ f'{cls._REPR.lower()}/{c.lstrip("ssh-")}'
198
+ for c in cls.existing_allowed_contexts(silent=True)
199
+ ]
200
+
201
+ @classmethod
202
+ def display_name(cls) -> str:
203
+ return 'SSH Node Pools'
sky/clouds/vast.py CHANGED
@@ -237,7 +237,8 @@ class Vast(clouds.Cloud):
237
237
  fuzzy_candidate_list, None)
238
238
 
239
239
  @classmethod
240
- def _check_compute_credentials(cls) -> Tuple[bool, Optional[str]]:
240
+ def _check_compute_credentials(
241
+ cls) -> Tuple[bool, Optional[Union[str, Dict[str, str]]]]:
241
242
  """Checks if the user has valid credentials for
242
243
  Vast's compute service. """
243
244
  try:
sky/clouds/vsphere.py CHANGED
@@ -261,7 +261,8 @@ class Vsphere(clouds.Cloud):
261
261
  fuzzy_candidate_list, None)
262
262
 
263
263
  @classmethod
264
- def _check_compute_credentials(cls) -> Tuple[bool, Optional[str]]:
264
+ def _check_compute_credentials(
265
+ cls) -> Tuple[bool, Optional[Union[str, Dict[str, str]]]]:
265
266
  """Checks if the user has access credentials to
266
267
  vSphere's compute service."""
267
268
 
sky/core.py CHANGED
@@ -470,7 +470,10 @@ def _stop_not_supported_message(resources: 'resources_lib.Resources') -> str:
470
470
  message = ('Stopping spot instances is currently not supported on '
471
471
  f'{resources.cloud}')
472
472
  else:
473
- message = f'Stopping is currently not supported for {resources}'
473
+ cloud_name = resources.cloud.display_name(
474
+ ) if resources.cloud else resources.cloud
475
+ message = ('Stopping is currently not supported for '
476
+ f'{cloud_name}')
474
477
  return message
475
478
 
476
479
 
@@ -1015,11 +1018,20 @@ def enabled_clouds() -> List[clouds.Cloud]:
1015
1018
  def realtime_kubernetes_gpu_availability(
1016
1019
  context: Optional[str] = None,
1017
1020
  name_filter: Optional[str] = None,
1018
- quantity_filter: Optional[int] = None
1021
+ quantity_filter: Optional[int] = None,
1022
+ is_ssh: Optional[bool] = None
1019
1023
  ) -> List[Tuple[str, List[models.RealtimeGpuAvailability]]]:
1020
1024
 
1021
1025
  if context is None:
1022
- context_list = clouds.Kubernetes.existing_allowed_contexts()
1026
+ # Include contexts from both Kubernetes and SSH clouds
1027
+ kubernetes_contexts = clouds.Kubernetes.existing_allowed_contexts()
1028
+ ssh_contexts = clouds.SSH.existing_allowed_contexts()
1029
+ if is_ssh is None:
1030
+ context_list = kubernetes_contexts + ssh_contexts
1031
+ elif is_ssh:
1032
+ context_list = ssh_contexts
1033
+ else:
1034
+ context_list = kubernetes_contexts
1023
1035
  else:
1024
1036
  context_list = [context]
1025
1037
 
@@ -1030,7 +1042,7 @@ def realtime_kubernetes_gpu_availability(
1030
1042
  ) -> List[models.RealtimeGpuAvailability]:
1031
1043
  counts, capacity, available = service_catalog.list_accelerator_realtime(
1032
1044
  gpus_only=True,
1033
- clouds='kubernetes',
1045
+ clouds='ssh' if is_ssh else 'kubernetes',
1034
1046
  name_filter=name_filter,
1035
1047
  region_filter=context,
1036
1048
  quantity_filter=quantity_filter,
@@ -1062,16 +1074,19 @@ def realtime_kubernetes_gpu_availability(
1062
1074
  name_filter=name_filter,
1063
1075
  quantity_filter=quantity_filter), context_list)
1064
1076
 
1077
+ cloud_identity = 'ssh' if is_ssh else 'kubernetes'
1078
+ cloud_identity_capital = 'SSH' if is_ssh else 'Kubernetes'
1079
+
1065
1080
  for ctx, queried in zip(context_list, parallel_queried):
1066
1081
  cumulative_count += len(queried)
1067
1082
  if len(queried) == 0:
1068
1083
  # don't add gpu results for clusters that don't have any
1069
- logger.debug(f'No gpus found in k8s cluster {ctx}')
1084
+ logger.debug(f'No gpus found in {cloud_identity} cluster {ctx}')
1070
1085
  continue
1071
1086
  availability_lists.append((ctx, queried))
1072
1087
 
1073
1088
  if cumulative_count == 0:
1074
- err_msg = 'No GPUs found in any Kubernetes clusters. '
1089
+ err_msg = f'No GPUs found in any {cloud_identity_capital} clusters. '
1075
1090
  debug_msg = 'To further debug, run: sky check '
1076
1091
  if name_filter is not None:
1077
1092
  gpu_info_msg = f' {name_filter!r}'
@@ -1079,9 +1094,9 @@ def realtime_kubernetes_gpu_availability(
1079
1094
  gpu_info_msg += (' with requested quantity'
1080
1095
  f' {quantity_filter}')
1081
1096
  err_msg = (f'Resources{gpu_info_msg} not found '
1082
- 'in Kubernetes clusters. ')
1083
- debug_msg = ('To show available accelerators on kubernetes,'
1084
- ' run: sky show-gpus --cloud kubernetes ')
1097
+ f'in {cloud_identity_capital} clusters. ')
1098
+ debug_msg = (f'To show available accelerators on {cloud_identity}, '
1099
+ f' run: sky show-gpus --cloud {cloud_identity} ')
1085
1100
  full_err_msg = (err_msg + kubernetes_constants.NO_GPU_HELP_MESSAGE +
1086
1101
  debug_msg)
1087
1102
  raise ValueError(full_err_msg)
@@ -1179,3 +1194,32 @@ def local_down() -> None:
1179
1194
  ux_utils.finishing_message('Local cluster removed.',
1180
1195
  log_path=log_path,
1181
1196
  is_local=True))
1197
+
1198
+
1199
+ @usage_lib.entrypoint
1200
+ def ssh_up(infra: Optional[str] = None, cleanup: bool = False) -> None:
1201
+ """Deploys or tears down a Kubernetes cluster on SSH targets.
1202
+
1203
+ Args:
1204
+ infra: Name of the cluster configuration in ssh_node_pools.yaml.
1205
+ If None, the first cluster in the file is used.
1206
+ cleanup: If True, clean up the cluster instead of deploying.
1207
+ """
1208
+ kubernetes_deploy_utils.deploy_ssh_cluster(
1209
+ cleanup=cleanup,
1210
+ infra=infra,
1211
+ )
1212
+
1213
+
1214
+ def get_all_contexts() -> List[str]:
1215
+ """Get all available contexts from Kubernetes and SSH clouds.
1216
+
1217
+ Returns:
1218
+ List[str]: A list of all available context names.
1219
+ """
1220
+ kube_contexts = clouds.Kubernetes.existing_allowed_contexts()
1221
+ ssh_contexts = clouds.SSH.get_ssh_node_pool_contexts()
1222
+ # Ensure ssh_contexts are prefixed appropriately if not already
1223
+ # For now, assuming get_ssh_node_pool_contexts already returns them
1224
+ # in the desired format (e.g., 'ssh-my-cluster')
1225
+ return sorted(list(set(kube_contexts + ssh_contexts)))
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link rel="preload" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_error-1be831200e60c5c0.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"CzOVV6JpRQBRt5GhZuhyK","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"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link rel="preload" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_error-1be831200e60c5c0.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"ECKwDNS9v9y3_IKFZ2lpp","assetPrefix":"/dashboard","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
@@ -1 +1 @@
1
- self.__BUILD_MANIFEST=function(s,c,e,t,a,r){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":["static/chunks/pages/index-6b0d9e5031b70c58.js"],"/_error":["static/chunks/pages/_error-1be831200e60c5c0.js"],"/clusters":[s,e,c,t,a,"static/chunks/pages/clusters-3a748bd76e5c2984.js"],"/clusters/[cluster]":[s,e,c,t,r,a,"static/chunks/pages/clusters/[cluster]-e2fc2dd1955e6c36.js"],"/clusters/[cluster]/[job]":[s,c,"static/chunks/pages/clusters/[cluster]/[job]-33bc2bec322249b1.js"],"/infra":[s,c,"static/chunks/pages/infra-9180cd91cee64b96.js"],"/jobs":[s,e,c,t,r,"static/chunks/pages/jobs-ecd804b9272f4a7c.js"],"/jobs/[job]":[s,c,"static/chunks/pages/jobs/[job]-70756c2dad850a7e.js"],sortedPages:["/","/_app","/_error","/clusters","/clusters/[cluster]","/clusters/[cluster]/[job]","/infra","/jobs","/jobs/[job]"]}}("static/chunks/582-683f4f27b81996dc.js","static/chunks/480-f28cd152a98997de.js","static/chunks/312-c3c8845990db8ffc.js","static/chunks/393-e1eaa440481337ec.js","static/chunks/37-d584022b0da4ac3b.js","static/chunks/236-1a3a9440417720eb.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
1
+ self.__BUILD_MANIFEST=function(s,c,e,t,a,r){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":["static/chunks/pages/index-6b0d9e5031b70c58.js"],"/_error":["static/chunks/pages/_error-1be831200e60c5c0.js"],"/clusters":[s,e,c,t,a,"static/chunks/pages/clusters-3a748bd76e5c2984.js"],"/clusters/[cluster]":[s,e,c,t,r,a,"static/chunks/pages/clusters/[cluster]-e2fc2dd1955e6c36.js"],"/clusters/[cluster]/[job]":[s,c,"static/chunks/pages/clusters/[cluster]/[job]-33bc2bec322249b1.js"],"/infra":[s,c,"static/chunks/pages/infra-abf08c4384190a39.js"],"/jobs":[s,e,c,t,r,"static/chunks/pages/jobs-ecd804b9272f4a7c.js"],"/jobs/[job]":[s,c,"static/chunks/pages/jobs/[job]-70756c2dad850a7e.js"],sortedPages:["/","/_app","/_error","/clusters","/clusters/[cluster]","/clusters/[cluster]/[job]","/infra","/jobs","/jobs/[job]"]}}("static/chunks/582-683f4f27b81996dc.js","static/chunks/480-f28cd152a98997de.js","static/chunks/312-c3c8845990db8ffc.js","static/chunks/393-e1eaa440481337ec.js","static/chunks/37-d584022b0da4ac3b.js","static/chunks/236-1a3a9440417720eb.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
@@ -0,0 +1 @@
1
+ (self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[588],{6206:function(e,t,r){(window.__NEXT_P=window.__NEXT_P||[]).push(["/infra",function(){return r(1090)}])},3266:function(e,t,r){"use strict";r.d(t,{QL:function(){return d},Sl:function(){return c},zd:function(){return o}});var s=r(7294),a=r(5821),n=r(3225);let l={UP:"RUNNING",STOPPED:"STOPPED",INIT:"LAUNCHING",null:"TERMINATED"};async function o(){let{clusterNames:e=null}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};try{let t=await fetch("".concat(n.f4,"/status"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cluster_names:e,all_users:!0})}),r=t.headers.get("X-Skypilot-Request-ID")||t.headers.get("X-Request-ID"),s=await fetch("".concat(n.f4,"/api/get?request_id=").concat(r)),a=await s.json();return(a.return_value?JSON.parse(a.return_value):[]).map(e=>{let t="",r=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 r=Math.floor((t-3)/2),s=r+(t-3)%2;return 0===r?e.substring(0,s)+"...":e.substring(0,s)+"..."+e.substring(e.length-r)}(t,25)),{status:l[e.status],cluster:e.name,user:e.user_name,cloud:e.cloud,infra:t?e.cloud+" ("+t+")":e.cloud,full_infra:r?"".concat(e.cloud," (").concat(r,")"):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,jobs:[],events:[{time:new Date(1e3*e.launched_at),event:"Cluster created."}]}})}catch(e){return console.error("Error fetching clusters:",e),[]}}async function c(e){let{clusterName:t,jobId:r,onNewLog:s}=e;try{let e=(await fetch("".concat(n.f4,"/logs"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({follow:!1,cluster_name:t,job_id:r})})).body.getReader();for(;;){let{done:t,value:r}=await e.read();if(t)break;let a=new TextDecoder().decode(r);s(a)}}catch(e){console.error("Error in streamClusterJobLogs:",e),(0,a.C)("Error in streamClusterJobLogs: ".concat(e.message),"error")}}async function i(e){let{clusterName:t}=e;try{let e=await fetch("".concat(n.f4,"/queue"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({cluster_name:t,all_users:!0})}),r=e.headers.get("X-Skypilot-Request-ID")||e.headers.get("X-Request-ID"),s=await fetch("".concat(n.f4,"/api/get?request_id=").concat(r)),a=await s.json();return JSON.parse(a.return_value).map(e=>{let r=e.end_at?e.end_at:Date.now()/1e3,s=0,a=0;return e.submitted_at&&(s=r-e.submitted_at),e.start_at&&(a=r-e.start_at),{id:e.job_id,status:e.status,job:e.job_name,user:e.username,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:a,infra:"",logs:""}})}catch(e){return console.error("Error fetching cluster jobs:",e),[]}}function d(e){let{cluster:t,job:r=null}=e,[a,n]=(0,s.useState)(null),[l,c]=(0,s.useState)(null),[d,u]=(0,s.useState)(!0),[m,h]=(0,s.useState)(!0),f=(0,s.useCallback)(async()=>{if(t)try{u(!0);let e=await o({clusterNames:[t]});n(e[0])}catch(e){console.error("Error fetching cluster data:",e)}finally{u(!1)}},[t]),x=(0,s.useCallback)(async()=>{if(t)try{h(!0);let e=await i({clusterName:t});c(e)}catch(e){console.error("Error fetching cluster job data:",e)}finally{h(!1)}},[t]),g=(0,s.useCallback)(async()=>{await Promise.all([f(),x()])},[f,x]);return(0,s.useEffect)(()=>{f(),x()},[t,r,f,x]),{clusterData:a,clusterJobData:l,loading:d||m,refreshData:g}}},8969:function(e,t,r){"use strict";r.d(t,{Ce:function(){return i},NJ:function(){return c},Pr:function(){return o},Vp:function(){return l}});var s=r(7294),a=r(5821),n=r(3225);async function l(){let{allUsers:e=!0}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};try{let t=(await fetch("".concat(n.f4,"/jobs/queue"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({all_users:e})})).headers.get("X-Skypilot-Request-ID"),r=await fetch("".concat(n.f4,"/api/get?request_id=").concat(t));if(500===r.status){try{let e=await r.json();if(e.detail&&e.detail.error)try{let t=JSON.parse(e.detail.error);if(t.type&&t.type===n.iW)return{jobs:[],controllerStopped:!0}}catch(e){console.error("Error parsing JSON:",e)}}catch(e){console.error("Error parsing JSON:",e)}return{jobs:[],controllerStopped:!1}}let s=await r.json();return{jobs:(s.return_value?JSON.parse(s.return_value):[]).map(e=>{let t=[];e.submitted_at&&t.push({time:new Date(1e3*e.submitted_at),event:"Job submitted."}),e.start_at&&t.push({time:new Date(1e3*e.start_at),event:"Job started."}),e.end_at&&("CANCELLING"==e.status||"CANCELLED"==e.status?t.push({time:new Date(1e3*e.end_at),event:"Job cancelled."}):t.push({time:new Date(1e3*e.end_at),event:"Job completed."})),e.last_recovered_at&&e.last_recovered_at!=e.start_at&&t.push({time:new Date(1e3*e.last_recovered_at),event:"Job recovered."});let r=(e.end_at?e.end_at:Date.now()/1e3)-e.submitted_at,s=e.cloud,a=e.cluster_resources;if(!s){if(e.cluster_resources&&"-"!==e.cluster_resources)try{s=e.cluster_resources.split("(")[0].split("x").pop().trim(),a=e.cluster_resources.replace("".concat(s,"("),"(").replace("x ","x")}catch(e){s="Unknown"}else s="Unknown"}let n="",l=n=e.zone?e.zone:e.region;n&&n.length>15&&(n=n.substring(0,15)+"...");let o=s+" ("+n+")";"-"===n&&(o=s);let c=s+" ("+l+")";return"-"===l&&(c=s),{id:e.job_id,task:e.task_name,name:e.job_name,job_duration:e.job_duration,total_duration:r,status:e.status,requested_resources:e.resources,resources_str:a,resources_str_full:e.cluster_resources_full||a,cloud:s,infra:o,full_infra:c,recoveries:e.recovery_count,details:e.failure_reason,user:e.user_name,submitted_at:e.submitted_at?new Date(1e3*e.submitted_at):null,events:t}}),controllerStopped:!1}}catch(e){return console.error("Error fetching managed job data:",e),{jobs:[],controllerStopped:!1}}}function o(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,[t,r]=(0,s.useState)(null),[a,n]=(0,s.useState)(!0);return(0,s.useEffect)(()=>{(async function(){try{n(!0);let e=await l({allUsers:!0});r(e)}catch(e){console.error("Error fetching managed job data:",e)}finally{n(!1)}})()},[e]),{jobData:t,loading:a}}async function c(e){let{jobId:t,controller:r=!1,signal:s,onNewLog:l}=e,o=new Promise(e=>{setTimeout(()=>{e({timeout:!0})},1e4)}),c=(async()=>{try{let e=(await fetch("".concat(n.f4,"/jobs/logs"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({controller:r,follow:!1,job_id:t}),...s?{signal:s}:{}})).body.getReader();try{for(;;){let{done:t,value:r}=await e.read();if(t)break;let s=new TextDecoder().decode(r);l(s)}}finally{e.cancel()}return{timeout:!1}}catch(e){if("AbortError"===e.name)return{timeout:!1};throw e}})();if((await Promise.race([c,o])).timeout){(0,a.C)("Log request for job ".concat(t," timed out after ").concat(1e4,"ms"),"error");return}}async function i(e,t,r){let s="",l="",o="",c={};if("restartcontroller"===e)s="Restarting",l="restarted",o="jobs/queue",c={all_users:!0,refresh:!0},t="controller";else throw Error("Invalid action: ".concat(e));(0,a.C)("".concat(s," job ").concat(t,"..."),"info");try{try{let e=(await fetch("".concat(n.f4,"/").concat(o),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)})).headers.get("X-Skypilot-Request-ID"),i=await fetch("".concat(n.f4,"/api/get?request_id=").concat(e));if(200===i.status)(0,a.C)("Job ".concat(t," ").concat(l," successfully."),"success");else if(500===i.status)try{let e=await i.json();if(e.detail&&e.detail.error)try{let l=JSON.parse(e.detail.error);l.type&&l.type===n.Bo?(0,a.C)("".concat(s," job ").concat(t," is not supported!"),"error",1e4):l.type&&l.type===n.mF?(0,a.C)("Cluster ".concat(r," does not exist."),"error"):l.type&&l.type===n.iW?(0,a.C)("Cluster ".concat(r," is not up."),"error"):(0,a.C)("".concat(s," job ").concat(t," failed: ").concat(l.type),"error")}catch(r){(0,a.C)("".concat(s," job ").concat(t," failed: ").concat(e.detail.error),"error")}else(0,a.C)("".concat(s," job ").concat(t," failed with no details."),"error")}catch(e){(0,a.C)("".concat(s," job ").concat(t," failed with parse error."),"error")}else(0,a.C)("".concat(s," job ").concat(t," failed with status ").concat(i.status,"."),"error")}catch(e){console.error("Fetch error:",e),(0,a.C)("Network error ".concat(s," job ").concat(t,": ").concat(e.message),"error")}}catch(e){console.error("Error in handleStop:",e),(0,a.C)("Critical error ".concat(s," job ").concat(t,": ").concat(e.message),"error")}}},1090:function(e,t,r){"use strict";r.r(t),r.d(t,{default:function(){return P}});var s=r(5893),a=r(7294),n=r(8799),l=r(9470),o=r(3626),c=r(3001),i=r(3225),d=r(3266),u=r(8969);async function m(){try{let[e,t]=await Promise.all([(0,d.zd)(),(0,u.Vp)()]),r=(null==t?void 0:t.jobs)||[],s=[];try{let e=await fetch("".concat(i.f4,"/enabled_clouds"),{method:"GET",headers:{"Content-Type":"application/json"}}),t=e.headers.get("X-Skypilot-Request-ID")||e.headers.get("X-Request-ID"),r=await fetch("".concat(i.f4,"/api/get?request_id=").concat(t)),a=await r.json();s=a.return_value?JSON.parse(a.return_value):[],console.log("Enabled clouds:",s)}catch(e){console.error("Error fetching enabled clouds:",e),s=[]}let a={};i.$m.forEach(e=>{let t=s.includes(e);a[e]={name:e,clusters:0,jobs:0,enabled:t}}),(e||[]).forEach(e=>{if(e.cloud){let t=e.cloud;a[t]&&(a[t].clusters+=1,a[t].enabled=!0)}}),r.forEach(e=>{if(e.cloud){let t=e.cloud;a[t]&&(a[t].jobs+=1,a[t].enabled=!0)}});let n=i.$m.length,l=Object.values(a).filter(e=>e.enabled).length;return{clouds:Object.values(a).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:i.$m.length,enabledClouds:0}}}async function h(){return await p()}async function f(){try{let e=await fetch("".concat(i.f4,"/realtime_kubernetes_gpu_availability"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({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 r=await fetch("".concat(i.f4,"/api/get?request_id=").concat(t)),s=await r.text();if(500===r.status){try{let e=JSON.parse(s);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:",s)}return[]}let a=JSON.parse(s);return a.return_value?JSON.parse(a.return_value):[]}catch(e){return console.error("[infra.jsx] Outer error in getKubernetesContextGPUs:",e),[]}}async function x(){try{let e=await fetch("".concat(i.f4,"/all_contexts"),{method:"GET",headers:{"Content-Type":"application/json"}});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 r=await fetch("".concat(i.f4,"/api/get?request_id=").concat(t)),s=await r.json();return s.return_value?JSON.parse(s.return_value):[]}catch(e){return console.error("[infra.jsx] Error in getAllContexts:",e),[]}}async function g(e){try{let t=await fetch("".concat(i.f4,"/kubernetes_node_info"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({context:e})}),r=t.headers.get("X-Skypilot-Request-ID")||t.headers.get("x-request-id"),s=await fetch("".concat(i.f4,"/api/get?request_id=").concat(r));if(500===s.status){try{let e=await s.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 a=await s.json();return(a.return_value?JSON.parse(a.return_value):{}).node_info_dict||{}}catch(t){return console.error("[infra.jsx] Error in getKubernetesPerNodeGPUs for context",e,":",t),{}}}async function p(){try{let a=await x();if(!a||0===a.length)return console.log("No contexts found from /all_contexts endpoint."),{allContextNames:[],allGPUs:[],perContextGPUs:[],perNodeGPUs:[]};let n=await f(),l=new Map;n&&n.forEach(e=>{l.set(e[0],e[1])});let o={},c={},i={};for(let n of a){c[n]||(c[n]=[]);let a=l.get(n);if(a&&a.length>0)for(let e of a){let t=e[0],r=e[1].join(", "),s=e[2],a=e[3];t in o?(o[t].gpu_total+=s,o[t].gpu_free+=a):o[t]={gpu_total:s,gpu_free:a,gpu_name:t},c[n].push({gpu_name:t,gpu_requestable_qty_per_node:r,gpu_total:s,gpu_free:a,context:n})}let d=await g(n);if(d&&Object.keys(d).length>0)for(let a in d){var e,t,r,s;let l=d[a],u=l.accelerator_type||"-",m=null!==(r=null===(e=l.total)||void 0===e?void 0:e.accelerator_count)&&void 0!==r?r:0,h=null!==(s=null===(t=l.free)||void 0===t?void 0:t.accelerators_available)&&void 0!==s?s:0;i["".concat(n,"/").concat(a)]={node_name:l.name,gpu_name:u,gpu_total:m,gpu_free:h,context:n},"-"===u||c[n].some(e=>e.gpu_name===u)||(u in o||(o[u]={gpu_total:0,gpu_free:0,gpu_name:u}),c[n].find(e=>e.gpu_name===u)||c[n].push({gpu_name:u,gpu_requestable_qty_per_node:"-",gpu_total:0,gpu_free:0,context:n}))}0===c[n].length&&d&&Object.keys(d).length}return{allContextNames:a.sort(),allGPUs:Object.values(o).sort((e,t)=>e.gpu_name.localeCompare(t.gpu_name)),perContextGPUs:Object.values(c).flat().sort((e,t)=>e.context.localeCompare(t.context)||e.gpu_name.localeCompare(t.gpu_name)),perNodeGPUs:Object.values(i).sort((e,t)=>e.context.localeCompare(t.context)||e.node_name.localeCompare(t.node_name)||e.gpu_name.localeCompare(t.gpu_name))}}catch(e){return console.error("[infra.jsx] Outer error in getKubernetesGPUs:",e),{allContextNames:[],allGPUs:[],perContextGPUs:[],perNodeGPUs:[]}}}var b=r(1163),j=r(1664),y=r.n(j),_=r(7469);function N(e){let{title:t,isLoading:r,isDataLoaded:a,contexts:l,gpus:o,groupedPerContextGPUs:c,groupedPerNodeGPUs:i,handleContextClick:d,isSSH:u=!1}=e;return r&&!a?(0,s.jsx)("div",{className:"rounded-lg border bg-card text-card-foreground shadow-sm mb-6",children:(0,s.jsxs)("div",{className:"p-5",children:[(0,s.jsx)("h3",{className:"text-lg font-semibold mb-4",children:t}),(0,s.jsxs)("div",{className:"flex items-center justify-center py-6",children:[(0,s.jsx)(n.Z,{size:24,className:"mr-3"}),(0,s.jsxs)("span",{className:"text-gray-500",children:["Loading ",t,"..."]})]})]})}):a&&0===l.length?(0,s.jsx)("div",{className:"rounded-lg border bg-card text-card-foreground shadow-sm mb-6",children:(0,s.jsxs)("div",{className:"p-5",children:[(0,s.jsx)("h3",{className:"text-lg font-semibold mb-4",children:t}),(0,s.jsxs)("p",{className:"text-sm text-gray-500",children:["No ",t," found or ",t," is not configured."]})]})}):a&&l.length>0?(0,s.jsx)("div",{className:"rounded-lg border bg-card text-card-foreground shadow-sm mb-6",children:(0,s.jsxs)("div",{className:"p-5",children:[(0,s.jsxs)("div",{className:"flex items-center mb-4",children:[(0,s.jsx)("h3",{className:"text-lg font-semibold",children:t}),(0,s.jsxs)("span",{className:"ml-2 px-2 py-0.5 bg-blue-100 text-blue-800 rounded-full text-xs font-medium",children:[l.length," ",1===l.length?u?"pool":"context":u?"pools":"contexts"]})]}),(0,s.jsxs)("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-6",children:[(0,s.jsx)("div",{children:(0,s.jsx)("div",{className:"overflow-x-auto rounded-md border border-gray-200 shadow-sm bg-white",children:(0,s.jsxs)("table",{className:"min-w-full text-sm",children:[(0,s.jsx)("thead",{className:"bg-gray-50",children:(0,s.jsxs)("tr",{children:[(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600 w-1/3",children:u?"Node Pool":"Context"}),(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600 w-1/6",children:"Nodes"}),(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600 w-1/3",children:"GPU Types"}),(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600 w-1/6",children:"#GPUs"})]})}),(0,s.jsx)("tbody",{className:"bg-white divide-y divide-gray-200 ".concat(l.length>5?"max-h-[250px] overflow-y-auto block":""),children:l.map(e=>{let t=c[e]||[],r=i[e]||[],a=t.reduce((e,t)=>e+(t.gpu_total||0),0),n=Object.keys(t.reduce((e,t)=>(e[t.gpu_name]=(e[t.gpu_name]||0)+(t.gpu_total||0),e),{})).join(", "),l=u?e.replace(/^ssh-/,""):e;return(0,s.jsxs)("tr",{className:"hover:bg-gray-50",children:[(0,s.jsx)("td",{className:"p-3",children:(0,s.jsx)(_.Md,{content:l,className:"text-sm text-muted-foreground",children:(0,s.jsx)("span",{className:"text-blue-600 hover:underline cursor-pointer",onClick:()=>d(e),children:l.length>30?"".concat(l.substring(0,Math.floor(13.5)),"...").concat(l.substring(l.length-Math.ceil(13.5))):l})})}),(0,s.jsx)("td",{className:"p-3",children:r.length}),(0,s.jsx)("td",{className:"p-3",children:n||"-"}),(0,s.jsx)("td",{className:"p-3",children:a})]},e)})})]})})}),o.length>0&&(0,s.jsx)("div",{children:(0,s.jsx)("div",{className:"overflow-x-auto rounded-md border border-gray-200 shadow-sm bg-white",children:(0,s.jsxs)("table",{className:"min-w-full text-sm",children:[(0,s.jsx)("thead",{className:"bg-gray-50",children:(0,s.jsxs)("tr",{children:[(0,s.jsxs)("th",{className:"p-3 text-left font-medium text-gray-600 w-1/4 whitespace-nowrap",children:["GPU",(0,s.jsxs)("span",{className:"ml-2 px-2 py-0.5 bg-green-100 text-green-800 rounded-full text-xs font-medium whitespace-nowrap",children:[o.reduce((e,t)=>e+t.gpu_free,0)," ","of"," ",o.reduce((e,t)=>e+t.gpu_total,0)," ","free"]})]}),(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600 w-1/4",children:"Requestable"}),(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600 w-1/2",children:(0,s.jsx)("div",{className:"flex items-center",children:(0,s.jsx)("span",{children:"Utilization"})})})]})}),(0,s.jsx)("tbody",{className:"bg-white divide-y divide-gray-200 ".concat(o.length>5?"max-h-[250px] overflow-y-auto block":""),children:o.map(e=>{let t=e.gpu_total-e.gpu_free,r=e.gpu_total>0?e.gpu_free/e.gpu_total*100:0,a=e.gpu_total>0?t/e.gpu_total*100:0,n=c?Object.values(c).flat().filter(t=>t.gpu_name===e.gpu_name&&(u?t.context.startsWith("ssh-"):!t.context.startsWith("ssh-"))).map(e=>e.gpu_requestable_qty_per_node).filter((e,t,r)=>r.indexOf(e)===t).join(", "):"-";return(0,s.jsxs)("tr",{children:[(0,s.jsx)("td",{className:"p-3 font-medium w-24 whitespace-nowrap",children:e.gpu_name}),(0,s.jsxs)("td",{className:"p-3 text-xs text-gray-600",children:[n||"-"," / node"]}),(0,s.jsx)("td",{className:"p-3 w-2/3",children:(0,s.jsx)("div",{className:"flex items-center gap-3",children:(0,s.jsxs)("div",{className:"flex-1 bg-gray-100 rounded-md h-5 flex overflow-hidden shadow-sm min-w-[100px] w-full",children:[a>0&&(0,s.jsx)("div",{style:{width:"".concat(a,"%")},className:"bg-yellow-500 h-full flex items-center justify-center text-white text-xs font-medium",children:a>15&&"".concat(t," used")}),r>0&&(0,s.jsx)("div",{style:{width:"".concat(r,"%")},className:"bg-green-700 h-full flex items-center justify-center text-white text-xs font-medium",children:r>15&&"".concat(e.gpu_free," free")})]})})})]},e.gpu_name)})})]})})})]})]})}):null}function w(e){let{contextName:t,gpusInContext:r,nodesInContext:a}=e;return t.startsWith("ssh-"),(0,s.jsx)("div",{className:"mb-4",children:(0,s.jsx)("div",{className:"rounded-lg border bg-card text-card-foreground shadow-sm h-full",children:(0,s.jsxs)("div",{className:"p-5",children:[(0,s.jsx)("h4",{className:"text-lg font-semibold mb-4",children:"Available GPUs"}),(0,s.jsx)("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-6",children:r.map(e=>{let t=e.gpu_total-e.gpu_free,r=e.gpu_total>0?e.gpu_free/e.gpu_total*100:0,a=e.gpu_total>0?t/e.gpu_total*100:0;return(0,s.jsxs)("div",{className:"p-3 bg-gray-50 rounded-md border border-gray-200 shadow-sm",children:[(0,s.jsxs)("div",{className:"flex justify-between items-center mb-1.5 flex-wrap",children:[(0,s.jsxs)("div",{className:"font-medium text-gray-800 text-sm",children:[e.gpu_name,(0,s.jsxs)("span",{className:"text-xs text-gray-500 ml-2",children:["(Requestable: ",e.gpu_requestable_qty_per_node," / node)"]})]}),(0,s.jsxs)("span",{className:"text-xs font-medium",children:[e.gpu_free," free / ",e.gpu_total," total"]})]}),(0,s.jsxs)("div",{className:"w-full bg-gray-100 rounded-md h-4 flex overflow-hidden shadow-sm",children:[a>0&&(0,s.jsx)("div",{style:{width:"".concat(a,"%")},className:"bg-yellow-500 h-full flex items-center justify-center text-white text-xs",children:a>15&&"".concat(t," used")}),r>0&&(0,s.jsx)("div",{style:{width:"".concat(r,"%")},className:"bg-green-700 h-full flex items-center justify-center text-white text-xs",children:r>15&&"".concat(e.gpu_free," free")})]})]},e.gpu_name)})}),a.length>0&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("h4",{className:"text-lg font-semibold mb-4",children:"Nodes"}),(0,s.jsx)("div",{className:"overflow-x-auto rounded-md border border-gray-200 shadow-sm",children:(0,s.jsxs)("table",{className:"min-w-full text-sm",children:[(0,s.jsx)("thead",{className:"bg-gray-100",children:(0,s.jsxs)("tr",{children:[(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600",children:"Node"}),(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600",children:"GPU"}),(0,s.jsx)("th",{className:"p-3 text-right font-medium text-gray-600",children:"Availability"})]})}),(0,s.jsx)("tbody",{className:"bg-white divide-y divide-gray-200",children:a.map((e,t)=>(0,s.jsxs)("tr",{className:"hover:bg-gray-50",children:[(0,s.jsx)("td",{className:"p-3 whitespace-nowrap text-gray-700",children:e.node_name}),(0,s.jsx)("td",{className:"p-3 whitespace-nowrap text-gray-700",children:e.gpu_name}),(0,s.jsx)("td",{className:"p-3 whitespace-nowrap text-right text-gray-700",children:"".concat(e.gpu_free," of ").concat(e.gpu_total," free")})]},"".concat(e.node_name,"-").concat(t)))})]})})]})]})})})}function v(){let[e,t]=(0,a.useState)(!0),[r,i]=(0,a.useState)(!0),[d,u]=(0,a.useState)(!0),f=a.useRef(null),x=(0,c.X)(),[g,p]=(0,a.useState)(!1),[j,_]=(0,a.useState)(!1),v=(0,b.useRouter)(),[C,S]=(0,a.useState)([]),[P,E]=(0,a.useState)([]),[O,k]=(0,a.useState)([]),[q,U]=(0,a.useState)([]),[G,J]=(0,a.useState)([]),[D,T]=(0,a.useState)(0),[I,R]=(0,a.useState)(0),[L,K]=(0,a.useState)(null),X=a.useCallback(async()=>{t(!0),i(!0);try{let{allContextNames:e,allGPUs:t,perContextGPUs:r,perNodeGPUs:s}=await h();S(e||[]),E(t||[]),k(r||[]),U(s||[]),p(!0)}catch(e){console.error("Error fetching Kubernetes data:",e),S([]),E([]),k([]),U([])}finally{t(!1)}try{let e=await m();J((null==e?void 0:e.clouds)||[]),T((null==e?void 0:e.totalClouds)||0),R((null==e?void 0:e.enabledClouds)||0),_(!0)}catch(e){console.error("Error fetching cloud infrastructure data:",e),J([]),T(0),R(0)}finally{i(!1),d&&u(!1)}},[d]);a.useEffect(()=>{f&&(f.current=X)},[f,X]),(0,a.useEffect)(()=>{let e=!0;X();let t=setInterval(()=>{e&&X()},6e4);return()=>{e=!1,clearInterval(t)}},[X]),P.length,P.reduce((e,t)=>e+t.gpu_total,0),P.reduce((e,t)=>e+t.gpu_free,0);let z=a.useMemo(()=>O?O.reduce((e,t)=>{let{context:r}=t;return e[r]||(e[r]=[]),e[r].push(t),e},{}):{},[O]),M=a.useMemo(()=>C.filter(e=>e.startsWith("ssh-")),[C]),A=a.useMemo(()=>C.filter(e=>!e.startsWith("ssh-")),[C]),W=a.useMemo(()=>{if(!O)return[];let e=new Set;return O.forEach(t=>{t.context.startsWith("ssh-")&&e.add(t.gpu_name)}),P.filter(t=>e.has(t.gpu_name))},[P,O]),F=a.useMemo(()=>{if(!O)return[];let e=new Set;return O.forEach(t=>{t.context.startsWith("ssh-")||e.add(t.gpu_name)}),P.filter(t=>e.has(t.gpu_name))},[P,O]),Z=a.useMemo(()=>q?q.reduce((e,t)=>{let{context:r}=t;return e[r]||(e[r]=[]),e[r].push(t),e},{}):{},[q]);(0,a.useEffect)(()=>{v.query.context&&K(decodeURIComponent(Array.isArray(v.query.context)?v.query.context[0]:v.query.context))},[v.isReady,v.query]);let H=e=>{K(e),v.replace({pathname:"/infra",query:e?{context:e}:void 0},e?"/infra/".concat(encodeURIComponent(e)):"/infra",{shallow:!0})},$=()=>{K(null),v.replace({pathname:"/infra"},"/infra",{shallow:!0})};(0,a.useEffect)(()=>{let e=e=>{let t=e.match(/\/infra\/([^\/]+)$/);t?K(decodeURIComponent(t[1])):"/infra"===e&&K(null)};return v.events.on("routeChangeComplete",e),()=>{v.events.off("routeChangeComplete",e)}},[v.events]);let V=e||r;return(0,s.jsxs)(l.A,{highlighted:"infra",children:[(0,s.jsxs)("div",{className:"flex items-center justify-between mb-4 h-5",children:[(0,s.jsxs)("div",{className:"text-base flex items-center",children:[(0,s.jsx)(y(),{href:"/infra",className:"text-sky-blue hover:underline ".concat(L?"":"cursor-default"),onClick:e=>{L&&(e.preventDefault(),$())},children:"Infrastructure"}),L&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("span",{className:"mx-2 text-gray-500",children:"›"}),L.startsWith("ssh-")?(0,s.jsx)("span",{className:"text-sky-blue hover:underline cursor-pointer",onClick:e=>{e.preventDefault(),$()},children:"SSH Node Pool"}):(0,s.jsx)("span",{className:"text-sky-blue hover:underline cursor-pointer",onClick:e=>{e.preventDefault(),$()},children:"Kubernetes"}),(0,s.jsx)("span",{className:"mx-2 text-gray-500",children:"›"}),(0,s.jsx)("span",{className:"text-sky-blue",children:L.startsWith("ssh-")?L.replace(/^ssh-/,""):L})]})]}),(0,s.jsxs)("div",{className:"flex items-center",children:[V&&(0,s.jsxs)("div",{className:"flex items-center mr-2",children:[(0,s.jsx)(n.Z,{size:15,className:"mt-0"}),(0,s.jsx)("span",{className:"ml-2 text-gray-500",children:"Loading..."})]}),(0,s.jsxs)("button",{onClick:()=>{f.current&&(u(!1),f.current())},disabled:V,className:"text-sky-blue hover:text-sky-blue-bright flex items-center",children:[(0,s.jsx)(o.Z,{className:"h-4 w-4 mr-1.5"}),!x&&"Refresh"]})]})]}),L?e&&!g?(0,s.jsxs)("div",{className:"flex flex-col items-center justify-center h-64",children:[(0,s.jsx)(n.Z,{size:32,className:"mb-4"}),(0,s.jsx)("span",{className:"text-gray-500 text-lg",children:"Loading Context..."})]}):(t=>{let r=z[t]||[],a=Z[t]||[];return e&&!g?(0,s.jsxs)("div",{className:"flex flex-col items-center justify-center h-64",children:[(0,s.jsx)(n.Z,{size:32,className:"mb-4"}),(0,s.jsx)("span",{className:"text-gray-500 text-lg",children:"Loading Context..."})]}):(0,s.jsx)(w,{contextName:t,gpusInContext:r,nodesInContext:a})})(L):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(N,{title:"SSH Node Pool",isLoading:e,isDataLoaded:g,contexts:M,gpus:W,groupedPerContextGPUs:z,groupedPerNodeGPUs:Z,handleContextClick:H,isSSH:!0}),(0,s.jsx)(N,{title:"Kubernetes",isLoading:e,isDataLoaded:g,contexts:A,gpus:F,groupedPerContextGPUs:z,groupedPerNodeGPUs:Z,handleContextClick:H,isSSH:!1}),r&&!j?(0,s.jsx)("div",{className:"rounded-lg border bg-card text-card-foreground shadow-sm mb-6",children:(0,s.jsxs)("div",{className:"p-5",children:[(0,s.jsx)("h3",{className:"text-lg font-semibold mb-4",children:"Cloud"}),(0,s.jsxs)("div",{className:"flex items-center justify-center py-6",children:[(0,s.jsx)(n.Z,{size:24,className:"mr-3"}),(0,s.jsx)("span",{className:"text-gray-500",children:"Loading Cloud..."})]})]})}):(0,s.jsx)("div",{className:"rounded-lg border bg-card text-card-foreground shadow-sm mb-6",children:(0,s.jsxs)("div",{className:"p-5",children:[(0,s.jsxs)("div",{className:"flex items-center mb-4",children:[(0,s.jsx)("h3",{className:"text-lg font-semibold",children:"Cloud"}),(0,s.jsxs)("span",{className:"ml-2 px-2 py-0.5 bg-blue-100 text-blue-800 rounded-full text-xs font-medium",children:[I," of ",D," enabled"]})]}),0===G.length?(0,s.jsx)("p",{className:"text-sm text-gray-500",children:"No enabled clouds available."}):(0,s.jsx)("div",{className:"overflow-x-auto rounded-md border border-gray-200 shadow-sm bg-white",children:(0,s.jsxs)("table",{className:"min-w-full text-sm",children:[(0,s.jsx)("thead",{className:"bg-gray-50",children:(0,s.jsxs)("tr",{children:[(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600 w-32",children:"Cloud"}),(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600 w-24",children:"Clusters"}),(0,s.jsx)("th",{className:"p-3 text-left font-medium text-gray-600 w-24",children:"Jobs"})]})}),(0,s.jsx)("tbody",{className:"bg-white divide-y divide-gray-200",children:G.map(e=>(0,s.jsxs)("tr",{className:"hover:bg-gray-50",children:[(0,s.jsx)("td",{className:"p-3 font-medium text-gray-700",children:e.name}),(0,s.jsx)("td",{className:"p-3",children:e.clusters>0?(0,s.jsx)("span",{className:"px-2 py-0.5 bg-blue-100 text-blue-800 rounded text-xs font-medium",children:e.clusters}):(0,s.jsx)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-500 rounded text-xs font-medium",children:"0"})}),(0,s.jsx)("td",{className:"p-3",children:e.jobs>0?(0,s.jsx)("span",{className:"px-2 py-0.5 bg-green-100 text-green-800 rounded text-xs font-medium",children:e.jobs}):(0,s.jsx)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-500 rounded text-xs font-medium",children:"0"})})]},e.name))})]})})]})})]})]})}var C=r(9008),S=r.n(C);function P(){return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(S(),{children:(0,s.jsx)("title",{children:"Infra | SkyPilot Dashboard"})}),(0,s.jsx)(v,{})]})}}},function(e){e.O(0,[582,480,888,774,179],function(){return e(e.s=6206)}),_N_E=e.O()}]);
@@ -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/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/582-683f4f27b81996dc.js" defer=""></script><script src="/dashboard/_next/static/chunks/480-f28cd152a98997de.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters/%5Bcluster%5D/%5Bjob%5D-33bc2bec322249b1.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div>Loading...</div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters/[cluster]/[job]","query":{},"buildId":"CzOVV6JpRQBRt5GhZuhyK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/582-683f4f27b81996dc.js" defer=""></script><script src="/dashboard/_next/static/chunks/480-f28cd152a98997de.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters/%5Bcluster%5D/%5Bjob%5D-33bc2bec322249b1.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div>Loading...</div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters/[cluster]/[job]","query":{},"buildId":"ECKwDNS9v9y3_IKFZ2lpp","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/582-683f4f27b81996dc.js" defer=""></script><script src="/dashboard/_next/static/chunks/312-c3c8845990db8ffc.js" defer=""></script><script src="/dashboard/_next/static/chunks/480-f28cd152a98997de.js" defer=""></script><script src="/dashboard/_next/static/chunks/393-e1eaa440481337ec.js" defer=""></script><script src="/dashboard/_next/static/chunks/236-1a3a9440417720eb.js" defer=""></script><script src="/dashboard/_next/static/chunks/37-d584022b0da4ac3b.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters/%5Bcluster%5D-e2fc2dd1955e6c36.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div>Loading...</div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters/[cluster]","query":{},"buildId":"CzOVV6JpRQBRt5GhZuhyK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/582-683f4f27b81996dc.js" defer=""></script><script src="/dashboard/_next/static/chunks/312-c3c8845990db8ffc.js" defer=""></script><script src="/dashboard/_next/static/chunks/480-f28cd152a98997de.js" defer=""></script><script src="/dashboard/_next/static/chunks/393-e1eaa440481337ec.js" defer=""></script><script src="/dashboard/_next/static/chunks/236-1a3a9440417720eb.js" defer=""></script><script src="/dashboard/_next/static/chunks/37-d584022b0da4ac3b.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters/%5Bcluster%5D-e2fc2dd1955e6c36.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div>Loading...</div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters/[cluster]","query":{},"buildId":"ECKwDNS9v9y3_IKFZ2lpp","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>Clusters | SkyPilot Dashboard</title><link rel="preload" href="/dashboard/skypilot.svg" as="image" fetchpriority="high"/><meta name="next-head-count" content="4"/><link rel="preload" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/582-683f4f27b81996dc.js" defer=""></script><script src="/dashboard/_next/static/chunks/312-c3c8845990db8ffc.js" defer=""></script><script src="/dashboard/_next/static/chunks/480-f28cd152a98997de.js" defer=""></script><script src="/dashboard/_next/static/chunks/393-e1eaa440481337ec.js" defer=""></script><script src="/dashboard/_next/static/chunks/37-d584022b0da4ac3b.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters-3a748bd76e5c2984.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div class="min-h-screen bg-gray-50"><div class="fixed top-0 left-0 right-0 z-50 shadow-sm"><div class="fixed top-0 left-0 right-0 bg-white z-30 h-14 px-4 border-b border-gray-200 shadow-sm"><div class="flex items-center h-full"><div class="flex items-center space-x-4 mr-6"><a class="flex items-center px-1 pt-1 h-full" href="/dashboard"><div class="h-20 w-20 flex items-center justify-center"><img alt="SkyPilot Logo" fetchpriority="high" width="80" height="80" decoding="async" data-nimg="1" class="w-full h-full object-contain" style="color:transparent" src="/dashboard/skypilot.svg"/></div></a></div><div class="flex items-center space-x-2 md:space-x-6 mr-6"><a class="inline-flex items-center border-b-2 border-transparent text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/clusters"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"></rect><rect width="20" height="8" x="2" y="14" rx="2" ry="2"></rect><line x1="6" x2="6.01" y1="6" y2="6"></line><line x1="6" x2="6.01" y1="18" y2="18"></line></svg><span>Clusters</span></a><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/jobs"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"></path><rect width="20" height="14" x="2" y="6" rx="2"></rect></svg><span>Jobs</span></a><div class="inline-flex items-center px-1 pt-1 text-gray-400"><svg class="w-4 h-4" viewBox="0 0 423.683 423.683" width="24" height="24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><g><path d="M54.376,287.577h310.459c26.48,0,48.02-13.979,48.02-40.453c0-17.916-10.001-34.07-25.559-42.292 c-19.021-72.951-86.061-125.196-162.002-125.223v-3.431h-3.854V61.814h3.854v-9.569h-31.38v9.569h3.854v14.363h-3.854v3.431 c-75.941,0.026-142.97,52.272-161.988,125.217c-15.56,8.216-25.573,24.376-25.573,42.291 C6.36,273.597,27.896,287.577,54.376,287.577z M47.676,227.145l7.214-2.424l1.617-7.447 c13.884-64.232,71.707-110.862,137.467-110.862h31.274c65.763,0,123.582,46.63,137.473,110.862l1.607,7.447l7.223,2.424 c8.678,2.92,14.506,10.946,14.506,19.979c0,11.703-9.517,13.647-21.221,13.647H54.376c-11.7,0-21.22-1.944-21.22-13.647 C33.162,238.091,38.984,230.065,47.676,227.145z M423.683,334.602v36.836H0v-36.836h25.348v-18.418h372.99v18.418H423.683z"></path></g></g></svg><span class="ml-2">Services</span><span class="text-xs ml-2 px-1.5 py-0.5 bg-gray-100 text-gray-500 rounded">Soon</span></div><div class="border-l border-gray-200 h-6 mx-1"></div><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/infra"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2" ry="2"></rect><rect x="9" y="9" width="6" height="6"></rect><line x1="9" y1="1" x2="9" y2="4"></line><line x1="15" y1="1" x2="15" y2="4"></line><line x1="9" y1="20" x2="9" y2="23"></line><line x1="15" y1="20" x2="15" y2="23"></line><line x1="20" y1="9" x2="23" y2="9"></line><line x1="20" y1="14" x2="23" y2="14"></line><line x1="1" y1="9" x2="4" y2="9"></line><line x1="1" y1="14" x2="4" y2="14"></line></svg><span>Infra</span></a></div><div class="flex items-center space-x-1 ml-auto"><a href="https://skypilot.readthedocs.io/en/latest/" target="_blank" rel="noopener noreferrer" class="inline-flex items-center px-2 py-1 text-gray-600 hover:text-blue-600 transition-colors duration-150 cursor-pointer" title="Docs"><span class="mr-1">Docs</span><svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg></a><div class="border-l border-gray-200 h-6 mx-1"></div><a href="https://github.com/skypilot-org/skypilot" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="GitHub"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"></path></svg></a><a href="https://slack.skypilot.co/" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="Slack"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path transform="scale(0.85) translate(1.8, 1.8)" d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"></path></svg></a><a href="https://github.com/skypilot-org/skypilot/issues/new" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="Leave Feedback"><svg class="w-5 h-5" stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g><path fill="none" d="M0 0h24v24H0z"></path><path d="M6.455 19L2 22.5V4a1 1 0 0 1 1-1h18a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H6.455zM4 18.385L5.763 17H20V5H4v13.385zM11 13h2v2h-2v-2zm0-6h2v5h-2V7z"></path></g></svg></a></div></div></div></div><div class="transition-all duration-200 ease-in-out min-h-screen" style="padding-top:56px"><main class="p-6"><div class="flex items-center justify-between mb-4 h-5"><div class="text-base"><a class="text-sky-blue hover:underline leading-none" href="/dashboard/clusters">Sky Clusters</a></div><div class="flex items-center"><button class="justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent h-10 px-4 py-2 text-sky-blue hover:text-sky-blue-bright flex items-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-rotate-cw h-4 w-4 mr-1.5"><path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"></path><path d="M21 3v5h-5"></path></svg><span>Refresh</span></button></div></div><div><div class="rounded-lg border bg-card text-card-foreground shadow-sm"><div class="relative w-full overflow-auto"><table class="w-full caption-bottom text-base"><thead class="[&amp;_tr]:border-b"><tr class="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Status</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Cluster</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">User</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Infra</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Resources</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Started</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0">Actions</th></tr></thead><tbody class="[&amp;_tr:last-child]:border-0"><tr class="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"><td class="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0 text-center py-6 text-gray-500" colSpan="7">No active clusters</td></tr></tbody></table></div></div></div></main></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters","query":{},"buildId":"CzOVV6JpRQBRt5GhZuhyK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>Clusters | SkyPilot Dashboard</title><link rel="preload" href="/dashboard/skypilot.svg" as="image" fetchpriority="high"/><meta name="next-head-count" content="4"/><link rel="preload" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/582-683f4f27b81996dc.js" defer=""></script><script src="/dashboard/_next/static/chunks/312-c3c8845990db8ffc.js" defer=""></script><script src="/dashboard/_next/static/chunks/480-f28cd152a98997de.js" defer=""></script><script src="/dashboard/_next/static/chunks/393-e1eaa440481337ec.js" defer=""></script><script src="/dashboard/_next/static/chunks/37-d584022b0da4ac3b.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/clusters-3a748bd76e5c2984.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div class="min-h-screen bg-gray-50"><div class="fixed top-0 left-0 right-0 z-50 shadow-sm"><div class="fixed top-0 left-0 right-0 bg-white z-30 h-14 px-4 border-b border-gray-200 shadow-sm"><div class="flex items-center h-full"><div class="flex items-center space-x-4 mr-6"><a class="flex items-center px-1 pt-1 h-full" href="/dashboard"><div class="h-20 w-20 flex items-center justify-center"><img alt="SkyPilot Logo" fetchpriority="high" width="80" height="80" decoding="async" data-nimg="1" class="w-full h-full object-contain" style="color:transparent" src="/dashboard/skypilot.svg"/></div></a></div><div class="flex items-center space-x-2 md:space-x-6 mr-6"><a class="inline-flex items-center border-b-2 border-transparent text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/clusters"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"></rect><rect width="20" height="8" x="2" y="14" rx="2" ry="2"></rect><line x1="6" x2="6.01" y1="6" y2="6"></line><line x1="6" x2="6.01" y1="18" y2="18"></line></svg><span>Clusters</span></a><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/jobs"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"></path><rect width="20" height="14" x="2" y="6" rx="2"></rect></svg><span>Jobs</span></a><div class="inline-flex items-center px-1 pt-1 text-gray-400"><svg class="w-4 h-4" viewBox="0 0 423.683 423.683" width="24" height="24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><g><path d="M54.376,287.577h310.459c26.48,0,48.02-13.979,48.02-40.453c0-17.916-10.001-34.07-25.559-42.292 c-19.021-72.951-86.061-125.196-162.002-125.223v-3.431h-3.854V61.814h3.854v-9.569h-31.38v9.569h3.854v14.363h-3.854v3.431 c-75.941,0.026-142.97,52.272-161.988,125.217c-15.56,8.216-25.573,24.376-25.573,42.291 C6.36,273.597,27.896,287.577,54.376,287.577z M47.676,227.145l7.214-2.424l1.617-7.447 c13.884-64.232,71.707-110.862,137.467-110.862h31.274c65.763,0,123.582,46.63,137.473,110.862l1.607,7.447l7.223,2.424 c8.678,2.92,14.506,10.946,14.506,19.979c0,11.703-9.517,13.647-21.221,13.647H54.376c-11.7,0-21.22-1.944-21.22-13.647 C33.162,238.091,38.984,230.065,47.676,227.145z M423.683,334.602v36.836H0v-36.836h25.348v-18.418h372.99v18.418H423.683z"></path></g></g></svg><span class="ml-2">Services</span><span class="text-xs ml-2 px-1.5 py-0.5 bg-gray-100 text-gray-500 rounded">Soon</span></div><div class="border-l border-gray-200 h-6 mx-1"></div><a class="inline-flex items-center border-b-2 border-transparent hover:text-blue-600 px-1 pt-1 space-x-2" href="/dashboard/infra"><svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2" ry="2"></rect><rect x="9" y="9" width="6" height="6"></rect><line x1="9" y1="1" x2="9" y2="4"></line><line x1="15" y1="1" x2="15" y2="4"></line><line x1="9" y1="20" x2="9" y2="23"></line><line x1="15" y1="20" x2="15" y2="23"></line><line x1="20" y1="9" x2="23" y2="9"></line><line x1="20" y1="14" x2="23" y2="14"></line><line x1="1" y1="9" x2="4" y2="9"></line><line x1="1" y1="14" x2="4" y2="14"></line></svg><span>Infra</span></a></div><div class="flex items-center space-x-1 ml-auto"><a href="https://skypilot.readthedocs.io/en/latest/" target="_blank" rel="noopener noreferrer" class="inline-flex items-center px-2 py-1 text-gray-600 hover:text-blue-600 transition-colors duration-150 cursor-pointer" title="Docs"><span class="mr-1">Docs</span><svg class="w-3.5 h-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg></a><div class="border-l border-gray-200 h-6 mx-1"></div><a href="https://github.com/skypilot-org/skypilot" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="GitHub"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"></path></svg></a><a href="https://slack.skypilot.co/" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="Slack"><svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path transform="scale(0.85) translate(1.8, 1.8)" d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"></path></svg></a><a href="https://github.com/skypilot-org/skypilot/issues/new" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center p-2 rounded-full text-gray-600 hover:bg-gray-100 transition-colors duration-150 cursor-pointer" title="Leave Feedback"><svg class="w-5 h-5" stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g><path fill="none" d="M0 0h24v24H0z"></path><path d="M6.455 19L2 22.5V4a1 1 0 0 1 1-1h18a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H6.455zM4 18.385L5.763 17H20V5H4v13.385zM11 13h2v2h-2v-2zm0-6h2v5h-2V7z"></path></g></svg></a></div></div></div></div><div class="transition-all duration-200 ease-in-out min-h-screen" style="padding-top:56px"><main class="p-6"><div class="flex items-center justify-between mb-4 h-5"><div class="text-base"><a class="text-sky-blue hover:underline leading-none" href="/dashboard/clusters">Sky Clusters</a></div><div class="flex items-center"><button class="justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent h-10 px-4 py-2 text-sky-blue hover:text-sky-blue-bright flex items-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-rotate-cw h-4 w-4 mr-1.5"><path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"></path><path d="M21 3v5h-5"></path></svg><span>Refresh</span></button></div></div><div><div class="rounded-lg border bg-card text-card-foreground shadow-sm"><div class="relative w-full overflow-auto"><table class="w-full caption-bottom text-base"><thead class="[&amp;_tr]:border-b"><tr class="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Status</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Cluster</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">User</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Infra</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Resources</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0 sortable whitespace-nowrap">Started</th><th class="h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&amp;:has([role=checkbox])]:pr-0">Actions</th></tr></thead><tbody class="[&amp;_tr:last-child]:border-0"><tr class="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"><td class="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0 text-center py-6 text-gray-500" colSpan="7">No active clusters</td></tr></tbody></table></div></div></div></main></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/clusters","query":{},"buildId":"ECKwDNS9v9y3_IKFZ2lpp","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/index-6b0d9e5031b70c58.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/CzOVV6JpRQBRt5GhZuhyK/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"CzOVV6JpRQBRt5GhZuhyK","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/7e7ce4ff31d3977b.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-830f59b8404e96b8.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-8cfab319f9fb3ae8.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/index-6b0d9e5031b70c58.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/ECKwDNS9v9y3_IKFZ2lpp/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"ECKwDNS9v9y3_IKFZ2lpp","assetPrefix":"/dashboard","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>