skypilot-nightly 1.0.0.dev20250623__py3-none-any.whl → 1.0.0.dev20250625__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.
- sky/__init__.py +2 -2
- sky/admin_policy.py +16 -5
- sky/backends/__init__.py +2 -1
- sky/backends/backend_utils.py +38 -11
- sky/backends/cloud_vm_ray_backend.py +52 -18
- sky/client/cli/command.py +264 -25
- sky/client/sdk.py +119 -85
- sky/clouds/aws.py +10 -7
- sky/clouds/azure.py +10 -7
- sky/clouds/cloud.py +2 -0
- sky/clouds/cudo.py +2 -0
- sky/clouds/do.py +10 -7
- sky/clouds/fluidstack.py +2 -0
- sky/clouds/gcp.py +10 -7
- sky/clouds/hyperbolic.py +10 -7
- sky/clouds/ibm.py +2 -0
- sky/clouds/kubernetes.py +27 -9
- sky/clouds/lambda_cloud.py +10 -7
- sky/clouds/nebius.py +10 -7
- sky/clouds/oci.py +10 -7
- sky/clouds/paperspace.py +10 -7
- sky/clouds/runpod.py +10 -7
- sky/clouds/scp.py +10 -7
- sky/clouds/vast.py +10 -7
- sky/clouds/vsphere.py +2 -0
- sky/core.py +89 -15
- sky/dag.py +14 -0
- sky/dashboard/out/404.html +1 -1
- sky/dashboard/out/_next/static/ZWdSYkqVe3WjnFR8ocqoG/_buildManifest.js +1 -0
- sky/dashboard/out/_next/static/chunks/230-d6e363362017ff3a.js +1 -0
- sky/dashboard/out/_next/static/chunks/310.2671028c20e892c7.js +16 -0
- sky/dashboard/out/_next/static/chunks/37-1f1e94f5a561202a.js +6 -0
- sky/dashboard/out/_next/static/chunks/42.bc85e5b1a4debf22.js +6 -0
- sky/dashboard/out/_next/static/chunks/470-92dd1614396389be.js +1 -0
- sky/dashboard/out/_next/static/chunks/{513.211357a2914a34b2.js → 513.309df9e18a9ff005.js} +1 -1
- sky/dashboard/out/_next/static/chunks/544.110e53813fb98e2e.js +1 -0
- sky/dashboard/out/_next/static/chunks/645.961f08e39b8ce447.js +1 -0
- sky/dashboard/out/_next/static/chunks/66-66ae330df2d3c1c7.js +1 -0
- sky/dashboard/out/_next/static/chunks/682.00e56a220dd26fe1.js +6 -0
- sky/dashboard/out/_next/static/chunks/697.6460bf72e760addd.js +20 -0
- sky/dashboard/out/_next/static/chunks/856-cdf66268ec878d0c.js +1 -0
- sky/dashboard/out/_next/static/chunks/938-068520cc11738deb.js +1 -0
- sky/dashboard/out/_next/static/chunks/969-d3a0b53f728d280a.js +1 -0
- sky/dashboard/out/_next/static/chunks/989-db34c16ad7ea6155.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/{_app-c416e87d5c2715cf.js → _app-0ef7418d1a3822f3.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-aff040d7bc5d0086.js +6 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-32ce4f49f2261f55.js +6 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters-4aa031d1f42723d8.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/config-3102d02a188f04b3.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/infra/[context]-6f1e02e31eecb5ce.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/infra-fd5dc8a91bd9169a.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-e4b23128db0774cd.js +16 -0
- sky/dashboard/out/_next/static/chunks/pages/jobs-26da173e20af16e4.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/users-ce29e7420385563d.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/volumes-476b670ef33d1ecd.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/workspace/new-09ae0f6f972aa871.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-c4ff1ec05e2f3daf.js → [name]-0b4c662a25e4747a.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/workspaces-862b120406461b10.js +1 -0
- sky/dashboard/out/_next/static/chunks/webpack-6133dc1e928bd0b5.js +1 -0
- sky/dashboard/out/_next/static/css/b23cb0257bf96c51.css +3 -0
- 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.html +1 -1
- sky/dashboard/out/users.html +1 -1
- sky/dashboard/out/volumes.html +1 -0
- 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/storage_utils.py +2 -4
- sky/exceptions.py +26 -0
- sky/execution.py +5 -0
- sky/global_user_state.py +263 -20
- sky/jobs/client/sdk.py +13 -12
- sky/jobs/controller.py +5 -1
- sky/jobs/scheduler.py +4 -3
- sky/jobs/server/core.py +121 -51
- sky/jobs/state.py +15 -0
- sky/jobs/utils.py +114 -8
- sky/models.py +16 -0
- sky/provision/__init__.py +26 -0
- sky/provision/kubernetes/__init__.py +3 -0
- sky/provision/kubernetes/instance.py +38 -77
- sky/provision/kubernetes/utils.py +52 -2
- sky/provision/kubernetes/volume.py +147 -0
- sky/resources.py +20 -76
- sky/serve/client/sdk.py +13 -13
- sky/serve/server/core.py +5 -1
- sky/server/common.py +40 -5
- sky/server/constants.py +5 -1
- sky/server/metrics.py +105 -0
- sky/server/requests/executor.py +30 -14
- sky/server/requests/payloads.py +22 -3
- sky/server/requests/requests.py +59 -2
- sky/server/rest.py +152 -0
- sky/server/server.py +70 -19
- sky/server/state.py +20 -0
- sky/server/stream_utils.py +8 -3
- sky/server/uvicorn.py +153 -13
- sky/setup_files/dependencies.py +2 -0
- sky/skylet/constants.py +19 -14
- sky/task.py +141 -43
- sky/templates/jobs-controller.yaml.j2 +12 -1
- sky/templates/kubernetes-ray.yml.j2 +31 -2
- sky/users/permission.py +2 -0
- sky/utils/admin_policy_utils.py +5 -1
- sky/utils/cli_utils/status_utils.py +25 -17
- sky/utils/command_runner.py +118 -12
- sky/utils/command_runner.pyi +57 -0
- sky/utils/common_utils.py +9 -1
- sky/utils/context.py +3 -1
- sky/utils/controller_utils.py +1 -2
- sky/utils/resources_utils.py +66 -0
- sky/utils/rich_utils.py +6 -0
- sky/utils/schemas.py +180 -38
- sky/utils/status_lib.py +10 -0
- sky/utils/validator.py +11 -1
- sky/volumes/__init__.py +0 -0
- sky/volumes/client/__init__.py +0 -0
- sky/volumes/client/sdk.py +64 -0
- sky/volumes/server/__init__.py +0 -0
- sky/volumes/server/core.py +199 -0
- sky/volumes/server/server.py +85 -0
- sky/volumes/utils.py +158 -0
- sky/volumes/volume.py +198 -0
- {skypilot_nightly-1.0.0.dev20250623.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/METADATA +2 -1
- {skypilot_nightly-1.0.0.dev20250623.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/RECORD +139 -123
- sky/dashboard/out/_next/static/F4kiZ6Zh72jA6HzZ3ncFo/_buildManifest.js +0 -1
- sky/dashboard/out/_next/static/chunks/350.9e123a4551f68b0d.js +0 -1
- sky/dashboard/out/_next/static/chunks/37-3a4d77ad62932eaf.js +0 -6
- sky/dashboard/out/_next/static/chunks/42.d39e24467181b06b.js +0 -6
- sky/dashboard/out/_next/static/chunks/470-4d1a5dbe58a8a2b9.js +0 -1
- sky/dashboard/out/_next/static/chunks/641.c8e452bc5070a630.js +0 -1
- sky/dashboard/out/_next/static/chunks/682.4dd5dc116f740b5f.js +0 -6
- sky/dashboard/out/_next/static/chunks/760-a89d354797ce7af5.js +0 -1
- sky/dashboard/out/_next/static/chunks/856-c2c39c0912285e54.js +0 -1
- sky/dashboard/out/_next/static/chunks/901-b424d293275e1fd7.js +0 -1
- sky/dashboard/out/_next/static/chunks/938-1493ac755eadeb35.js +0 -1
- sky/dashboard/out/_next/static/chunks/969-20d54a9d998dc102.js +0 -1
- sky/dashboard/out/_next/static/chunks/984.ae8c08791d274ca0.js +0 -50
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-89216c616dbaa9c5.js +0 -6
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-36bc0962129f72df.js +0 -6
- sky/dashboard/out/_next/static/chunks/pages/clusters-82a651dbad53ec6e.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/config-497a35a7ed49734a.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/infra/[context]-d2910be98e9227cb.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/infra-780860bcc1103945.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-cf490d1fa38f3740.js +0 -16
- sky/dashboard/out/_next/static/chunks/pages/jobs-336ab80e270ce2ce.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/users-928edf039219e47b.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/workspace/new-31aa8bdcb7592635.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/workspaces-82e6601baa5dd280.js +0 -1
- sky/dashboard/out/_next/static/chunks/webpack-0263b00d6a10e64a.js +0 -1
- sky/dashboard/out/_next/static/css/6c12ecc3bd2239b6.css +0 -3
- /sky/dashboard/out/_next/static/{F4kiZ6Zh72jA6HzZ3ncFo → ZWdSYkqVe3WjnFR8ocqoG}/_ssgManifest.js +0 -0
- /sky/dashboard/out/_next/static/chunks/{843-b3040e493f6e7947.js → 843-07d25a7e64462fd8.js} +0 -0
- /sky/dashboard/out/_next/static/chunks/{973-db3c97c2bfbceb65.js → 973-5b5019ba333e8d62.js} +0 -0
- {skypilot_nightly-1.0.0.dev20250623.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20250623.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250623.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/licenses/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250623.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/top_level.txt +0 -0
sky/client/cli/command.py
CHANGED
@@ -81,6 +81,8 @@ from sky.utils import subprocess_utils
|
|
81
81
|
from sky.utils import timeline
|
82
82
|
from sky.utils import ux_utils
|
83
83
|
from sky.utils.cli_utils import status_utils
|
84
|
+
from sky.volumes import utils as volumes_utils
|
85
|
+
from sky.volumes.client import sdk as volumes_sdk
|
84
86
|
|
85
87
|
if typing.TYPE_CHECKING:
|
86
88
|
import types
|
@@ -202,13 +204,14 @@ def _get_cluster_records_and_set_ssh_config(
|
|
202
204
|
|
203
205
|
|
204
206
|
def _get_glob_matches(candidate_names: List[str],
|
205
|
-
glob_patterns: List[str]
|
207
|
+
glob_patterns: List[str],
|
208
|
+
resource_type: str = 'Storage') -> List[str]:
|
206
209
|
"""Returns a list of names that match the glob pattern."""
|
207
210
|
glob_storages = []
|
208
211
|
for glob_pattern in glob_patterns:
|
209
212
|
glob_storage = fnmatch.filter(candidate_names, glob_pattern)
|
210
213
|
if not glob_storage:
|
211
|
-
click.echo(f'
|
214
|
+
click.echo(f'{resource_type} {glob_pattern} not found.')
|
212
215
|
glob_storages.extend(glob_storage)
|
213
216
|
return list(set(glob_storages))
|
214
217
|
|
@@ -290,6 +293,19 @@ def _complete_storage_name(ctx: click.Context, param: click.Parameter,
|
|
290
293
|
return response.json()
|
291
294
|
|
292
295
|
|
296
|
+
def _complete_volume_name(ctx: click.Context, param: click.Parameter,
|
297
|
+
incomplete: str) -> List[str]:
|
298
|
+
"""Handle shell completion for volume names."""
|
299
|
+
del ctx, param # Unused.
|
300
|
+
response = requests_lib.get(
|
301
|
+
f'{server_common.get_server_url()}'
|
302
|
+
f'/api/completion/volume_name?incomplete={incomplete}',
|
303
|
+
timeout=2.0,
|
304
|
+
)
|
305
|
+
response.raise_for_status()
|
306
|
+
return response.json()
|
307
|
+
|
308
|
+
|
293
309
|
def _complete_file_name(ctx: click.Context, param: click.Parameter,
|
294
310
|
incomplete: str) -> List[str]:
|
295
311
|
"""Handle shell completion for file names.
|
@@ -531,8 +547,9 @@ def _parse_override_params(
|
|
531
547
|
return override_params
|
532
548
|
|
533
549
|
|
534
|
-
def
|
535
|
-
|
550
|
+
def _check_yaml_only(
|
551
|
+
entrypoint: str) -> Tuple[bool, Optional[Dict[str, Any]], bool, str]:
|
552
|
+
"""Checks if entrypoint is a readable YAML file without confirmation.
|
536
553
|
|
537
554
|
Args:
|
538
555
|
entrypoint: Path to a YAML file.
|
@@ -580,6 +597,17 @@ def _check_yaml(entrypoint: str) -> Tuple[bool, Optional[Dict[str, Any]]]:
|
|
580
597
|
invalid_reason = ('yaml.safe_load() failed. Please check if the'
|
581
598
|
' path is correct.')
|
582
599
|
is_yaml = False
|
600
|
+
return is_yaml, result, yaml_file_provided, invalid_reason
|
601
|
+
|
602
|
+
|
603
|
+
def _check_yaml(entrypoint: str) -> Tuple[bool, Optional[Dict[str, Any]]]:
|
604
|
+
"""Checks if entrypoint is a readable YAML file.
|
605
|
+
|
606
|
+
Args:
|
607
|
+
entrypoint: Path to a YAML file.
|
608
|
+
"""
|
609
|
+
is_yaml, result, yaml_file_provided, invalid_reason = _check_yaml_only(
|
610
|
+
entrypoint)
|
583
611
|
if not is_yaml:
|
584
612
|
if yaml_file_provided:
|
585
613
|
click.confirm(
|
@@ -632,7 +660,6 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
|
|
632
660
|
field_to_ignore: Optional[List[str]] = None,
|
633
661
|
# job launch specific
|
634
662
|
job_recovery: Optional[str] = None,
|
635
|
-
priority: Optional[int] = None,
|
636
663
|
config_override: Optional[Dict[str, Any]] = None,
|
637
664
|
) -> Union[sky.Task, sky.Dag]:
|
638
665
|
"""Creates a task or a dag from an entrypoint with overrides.
|
@@ -714,9 +741,6 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
|
|
714
741
|
task.num_nodes = num_nodes
|
715
742
|
if name is not None:
|
716
743
|
task.name = name
|
717
|
-
# job launch specific.
|
718
|
-
if priority is not None:
|
719
|
-
task.set_job_priority(priority)
|
720
744
|
return task
|
721
745
|
|
722
746
|
|
@@ -1243,7 +1267,7 @@ def _handle_jobs_queue_request(
|
|
1243
1267
|
try:
|
1244
1268
|
if not is_called_by_user:
|
1245
1269
|
usage_lib.messages.usage.set_internal()
|
1246
|
-
managed_jobs_ = sdk.
|
1270
|
+
managed_jobs_ = sdk.stream_and_get(request_id)
|
1247
1271
|
num_in_progress_jobs = len(set(job['job_id'] for job in managed_jobs_))
|
1248
1272
|
except exceptions.ClusterNotUpError as e:
|
1249
1273
|
controller_status = e.cluster_status
|
@@ -1800,8 +1824,13 @@ def status(verbose: bool, refresh: bool, ip: bool, endpoints: bool,
|
|
1800
1824
|
@cli.command()
|
1801
1825
|
@flags.config_option(expose_value=False)
|
1802
1826
|
@flags.all_option('Show all cluster information.')
|
1827
|
+
@click.option('--days',
|
1828
|
+
default=30,
|
1829
|
+
type=int,
|
1830
|
+
help='Show clusters from the last N days. Default is 30 days. '
|
1831
|
+
'If set to 0, show all clusters.')
|
1803
1832
|
@usage_lib.entrypoint
|
1804
|
-
def cost_report(all: bool): # pylint: disable=redefined-builtin
|
1833
|
+
def cost_report(all: bool, days: int): # pylint: disable=redefined-builtin
|
1805
1834
|
# NOTE(dev): Keep the docstring consistent between the Python API and CLI.
|
1806
1835
|
"""Show estimated costs for launched clusters.
|
1807
1836
|
|
@@ -1820,13 +1849,22 @@ def cost_report(all: bool): # pylint: disable=redefined-builtin
|
|
1820
1849
|
|
1821
1850
|
- Clusters that were terminated/stopped on the cloud console.
|
1822
1851
|
"""
|
1823
|
-
|
1852
|
+
days_to_query: Optional[int] = days
|
1853
|
+
if days == 0:
|
1854
|
+
days_to_query = None
|
1855
|
+
cluster_records = sdk.get(sdk.cost_report(days=days_to_query))
|
1824
1856
|
|
1825
1857
|
normal_cluster_records = []
|
1826
1858
|
controllers = dict()
|
1827
1859
|
for cluster_record in cluster_records:
|
1828
1860
|
cluster_name = cluster_record['name']
|
1829
|
-
|
1861
|
+
try:
|
1862
|
+
controller = controller_utils.Controllers.from_name(cluster_name)
|
1863
|
+
except AssertionError:
|
1864
|
+
# There could be some old controller clusters from previous
|
1865
|
+
# versions that we should not show in the cost report.
|
1866
|
+
logger.debug(f'Cluster {cluster_name} is not a controller cluster.')
|
1867
|
+
continue
|
1830
1868
|
if controller is not None:
|
1831
1869
|
controller_name = controller.value.name
|
1832
1870
|
# to display most recent entry for each controller cluster
|
@@ -1839,10 +1877,14 @@ def cost_report(all: bool): # pylint: disable=redefined-builtin
|
|
1839
1877
|
total_cost = status_utils.get_total_cost_of_displayed_records(
|
1840
1878
|
normal_cluster_records, all)
|
1841
1879
|
|
1842
|
-
status_utils.show_cost_report_table(normal_cluster_records,
|
1880
|
+
status_utils.show_cost_report_table(normal_cluster_records,
|
1881
|
+
all,
|
1882
|
+
days=days_to_query)
|
1843
1883
|
for controller_name, cluster_record in controllers.items():
|
1844
|
-
status_utils.show_cost_report_table(
|
1845
|
-
|
1884
|
+
status_utils.show_cost_report_table([cluster_record],
|
1885
|
+
all,
|
1886
|
+
controller_name=controller_name,
|
1887
|
+
days=days_to_query)
|
1846
1888
|
total_cost += cluster_record['total_cost']
|
1847
1889
|
|
1848
1890
|
click.echo(f'\n{colorama.Style.BRIGHT}'
|
@@ -2643,6 +2685,23 @@ def _hint_or_raise_for_down_jobs_controller(controller_name: str,
|
|
2643
2685
|
# the controller being STOPPED or being firstly launched, i.e.,
|
2644
2686
|
# there is no in-prgress managed jobs.
|
2645
2687
|
managed_jobs_ = []
|
2688
|
+
except exceptions.InconsistentConsolidationModeError:
|
2689
|
+
# If this error is raised, it means the user switched to the
|
2690
|
+
# consolidation mode but the previous controller cluster is still
|
2691
|
+
# running. We should allow the user to tear down the controller
|
2692
|
+
# cluster in this case.
|
2693
|
+
with skypilot_config.override_skypilot_config(
|
2694
|
+
{'jobs': {
|
2695
|
+
'controller': {
|
2696
|
+
'consolidation_mode': False
|
2697
|
+
}
|
2698
|
+
}}):
|
2699
|
+
# Check again with the consolidation mode disabled. This is to
|
2700
|
+
# make sure there is no in-progress managed jobs.
|
2701
|
+
request_id = managed_jobs.queue(refresh=False,
|
2702
|
+
skip_finished=True,
|
2703
|
+
all_users=True)
|
2704
|
+
managed_jobs_ = sdk.stream_and_get(request_id)
|
2646
2705
|
|
2647
2706
|
msg = (f'{colorama.Fore.YELLOW}WARNING: Tearing down the managed '
|
2648
2707
|
'jobs controller. Please be aware of the following:'
|
@@ -3736,6 +3795,196 @@ def storage_delete(names: List[str], all: bool, yes: bool, async_call: bool): #
|
|
3736
3795
|
f'{colorama.Style.RESET_ALL}')
|
3737
3796
|
|
3738
3797
|
|
3798
|
+
@cli.group(cls=_NaturalOrderGroup)
|
3799
|
+
def volumes():
|
3800
|
+
"""SkyPilot Volumes CLI."""
|
3801
|
+
pass
|
3802
|
+
|
3803
|
+
|
3804
|
+
@volumes.command('apply', cls=_DocumentedCodeCommand)
|
3805
|
+
@flags.config_option(expose_value=False)
|
3806
|
+
@click.argument('entrypoint',
|
3807
|
+
required=False,
|
3808
|
+
type=str,
|
3809
|
+
nargs=-1,
|
3810
|
+
**_get_shell_complete_args(_complete_file_name))
|
3811
|
+
@click.option('--name',
|
3812
|
+
'-n',
|
3813
|
+
required=False,
|
3814
|
+
type=str,
|
3815
|
+
help='Volume name. Override the name defined in the YAML.')
|
3816
|
+
@click.option('--infra',
|
3817
|
+
required=False,
|
3818
|
+
type=str,
|
3819
|
+
help='Infra. Format: k8s, k8s/context-name. '
|
3820
|
+
'Override the infra defined in the YAML.')
|
3821
|
+
@click.option(
|
3822
|
+
'--type',
|
3823
|
+
required=False,
|
3824
|
+
type=str,
|
3825
|
+
help='Volume type. Format: pvc. Override the type defined in the YAML.')
|
3826
|
+
@click.option('--size',
|
3827
|
+
required=False,
|
3828
|
+
type=str,
|
3829
|
+
help='Volume size. Override the size defined in the YAML.')
|
3830
|
+
@click.option('--yes',
|
3831
|
+
'-y',
|
3832
|
+
is_flag=True,
|
3833
|
+
default=False,
|
3834
|
+
required=False,
|
3835
|
+
help='Skip confirmation prompt.')
|
3836
|
+
@_add_click_options(flags.COMMON_OPTIONS)
|
3837
|
+
@usage_lib.entrypoint
|
3838
|
+
def volumes_apply(
|
3839
|
+
entrypoint: Optional[Tuple[str, ...]],
|
3840
|
+
name: Optional[str],
|
3841
|
+
infra: Optional[str],
|
3842
|
+
type: Optional[str], # pylint: disable=redefined-builtin
|
3843
|
+
size: Optional[str],
|
3844
|
+
yes: bool,
|
3845
|
+
async_call: bool):
|
3846
|
+
"""Apply a volume.
|
3847
|
+
|
3848
|
+
Examples:
|
3849
|
+
|
3850
|
+
.. code-block:: bash
|
3851
|
+
|
3852
|
+
# Apply a volume from a YAML file.
|
3853
|
+
sky volumes apply volume.yaml
|
3854
|
+
\b
|
3855
|
+
# Apply a volume from a command.
|
3856
|
+
sky volumes apply --name pvc1 --infra k8s --type pvc --size 100Gi
|
3857
|
+
"""
|
3858
|
+
# pylint: disable=import-outside-toplevel
|
3859
|
+
from sky.volumes import volume as volume_lib
|
3860
|
+
|
3861
|
+
volume_config_dict: Dict[str, Any] = {}
|
3862
|
+
if entrypoint is not None and len(entrypoint) > 0:
|
3863
|
+
entrypoint_str = ' '.join(entrypoint)
|
3864
|
+
is_yaml, yaml_config, yaml_file_provided, invalid_reason = (
|
3865
|
+
_check_yaml_only(entrypoint_str))
|
3866
|
+
if not is_yaml:
|
3867
|
+
if yaml_file_provided:
|
3868
|
+
raise click.BadParameter(f'{entrypoint_str!r} looks like a '
|
3869
|
+
f'yaml path but {invalid_reason}')
|
3870
|
+
else:
|
3871
|
+
raise click.BadParameter(
|
3872
|
+
f'{entrypoint_str!r} needs to be a YAML file')
|
3873
|
+
if yaml_config is not None:
|
3874
|
+
volume_config_dict = yaml_config.copy()
|
3875
|
+
|
3876
|
+
# Create Volume instance
|
3877
|
+
volume = volume_lib.Volume.from_dict(volume_config_dict)
|
3878
|
+
|
3879
|
+
# Normalize the volume config with CLI options
|
3880
|
+
volume.normalize_config(name=name, infra=infra, type=type, size=size)
|
3881
|
+
|
3882
|
+
logger.debug(f'Volume config: {volume.to_dict()}')
|
3883
|
+
|
3884
|
+
if not yes:
|
3885
|
+
click.confirm(f'Proceed to create volume {volume.name!r}?',
|
3886
|
+
default=True,
|
3887
|
+
abort=True,
|
3888
|
+
show_default=True)
|
3889
|
+
|
3890
|
+
# Call SDK to create volume
|
3891
|
+
try:
|
3892
|
+
request_id = volumes_sdk.apply(volume)
|
3893
|
+
_async_call_or_wait(request_id, async_call, 'sky.volumes.apply')
|
3894
|
+
except RuntimeError as e:
|
3895
|
+
logger.error(f'{colorama.Fore.RED}Error applying volume: '
|
3896
|
+
f'{common_utils.format_exception(e, use_bracket=True)}'
|
3897
|
+
f'{colorama.Style.RESET_ALL}')
|
3898
|
+
|
3899
|
+
|
3900
|
+
@volumes.command('ls', cls=_DocumentedCodeCommand)
|
3901
|
+
@flags.config_option(expose_value=False)
|
3902
|
+
@click.option('--verbose',
|
3903
|
+
'-v',
|
3904
|
+
default=False,
|
3905
|
+
is_flag=True,
|
3906
|
+
required=False,
|
3907
|
+
help='Show all information in full.')
|
3908
|
+
@usage_lib.entrypoint
|
3909
|
+
def volumes_ls(verbose: bool):
|
3910
|
+
"""List volumes managed by SkyPilot."""
|
3911
|
+
request_id = volumes_sdk.ls()
|
3912
|
+
all_volumes = sdk.stream_and_get(request_id)
|
3913
|
+
volume_table = volumes_utils.format_volume_table(all_volumes,
|
3914
|
+
show_all=verbose)
|
3915
|
+
click.echo(volume_table)
|
3916
|
+
|
3917
|
+
|
3918
|
+
@volumes.command('delete', cls=_DocumentedCodeCommand)
|
3919
|
+
@flags.config_option(expose_value=False)
|
3920
|
+
@click.argument('names',
|
3921
|
+
required=False,
|
3922
|
+
type=str,
|
3923
|
+
nargs=-1,
|
3924
|
+
**_get_shell_complete_args(_complete_volume_name))
|
3925
|
+
@click.option('--all',
|
3926
|
+
'-a',
|
3927
|
+
default=False,
|
3928
|
+
is_flag=True,
|
3929
|
+
required=False,
|
3930
|
+
help='Delete all volumes.')
|
3931
|
+
@click.option('--yes',
|
3932
|
+
'-y',
|
3933
|
+
default=False,
|
3934
|
+
is_flag=True,
|
3935
|
+
required=False,
|
3936
|
+
help='Skip confirmation prompt.')
|
3937
|
+
@_add_click_options(flags.COMMON_OPTIONS)
|
3938
|
+
@usage_lib.entrypoint
|
3939
|
+
def volumes_delete(names: List[str], all: bool, yes: bool, async_call: bool): # pylint: disable=redefined-builtin
|
3940
|
+
"""Delete volumes.
|
3941
|
+
|
3942
|
+
Examples:
|
3943
|
+
|
3944
|
+
.. code-block:: bash
|
3945
|
+
|
3946
|
+
# Delete two volumes.
|
3947
|
+
sky volumes delete pvc1 pvc2
|
3948
|
+
\b
|
3949
|
+
# Delete all volumes matching glob pattern 'pvc*'.
|
3950
|
+
sky volumes delete "pvc*"
|
3951
|
+
\b
|
3952
|
+
# Delete all volumes.
|
3953
|
+
sky volumes delete -a
|
3954
|
+
"""
|
3955
|
+
if sum([bool(names), all]) != 1:
|
3956
|
+
raise click.UsageError('Either --all or a name must be specified.')
|
3957
|
+
all_volumes = sdk.get(volumes_sdk.ls())
|
3958
|
+
if all:
|
3959
|
+
if not all_volumes:
|
3960
|
+
click.echo('No volumes to delete.')
|
3961
|
+
return
|
3962
|
+
names = [volume['name'] for volume in all_volumes]
|
3963
|
+
else:
|
3964
|
+
existing_volume_names = [volume['name'] for volume in all_volumes]
|
3965
|
+
names = _get_glob_matches(existing_volume_names,
|
3966
|
+
names,
|
3967
|
+
resource_type='Volume')
|
3968
|
+
if names:
|
3969
|
+
if not yes:
|
3970
|
+
volume_names = ', '.join(names)
|
3971
|
+
volume_str = 'volumes' if len(names) > 1 else 'volume'
|
3972
|
+
click.confirm(
|
3973
|
+
f'Deleting {len(names)} {volume_str}: '
|
3974
|
+
f'{volume_names}. Proceed?',
|
3975
|
+
default=True,
|
3976
|
+
abort=True,
|
3977
|
+
show_default=True)
|
3978
|
+
|
3979
|
+
try:
|
3980
|
+
_async_call_or_wait(volumes_sdk.delete(names), async_call,
|
3981
|
+
'sky.volumes.delete')
|
3982
|
+
except Exception as e: # pylint: disable=broad-except
|
3983
|
+
logger.error(f'{colorama.Fore.RED}Error deleting volumes {names}: '
|
3984
|
+
f'{common_utils.format_exception(e, use_bracket=True)}'
|
3985
|
+
f'{colorama.Style.RESET_ALL}')
|
3986
|
+
|
3987
|
+
|
3739
3988
|
@cli.group(cls=_NaturalOrderGroup)
|
3740
3989
|
def jobs():
|
3741
3990
|
"""Managed Jobs CLI (jobs with auto-recovery)."""
|
@@ -3762,14 +4011,6 @@ def jobs():
|
|
3762
4011
|
default=None,
|
3763
4012
|
type=str,
|
3764
4013
|
help='Recovery strategy to use for managed jobs.')
|
3765
|
-
@click.option('--priority',
|
3766
|
-
type=click.IntRange(constants.MIN_PRIORITY,
|
3767
|
-
constants.MAX_PRIORITY),
|
3768
|
-
default=None,
|
3769
|
-
show_default=True,
|
3770
|
-
help=f'Job priority from ({constants.MIN_PRIORITY} '
|
3771
|
-
f'to {constants.MAX_PRIORITY}). '
|
3772
|
-
f'Default: {constants.DEFAULT_PRIORITY}.')
|
3773
4014
|
@click.option(
|
3774
4015
|
'--detach-run',
|
3775
4016
|
'-d',
|
@@ -3804,7 +4045,6 @@ def jobs_launch(
|
|
3804
4045
|
disk_tier: Optional[str],
|
3805
4046
|
network_tier: Optional[str],
|
3806
4047
|
ports: Tuple[str],
|
3807
|
-
priority: Optional[int],
|
3808
4048
|
detach_run: bool,
|
3809
4049
|
yes: bool,
|
3810
4050
|
async_call: bool,
|
@@ -3853,7 +4093,6 @@ def jobs_launch(
|
|
3853
4093
|
network_tier=network_tier,
|
3854
4094
|
ports=ports,
|
3855
4095
|
job_recovery=job_recovery,
|
3856
|
-
priority=priority,
|
3857
4096
|
config_override=config_override,
|
3858
4097
|
)
|
3859
4098
|
|