skypilot-nightly 1.0.0.dev20250922__py3-none-any.whl → 1.0.0.dev20250925__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.
Potentially problematic release.
This version of skypilot-nightly might be problematic. Click here for more details.
- sky/__init__.py +2 -2
- sky/backends/backend.py +10 -0
- sky/backends/backend_utils.py +194 -69
- sky/backends/cloud_vm_ray_backend.py +37 -13
- sky/backends/local_docker_backend.py +9 -0
- sky/client/cli/command.py +104 -53
- sky/client/sdk.py +13 -5
- sky/client/sdk_async.py +4 -2
- sky/clouds/kubernetes.py +2 -1
- sky/clouds/runpod.py +20 -7
- sky/core.py +7 -53
- sky/dashboard/out/404.html +1 -1
- sky/dashboard/out/_next/static/{KP6HCNMqb_bnJB17oplgW → bn-NHt5qTzeTN2PefXuDA}/_buildManifest.js +1 -1
- sky/dashboard/out/_next/static/chunks/1121-b911fc0a0b4742f0.js +1 -0
- sky/dashboard/out/_next/static/chunks/6856-2b3600ff2854d066.js +1 -0
- sky/dashboard/out/_next/static/chunks/8969-d8bc3a2b9cf839a9.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-2cb9b15e09cda628.js +16 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/{[cluster]-9525660179df3605.js → [cluster]-e052384df65ef200.js} +1 -1
- sky/dashboard/out/_next/static/chunks/{webpack-26167a9e6d91fa51.js → webpack-16ba1d7187d2e3b1.js} +1 -1
- sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
- sky/dashboard/out/clusters/[cluster].html +1 -1
- sky/dashboard/out/clusters.html +1 -1
- sky/dashboard/out/config.html +1 -1
- sky/dashboard/out/index.html +1 -1
- sky/dashboard/out/infra/[context].html +1 -1
- sky/dashboard/out/infra.html +1 -1
- sky/dashboard/out/jobs/[job].html +1 -1
- sky/dashboard/out/jobs/pools/[pool].html +1 -1
- sky/dashboard/out/jobs.html +1 -1
- sky/dashboard/out/users.html +1 -1
- sky/dashboard/out/volumes.html +1 -1
- sky/dashboard/out/workspace/new.html +1 -1
- sky/dashboard/out/workspaces/[name].html +1 -1
- sky/dashboard/out/workspaces.html +1 -1
- sky/data/mounting_utils.py +19 -10
- sky/execution.py +4 -2
- sky/global_user_state.py +217 -36
- sky/jobs/client/sdk.py +10 -1
- sky/jobs/controller.py +7 -7
- sky/jobs/server/core.py +3 -3
- sky/jobs/server/server.py +15 -11
- sky/jobs/utils.py +1 -1
- sky/logs/agent.py +30 -3
- sky/logs/aws.py +9 -19
- sky/provision/__init__.py +2 -1
- sky/provision/aws/instance.py +2 -1
- sky/provision/azure/instance.py +2 -1
- sky/provision/cudo/instance.py +2 -2
- sky/provision/do/instance.py +2 -2
- sky/provision/docker_utils.py +41 -19
- sky/provision/fluidstack/instance.py +2 -2
- sky/provision/gcp/instance.py +2 -1
- sky/provision/hyperbolic/instance.py +2 -1
- sky/provision/instance_setup.py +1 -1
- sky/provision/kubernetes/instance.py +134 -8
- sky/provision/lambda_cloud/instance.py +2 -1
- sky/provision/nebius/instance.py +2 -1
- sky/provision/oci/instance.py +2 -1
- sky/provision/paperspace/instance.py +2 -2
- sky/provision/primeintellect/instance.py +2 -2
- sky/provision/provisioner.py +1 -0
- sky/provision/runpod/instance.py +2 -2
- sky/provision/scp/instance.py +2 -2
- sky/provision/seeweb/instance.py +2 -1
- sky/provision/vast/instance.py +2 -1
- sky/provision/vsphere/instance.py +6 -5
- sky/schemas/api/responses.py +2 -1
- sky/serve/autoscalers.py +2 -0
- sky/serve/client/impl.py +45 -19
- sky/serve/replica_managers.py +12 -5
- sky/serve/serve_utils.py +5 -7
- sky/serve/server/core.py +9 -6
- sky/serve/server/impl.py +78 -25
- sky/serve/server/server.py +4 -5
- sky/serve/service_spec.py +33 -0
- sky/server/constants.py +1 -1
- sky/server/daemons.py +2 -3
- sky/server/requests/executor.py +56 -6
- sky/server/requests/payloads.py +31 -8
- sky/server/requests/preconditions.py +2 -3
- sky/server/rest.py +2 -0
- sky/server/server.py +28 -19
- sky/server/stream_utils.py +34 -12
- sky/setup_files/dependencies.py +4 -1
- sky/setup_files/setup.py +44 -44
- sky/templates/kubernetes-ray.yml.j2 +16 -15
- sky/usage/usage_lib.py +3 -0
- sky/utils/cli_utils/status_utils.py +4 -5
- sky/utils/context.py +104 -29
- sky/utils/controller_utils.py +7 -6
- sky/utils/kubernetes/create_cluster.sh +13 -28
- sky/utils/kubernetes/delete_cluster.sh +10 -7
- sky/utils/kubernetes/generate_kind_config.py +6 -66
- sky/utils/kubernetes/kubernetes_deploy_utils.py +170 -37
- sky/utils/kubernetes_enums.py +5 -0
- sky/utils/ux_utils.py +35 -1
- sky/utils/yaml_utils.py +9 -0
- sky/volumes/client/sdk.py +44 -8
- sky/volumes/server/server.py +33 -7
- sky/volumes/volume.py +22 -14
- {skypilot_nightly-1.0.0.dev20250922.dist-info → skypilot_nightly-1.0.0.dev20250925.dist-info}/METADATA +40 -35
- {skypilot_nightly-1.0.0.dev20250922.dist-info → skypilot_nightly-1.0.0.dev20250925.dist-info}/RECORD +107 -107
- sky/dashboard/out/_next/static/chunks/1121-4ff1ec0dbc5792ab.js +0 -1
- sky/dashboard/out/_next/static/chunks/6856-9a2538f38c004652.js +0 -1
- sky/dashboard/out/_next/static/chunks/8969-a39efbadcd9fde80.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-1e9248ddbddcd122.js +0 -16
- /sky/dashboard/out/_next/static/{KP6HCNMqb_bnJB17oplgW → bn-NHt5qTzeTN2PefXuDA}/_ssgManifest.js +0 -0
- {skypilot_nightly-1.0.0.dev20250922.dist-info → skypilot_nightly-1.0.0.dev20250925.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20250922.dist-info → skypilot_nightly-1.0.0.dev20250925.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250922.dist-info → skypilot_nightly-1.0.0.dev20250925.dist-info}/licenses/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250922.dist-info → skypilot_nightly-1.0.0.dev20250925.dist-info}/top_level.txt +0 -0
sky/client/cli/command.py
CHANGED
|
@@ -127,6 +127,7 @@ def _get_cluster_records_and_set_ssh_config(
|
|
|
127
127
|
clusters: Optional[List[str]],
|
|
128
128
|
refresh: common.StatusRefreshMode = common.StatusRefreshMode.NONE,
|
|
129
129
|
all_users: bool = False,
|
|
130
|
+
verbose: bool = False,
|
|
130
131
|
) -> List[responses.StatusResponse]:
|
|
131
132
|
"""Returns a list of clusters that match the glob pattern.
|
|
132
133
|
|
|
@@ -144,7 +145,8 @@ def _get_cluster_records_and_set_ssh_config(
|
|
|
144
145
|
request_id = sdk.status(clusters,
|
|
145
146
|
refresh=refresh,
|
|
146
147
|
all_users=all_users,
|
|
147
|
-
_include_credentials=True
|
|
148
|
+
_include_credentials=True,
|
|
149
|
+
_summary_response=not verbose)
|
|
148
150
|
cluster_records = sdk.stream_and_get(request_id)
|
|
149
151
|
# Update the SSH config for all clusters
|
|
150
152
|
for record in cluster_records:
|
|
@@ -1858,7 +1860,7 @@ def status(verbose: bool, refresh: bool, ip: bool, endpoints: bool,
|
|
|
1858
1860
|
|
|
1859
1861
|
# Phase 3: Get cluster records and handle special cases
|
|
1860
1862
|
cluster_records = _get_cluster_records_and_set_ssh_config(
|
|
1861
|
-
query_clusters, refresh_mode, all_users)
|
|
1863
|
+
query_clusters, refresh_mode, all_users, verbose)
|
|
1862
1864
|
|
|
1863
1865
|
# TOOD(zhwu): setup the ssh config for status
|
|
1864
1866
|
if ip or show_endpoints:
|
|
@@ -4184,6 +4186,13 @@ def volumes_apply(
|
|
|
4184
4186
|
|
|
4185
4187
|
logger.debug(f'Volume config: {volume.to_yaml_config()}')
|
|
4186
4188
|
|
|
4189
|
+
# TODO(kevin): remove the try block in v0.13.0
|
|
4190
|
+
try:
|
|
4191
|
+
volumes_sdk.validate(volume)
|
|
4192
|
+
except exceptions.APINotSupportedError:
|
|
4193
|
+
# Do best-effort client-side validation.
|
|
4194
|
+
volume.validate(skip_cloud_compatibility=True)
|
|
4195
|
+
|
|
4187
4196
|
if not yes:
|
|
4188
4197
|
click.confirm(f'Proceed to create volume {volume.name!r}?',
|
|
4189
4198
|
default=True,
|
|
@@ -4780,7 +4789,7 @@ def pool():
|
|
|
4780
4789
|
@pool.command('apply', cls=_DocumentedCodeCommand)
|
|
4781
4790
|
@flags.config_option(expose_value=False)
|
|
4782
4791
|
@click.argument('pool_yaml',
|
|
4783
|
-
required=
|
|
4792
|
+
required=False,
|
|
4784
4793
|
type=str,
|
|
4785
4794
|
nargs=-1,
|
|
4786
4795
|
**_get_shell_complete_args(_complete_file_name))
|
|
@@ -4799,13 +4808,18 @@ def pool():
|
|
|
4799
4808
|
'with rolling update. If "blue_green", cluster pool will '
|
|
4800
4809
|
'be updated with blue-green update. This option is only '
|
|
4801
4810
|
'valid when the pool is already running.'))
|
|
4811
|
+
@click.option('--workers',
|
|
4812
|
+
default=None,
|
|
4813
|
+
type=int,
|
|
4814
|
+
required=False,
|
|
4815
|
+
help='Can be used to update the number of workers in the pool.')
|
|
4802
4816
|
@_add_click_options(flags.TASK_OPTIONS + flags.EXTRA_RESOURCES_OPTIONS +
|
|
4803
4817
|
flags.COMMON_OPTIONS)
|
|
4804
4818
|
@flags.yes_option()
|
|
4805
4819
|
@timeline.event
|
|
4806
4820
|
@usage_lib.entrypoint
|
|
4807
4821
|
def jobs_pool_apply(
|
|
4808
|
-
pool_yaml: Tuple[str, ...],
|
|
4822
|
+
pool_yaml: Optional[Tuple[str, ...]],
|
|
4809
4823
|
pool: Optional[str], # pylint: disable=redefined-outer-name
|
|
4810
4824
|
workdir: Optional[str],
|
|
4811
4825
|
infra: Optional[str],
|
|
@@ -4827,60 +4841,80 @@ def jobs_pool_apply(
|
|
|
4827
4841
|
disk_tier: Optional[str],
|
|
4828
4842
|
network_tier: Optional[str],
|
|
4829
4843
|
mode: str,
|
|
4844
|
+
workers: Optional[int],
|
|
4830
4845
|
yes: bool,
|
|
4831
4846
|
async_call: bool,
|
|
4832
4847
|
):
|
|
4833
|
-
"""
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4848
|
+
"""Either apply a config to a cluster pool for managed jobs submission
|
|
4849
|
+
or update the number of workers in the pool. One of POOL_YAML or --workers
|
|
4850
|
+
must be provided.
|
|
4851
|
+
Config:
|
|
4852
|
+
If the pool is already running, the config will be applied to the pool.
|
|
4853
|
+
Otherwise, a new pool will be created.
|
|
4854
|
+
Workers:
|
|
4855
|
+
The --workers option can be used to override the number of workers
|
|
4856
|
+
specified in the YAML file, or to update workers without a YAML file.
|
|
4857
|
+
Example:
|
|
4858
|
+
sky jobs pool apply -p my-pool --workers 5
|
|
4839
4859
|
"""
|
|
4840
4860
|
cloud, region, zone = _handle_infra_cloud_region_zone_options(
|
|
4841
4861
|
infra, cloud, region, zone)
|
|
4842
|
-
if
|
|
4843
|
-
|
|
4862
|
+
if workers is not None and pool_yaml is not None and len(pool_yaml) > 0:
|
|
4863
|
+
raise click.UsageError(
|
|
4864
|
+
'Cannot specify both --workers and POOL_YAML. Please use one of '
|
|
4865
|
+
'them.')
|
|
4844
4866
|
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4867
|
+
if pool_yaml is None or len(pool_yaml) == 0:
|
|
4868
|
+
if pool is None:
|
|
4869
|
+
raise click.UsageError(
|
|
4870
|
+
'A pool name must be provided to update the number of workers.')
|
|
4871
|
+
task = None
|
|
4872
|
+
click.secho(f'Attempting to update {pool} to have {workers} workers',
|
|
4873
|
+
fg='cyan')
|
|
4874
|
+
else:
|
|
4875
|
+
if pool is None:
|
|
4876
|
+
pool = serve_lib.generate_service_name(pool=True)
|
|
4877
|
+
|
|
4878
|
+
task = _generate_task_with_service(
|
|
4879
|
+
service_name=pool,
|
|
4880
|
+
service_yaml_args=pool_yaml,
|
|
4881
|
+
workdir=workdir,
|
|
4882
|
+
cloud=cloud,
|
|
4883
|
+
region=region,
|
|
4884
|
+
zone=zone,
|
|
4885
|
+
gpus=gpus,
|
|
4886
|
+
cpus=cpus,
|
|
4887
|
+
memory=memory,
|
|
4888
|
+
instance_type=instance_type,
|
|
4889
|
+
num_nodes=num_nodes,
|
|
4890
|
+
use_spot=use_spot,
|
|
4891
|
+
image_id=image_id,
|
|
4892
|
+
env_file=env_file,
|
|
4893
|
+
env=env,
|
|
4894
|
+
secret=secret,
|
|
4895
|
+
disk_size=disk_size,
|
|
4896
|
+
disk_tier=disk_tier,
|
|
4897
|
+
network_tier=network_tier,
|
|
4898
|
+
ports=ports,
|
|
4899
|
+
not_supported_cmd='sky jobs pool up',
|
|
4900
|
+
pool=True,
|
|
4901
|
+
)
|
|
4902
|
+
assert task.service is not None
|
|
4903
|
+
if not task.service.pool:
|
|
4904
|
+
raise click.UsageError('The YAML file needs a `pool` section.')
|
|
4905
|
+
click.secho('Pool spec:', fg='cyan')
|
|
4906
|
+
click.echo(task.service)
|
|
4907
|
+
serve_lib.validate_service_task(task, pool=True)
|
|
4875
4908
|
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4909
|
+
click.secho(
|
|
4910
|
+
'Each pool worker will use the following resources (estimated):',
|
|
4911
|
+
fg='cyan')
|
|
4912
|
+
with dag_lib.Dag() as dag:
|
|
4913
|
+
dag.add(task)
|
|
4881
4914
|
|
|
4882
4915
|
request_id = managed_jobs.pool_apply(task,
|
|
4883
4916
|
pool,
|
|
4917
|
+
workers=workers,
|
|
4884
4918
|
mode=serve_lib.UpdateMode(mode),
|
|
4885
4919
|
_need_confirmation=not yes)
|
|
4886
4920
|
_async_call_or_wait(request_id, async_call, 'sky.jobs.pool_apply')
|
|
@@ -5487,6 +5521,8 @@ def serve_update(
|
|
|
5487
5521
|
sky serve update --mode blue_green sky-service-16aa new_service.yaml
|
|
5488
5522
|
|
|
5489
5523
|
"""
|
|
5524
|
+
# TODO(lloyd-brown): Add a way to update number of replicas for serve
|
|
5525
|
+
# the way we did for pools.
|
|
5490
5526
|
cloud, region, zone = _handle_infra_cloud_region_zone_options(
|
|
5491
5527
|
infra, cloud, region, zone)
|
|
5492
5528
|
task = _generate_task_with_service(
|
|
@@ -5868,7 +5904,13 @@ def local():
|
|
|
5868
5904
|
'--context-name',
|
|
5869
5905
|
type=str,
|
|
5870
5906
|
required=False,
|
|
5871
|
-
help='Name to use for the kubeconfig context. Defaults to "default".'
|
|
5907
|
+
help='Name to use for the kubeconfig context. Defaults to "default". '
|
|
5908
|
+
'Used with the ip list.')
|
|
5909
|
+
@click.option(
|
|
5910
|
+
'--name',
|
|
5911
|
+
type=str,
|
|
5912
|
+
required=False,
|
|
5913
|
+
help='Name of the cluster. Defaults to "skypilot". Used without ip list.')
|
|
5872
5914
|
@click.option('--password',
|
|
5873
5915
|
type=str,
|
|
5874
5916
|
required=False,
|
|
@@ -5879,7 +5921,7 @@ def local():
|
|
|
5879
5921
|
@_add_click_options(flags.COMMON_OPTIONS)
|
|
5880
5922
|
@usage_lib.entrypoint
|
|
5881
5923
|
def local_up(gpus: bool, ips: str, ssh_user: str, ssh_key_path: str,
|
|
5882
|
-
cleanup: bool, context_name: Optional[str],
|
|
5924
|
+
cleanup: bool, context_name: Optional[str], name: Optional[str],
|
|
5883
5925
|
password: Optional[str], async_call: bool):
|
|
5884
5926
|
"""Creates a local or remote cluster."""
|
|
5885
5927
|
|
|
@@ -5926,17 +5968,26 @@ def local_up(gpus: bool, ips: str, ssh_user: str, ssh_key_path: str,
|
|
|
5926
5968
|
f'Failed to read SSH key file {ssh_key_path}: {str(e)}')
|
|
5927
5969
|
|
|
5928
5970
|
request_id = sdk.local_up(gpus, ip_list, ssh_user, ssh_key, cleanup,
|
|
5929
|
-
context_name, password)
|
|
5971
|
+
context_name, name, password)
|
|
5930
5972
|
_async_call_or_wait(request_id, async_call, request_name='local up')
|
|
5931
5973
|
|
|
5932
5974
|
|
|
5975
|
+
@click.option('--name',
|
|
5976
|
+
type=str,
|
|
5977
|
+
required=False,
|
|
5978
|
+
help='Name of the cluster to down. Defaults to "skypilot".')
|
|
5933
5979
|
@local.command('down', cls=_DocumentedCodeCommand)
|
|
5934
5980
|
@flags.config_option(expose_value=False)
|
|
5935
5981
|
@_add_click_options(flags.COMMON_OPTIONS)
|
|
5936
5982
|
@usage_lib.entrypoint
|
|
5937
|
-
def local_down(async_call: bool):
|
|
5938
|
-
"""Deletes a local cluster.
|
|
5939
|
-
|
|
5983
|
+
def local_down(name: Optional[str], async_call: bool):
|
|
5984
|
+
"""Deletes a local cluster.
|
|
5985
|
+
|
|
5986
|
+
This will only delete a local cluster started without the ip list.
|
|
5987
|
+
To clean up the local cluster started with a ip list, use `sky local up`
|
|
5988
|
+
with the cleanup flag.
|
|
5989
|
+
"""
|
|
5990
|
+
request_id = sdk.local_down(name)
|
|
5940
5991
|
_async_call_or_wait(request_id, async_call, request_name='sky.local.down')
|
|
5941
5992
|
|
|
5942
5993
|
|
sky/client/sdk.py
CHANGED
|
@@ -1429,6 +1429,7 @@ def status(
|
|
|
1429
1429
|
all_users: bool = False,
|
|
1430
1430
|
*,
|
|
1431
1431
|
_include_credentials: bool = False,
|
|
1432
|
+
_summary_response: bool = False,
|
|
1432
1433
|
) -> server_common.RequestId[List[responses.StatusResponse]]:
|
|
1433
1434
|
"""Gets cluster statuses.
|
|
1434
1435
|
|
|
@@ -1514,6 +1515,7 @@ def status(
|
|
|
1514
1515
|
refresh=refresh,
|
|
1515
1516
|
all_users=all_users,
|
|
1516
1517
|
include_credentials=_include_credentials,
|
|
1518
|
+
summary_response=_summary_response,
|
|
1517
1519
|
)
|
|
1518
1520
|
response = server_common.make_authenticated_request(
|
|
1519
1521
|
'POST', '/status', json=json.loads(body.model_dump_json()))
|
|
@@ -1675,6 +1677,7 @@ def local_up(gpus: bool,
|
|
|
1675
1677
|
ssh_key: Optional[str],
|
|
1676
1678
|
cleanup: bool,
|
|
1677
1679
|
context_name: Optional[str] = None,
|
|
1680
|
+
name: Optional[str] = None,
|
|
1678
1681
|
password: Optional[str] = None) -> server_common.RequestId[None]:
|
|
1679
1682
|
"""Launches a Kubernetes cluster on local machines.
|
|
1680
1683
|
|
|
@@ -1686,8 +1689,8 @@ def local_up(gpus: bool,
|
|
|
1686
1689
|
# TODO: move this check to server.
|
|
1687
1690
|
if not server_common.is_api_server_local():
|
|
1688
1691
|
with ux_utils.print_exception_no_traceback():
|
|
1689
|
-
raise ValueError(
|
|
1690
|
-
|
|
1692
|
+
raise ValueError('`sky local up` is only supported when '
|
|
1693
|
+
'running SkyPilot locally.')
|
|
1691
1694
|
|
|
1692
1695
|
body = payloads.LocalUpBody(gpus=gpus,
|
|
1693
1696
|
ips=ips,
|
|
@@ -1695,6 +1698,7 @@ def local_up(gpus: bool,
|
|
|
1695
1698
|
ssh_key=ssh_key,
|
|
1696
1699
|
cleanup=cleanup,
|
|
1697
1700
|
context_name=context_name,
|
|
1701
|
+
name=name,
|
|
1698
1702
|
password=password)
|
|
1699
1703
|
response = server_common.make_authenticated_request(
|
|
1700
1704
|
'POST', '/local_up', json=json.loads(body.model_dump_json()))
|
|
@@ -1704,16 +1708,19 @@ def local_up(gpus: bool,
|
|
|
1704
1708
|
@usage_lib.entrypoint
|
|
1705
1709
|
@server_common.check_server_healthy_or_start
|
|
1706
1710
|
@annotations.client_api
|
|
1707
|
-
def local_down() -> server_common.RequestId[None]:
|
|
1711
|
+
def local_down(name: Optional[str]) -> server_common.RequestId[None]:
|
|
1708
1712
|
"""Tears down the Kubernetes cluster started by local_up."""
|
|
1709
1713
|
# We do not allow local up when the API server is running remotely since it
|
|
1710
1714
|
# will modify the kubeconfig.
|
|
1711
1715
|
# TODO: move this check to remote server.
|
|
1712
1716
|
if not server_common.is_api_server_local():
|
|
1713
1717
|
with ux_utils.print_exception_no_traceback():
|
|
1714
|
-
raise ValueError('sky local down is only supported when running '
|
|
1718
|
+
raise ValueError('`sky local down` is only supported when running '
|
|
1715
1719
|
'SkyPilot locally.')
|
|
1716
|
-
|
|
1720
|
+
|
|
1721
|
+
body = payloads.LocalDownBody(name=name)
|
|
1722
|
+
response = server_common.make_authenticated_request(
|
|
1723
|
+
'POST', '/local_down', json=json.loads(body.model_dump_json()))
|
|
1717
1724
|
return server_common.get_request_id(response)
|
|
1718
1725
|
|
|
1719
1726
|
|
|
@@ -2083,6 +2090,7 @@ def stream_and_get(
|
|
|
2083
2090
|
return stream_response(request_id,
|
|
2084
2091
|
response,
|
|
2085
2092
|
output_stream,
|
|
2093
|
+
resumable=True,
|
|
2086
2094
|
get_result=follow)
|
|
2087
2095
|
|
|
2088
2096
|
|
sky/client/sdk_async.py
CHANGED
|
@@ -661,13 +661,14 @@ async def local_up(
|
|
|
661
661
|
ssh_key: Optional[str],
|
|
662
662
|
cleanup: bool,
|
|
663
663
|
context_name: Optional[str] = None,
|
|
664
|
+
name: Optional[str] = None,
|
|
664
665
|
password: Optional[str] = None,
|
|
665
666
|
stream_logs: Optional[StreamConfig] = DEFAULT_STREAM_CONFIG) -> None:
|
|
666
667
|
"""Async version of local_up() that launches a Kubernetes cluster on
|
|
667
668
|
local machines."""
|
|
668
669
|
request_id = await context_utils.to_thread(sdk.local_up, gpus, ips,
|
|
669
670
|
ssh_user, ssh_key, cleanup,
|
|
670
|
-
context_name, password)
|
|
671
|
+
context_name, name, password)
|
|
671
672
|
if stream_logs is not None:
|
|
672
673
|
return await _stream_and_get(request_id, stream_logs)
|
|
673
674
|
else:
|
|
@@ -677,10 +678,11 @@ async def local_up(
|
|
|
677
678
|
@usage_lib.entrypoint
|
|
678
679
|
@annotations.client_api
|
|
679
680
|
async def local_down(
|
|
681
|
+
name: Optional[str] = None,
|
|
680
682
|
stream_logs: Optional[StreamConfig] = DEFAULT_STREAM_CONFIG) -> None:
|
|
681
683
|
"""Async version of local_down() that tears down the Kubernetes cluster
|
|
682
684
|
started by local_up."""
|
|
683
|
-
request_id = await context_utils.to_thread(sdk.local_down)
|
|
685
|
+
request_id = await context_utils.to_thread(sdk.local_down, name)
|
|
684
686
|
if stream_logs is not None:
|
|
685
687
|
return await _stream_and_get(request_id, stream_logs)
|
|
686
688
|
else:
|
sky/clouds/kubernetes.py
CHANGED
|
@@ -62,6 +62,7 @@ class Kubernetes(clouds.Cloud):
|
|
|
62
62
|
_SUPPORTS_SERVICE_ACCOUNT_ON_REMOTE = True
|
|
63
63
|
|
|
64
64
|
_DEFAULT_NUM_VCPUS = 2
|
|
65
|
+
_DEFAULT_NUM_VCPUS_WITH_GPU = 4
|
|
65
66
|
_DEFAULT_MEMORY_CPU_RATIO = 1
|
|
66
67
|
_DEFAULT_MEMORY_CPU_RATIO_WITH_GPU = 4 # Allocate more memory for GPU tasks
|
|
67
68
|
_REPR = 'Kubernetes'
|
|
@@ -842,7 +843,7 @@ class Kubernetes(clouds.Cloud):
|
|
|
842
843
|
|
|
843
844
|
gpu_task_cpus = k8s_instance_type.cpus
|
|
844
845
|
if resources.cpus is None:
|
|
845
|
-
gpu_task_cpus =
|
|
846
|
+
gpu_task_cpus = self._DEFAULT_NUM_VCPUS_WITH_GPU * acc_count
|
|
846
847
|
# Special handling to bump up memory multiplier for GPU instances
|
|
847
848
|
gpu_task_memory = (float(resources.memory.strip('+')) if
|
|
848
849
|
resources.memory is not None else gpu_task_cpus *
|
sky/clouds/runpod.py
CHANGED
|
@@ -286,14 +286,16 @@ class RunPod(clouds.Cloud):
|
|
|
286
286
|
@classmethod
|
|
287
287
|
def _check_credentials(cls) -> Tuple[bool, Optional[str]]:
|
|
288
288
|
"""Verify that the user has valid credentials for RunPod. """
|
|
289
|
-
dependency_error_msg = ('Failed to import runpod. '
|
|
290
|
-
'
|
|
289
|
+
dependency_error_msg = ('Failed to import runpod or TOML parser. '
|
|
290
|
+
'Install: pip install "skypilot[runpod]".')
|
|
291
291
|
try:
|
|
292
292
|
runpod_spec = import_lib_util.find_spec('runpod')
|
|
293
293
|
if runpod_spec is None:
|
|
294
294
|
return False, dependency_error_msg
|
|
295
|
-
|
|
296
|
-
|
|
295
|
+
# Prefer stdlib tomllib (Python 3.11+); fallback to tomli
|
|
296
|
+
tomllib_spec = import_lib_util.find_spec('tomllib')
|
|
297
|
+
tomli_spec = import_lib_util.find_spec('tomli')
|
|
298
|
+
if tomllib_spec is None and tomli_spec is None:
|
|
297
299
|
return False, dependency_error_msg
|
|
298
300
|
except ValueError:
|
|
299
301
|
# docstring of importlib_util.find_spec:
|
|
@@ -322,9 +324,20 @@ class RunPod(clouds.Cloud):
|
|
|
322
324
|
if not os.path.exists(credential_file):
|
|
323
325
|
return False, '~/.runpod/config.toml does not exist.'
|
|
324
326
|
|
|
325
|
-
#
|
|
326
|
-
#
|
|
327
|
-
|
|
327
|
+
# We don't need to import TOML parser if config.toml does not exist.
|
|
328
|
+
# When needed, prefer stdlib tomllib (py>=3.11); otherwise use tomli.
|
|
329
|
+
# TODO(andy): remove this fallback after dropping Python 3.10 support.
|
|
330
|
+
try:
|
|
331
|
+
try:
|
|
332
|
+
import tomllib as toml # pylint: disable=import-outside-toplevel
|
|
333
|
+
except ModuleNotFoundError: # py<3.11
|
|
334
|
+
import tomli as toml # pylint: disable=import-outside-toplevel
|
|
335
|
+
except ModuleNotFoundError:
|
|
336
|
+
# Should never happen. We already installed proper dependencies for
|
|
337
|
+
# different Python versions in setup_files/dependencies.py.
|
|
338
|
+
return False, (
|
|
339
|
+
'~/.runpod/config.toml exists but no TOML parser is available. '
|
|
340
|
+
'Install tomli for Python < 3.11: pip install tomli.')
|
|
328
341
|
|
|
329
342
|
# Check for default api_key
|
|
330
343
|
try:
|
sky/core.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
"""SDK functions for cluster/job management."""
|
|
2
|
-
import os
|
|
3
|
-
import shlex
|
|
4
2
|
import typing
|
|
5
3
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
6
4
|
|
|
@@ -9,7 +7,6 @@ import colorama
|
|
|
9
7
|
from sky import admin_policy
|
|
10
8
|
from sky import backends
|
|
11
9
|
from sky import catalog
|
|
12
|
-
from sky import check as sky_check
|
|
13
10
|
from sky import clouds
|
|
14
11
|
from sky import dag as dag_lib
|
|
15
12
|
from sky import data
|
|
@@ -31,7 +28,6 @@ from sky.schemas.api import responses
|
|
|
31
28
|
from sky.skylet import autostop_lib
|
|
32
29
|
from sky.skylet import constants
|
|
33
30
|
from sky.skylet import job_lib
|
|
34
|
-
from sky.skylet import log_lib
|
|
35
31
|
from sky.usage import usage_lib
|
|
36
32
|
from sky.utils import admin_policy_utils
|
|
37
33
|
from sky.utils import common
|
|
@@ -102,6 +98,7 @@ def status(
|
|
|
102
98
|
refresh: common.StatusRefreshMode = common.StatusRefreshMode.NONE,
|
|
103
99
|
all_users: bool = False,
|
|
104
100
|
include_credentials: bool = False,
|
|
101
|
+
summary_response: bool = False,
|
|
105
102
|
) -> List[responses.StatusResponse]:
|
|
106
103
|
# NOTE(dev): Keep the docstring consistent between the Python API and CLI.
|
|
107
104
|
"""Gets cluster statuses.
|
|
@@ -181,7 +178,8 @@ def status(
|
|
|
181
178
|
refresh=refresh,
|
|
182
179
|
cluster_names=cluster_names,
|
|
183
180
|
all_users=all_users,
|
|
184
|
-
include_credentials=include_credentials
|
|
181
|
+
include_credentials=include_credentials,
|
|
182
|
+
summary_response=summary_response)
|
|
185
183
|
|
|
186
184
|
status_responses = []
|
|
187
185
|
for cluster in clusters:
|
|
@@ -1301,6 +1299,7 @@ def local_up(gpus: bool,
|
|
|
1301
1299
|
ssh_key: Optional[str],
|
|
1302
1300
|
cleanup: bool,
|
|
1303
1301
|
context_name: Optional[str] = None,
|
|
1302
|
+
name: Optional[str] = None,
|
|
1304
1303
|
password: Optional[str] = None) -> None:
|
|
1305
1304
|
"""Creates a local or remote cluster."""
|
|
1306
1305
|
|
|
@@ -1331,57 +1330,12 @@ def local_up(gpus: bool,
|
|
|
1331
1330
|
password)
|
|
1332
1331
|
else:
|
|
1333
1332
|
# Run local deployment (kind) if no remote args are specified
|
|
1334
|
-
kubernetes_deploy_utils.deploy_local_cluster(gpus)
|
|
1333
|
+
kubernetes_deploy_utils.deploy_local_cluster(name, gpus)
|
|
1335
1334
|
|
|
1336
1335
|
|
|
1337
|
-
def local_down() -> None:
|
|
1336
|
+
def local_down(name: Optional[str] = None) -> None:
|
|
1338
1337
|
"""Tears down the Kubernetes cluster started by local_up."""
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
path_to_package = os.path.dirname(__file__)
|
|
1342
|
-
down_script_path = os.path.join(path_to_package, 'utils/kubernetes',
|
|
1343
|
-
'delete_cluster.sh')
|
|
1344
|
-
|
|
1345
|
-
cwd = os.path.dirname(os.path.abspath(down_script_path))
|
|
1346
|
-
run_command = shlex.split(down_script_path)
|
|
1347
|
-
|
|
1348
|
-
# Setup logging paths
|
|
1349
|
-
run_timestamp = sky_logging.get_run_timestamp()
|
|
1350
|
-
log_path = os.path.join(constants.SKY_LOGS_DIRECTORY, run_timestamp,
|
|
1351
|
-
'local_down.log')
|
|
1352
|
-
|
|
1353
|
-
with rich_utils.safe_status(
|
|
1354
|
-
ux_utils.spinner_message('Removing local cluster',
|
|
1355
|
-
log_path=log_path,
|
|
1356
|
-
is_local=True)):
|
|
1357
|
-
|
|
1358
|
-
returncode, stdout, stderr = log_lib.run_with_log(cmd=run_command,
|
|
1359
|
-
log_path=log_path,
|
|
1360
|
-
require_outputs=True,
|
|
1361
|
-
stream_logs=False,
|
|
1362
|
-
cwd=cwd)
|
|
1363
|
-
stderr = stderr.replace('No kind clusters found.\n', '')
|
|
1364
|
-
|
|
1365
|
-
if returncode == 0:
|
|
1366
|
-
cluster_removed = True
|
|
1367
|
-
elif returncode == 100:
|
|
1368
|
-
logger.info(ux_utils.error_message('Local cluster does not exist.'))
|
|
1369
|
-
else:
|
|
1370
|
-
with ux_utils.print_exception_no_traceback():
|
|
1371
|
-
raise RuntimeError('Failed to create local cluster. '
|
|
1372
|
-
f'Stdout: {stdout}'
|
|
1373
|
-
f'\nError: {stderr}')
|
|
1374
|
-
if cluster_removed:
|
|
1375
|
-
# Run sky check
|
|
1376
|
-
with rich_utils.safe_status(
|
|
1377
|
-
ux_utils.spinner_message('Running sky check...')):
|
|
1378
|
-
sky_check.check_capability(sky_cloud.CloudCapability.COMPUTE,
|
|
1379
|
-
clouds=['kubernetes'],
|
|
1380
|
-
quiet=True)
|
|
1381
|
-
logger.info(
|
|
1382
|
-
ux_utils.finishing_message('Local cluster removed.',
|
|
1383
|
-
log_path=log_path,
|
|
1384
|
-
is_local=True))
|
|
1338
|
+
kubernetes_deploy_utils.teardown_local_cluster(name)
|
|
1385
1339
|
|
|
1386
1340
|
|
|
1387
1341
|
@usage_lib.entrypoint
|
sky/dashboard/out/404.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.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-
|
|
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/4614e06482d7309e.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/4614e06482d7309e.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-16ba1d7187d2e3b1.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-ce361c6959bc2001.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_error-c66a4e8afc46f17b.js" defer=""></script><script src="/dashboard/_next/static/bn-NHt5qTzeTN2PefXuDA/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/bn-NHt5qTzeTN2PefXuDA/_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":"bn-NHt5qTzeTN2PefXuDA","assetPrefix":"/dashboard","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
|
sky/dashboard/out/_next/static/{KP6HCNMqb_bnJB17oplgW → bn-NHt5qTzeTN2PefXuDA}/_buildManifest.js
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
self.__BUILD_MANIFEST=function(s,c,a,e,t,f,u,n,
|
|
1
|
+
self.__BUILD_MANIFEST=function(s,c,a,e,t,f,u,b,n,o,j,i,r,k){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":["static/chunks/pages/index-444f1804401f04ea.js"],"/_error":["static/chunks/pages/_error-c66a4e8afc46f17b.js"],"/clusters":["static/chunks/pages/clusters-469814d711d63b1b.js"],"/clusters/[cluster]":[s,c,a,f,u,"static/chunks/4676-9da7fdbde90b5549.js",o,e,t,b,j,n,i,"static/chunks/6856-2b3600ff2854d066.js",r,k,"static/chunks/9037-472ee1222cb1e158.js","static/chunks/pages/clusters/[cluster]-e052384df65ef200.js"],"/clusters/[cluster]/[job]":[s,c,a,f,e,t,n,"static/chunks/pages/clusters/[cluster]/[job]-2cb9b15e09cda628.js"],"/config":["static/chunks/pages/config-dfb9bf07b13045f4.js"],"/infra":["static/chunks/pages/infra-aabba60d57826e0f.js"],"/infra/[context]":["static/chunks/pages/infra/[context]-6563820e094f68ca.js"],"/jobs":["static/chunks/pages/jobs-1f70d9faa564804f.js"],"/jobs/pools/[pool]":[s,c,a,u,o,e,t,b,"static/chunks/pages/jobs/pools/[pool]-07349868f7905d37.js"],"/jobs/[job]":[s,c,a,f,u,o,e,t,b,n,"static/chunks/pages/jobs/[job]-dd64309c3fe67ed2.js"],"/users":["static/chunks/pages/users-018bf31cda52e11b.js"],"/volumes":["static/chunks/pages/volumes-739726d6b823f532.js"],"/workspace/new":["static/chunks/pages/workspace/new-3f88a1c7e86a3f86.js"],"/workspaces":["static/chunks/pages/workspaces-7528cc0ef8c522c5.js"],"/workspaces/[name]":[s,c,a,f,u,"static/chunks/1836-37fede578e2da5f8.js",e,t,b,j,n,i,r,k,"static/chunks/1141-159df2d4c441a9d1.js","static/chunks/pages/workspaces/[name]-af76bb06dbb3954f.js"],sortedPages:["/","/_app","/_error","/clusters","/clusters/[cluster]","/clusters/[cluster]/[job]","/config","/infra","/infra/[context]","/jobs","/jobs/pools/[pool]","/jobs/[job]","/users","/volumes","/workspace/new","/workspaces","/workspaces/[name]"]}}("static/chunks/616-3d59f75e2ccf9321.js","static/chunks/6130-2be46d70a38f1e82.js","static/chunks/5739-d67458fcb1386c92.js","static/chunks/6989-01359c57e018caa4.js","static/chunks/3850-ff4a9a69d978632b.js","static/chunks/7411-b15471acd2cba716.js","static/chunks/1272-1ef0bf0237faccdb.js","static/chunks/8969-d8bc3a2b9cf839a9.js","static/chunks/6135-4b4d5e824b7f9d3c.js","static/chunks/754-d0da8ab45f9509e9.js","static/chunks/6990-f6818c84ed8f1c86.js","static/chunks/1121-b911fc0a0b4742f0.js","static/chunks/6601-06114c982db410b6.js","static/chunks/3015-88c7c8d69b0b6dba.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1121],{50326:function(e,t,a){a.d(t,{$N:function(){return m},Be:function(){return h},Vq:function(){return c},cN:function(){return _},cZ:function(){return d},fK:function(){return f}});var r=a(85893),s=a(67294),o=a(6327),n=a(32350),l=a(43767);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 f=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})};f.displayName="DialogHeader";let _=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})};_.displayName="DialogFooter";let m=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})});m.displayName=o.Dx.displayName;let h=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})});h.displayName=o.dk.displayName},23266:function(e,t,a){a.d(t,{GH:function(){return f},QL:function(){return m},Sl:function(){return d},getClusters:function(){return u},uR:function(){return i}});var r=a(67294),s=a(15821),o=a(47145),n=a(93225),l=a(6378);let c={UP:"RUNNING",STOPPED:"STOPPED",INIT:"LAUNCHING",null:"TERMINATED"};async function u(){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,include_credentials:!1,summary_response:null==e})).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:c[e.status],cluster:e.name,user:e.user_name,user_hash:e.user_hash,cluster_hash:e.cluster_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,last_event:e.last_event,to_down:e.to_down,cluster_name_on_cloud:e.cluster_name_on_cloud,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 i(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;try{let t={days:30,dashboard_summary_response:!0};e&&(t.cluster_hashes=[e]);let a=await o.x.fetch("/cost_report",t);console.log("Raw cluster history data:",a);let r=a.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?c[e.status]:"TERMINATED",cluster:e.name,user:a,user_hash:e.user_hash,cluster_hash:e.cluster_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,last_event:e.last_event,to_down:!1,cluster_name_on_cloud:null,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:",r),r}catch(e){return console.error("Error fetching cluster history:",e),[]}}async function d(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,tail:1e4,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 f(e){let{clusterName:t,jobIds:a=null,workspace:r}=e;try{let e=await o.x.fetch("/download_logs",{cluster_name:t,job_ids:a?a.map(String):null,override_skypilot_config:{active_workspace:r||"default"}}),l=Object.values(e||{});if(!l.length){(0,s.C)("No logs found to download.","warning");return}let c=window.location.origin,u="".concat(c).concat(n.f4,"/download"),i=await fetch("".concat(u,"?relative=items"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({folder_paths:l})});if(!i.ok){let e=await i.text();throw Error("Download failed: ".concat(i.status," ").concat(e))}let d=await i.blob(),f=window.URL.createObjectURL(d),_=document.createElement("a"),m=new Date().toISOString().replace(/[:.]/g,"-"),h=a&&1===a.length?"job-".concat(a[0]):"jobs";_.href=f,_.download="".concat(t,"-").concat(h,"-logs-").concat(m,".zip"),document.body.appendChild(_),_.click(),_.remove(),window.URL.revokeObjectURL(f)}catch(e){console.error("Error downloading logs:",e),(0,s.C)("Error downloading logs: ".concat(e.message),"error")}}async function _(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=>{var r;let s=e.end_at?e.end_at:Date.now()/1e3,o=0,n=0;return e.submitted_at&&(o=s-e.submitted_at),e.start_at&&(n=s-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:o,job_duration:n,infra:"",logs:"",workspace:a||"default",git_commit:(null===(r=e.metadata)||void 0===r?void 0:r.git_commit)||"-"}})}catch(e){return console.error("Error fetching cluster jobs:",e),[]}}function m(e){let{cluster:t,job:a=null}=e,[s,o]=(0,r.useState)(null),[n,c]=(0,r.useState)(null),[i,d]=(0,r.useState)(!0),[f,m]=(0,r.useState)(!0),h=(0,r.useCallback)(async()=>{if(t)try{d(!0);let e=await l.default.get(u,[{clusterNames:[t]}]);return o(e[0]),e[0]}catch(e){console.error("Error fetching cluster data:",e)}finally{d(!1)}return null},[t]),g=(0,r.useCallback)(async e=>{if(t)try{m(!0);let a=await l.default.get(_,[{clusterName:t,workspace:e||"default"}]);c(a)}catch(e){console.error("Error fetching cluster job data:",e)}finally{m(!1)}},[t]),p=(0,r.useCallback)(async()=>{l.default.invalidate(u,[{clusterNames:[t]}]);let e=await h();e&&(l.default.invalidate(_,[{clusterName:t,workspace:e.workspace||"default"}]),await g(e.workspace))},[h,g,t]),w=(0,r.useCallback)(async()=>{s&&(l.default.invalidate(_,[{clusterName:t,workspace:s.workspace||"default"}]),await g(s.workspace))},[g,s,t]);return(0,r.useEffect)(()=>{(async()=>{let e=await h();e&&g(e.workspace)})()},[t,a,h,g]),{clusterData:s,clusterJobData:n,loading:i,clusterDetailsLoading:i,clusterJobsLoading:f,refreshData:p,refreshClusterJobsOnly:w}}},53081:function(e,t,a){a.d(t,{R:function(){return s}}),a(23266),a(68969);var r=a(47145);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,created_at:e.created_at}))||[]}catch(e){return console.error("Failed to fetch users:",e),[]}}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[6856],{32045:function(e,t,o){o.d(t,{Cu:function(){return s},R8:function(){return u},Xg:function(){return c},ef:function(){return n}});var r=o(93225),a=o(47145);async function n(){let e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=(await Promise.resolve().then(o.bind(o,6378))).default,{getClusters:n}=await Promise.resolve().then(o.bind(o,23266)),{getManagedJobs:s}=await Promise.resolve().then(o.bind(o,68969));try{let o=await t.get(s,[{allUsers:!0}]),c=(null==o?void 0:o.jobs)||[],l=await t.get(n),i=[];try{if(e){console.log("Force refreshing clouds by running sky check...");try{let e=await a.x.post("/check",{}),t=e.headers.get("X-Skypilot-Request-ID")||e.headers.get("X-Request-ID"),o=await a.x.get("/api/get?request_id=".concat(t)),r=await o.json();console.log("Sky check completed:",r)}catch(e){console.error("Error running sky check:",e)}}let t=await a.x.get("/enabled_clouds"),o=t.headers.get("X-Skypilot-Request-ID")||t.headers.get("X-Request-ID"),r=await a.x.get("/api/get?request_id=".concat(o)),n=await r.json();i=n.return_value?JSON.parse(n.return_value):[],console.log("Enabled clouds:",i)}catch(e){console.error("Error fetching enabled clouds:",e),i=[]}let u={};r.$m.forEach(e=>{let t=i.includes(e.toLowerCase());u[e]={name:e,clusters:0,jobs:0,enabled:t}}),(l||[]).forEach(e=>{if(e.cloud){let t=e.cloud;u[t]&&(u[t].clusters+=1,u[t].enabled=!0)}}),c.forEach(e=>{if(e.cloud){let t=e.cloud;u[t]&&(u[t].jobs+=1,u[t].enabled=!0)}});let d=r.$m.length,g=Object.values(u).filter(e=>e.enabled).length;return{clouds:Object.values(u).filter(e=>e.enabled).sort((e,t)=>e.name.localeCompare(t.name)),totalClouds:d,enabledClouds:g}}catch(e){return console.error("Error fetching cloud infrastructure:",e),{clouds:[],totalClouds:r.$m.length,enabledClouds:0}}}async function s(){return await c()}async function c(){try{console.log("[DEBUG] Starting workspace-aware infrastructure fetch");let{getWorkspaces:e}=await Promise.resolve().then(o.bind(o,17324));console.log("[DEBUG] About to call getWorkspaces()");let t=await e();if(console.log("[DEBUG] Workspaces data received:",t),console.log("[DEBUG] Number of accessible workspaces:",Object.keys(t||{}).length),console.log("[DEBUG] Workspace names:",Object.keys(t||{})),!t||0===Object.keys(t).length)return console.log("[DEBUG] No accessible workspaces found - returning empty result"),{workspaces:{},allContextNames:[],allGPUs:[],perContextGPUs:[],perNodeGPUs:[],contextStats:{},contextWorkspaceMap:{}};let{getEnabledClouds:r}=await Promise.resolve().then(o.bind(o,17324)),a={},n=[],s={};for(let[e,o]of Object.entries(t)){console.log("Fetching infrastructure for workspace: ".concat(e));try{console.log("[DEBUG] Fetching enabled clouds for workspace: ".concat(e));let t=await r(e,!0);console.log("[DEBUG] Expanded clouds for ".concat(e,":"),t),a[e]={config:o,clouds:t,contexts:[]},console.log("[DEBUG] Processing expandedClouds for ".concat(e,":"),t),t&&Array.isArray(t)?t.forEach(t=>{if(console.log("[DEBUG] Processing infraItem: ".concat(t)),t.toLowerCase().startsWith("kubernetes/")){let o=t.replace(/^kubernetes\//i,"");console.log("[DEBUG] Extracted kubernetes context: ".concat(o)),n.push(o),s[o]||(s[o]=[]),s[o].includes(e)||s[o].push(e),a[e].contexts.push(o)}else if(t.toLowerCase().startsWith("ssh/")){let o=t.replace(/^ssh\//i,""),r="ssh-".concat(o);console.log("[DEBUG] Extracted SSH context: ".concat(r)),n.push(r),s[r]||(s[r]=[]),s[r].includes(e)||s[r].push(e),a[e].contexts.push(r)}}):console.log("[DEBUG] No expanded clouds or not an array for ".concat(e))}catch(t){console.error("Failed to fetch infrastructure for workspace ".concat(e,":"),t),a[e]={config:o,clouds:[],contexts:[],error:t.message}}}let{getClusters:c}=await Promise.resolve().then(o.bind(o,23266)),i=(await Promise.resolve().then(o.bind(o,6378))).default,u=await i.get(c),g=await d(u||[]),f=n.filter(e=>e&&"string"==typeof e),p=await l(f),h={workspaces:a,allContextNames:[...new Set(n)].sort(),allGPUs:p.allGPUs||[],perContextGPUs:p.perContextGPUs||[],perNodeGPUs:p.perNodeGPUs||[],contextStats:g,contextWorkspaceMap:s};return console.log("[DEBUG] Final result:",h),console.log("[DEBUG] All contexts found:",n),console.log("[DEBUG] Context workspace map:",s),h}catch(e){return console.error("[DEBUG] Failed to fetch workspace infrastructure:",e),console.error("[DEBUG] Error stack:",e.stack),{workspaces:{},allContextNames:[],allGPUs:[],perContextGPUs:[],perNodeGPUs:[],contextStats:{},contextWorkspaceMap:{},error:e.message}}}async function l(e){try{var t,o,r,a,n,s;if(!e||0===e.length)return{allGPUs:[],perContextGPUs:[],perNodeGPUs:[]};let c={},l={},u={},d=await Promise.all(e.map(e=>i(e))),g={};for(let t=0;t<e.length;t++)g[e[t]]=d[t];for(let r of e){let e=g[r]||{};if(e&&Object.keys(e).length>0){let a={};for(let n in e){let s=e[n];if(!s){console.warn("No node data for node ".concat(n," in context ").concat(r));continue}let c=s.accelerator_type,l=(null===(t=s.total)||void 0===t?void 0:t.accelerator_count)||0,i=(null===(o=s.free)||void 0===o?void 0:o.accelerators_available)||0;l>0&&(a[c]||(a[c]={gpu_name:c,gpu_requestable_qty_per_node:0,gpu_total:0,gpu_free:0,context:r}),a[c].gpu_total+=l,a[c].gpu_free+=i,a[c].gpu_requestable_qty_per_node=l)}for(let e in l[r]=Object.values(a),a)e in c?(c[e].gpu_total+=a[e].gpu_total,c[e].gpu_free+=a[e].gpu_free):c[e]={gpu_total:a[e].gpu_total,gpu_free:a[e].gpu_free,gpu_name:e}}else l[r]=[]}for(let t of e){let e=g[t];if(e&&Object.keys(e).length>0)for(let o in e){let i=e[o];if(!i){console.warn("No node data for node ".concat(o," in context ").concat(t));continue}let d=i.accelerator_type||"-",g=null!==(n=null===(r=i.total)||void 0===r?void 0:r.accelerator_count)&&void 0!==n?n:0,f=null!==(s=null===(a=i.free)||void 0===a?void 0:a.accelerators_available)&&void 0!==s?s:0;u["".concat(t,"/").concat(o)]={node_name:i.name||o,gpu_name:d,gpu_total:g,gpu_free:f,ip_address:i.ip_address||null,context:t},"-"===d||!l[t]||l[t].some(e=>e.gpu_name===d)||(d in c||(c[d]={gpu_total:0,gpu_free:0,gpu_name:d}),l[t].find(e=>e.gpu_name===d)||l[t].push({gpu_name:d,gpu_requestable_qty_per_node:"-",gpu_total:0,gpu_free:0,context:t}))}}return{allGPUs:Object.values(c).sort((e,t)=>e.gpu_name.localeCompare(t.gpu_name)),perContextGPUs:Object.values(l).flat().sort((e,t)=>e.context.localeCompare(t.context)||e.gpu_name.localeCompare(t.gpu_name)),perNodeGPUs:Object.values(u).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] Error in getKubernetesGPUsFromContexts:",e),{allGPUs:[],perContextGPUs:[],perNodeGPUs:[]}}}async function i(e){try{let t=await a.x.post("/kubernetes_node_info",{context:e}),o=t.headers.get("X-Skypilot-Request-ID")||t.headers.get("x-request-id"),r=await a.x.get("/api/get?request_id=".concat(o));if(500===r.status){try{let t=await r.json();if(t.detail&&t.detail.error)try{let o=JSON.parse(t.detail.error);console.warn("[infra.jsx] Context ".concat(e," unavailable:"),o.message)}catch(e){console.error("Error parsing JSON:",e)}}catch(e){console.error("Error parsing JSON:",e)}return{}}let n=await r.json();return(n.return_value?JSON.parse(n.return_value):{}).node_info_dict||{}}catch(t){return console.warn("[infra.jsx] Context ".concat(e," unavailable or timed out:"),t.message),{}}}async function u(e){try{let t={};return e.forEach(e=>{let o=null;if("Kubernetes"===e.cloud)(o=e.region)&&(o="kubernetes/".concat(o));else if("SSH"===e.cloud&&(o=e.region)){let e=o.startsWith("ssh-")?o.substring(4):o;o="ssh/".concat(e)}o&&(t[o]||(t[o]={clusters:0,jobs:0}),t[o].jobs+=1)}),t}catch(e){return console.error("=== Error in getContextJobs ===",e),{}}}async function d(e){try{let t={};return e.forEach(e=>{let o=null;if("Kubernetes"===e.cloud)(o=e.region)&&(o="kubernetes/".concat(o));else if("SSH"===e.cloud&&(o=e.region)){let e=o.startsWith("ssh-")?o.substring(4):o;o="ssh/".concat(e)}o&&(t[o]||(t[o]={clusters:0,jobs:0}),t[o].clusters+=1)}),t}catch(e){return console.error("=== Error in getContextClusters ===",e),{}}}},29326:function(e,t,o){o.d(t,{IS:function(){return d},It:function(){return n},MV:function(){return c},Ri:function(){return s},_x:function(){return i},ez:function(){return u},hY:function(){return l},mF:function(){return f},wJ:function(){return g}});var r=o(93225),a=o(15821);async function n(){try{let e=await fetch("".concat(r.f4,"/ssh_node_pools"),{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok)throw Error("HTTP error! status: ".concat(e.status));return await e.json()}catch(e){return console.error("Error fetching SSH Node Pools:",e),{}}}async function s(e){try{let t=await fetch("".concat(r.f4,"/ssh_node_pools"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok)throw Error("HTTP error! status: ".concat(t.status));return await t.json()}catch(e){throw console.error("Error updating SSH Node Pools:",e),e}}async function c(e){try{let t=await fetch("".concat(r.f4,"/ssh_node_pools/").concat(e),{method:"DELETE",headers:{"Content-Type":"application/json"}});if(!t.ok)throw Error("HTTP error! status: ".concat(t.status));return await t.json()}catch(e){throw console.error("Error deleting SSH Node Pool:",e),e}}async function l(e,t){try{let o=new FormData;o.append("key_name",e),o.append("key_file",t);let a=await fetch("".concat(r.f4,"/ssh_node_pools/keys"),{method:"POST",body:o});if(!a.ok)throw Error("HTTP error! status: ".concat(a.status));return await a.json()}catch(e){throw console.error("Error uploading SSH key:",e),e}}async function i(e){try{let t=await fetch("".concat(r.f4,"/ssh_node_pools/").concat(e,"/deploy"),{method:"POST",headers:{"Content-Type":"application/json"}});if(!t.ok)throw Error("HTTP error! status: ".concat(t.status));return await t.json()}catch(e){throw console.error("Error deploying SSH Node Pool:",e),e}}async function u(e){try{let t=await fetch("".concat(r.f4,"/ssh_node_pools/").concat(e,"/down"),{method:"POST",headers:{"Content-Type":"application/json"}});if(!t.ok)throw Error("HTTP error! status: ".concat(t.status));return await t.json()}catch(e){throw console.error("Error tearing down SSH Node Pool:",e),e}}async function d(e){try{let t=await fetch("".concat(r.f4,"/ssh_node_pools/").concat(e,"/status"),{method:"GET",headers:{"Content-Type":"application/json"}});if(!t.ok)throw Error("HTTP error! status: ".concat(t.status));return await t.json()}catch(e){throw console.error("Error fetching SSH Node Pool status:",e),e}}async function g(e){let t,{requestId:o,signal:n,onNewLog:s}=e,c=Date.now(),l=new Promise(e=>{let o=()=>{let r=Date.now()-c;r>=3e5?e({timeout:!0}):t=setTimeout(o,3e5-r)};t=setTimeout(o,3e5)}),i=(async()=>{try{let e=await fetch("".concat(r.f4,"/api/stream?request_id=").concat(o,"&format=plain&tail=").concat(1e3,"&follow=true"),{method:"GET",headers:{"Content-Type":"application/json"},...n?{signal:n}:{}});if(!e.ok)throw Error("HTTP error! status: ".concat(e.status));let a=e.body.getReader();try{for(;;){let{done:e,value:t}=await a.read();if(e)break;c=Date.now();let o=new TextDecoder().decode(t);s(o)}}finally{a.cancel(),t&&clearTimeout(t)}return{timeout:!1}}catch(e){if(t&&clearTimeout(t),"AbortError"===e.name)return{timeout:!1};throw e}})(),u=await Promise.race([i,l]);if(t&&clearTimeout(t),u.timeout){(0,a.C)("SSH deployment log stream timed out after ".concat(300,"s of inactivity"),"warning");return}}async function f(e){let t,{requestId:o,signal:n,onNewLog:s,operationType:c="operation"}=e,l=Date.now(),i=new Promise(e=>{let o=()=>{let r=Date.now()-l;r>=3e5?e({timeout:!0}):t=setTimeout(o,3e5-r)};t=setTimeout(o,3e5)}),u=(async()=>{try{let e=await fetch("".concat(r.f4,"/api/stream?request_id=").concat(o,"&format=plain&tail=").concat(1e3,"&follow=true"),{method:"GET",headers:{"Content-Type":"application/json"},...n?{signal:n}:{}});if(!e.ok)throw Error("HTTP error! status: ".concat(e.status));let a=e.body.getReader();try{for(;;){let{done:e,value:t}=await a.read();if(e)break;l=Date.now();let o=new TextDecoder().decode(t);s(o)}}finally{a.cancel(),t&&clearTimeout(t)}return{timeout:!1}}catch(e){if(t&&clearTimeout(t),"AbortError"===e.name)return{timeout:!1};throw e}})(),d=await Promise.race([u,i]);if(t&&clearTimeout(t),d.timeout){(0,a.C)("SSH ".concat(c," log stream timed out after ").concat(300,"s of inactivity"),"warning");return}}},19238:function(e,t,o){o.d(t,{C:function(){return a},w:function(){return n}});var r=o(47145);async function a(){try{return(await r.x.fetch("/volumes",{},"GET")).map(e=>{var t,o,r;let a=e.cloud||"";return e.region&&(a+="/".concat(e.region)),e.zone&&(a+="/".concat(e.zone)),{name:e.name,launched_at:e.launched_at,user_hash:e.user_hash,user_name:e.user_name||"-",workspace:e.workspace||"-",last_attached_at:e.last_attached_at,status:e.status,type:e.type,cloud:e.cloud,region:e.region,zone:e.zone,infra:a,size:"".concat(e.size,"Gi"),config:e.config,storage_class:(null===(t=e.config)||void 0===t?void 0:t.storage_class_name)||"-",access_mode:(null===(o=e.config)||void 0===o?void 0:o.access_mode)||"-",namespace:(null===(r=e.config)||void 0===r?void 0:r.namespace)||"-",name_on_cloud:e.name_on_cloud,usedby_pods:e.usedby_pods,usedby_clusters:e.usedby_clusters}})||[]}catch(e){return console.error("Failed to fetch volumes:",e),[]}}async function n(e){let t="";try{let o=await r.x.post("/volumes/delete",{names:[e]}),a=o.headers.get("X-SkyPilot-Request-ID")||o.headers.get("X-Request-ID"),n=await r.x.get("/api/get?request_id=".concat(a));if(500===n.status){try{let e=await n.json();if(e.detail&&e.detail.error)try{t=JSON.parse(e.detail.error).message}catch(e){console.error("Error parsing JSON:",e)}}catch(e){console.error("Error parsing JSON:",e)}return{success:!1,msg:t}}return{success:!0}}catch(e){return console.error("Failed to delete volume:",e),{success:!1,msg:e.message}}}},36856:function(e,t,o){var r=o(6378),a=o(23266),n=o(68969),s=o(17324),c=o(53081),l=o(19238),i=o(32045),u=o(29326);let d={base:{getClusters:{fn:a.getClusters,args:[]},getManagedJobs:{fn:n.aT,args:[{allUsers:!0}]},getWorkspaces:{fn:s.getWorkspaces,args:[]},getUsers:{fn:c.R,args:[]},getGPUs:{fn:i.Cu,args:[]},getCloudInfrastructure:{fn:i.ef,args:[!1]},getSSHNodePools:{fn:u.It,args:[]},getVolumes:{fn:l.C,args:[]}},dynamic:{getEnabledClouds:{fn:s.getEnabledClouds,requiresWorkspaces:!0}},pages:{clusters:["getClusters","getWorkspaces"],jobs:["getManagedJobs","getClusters","getWorkspaces","getUsers"],infra:["getClusters","getManagedJobs","getGPUs","getCloudInfrastructure","getSSHNodePools"],workspaces:["getWorkspaces","getClusters","getManagedJobs","getEnabledClouds"],users:["getUsers","getClusters","getManagedJobs"],volumes:["getVolumes"]}};class g{async preloadForPage(e,t){let{backgroundPreload:o=!0,force:r=!1}=t||{};if(!d.pages[e]){console.warn("Unknown page: ".concat(e));return}console.log("[CachePreloader] Preloading cache for page: ".concat(e));try{await this._loadPageData(e,r),o&&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],o=d.pages[e],a=[];for(let e of o)if(d.base[e]){let{fn:o,args:n}=d.base[e];t&&r.default.invalidate(o,n),a.push(r.default.get(o,n).then(e=>(this._markAsPreloaded(o,n),e)))}else"getEnabledClouds"===e&&a.push(this._loadEnabledCloudsForAllWorkspaces(t));await Promise.allSettled(a),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(s.getWorkspaces);let t=await r.default.get(s.getWorkspaces),o=Object.keys(t||{}).map(t=>(e&&r.default.invalidate(s.getEnabledClouds,[t]),r.default.get(s.getEnabledClouds,[t])));await Promise.allSettled(o)}catch(e){console.error("[CachePreloader] Error loading enabled clouds:",e)}}_backgroundPreloadOtherPages(e){if(this.isPreloading)return;this.isPreloading=!0;let t=new Set(d.pages[e]),o=new Set;Object.keys(d.pages).filter(t=>t!==e).forEach(e=>{d.pages[e].forEach(e=>{t.has(e)||o.add(e)})}),console.log("[CachePreloader] Background preloading ".concat(o.size," unique functions: ").concat(Array.from(o).join(", "))),Promise.allSettled(Array.from(o).map(async e=>{try{if(d.base[e]){let{fn:t,args:o}=d.base[e];await r.default.get(t,o),this._markAsPreloaded(t,o)}else"getEnabledClouds"===e&&await this._loadEnabledCloudsForAllWorkspaces(!1);console.log("[CachePreloader] Background loaded function: ".concat(e))}catch(t){console.error("[CachePreloader] Background load failed for function ".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(d.base).map(t=>{let[o,{fn:a,args:n}]=t;return e&&r.default.invalidate(a,n),r.default.get(a,n).catch(e=>{console.error("[CachePreloader] Failed to preload ".concat(o,":"),e)})});await Promise.allSettled(t),console.log("[CachePreloader] Base functions preloaded")}getCacheStats(){return{...r.default.getStats(),isPreloading:this.isPreloading}}wasRecentlyPreloaded(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],o=this._generateKey(e,t),r=this.recentlyPreloaded.get(o);if(!r)return!1;let a=Date.now()-r<this.PRELOAD_GRACE_PERIOD;return a||this.recentlyPreloaded.delete(o),a}_markAsPreloaded(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],o=this._generateKey(e,t);this.recentlyPreloaded.set(o,Date.now())}_generateKey(e,t){let o=e.toString(),r=this._simpleHash(o),a=t.length>0?JSON.stringify(t):"";return"".concat(r,"_").concat(a)}_simpleHash(e){let t=5381;for(let o=0;o<e.length;o++)t=(t<<5)+t+e.charCodeAt(o);return t>>>0}clearCache(){r.default.clear(),this.isPreloading=!1,this.preloadPromises.clear(),this.recentlyPreloaded.clear(),console.log("[CachePreloader] Cache cleared")}constructor(){this.isPreloading=!1,this.preloadPromises=new Map,this.recentlyPreloaded=new Map,this.PRELOAD_GRACE_PERIOD=5e3}}let f=new g;r.default.setPreloader(f),t.ZP=f}}]);
|