skypilot-nightly 1.0.0.dev20250319__py3-none-any.whl → 1.0.0.dev20250320__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/adaptors/cloudflare.py +4 -0
- sky/check.py +156 -53
- sky/clouds/aws.py +5 -0
- sky/clouds/azure.py +5 -0
- sky/clouds/cloud.py +12 -0
- sky/clouds/gcp.py +55 -33
- sky/clouds/ibm.py +5 -0
- sky/clouds/oci.py +5 -0
- sky/clouds/utils/gcp_utils.py +11 -1
- sky/core.py +3 -1
- sky/data/storage.py +7 -9
- sky/global_user_state.py +30 -0
- sky/optimizer.py +2 -1
- sky/provision/gcp/config.py +3 -3
- sky/provision/gcp/constants.py +16 -2
- sky/provision/gcp/instance.py +4 -1
- sky/provision/kubernetes/utils.py +26 -21
- sky/serve/replica_managers.py +10 -1
- sky/utils/controller_utils.py +7 -1
- sky/utils/kubernetes/kubernetes_deploy_utils.py +3 -1
- {skypilot_nightly-1.0.0.dev20250319.dist-info → skypilot_nightly-1.0.0.dev20250320.dist-info}/METADATA +3 -2
- {skypilot_nightly-1.0.0.dev20250319.dist-info → skypilot_nightly-1.0.0.dev20250320.dist-info}/RECORD +27 -27
- {skypilot_nightly-1.0.0.dev20250319.dist-info → skypilot_nightly-1.0.0.dev20250320.dist-info}/WHEEL +1 -1
- {skypilot_nightly-1.0.0.dev20250319.dist-info → skypilot_nightly-1.0.0.dev20250320.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250319.dist-info → skypilot_nightly-1.0.0.dev20250320.dist-info/licenses}/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250319.dist-info → skypilot_nightly-1.0.0.dev20250320.dist-info}/top_level.txt +0 -0
sky/__init__.py
CHANGED
@@ -5,7 +5,7 @@ from typing import Optional
|
|
5
5
|
import urllib.request
|
6
6
|
|
7
7
|
# Replaced with the current commit when building the wheels.
|
8
|
-
_SKYPILOT_COMMIT_SHA = '
|
8
|
+
_SKYPILOT_COMMIT_SHA = 'a480f342522afcd17a3b30a20086f28333ddb7b5'
|
9
9
|
|
10
10
|
|
11
11
|
def _get_git_commit():
|
@@ -35,7 +35,7 @@ def _get_git_commit():
|
|
35
35
|
|
36
36
|
|
37
37
|
__commit__ = _get_git_commit()
|
38
|
-
__version__ = '1.0.0.
|
38
|
+
__version__ = '1.0.0.dev20250320'
|
39
39
|
__root_dir__ = os.path.dirname(os.path.abspath(__file__))
|
40
40
|
|
41
41
|
|
sky/adaptors/cloudflare.py
CHANGED
@@ -149,6 +149,10 @@ def create_endpoint():
|
|
149
149
|
|
150
150
|
|
151
151
|
def check_credentials() -> Tuple[bool, Optional[str]]:
|
152
|
+
return check_storage_credentials()
|
153
|
+
|
154
|
+
|
155
|
+
def check_storage_credentials() -> Tuple[bool, Optional[str]]:
|
152
156
|
"""Checks if the user has access credentials to Cloudflare R2.
|
153
157
|
|
154
158
|
Returns:
|
sky/check.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
"""Credential checks: check cloud credentials and enable clouds."""
|
2
|
+
import enum
|
2
3
|
import os
|
3
4
|
import traceback
|
4
5
|
from types import ModuleType
|
5
|
-
from typing import Dict, Iterable, List, Optional, Tuple, Union
|
6
|
+
from typing import Dict, Iterable, List, Optional, Set, Tuple, Union
|
6
7
|
|
7
8
|
import click
|
8
9
|
import colorama
|
@@ -20,44 +21,91 @@ CHECK_MARK_EMOJI = '\U00002714' # Heavy check mark unicode
|
|
20
21
|
PARTY_POPPER_EMOJI = '\U0001F389' # Party popper unicode
|
21
22
|
|
22
23
|
|
23
|
-
|
24
|
+
# Declaring CloudCapability as a subclass of str
|
25
|
+
# allows it to be JSON serializable.
|
26
|
+
class CloudCapability(str, enum.Enum):
|
27
|
+
# Compute capability.
|
28
|
+
COMPUTE = 'compute'
|
29
|
+
# Storage capability.
|
30
|
+
STORAGE = 'storage'
|
31
|
+
|
32
|
+
|
33
|
+
ALL_CAPABILITIES = [CloudCapability.COMPUTE, CloudCapability.STORAGE]
|
34
|
+
|
35
|
+
|
36
|
+
def check_capabilities(
|
24
37
|
quiet: bool = False,
|
25
38
|
verbose: bool = False,
|
26
39
|
clouds: Optional[Iterable[str]] = None,
|
27
|
-
|
40
|
+
capabilities: Optional[List[CloudCapability]] = None,
|
41
|
+
) -> Dict[str, List[CloudCapability]]:
|
28
42
|
echo = (lambda *_args, **_kwargs: None
|
29
43
|
) if quiet else lambda *args, **kwargs: click.echo(
|
30
44
|
*args, **kwargs, color=True)
|
31
45
|
echo('Checking credentials to enable clouds for SkyPilot.')
|
32
|
-
|
33
|
-
|
46
|
+
if capabilities is None:
|
47
|
+
capabilities = ALL_CAPABILITIES
|
48
|
+
assert capabilities is not None
|
49
|
+
enabled_clouds: Dict[str, List[CloudCapability]] = {}
|
50
|
+
disabled_clouds: Dict[str, List[CloudCapability]] = {}
|
51
|
+
|
52
|
+
def check_credentials(
|
53
|
+
cloud: Union[sky_clouds.Cloud, ModuleType],
|
54
|
+
capability: CloudCapability) -> Tuple[bool, Optional[str]]:
|
55
|
+
if capability == CloudCapability.COMPUTE:
|
56
|
+
return cloud.check_credentials()
|
57
|
+
elif capability == CloudCapability.STORAGE:
|
58
|
+
return cloud.check_storage_credentials()
|
59
|
+
else:
|
60
|
+
raise ValueError(f'Invalid capability: {capability}')
|
61
|
+
|
62
|
+
def get_cached_state(capability: CloudCapability) -> List[sky_clouds.Cloud]:
|
63
|
+
if capability == CloudCapability.COMPUTE:
|
64
|
+
return global_user_state.get_cached_enabled_clouds()
|
65
|
+
elif capability == CloudCapability.STORAGE:
|
66
|
+
return global_user_state.get_cached_enabled_storage_clouds()
|
67
|
+
else:
|
68
|
+
raise ValueError(f'Invalid capability: {capability}')
|
69
|
+
|
70
|
+
def set_cached_state(clouds: List[str],
|
71
|
+
capability: CloudCapability) -> None:
|
72
|
+
if capability == CloudCapability.COMPUTE:
|
73
|
+
global_user_state.set_enabled_clouds(clouds)
|
74
|
+
elif capability == CloudCapability.STORAGE:
|
75
|
+
global_user_state.set_enabled_storage_clouds(clouds)
|
76
|
+
else:
|
77
|
+
raise ValueError(f'Invalid capability: {capability}')
|
34
78
|
|
35
79
|
def check_one_cloud(
|
36
80
|
cloud_tuple: Tuple[str, Union[sky_clouds.Cloud,
|
37
81
|
ModuleType]]) -> None:
|
38
82
|
cloud_repr, cloud = cloud_tuple
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
83
|
+
assert capabilities is not None
|
84
|
+
for capability in capabilities:
|
85
|
+
with rich_utils.safe_status(f'Checking {cloud_repr}...'):
|
86
|
+
try:
|
87
|
+
ok, reason = check_credentials(cloud, capability)
|
88
|
+
except exceptions.NotSupportedError:
|
89
|
+
continue
|
90
|
+
except Exception: # pylint: disable=broad-except
|
91
|
+
# Catch all exceptions to prevent a single cloud
|
92
|
+
# from blocking the check for other clouds.
|
93
|
+
ok, reason = False, traceback.format_exc()
|
94
|
+
status_msg = ('enabled' if ok else 'disabled')
|
95
|
+
styles = {'fg': 'green', 'bold': False} if ok else {'dim': True}
|
96
|
+
echo(' ' + click.style(f'{cloud_repr}: {status_msg}', **styles) +
|
97
|
+
' ' * 30)
|
98
|
+
if ok:
|
99
|
+
enabled_clouds.setdefault(cloud_repr, []).append(capability)
|
100
|
+
if verbose and cloud is not cloudflare:
|
101
|
+
activated_account = cloud.get_active_user_identity_str()
|
102
|
+
if activated_account is not None:
|
103
|
+
echo(f' Activated account: {activated_account}')
|
104
|
+
if reason is not None:
|
105
|
+
echo(f' Hint: {reason}')
|
106
|
+
else:
|
107
|
+
disabled_clouds.setdefault(cloud_repr, []).append(capability)
|
108
|
+
echo(f' Reason: {reason}')
|
61
109
|
|
62
110
|
def get_cloud_tuple(
|
63
111
|
cloud_name: str) -> Tuple[str, Union[sky_clouds.Cloud, ModuleType]]:
|
@@ -99,33 +147,37 @@ def check(
|
|
99
147
|
for cloud_tuple in sorted(clouds_to_check):
|
100
148
|
check_one_cloud(cloud_tuple)
|
101
149
|
|
102
|
-
# Cloudflare is not a real cloud in registry.CLOUD_REGISTRY, and should
|
103
|
-
# not be inserted into the DB (otherwise `sky launch` and other code would
|
104
|
-
# error out when it's trying to look it up in the registry).
|
105
|
-
enabled_clouds_set = {
|
106
|
-
cloud for cloud in enabled_clouds if not cloud.startswith('Cloudflare')
|
107
|
-
}
|
108
|
-
disabled_clouds_set = {
|
109
|
-
cloud for cloud in disabled_clouds if not cloud.startswith('Cloudflare')
|
110
|
-
}
|
111
|
-
config_allowed_clouds_set = {
|
112
|
-
cloud for cloud in config_allowed_cloud_names
|
113
|
-
if not cloud.startswith('Cloudflare')
|
114
|
-
}
|
115
|
-
previously_enabled_clouds_set = {
|
116
|
-
repr(cloud) for cloud in global_user_state.get_cached_enabled_clouds()
|
117
|
-
}
|
118
|
-
|
119
150
|
# Determine the set of enabled clouds: (previously enabled clouds + newly
|
120
151
|
# enabled clouds - newly disabled clouds) intersected with
|
121
152
|
# config_allowed_clouds, if specified in config.yaml.
|
122
153
|
# This means that if a cloud is already enabled and is not included in
|
123
154
|
# allowed_clouds in config.yaml, it will be disabled.
|
124
|
-
all_enabled_clouds = (
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
155
|
+
all_enabled_clouds: Set[str] = set()
|
156
|
+
for capability in capabilities:
|
157
|
+
# Cloudflare is not a real cloud in registry.CLOUD_REGISTRY, and should
|
158
|
+
# not be inserted into the DB (otherwise `sky launch` and other code
|
159
|
+
# would error out when it's trying to look it up in the registry).
|
160
|
+
enabled_clouds_set = {
|
161
|
+
cloud for cloud, capabilities in enabled_clouds.items()
|
162
|
+
if capability in capabilities and not cloud.startswith('Cloudflare')
|
163
|
+
}
|
164
|
+
disabled_clouds_set = {
|
165
|
+
cloud for cloud, capabilities in disabled_clouds.items()
|
166
|
+
if capability in capabilities and not cloud.startswith('Cloudflare')
|
167
|
+
}
|
168
|
+
config_allowed_clouds_set = {
|
169
|
+
cloud for cloud in config_allowed_cloud_names
|
170
|
+
if not cloud.startswith('Cloudflare')
|
171
|
+
}
|
172
|
+
previously_enabled_clouds_set = {
|
173
|
+
repr(cloud) for cloud in get_cached_state(capability)
|
174
|
+
}
|
175
|
+
enabled_clouds_for_capability = (config_allowed_clouds_set & (
|
176
|
+
(previously_enabled_clouds_set | enabled_clouds_set) -
|
177
|
+
disabled_clouds_set))
|
178
|
+
set_cached_state(list(enabled_clouds_for_capability), capability)
|
179
|
+
all_enabled_clouds = all_enabled_clouds.union(
|
180
|
+
enabled_clouds_for_capability)
|
129
181
|
disallowed_clouds_hint = None
|
130
182
|
if disallowed_cloud_names:
|
131
183
|
disallowed_clouds_hint = (
|
@@ -160,8 +212,7 @@ def check(
|
|
160
212
|
# Pretty print for UX.
|
161
213
|
if not quiet:
|
162
214
|
enabled_clouds_str = '\n ' + '\n '.join([
|
163
|
-
_format_enabled_cloud(cloud)
|
164
|
-
for cloud in sorted(all_enabled_clouds)
|
215
|
+
_format_enabled_cloud(cloud) for cloud in sorted(enabled_clouds)
|
165
216
|
])
|
166
217
|
echo(f'\n{colorama.Fore.GREEN}{PARTY_POPPER_EMOJI} '
|
167
218
|
f'Enabled clouds {PARTY_POPPER_EMOJI}'
|
@@ -169,6 +220,23 @@ def check(
|
|
169
220
|
return enabled_clouds
|
170
221
|
|
171
222
|
|
223
|
+
# 'sky check' command and associated '/check' server endpoint
|
224
|
+
# only checks compute capability for backward compatibility.
|
225
|
+
# This necessitates setting default capability to CloudCapability.COMPUTE.
|
226
|
+
def check(
|
227
|
+
quiet: bool = False,
|
228
|
+
verbose: bool = False,
|
229
|
+
clouds: Optional[Iterable[str]] = None,
|
230
|
+
capability: CloudCapability = CloudCapability.COMPUTE,
|
231
|
+
) -> List[str]:
|
232
|
+
clouds_with_capability = []
|
233
|
+
enabled_clouds = check_capabilities(quiet, verbose, clouds, [capability])
|
234
|
+
for cloud, capabilities in enabled_clouds.items():
|
235
|
+
if capability in capabilities:
|
236
|
+
clouds_with_capability.append(cloud)
|
237
|
+
return clouds_with_capability
|
238
|
+
|
239
|
+
|
172
240
|
def get_cached_enabled_clouds_or_refresh(
|
173
241
|
raise_if_no_cloud_access: bool = False) -> List[sky_clouds.Cloud]:
|
174
242
|
"""Returns cached enabled clouds and if no cloud is enabled, refresh.
|
@@ -186,7 +254,7 @@ def get_cached_enabled_clouds_or_refresh(
|
|
186
254
|
cached_enabled_clouds = global_user_state.get_cached_enabled_clouds()
|
187
255
|
if not cached_enabled_clouds:
|
188
256
|
try:
|
189
|
-
check(quiet=True)
|
257
|
+
check(quiet=True, capability=CloudCapability.COMPUTE)
|
190
258
|
except SystemExit:
|
191
259
|
# If no cloud is enabled, check() will raise SystemExit.
|
192
260
|
# Here we catch it and raise the exception later only if
|
@@ -201,6 +269,41 @@ def get_cached_enabled_clouds_or_refresh(
|
|
201
269
|
return cached_enabled_clouds
|
202
270
|
|
203
271
|
|
272
|
+
def get_cached_enabled_storage_clouds_or_refresh(
|
273
|
+
raise_if_no_cloud_access: bool = False) -> List[sky_clouds.Cloud]:
|
274
|
+
"""Returns cached enabled storage clouds and if no cloud is enabled,
|
275
|
+
refresh.
|
276
|
+
|
277
|
+
This function will perform a refresh if no public cloud is enabled.
|
278
|
+
|
279
|
+
Args:
|
280
|
+
raise_if_no_cloud_access: if True, raise an exception if no public
|
281
|
+
cloud is enabled.
|
282
|
+
|
283
|
+
Raises:
|
284
|
+
exceptions.NoCloudAccessError: if no public cloud is enabled and
|
285
|
+
raise_if_no_cloud_access is set to True.
|
286
|
+
"""
|
287
|
+
cached_enabled_storage_clouds = (
|
288
|
+
global_user_state.get_cached_enabled_storage_clouds())
|
289
|
+
if not cached_enabled_storage_clouds:
|
290
|
+
try:
|
291
|
+
check(quiet=True, capability=CloudCapability.STORAGE)
|
292
|
+
except SystemExit:
|
293
|
+
# If no cloud is enabled, check() will raise SystemExit.
|
294
|
+
# Here we catch it and raise the exception later only if
|
295
|
+
# raise_if_no_cloud_access is set to True.
|
296
|
+
pass
|
297
|
+
cached_enabled_storage_clouds = (
|
298
|
+
global_user_state.get_cached_enabled_storage_clouds())
|
299
|
+
if raise_if_no_cloud_access and not cached_enabled_storage_clouds:
|
300
|
+
with ux_utils.print_exception_no_traceback():
|
301
|
+
raise exceptions.NoCloudAccessError(
|
302
|
+
'Cloud access is not set up. Run: '
|
303
|
+
f'{colorama.Style.BRIGHT}sky check{colorama.Style.RESET_ALL}')
|
304
|
+
return cached_enabled_storage_clouds
|
305
|
+
|
306
|
+
|
204
307
|
def get_cloud_credential_file_mounts(
|
205
308
|
excluded_clouds: Optional[Iterable[sky_clouds.Cloud]]
|
206
309
|
) -> Dict[str, str]:
|
@@ -226,7 +329,7 @@ def get_cloud_credential_file_mounts(
|
|
226
329
|
# Currently, get_cached_enabled_clouds_or_refresh() does not support r2 as
|
227
330
|
# only clouds with computing instances are marked as enabled by skypilot.
|
228
331
|
# This will be removed when cloudflare/r2 is added as a 'cloud'.
|
229
|
-
r2_is_enabled, _ = cloudflare.
|
332
|
+
r2_is_enabled, _ = cloudflare.check_storage_credentials()
|
230
333
|
if r2_is_enabled:
|
231
334
|
r2_credential_mounts = cloudflare.get_credential_file_mounts()
|
232
335
|
file_mounts.update(r2_credential_mounts)
|
sky/clouds/aws.py
CHANGED
@@ -666,6 +666,11 @@ class AWS(clouds.Cloud):
|
|
666
666
|
f'{common_utils.format_exception(e, use_bracket=True)}')
|
667
667
|
return True, hints
|
668
668
|
|
669
|
+
@classmethod
|
670
|
+
def check_storage_credentials(cls) -> Tuple[bool, Optional[str]]:
|
671
|
+
# TODO(seungjin): Check if the user has access to S3.
|
672
|
+
return cls.check_credentials()
|
673
|
+
|
669
674
|
@classmethod
|
670
675
|
def _current_identity_type(cls) -> Optional[AWSIdentityType]:
|
671
676
|
stdout = cls._aws_configure_list()
|
sky/clouds/azure.py
CHANGED
@@ -574,6 +574,11 @@ class Azure(clouds.Cloud):
|
|
574
574
|
return service_catalog.instance_type_exists(instance_type,
|
575
575
|
clouds='azure')
|
576
576
|
|
577
|
+
@classmethod
|
578
|
+
def check_storage_credentials(cls) -> Tuple[bool, Optional[str]]:
|
579
|
+
# TODO(seungjin): Check if the user has access to Azure Blob Storage.
|
580
|
+
return cls.check_credentials()
|
581
|
+
|
577
582
|
@classmethod
|
578
583
|
@annotations.lru_cache(scope='global',
|
579
584
|
maxsize=1) # Cache since getting identity is slow.
|
sky/clouds/cloud.py
CHANGED
@@ -443,6 +443,18 @@ class Cloud:
|
|
443
443
|
"""
|
444
444
|
raise NotImplementedError
|
445
445
|
|
446
|
+
@classmethod
|
447
|
+
def check_storage_credentials(cls) -> Tuple[bool, Optional[str]]:
|
448
|
+
"""Checks if the user has access credentials to this cloud's storage.
|
449
|
+
|
450
|
+
Returns a boolean of whether the user can access this cloud's storage,
|
451
|
+
and a string describing the reason if the user cannot access.
|
452
|
+
"""
|
453
|
+
# A given cloud does not support storage
|
454
|
+
# unless it overrides this method.
|
455
|
+
raise exceptions.NotSupportedError(
|
456
|
+
f'{cls._REPR} does not support storage.')
|
457
|
+
|
446
458
|
# TODO(zhwu): Make the return type immutable.
|
447
459
|
@classmethod
|
448
460
|
def get_user_identities(cls) -> Optional[List[List[str]]]:
|
sky/clouds/gcp.py
CHANGED
@@ -124,6 +124,7 @@ def _run_output(cmd):
|
|
124
124
|
|
125
125
|
|
126
126
|
def is_api_disabled(endpoint: str, project_id: str) -> bool:
|
127
|
+
# requires serviceusage.services.list
|
127
128
|
proc = subprocess.run((f'gcloud services list --project {project_id} '
|
128
129
|
f' | grep {endpoint}.googleapis.com'),
|
129
130
|
check=False,
|
@@ -719,6 +720,28 @@ class GCP(clouds.Cloud):
|
|
719
720
|
|
720
721
|
@classmethod
|
721
722
|
def check_credentials(cls) -> Tuple[bool, Optional[str]]:
|
723
|
+
"""Checks if the user has compute access credentials to this cloud."""
|
724
|
+
return cls._check_credentials( # Check APIs.
|
725
|
+
[
|
726
|
+
('compute', 'Compute Engine'),
|
727
|
+
('cloudresourcemanager', 'Cloud Resource Manager'),
|
728
|
+
('iam', 'Identity and Access Management (IAM)'),
|
729
|
+
('tpu', 'Cloud TPU'), # Keep as final element.
|
730
|
+
],
|
731
|
+
gcp_utils.get_minimal_compute_permissions())
|
732
|
+
|
733
|
+
@classmethod
|
734
|
+
def check_storage_credentials(cls) -> Tuple[bool, Optional[str]]:
|
735
|
+
"""Checks if the user has compute access credentials to this cloud."""
|
736
|
+
return cls._check_credentials( # Check APIs.
|
737
|
+
[
|
738
|
+
('storage', 'Cloud Storage'),
|
739
|
+
], gcp_utils.get_minimal_storage_permissions())
|
740
|
+
|
741
|
+
@classmethod
|
742
|
+
def _check_credentials(
|
743
|
+
cls, apis: List[Tuple[str, str]],
|
744
|
+
gcp_minimal_permissions: List[str]) -> Tuple[bool, Optional[str]]:
|
722
745
|
"""Checks if the user has access credentials to this cloud."""
|
723
746
|
try:
|
724
747
|
# pylint: disable=import-outside-toplevel,unused-import
|
@@ -783,13 +806,37 @@ class GCP(clouds.Cloud):
|
|
783
806
|
f'{cls._INDENT_PREFIX}Details: '
|
784
807
|
f'{common_utils.format_exception(e, use_bracket=True)}')
|
785
808
|
|
786
|
-
#
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
809
|
+
# pylint: disable=import-outside-toplevel,unused-import
|
810
|
+
import google.auth
|
811
|
+
|
812
|
+
# This takes user's credential info from "~/.config/gcloud/application_default_credentials.json". # pylint: disable=line-too-long
|
813
|
+
credentials, project = google.auth.default()
|
814
|
+
crm = gcp.build('cloudresourcemanager',
|
815
|
+
'v1',
|
816
|
+
credentials=credentials,
|
817
|
+
cache_discovery=False)
|
818
|
+
permissions = {'permissions': gcp_minimal_permissions}
|
819
|
+
request = crm.projects().testIamPermissions(resource=project,
|
820
|
+
body=permissions)
|
821
|
+
try:
|
822
|
+
ret_permissions = request.execute().get('permissions', [])
|
823
|
+
except gcp.gcp_auth_refresh_error_exception() as e:
|
824
|
+
return False, common_utils.format_exception(e, use_bracket=True)
|
825
|
+
|
826
|
+
diffs = set(gcp_minimal_permissions).difference(set(ret_permissions))
|
827
|
+
if diffs:
|
828
|
+
identity_str = identity[0] if identity else None
|
829
|
+
return False, (
|
830
|
+
'The following permissions are not enabled for the current '
|
831
|
+
f'GCP identity ({identity_str}):\n '
|
832
|
+
f'{diffs}\n '
|
833
|
+
'For more details, visit: https://docs.skypilot.co/en/latest/cloud-setup/cloud-permissions/gcp.html') # pylint: disable=line-too-long
|
834
|
+
|
835
|
+
# This code must be executed after the iam check above,
|
836
|
+
# as the check below for api enablement itself needs:
|
837
|
+
# - serviceusage.services.enable
|
838
|
+
# - serviceusage.services.list
|
839
|
+
# iam permissions.
|
793
840
|
enabled_api = False
|
794
841
|
for endpoint, display_name in apis:
|
795
842
|
if is_api_disabled(endpoint, project_id):
|
@@ -801,6 +848,7 @@ class GCP(clouds.Cloud):
|
|
801
848
|
suffix = ' (free of charge)'
|
802
849
|
print(f'\nEnabling {display_name} API{suffix}...')
|
803
850
|
t1 = time.time()
|
851
|
+
# requires serviceusage.services.enable
|
804
852
|
proc = subprocess.run(
|
805
853
|
f'gcloud services enable {endpoint}.googleapis.com '
|
806
854
|
f'--project {project_id}',
|
@@ -830,32 +878,6 @@ class GCP(clouds.Cloud):
|
|
830
878
|
'effect. If any SkyPilot commands/calls failed, retry after '
|
831
879
|
'some time.')
|
832
880
|
|
833
|
-
# pylint: disable=import-outside-toplevel,unused-import
|
834
|
-
import google.auth
|
835
|
-
|
836
|
-
# This takes user's credential info from "~/.config/gcloud/application_default_credentials.json". # pylint: disable=line-too-long
|
837
|
-
credentials, project = google.auth.default()
|
838
|
-
crm = gcp.build('cloudresourcemanager',
|
839
|
-
'v1',
|
840
|
-
credentials=credentials,
|
841
|
-
cache_discovery=False)
|
842
|
-
gcp_minimal_permissions = gcp_utils.get_minimal_permissions()
|
843
|
-
permissions = {'permissions': gcp_minimal_permissions}
|
844
|
-
request = crm.projects().testIamPermissions(resource=project,
|
845
|
-
body=permissions)
|
846
|
-
try:
|
847
|
-
ret_permissions = request.execute().get('permissions', [])
|
848
|
-
except gcp.gcp_auth_refresh_error_exception() as e:
|
849
|
-
return False, common_utils.format_exception(e, use_bracket=True)
|
850
|
-
|
851
|
-
diffs = set(gcp_minimal_permissions).difference(set(ret_permissions))
|
852
|
-
if diffs:
|
853
|
-
identity_str = identity[0] if identity else None
|
854
|
-
return False, (
|
855
|
-
'The following permissions are not enabled for the current '
|
856
|
-
f'GCP identity ({identity_str}):\n '
|
857
|
-
f'{diffs}\n '
|
858
|
-
'For more details, visit: https://docs.skypilot.co/en/latest/cloud-setup/cloud-permissions/gcp.html') # pylint: disable=line-too-long
|
859
881
|
return True, None
|
860
882
|
|
861
883
|
def get_credential_file_mounts(self) -> Dict[str, str]:
|
sky/clouds/ibm.py
CHANGED
@@ -433,6 +433,11 @@ class IBM(clouds.Cloud):
|
|
433
433
|
except Exception as e:
|
434
434
|
return (False, f'{str(e)}' + help_str)
|
435
435
|
|
436
|
+
@classmethod
|
437
|
+
def check_storage_credentials(cls) -> Tuple[bool, Optional[str]]:
|
438
|
+
# TODO(seungjin): Check if the user has access to IBM COS.
|
439
|
+
return cls.check_credentials()
|
440
|
+
|
436
441
|
def get_credential_file_mounts(self) -> Dict[str, str]:
|
437
442
|
"""Returns a {remote:local} credential path mapping
|
438
443
|
written to the cluster's file_mounts segment
|
sky/clouds/oci.py
CHANGED
@@ -456,6 +456,11 @@ class OCI(clouds.Cloud):
|
|
456
456
|
f'{cls._INDENT_PREFIX}Error details: '
|
457
457
|
f'{common_utils.format_exception(e, use_bracket=True)}')
|
458
458
|
|
459
|
+
@classmethod
|
460
|
+
def check_storage_credentials(cls) -> Tuple[bool, Optional[str]]:
|
461
|
+
# TODO(seungjin): Check if the user has access to OCI Object Storage.
|
462
|
+
return cls.check_credentials()
|
463
|
+
|
459
464
|
@classmethod
|
460
465
|
def check_disk_tier(
|
461
466
|
cls, instance_type: Optional[str],
|
sky/clouds/utils/gcp_utils.py
CHANGED
@@ -167,7 +167,7 @@ def _list_reservations_for_instance_type(
|
|
167
167
|
return [GCPReservation.from_dict(r) for r in json.loads(stdout)]
|
168
168
|
|
169
169
|
|
170
|
-
def
|
170
|
+
def get_minimal_compute_permissions() -> List[str]:
|
171
171
|
permissions = copy.copy(constants.VM_MINIMAL_PERMISSIONS)
|
172
172
|
if skypilot_config.get_nested(('gcp', 'vpc_name'), None) is None:
|
173
173
|
# If custom VPC is not specified, permissions to modify network are
|
@@ -179,4 +179,14 @@ def get_minimal_permissions() -> List[str]:
|
|
179
179
|
skypilot_config.get_nested(('gcp', 'specific_reservations'), [])):
|
180
180
|
permissions += constants.RESERVATION_PERMISSIONS
|
181
181
|
|
182
|
+
permissions += constants.GCP_MINIMAL_PERMISSIONS
|
183
|
+
|
184
|
+
return permissions
|
185
|
+
|
186
|
+
|
187
|
+
def get_minimal_storage_permissions() -> List[str]:
|
188
|
+
permissions = copy.copy(constants.STORAGE_MINIMAL_PERMISSIONS)
|
189
|
+
|
190
|
+
permissions += constants.GCP_MINIMAL_PERMISSIONS
|
191
|
+
|
182
192
|
return permissions
|
sky/core.py
CHANGED
@@ -1134,7 +1134,9 @@ def local_down() -> None:
|
|
1134
1134
|
# Run sky check
|
1135
1135
|
with rich_utils.safe_status(
|
1136
1136
|
ux_utils.spinner_message('Running sky check...')):
|
1137
|
-
sky_check.check(clouds=['kubernetes'],
|
1137
|
+
sky_check.check(clouds=['kubernetes'],
|
1138
|
+
quiet=True,
|
1139
|
+
capability=sky_check.CloudCapability.COMPUTE)
|
1138
1140
|
logger.info(
|
1139
1141
|
ux_utils.finishing_message('Local cluster removed.',
|
1140
1142
|
log_path=log_path,
|
sky/data/storage.py
CHANGED
@@ -82,20 +82,17 @@ def get_cached_enabled_storage_clouds_or_refresh(
|
|
82
82
|
raise_if_no_cloud_access: bool = False) -> List[str]:
|
83
83
|
# This is a temporary solution until https://github.com/skypilot-org/skypilot/issues/1943 # pylint: disable=line-too-long
|
84
84
|
# is resolved by implementing separate 'enabled_storage_clouds'
|
85
|
-
enabled_clouds = sky_check.
|
85
|
+
enabled_clouds = sky_check.get_cached_enabled_storage_clouds_or_refresh()
|
86
86
|
enabled_clouds = [str(cloud) for cloud in enabled_clouds]
|
87
87
|
|
88
|
-
|
89
|
-
cloud for cloud in enabled_clouds if cloud in STORE_ENABLED_CLOUDS
|
90
|
-
]
|
91
|
-
r2_is_enabled, _ = cloudflare.check_credentials()
|
88
|
+
r2_is_enabled, _ = cloudflare.check_storage_credentials()
|
92
89
|
if r2_is_enabled:
|
93
|
-
|
94
|
-
if raise_if_no_cloud_access and not
|
90
|
+
enabled_clouds.append(cloudflare.NAME)
|
91
|
+
if raise_if_no_cloud_access and not enabled_clouds:
|
95
92
|
raise exceptions.NoCloudAccessError(
|
96
93
|
'No cloud access available for storage. '
|
97
94
|
'Please check your cloud credentials.')
|
98
|
-
return
|
95
|
+
return enabled_clouds
|
99
96
|
|
100
97
|
|
101
98
|
def _is_storage_cloud_enabled(cloud_name: str,
|
@@ -105,7 +102,8 @@ def _is_storage_cloud_enabled(cloud_name: str,
|
|
105
102
|
return True
|
106
103
|
if try_fix_with_sky_check:
|
107
104
|
# TODO(zhwu): Only check the specified cloud to speed up.
|
108
|
-
sky_check.check(quiet=True
|
105
|
+
sky_check.check(quiet=True,
|
106
|
+
capability=sky_check.CloudCapability.STORAGE)
|
109
107
|
return _is_storage_cloud_enabled(cloud_name,
|
110
108
|
try_fix_with_sky_check=False)
|
111
109
|
return False
|
sky/global_user_state.py
CHANGED
@@ -31,6 +31,7 @@ if typing.TYPE_CHECKING:
|
|
31
31
|
logger = sky_logging.init_logger(__name__)
|
32
32
|
|
33
33
|
_ENABLED_CLOUDS_KEY = 'enabled_clouds'
|
34
|
+
_ENABLED_STORAGE_CLOUDS_KEY = 'enabled_storage_clouds'
|
34
35
|
|
35
36
|
_DB_PATH = os.path.expanduser('~/.sky/state.db')
|
36
37
|
pathlib.Path(_DB_PATH).parents[0].mkdir(parents=True, exist_ok=True)
|
@@ -817,12 +818,41 @@ def get_cached_enabled_clouds() -> List['clouds.Cloud']:
|
|
817
818
|
return enabled_clouds
|
818
819
|
|
819
820
|
|
821
|
+
def get_cached_enabled_storage_clouds() -> List['clouds.Cloud']:
|
822
|
+
rows = _DB.cursor.execute('SELECT value FROM config WHERE key = ?',
|
823
|
+
(_ENABLED_STORAGE_CLOUDS_KEY,))
|
824
|
+
ret = []
|
825
|
+
for (value,) in rows:
|
826
|
+
ret = json.loads(value)
|
827
|
+
break
|
828
|
+
enabled_clouds: List['clouds.Cloud'] = []
|
829
|
+
for c in ret:
|
830
|
+
try:
|
831
|
+
cloud = registry.CLOUD_REGISTRY.from_str(c)
|
832
|
+
except ValueError:
|
833
|
+
# Handle the case for the clouds whose support has been removed from
|
834
|
+
# SkyPilot, e.g., 'local' was a cloud in the past and may be stored
|
835
|
+
# in the database for users before #3037. We should ignore removed
|
836
|
+
# clouds and continue.
|
837
|
+
continue
|
838
|
+
if cloud is not None:
|
839
|
+
enabled_clouds.append(cloud)
|
840
|
+
return enabled_clouds
|
841
|
+
|
842
|
+
|
820
843
|
def set_enabled_clouds(enabled_clouds: List[str]) -> None:
|
821
844
|
_DB.cursor.execute('INSERT OR REPLACE INTO config VALUES (?, ?)',
|
822
845
|
(_ENABLED_CLOUDS_KEY, json.dumps(enabled_clouds)))
|
823
846
|
_DB.conn.commit()
|
824
847
|
|
825
848
|
|
849
|
+
def set_enabled_storage_clouds(enabled_storage_clouds: List[str]) -> None:
|
850
|
+
_DB.cursor.execute(
|
851
|
+
'INSERT OR REPLACE INTO config VALUES (?, ?)',
|
852
|
+
(_ENABLED_STORAGE_CLOUDS_KEY, json.dumps(enabled_storage_clouds)))
|
853
|
+
_DB.conn.commit()
|
854
|
+
|
855
|
+
|
826
856
|
def add_or_update_storage(storage_name: str,
|
827
857
|
storage_handle: 'Storage.StorageMetadata',
|
828
858
|
storage_status: status_lib.StorageStatus):
|
sky/optimizer.py
CHANGED
@@ -1225,7 +1225,8 @@ def _check_specified_clouds(dag: 'dag_lib.Dag') -> None:
|
|
1225
1225
|
# Explicitly check again to update the enabled cloud list.
|
1226
1226
|
sky_check.check(quiet=True,
|
1227
1227
|
clouds=list(clouds_need_recheck -
|
1228
|
-
global_disabled_clouds)
|
1228
|
+
global_disabled_clouds),
|
1229
|
+
capability=sky_check.CloudCapability.COMPUTE)
|
1229
1230
|
enabled_clouds = sky_check.get_cached_enabled_clouds_or_refresh(
|
1230
1231
|
raise_if_no_cloud_access=True)
|
1231
1232
|
disabled_clouds = (clouds_need_recheck -
|
sky/provision/gcp/config.py
CHANGED
@@ -297,8 +297,8 @@ def _is_permission_satisfied(service_account, crm, iam, required_permissions,
|
|
297
297
|
def _configure_iam_role(config: common.ProvisionConfig, crm, iam) -> dict:
|
298
298
|
"""Setup a gcp service account with IAM roles.
|
299
299
|
|
300
|
-
Creates a gcp service
|
301
|
-
|
300
|
+
Creates a gcp service account and binds IAM roles which allow it to control
|
301
|
+
storage/compute services. Specifically, the head node needs to have
|
302
302
|
an IAM role that allows it to create further gce instances and store items
|
303
303
|
in google cloud storage.
|
304
304
|
|
@@ -311,7 +311,7 @@ def _configure_iam_role(config: common.ProvisionConfig, crm, iam) -> dict:
|
|
311
311
|
)
|
312
312
|
service_account = _get_service_account(email, project_id, iam)
|
313
313
|
|
314
|
-
permissions = gcp_utils.
|
314
|
+
permissions = gcp_utils.get_minimal_compute_permissions()
|
315
315
|
roles = constants.DEFAULT_SERVICE_ACCOUNT_ROLES
|
316
316
|
if config.provider_config.get(constants.HAS_TPU_PROVIDER_FIELD, False):
|
317
317
|
roles = (constants.DEFAULT_SERVICE_ACCOUNT_ROLES +
|
sky/provision/gcp/constants.py
CHANGED
@@ -141,6 +141,11 @@ FIREWALL_RULES_TEMPLATE = [
|
|
141
141
|
},
|
142
142
|
]
|
143
143
|
|
144
|
+
GCP_MINIMAL_PERMISSIONS = [
|
145
|
+
'serviceusage.services.enable',
|
146
|
+
'serviceusage.services.list',
|
147
|
+
]
|
148
|
+
|
144
149
|
# A list of permissions required to run SkyPilot on GCP.
|
145
150
|
# Keep this in sync with https://docs.skypilot.co/en/latest/cloud-setup/cloud-permissions/gcp.html # pylint: disable=line-too-long
|
146
151
|
VM_MINIMAL_PERMISSIONS = [
|
@@ -170,13 +175,22 @@ VM_MINIMAL_PERMISSIONS = [
|
|
170
175
|
# Check: sky.provision.gcp.config::_is_permission_satisfied
|
171
176
|
# 'iam.serviceAccounts.actAs',
|
172
177
|
'iam.serviceAccounts.get',
|
173
|
-
'serviceusage.services.enable',
|
174
|
-
'serviceusage.services.list',
|
175
178
|
'serviceusage.services.use',
|
176
179
|
'resourcemanager.projects.get',
|
177
180
|
'resourcemanager.projects.getIamPolicy',
|
178
181
|
]
|
179
182
|
|
183
|
+
STORAGE_MINIMAL_PERMISSIONS = [
|
184
|
+
'storage.buckets.create',
|
185
|
+
'storage.buckets.get',
|
186
|
+
'storage.buckets.delete',
|
187
|
+
'storage.objects.create',
|
188
|
+
'storage.objects.update',
|
189
|
+
'storage.objects.delete',
|
190
|
+
'storage.objects.get',
|
191
|
+
'storage.objects.list',
|
192
|
+
]
|
193
|
+
|
180
194
|
# Permissions implied by GCP built-in roles. We hardcode these here, as we
|
181
195
|
# cannot get the permissions of built-in role from the GCP Python API.
|
182
196
|
# The lists are not exhaustive, but should cover the permissions listed in
|
sky/provision/gcp/instance.py
CHANGED
@@ -586,8 +586,11 @@ def open_ports(
|
|
586
586
|
}
|
587
587
|
handlers: List[Type[instance_utils.GCPInstance]] = [
|
588
588
|
instance_utils.GCPComputeInstance,
|
589
|
-
instance_utils.GCPTPUVMInstance,
|
590
589
|
]
|
590
|
+
use_tpu_vms = provider_config.get('_has_tpus', False)
|
591
|
+
if use_tpu_vms:
|
592
|
+
handlers.append(instance_utils.GCPTPUVMInstance)
|
593
|
+
|
591
594
|
handler_to_instances = _filter_instances(handlers, project_id, zone,
|
592
595
|
label_filters, lambda _: None)
|
593
596
|
operations = collections.defaultdict(list)
|
@@ -663,18 +663,25 @@ class GKEAutoscaler(Autoscaler):
|
|
663
663
|
|
664
664
|
# Check if any node pool with autoscaling enabled can
|
665
665
|
# fit the instance type.
|
666
|
-
|
667
|
-
|
666
|
+
node_pools = cluster.get('nodePools', [])
|
667
|
+
for node_pool in node_pools:
|
668
|
+
name = node_pool.get('name', '')
|
669
|
+
logger.debug(f'checking if node pool {name} '
|
668
670
|
'has autoscaling enabled.')
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
logger.debug(
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
671
|
+
autoscaling_enabled = (node_pool.get('autoscaling',
|
672
|
+
{}).get('enabled', False))
|
673
|
+
if autoscaling_enabled:
|
674
|
+
logger.debug(f'node pool {name} has autoscaling enabled. '
|
675
|
+
'Checking if it can create a node '
|
676
|
+
f'satisfying {instance_type}')
|
677
|
+
try:
|
678
|
+
if cls._check_instance_fits_gke_autoscaler_node_pool(
|
679
|
+
instance_type, node_pool):
|
680
|
+
return True
|
681
|
+
except KeyError:
|
682
|
+
logger.debug('encountered KeyError while checking if '
|
683
|
+
f'node pool {name} can create a node '
|
684
|
+
f'satisfying {instance_type}.')
|
678
685
|
return True
|
679
686
|
return False
|
680
687
|
|
@@ -776,9 +783,9 @@ class GKEAutoscaler(Autoscaler):
|
|
776
783
|
to fit the instance type.
|
777
784
|
"""
|
778
785
|
for accelerator in node_pool_accelerators:
|
779
|
-
node_accelerator_type =
|
780
|
-
get_accelerator_from_label_value(
|
781
|
-
accelerator['acceleratorType'])
|
786
|
+
node_accelerator_type = (
|
787
|
+
GKELabelFormatter.get_accelerator_from_label_value(
|
788
|
+
accelerator['acceleratorType']))
|
782
789
|
node_accelerator_count = accelerator['acceleratorCount']
|
783
790
|
if node_accelerator_type == requested_gpu_type and int(
|
784
791
|
node_accelerator_count) >= requested_gpu_count:
|
@@ -812,24 +819,22 @@ class GKEAutoscaler(Autoscaler):
|
|
812
819
|
@classmethod
|
813
820
|
def _tpu_chip_count_from_instance_type(cls, machine_type: str) -> int:
|
814
821
|
"""Infer the number of TPU chips from the instance type."""
|
815
|
-
machine_type_parts = machine_type.split('-')
|
816
822
|
# according to
|
817
823
|
# https://cloud.google.com/kubernetes-engine/docs/concepts/tpus#machine_type
|
818
824
|
# GKE TPU machine types have the format of
|
819
825
|
# ct<version>-<type>-<node-chip-count>t
|
820
826
|
logger.debug(
|
821
827
|
f'inferring TPU chip count from machine type: {machine_type}')
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
not machine_type_parts[2].strip('t').isdigit()):
|
828
|
+
pattern = r'ct[a-z0-9]+-[a-z]+-([0-9]+)t'
|
829
|
+
search = re.search(pattern, machine_type)
|
830
|
+
if search is None:
|
826
831
|
logger.debug(f'machine type {machine_type} is not a '
|
827
832
|
'valid TPU machine type format.')
|
828
833
|
return 0
|
829
|
-
num_tpu_chips =
|
834
|
+
num_tpu_chips = search.group(1)
|
830
835
|
logger.debug(
|
831
836
|
f'machine type {machine_type} has {num_tpu_chips} TPU chips.')
|
832
|
-
return num_tpu_chips
|
837
|
+
return int(num_tpu_chips)
|
833
838
|
|
834
839
|
@classmethod
|
835
840
|
def _is_node_multi_host_tpu(cls, resource_labels: dict) -> bool:
|
sky/serve/replica_managers.py
CHANGED
@@ -1205,7 +1205,16 @@ class SkyPilotReplicaManager(ReplicaManager):
|
|
1205
1205
|
for key in ['service']:
|
1206
1206
|
old_config.pop(key)
|
1207
1207
|
# Bump replica version if all fields except for service are
|
1208
|
-
# the same.
|
1208
|
+
# the same.
|
1209
|
+
# Here, we manually convert the any_of field to a set to avoid
|
1210
|
+
# only the difference in the random order of the any_of fields.
|
1211
|
+
old_config_any_of = old_config.get('resources',
|
1212
|
+
{}).pop('any_of', [])
|
1213
|
+
new_config_any_of = new_config.get('resources',
|
1214
|
+
{}).pop('any_of', [])
|
1215
|
+
if set(old_config_any_of) != set(new_config_any_of):
|
1216
|
+
continue
|
1217
|
+
# File mounts should both be empty, as update always
|
1209
1218
|
# create new buckets if they are not empty.
|
1210
1219
|
if (old_config == new_config and
|
1211
1220
|
old_config.get('file_mounts', None) == {}):
|
sky/utils/controller_utils.py
CHANGED
@@ -215,7 +215,13 @@ def _get_cloud_dependencies_installation_commands(
|
|
215
215
|
commands.append(f'echo -en "\\r{step_prefix}uv{empty_str}" &&'
|
216
216
|
f'{constants.SKY_UV_INSTALL_CMD} >/dev/null 2>&1')
|
217
217
|
|
218
|
-
|
218
|
+
enabled_compute_clouds = set(
|
219
|
+
sky_check.get_cached_enabled_clouds_or_refresh())
|
220
|
+
enabled_storage_clouds = set(
|
221
|
+
sky_check.get_cached_enabled_storage_clouds_or_refresh())
|
222
|
+
enabled_clouds = enabled_compute_clouds.union(enabled_storage_clouds)
|
223
|
+
|
224
|
+
for cloud in enabled_clouds:
|
219
225
|
cloud_python_dependencies: List[str] = copy.deepcopy(
|
220
226
|
dependencies.extras_require[cloud.canonical_name()])
|
221
227
|
|
@@ -167,7 +167,9 @@ def deploy_local_cluster(gpus: bool):
|
|
167
167
|
f'\nError: {stderr}')
|
168
168
|
# Run sky check
|
169
169
|
with rich_utils.safe_status('[bold cyan]Running sky check...'):
|
170
|
-
sky_check.check(clouds=['kubernetes'],
|
170
|
+
sky_check.check(clouds=['kubernetes'],
|
171
|
+
quiet=True,
|
172
|
+
capability=sky_check.CloudCapability.COMPUTE)
|
171
173
|
if cluster_created:
|
172
174
|
# Prepare completion message which shows CPU and GPU count
|
173
175
|
# Get number of CPUs
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: skypilot-nightly
|
3
|
-
Version: 1.0.0.
|
3
|
+
Version: 1.0.0.dev20250320
|
4
4
|
Summary: SkyPilot: An intercloud broker for the clouds
|
5
5
|
Author: SkyPilot Team
|
6
6
|
License: Apache 2.0
|
@@ -156,6 +156,7 @@ Dynamic: classifier
|
|
156
156
|
Dynamic: description
|
157
157
|
Dynamic: description-content-type
|
158
158
|
Dynamic: license
|
159
|
+
Dynamic: license-file
|
159
160
|
Dynamic: project-url
|
160
161
|
Dynamic: provides-extra
|
161
162
|
Dynamic: requires-dist
|
{skypilot_nightly-1.0.0.dev20250319.dist-info → skypilot_nightly-1.0.0.dev20250320.dist-info}/RECORD
RENAMED
@@ -1,16 +1,16 @@
|
|
1
|
-
sky/__init__.py,sha256=
|
1
|
+
sky/__init__.py,sha256=QfQeD1Wm9yNNJl0Tuk92yJ1R5u-p0hTxTZT9lSqpvtY,6428
|
2
2
|
sky/admin_policy.py,sha256=hPo02f_A32gCqhUueF0QYy1fMSSKqRwYEg_9FxScN_s,3248
|
3
3
|
sky/authentication.py,sha256=hCEqi77nprQEg3ktfRL51xiiw16zwZOmFEDB_Z7fWVU,22384
|
4
|
-
sky/check.py,sha256=
|
4
|
+
sky/check.py,sha256=UgHpR6D0SAnbKeOeBXyX4Px6q01uEwvKD9MriKmOQOU,15944
|
5
5
|
sky/cli.py,sha256=o1IHTY4YSJzsfkynTynaN1dB4RBPZIRZGWQ4rTnVVnQ,221956
|
6
6
|
sky/cloud_stores.py,sha256=kEHXd2divyra-1c3EusHxKyM5yTQlTXc6cKVXofsefA,23978
|
7
|
-
sky/core.py,sha256=
|
7
|
+
sky/core.py,sha256=WM0SVu0MygIhXSdu2rB7urryEBbJ8BqskBsRZqUJ0Bw,47711
|
8
8
|
sky/dag.py,sha256=Yl7Ry26Vql5cv4YMz8g9kOUgtoCihJnw7c8NgZYakMY,3242
|
9
9
|
sky/exceptions.py,sha256=cEZ5nm7RhTW22Npw-oYS5Wp9rtxoHxdPQHfkNa92wOo,16641
|
10
10
|
sky/execution.py,sha256=9L8NFOXNphtabnsL7mHGPJeGdw4n6gIIUEOzjW7CEHw,28294
|
11
|
-
sky/global_user_state.py,sha256=
|
11
|
+
sky/global_user_state.py,sha256=LgC5HJrNwJPJ3QWSiChN0eSQihlu9OaqcnQ8UalTDPg,34393
|
12
12
|
sky/models.py,sha256=4xSW05BdDPEjW8Ubvj3VlVOVnzv0TbrolsFvR5R5v1U,638
|
13
|
-
sky/optimizer.py,sha256=
|
13
|
+
sky/optimizer.py,sha256=qrY7JCPxcPC4JTcgYDKv4jMOUtAdCHJ4jMwHvn1QnXM,60527
|
14
14
|
sky/resources.py,sha256=f2Qo_Wt0kFruKmYm6cgYbICH_wn0Zkb8uIv6LA82SRs,72153
|
15
15
|
sky/sky_logging.py,sha256=pID2RINjH62n7SZpv70DuN8BSFYdCfTJ2ScGQpVmugg,5725
|
16
16
|
sky/skypilot_config.py,sha256=bt1vSis2aKKdQfPz80-KcjM9vNIg_qYKLNXur782Poo,8693
|
@@ -18,7 +18,7 @@ sky/task.py,sha256=elzRNKy0twCOgz4VaCpd4k-EQZ3ZKy4N6nNg0yldnYo,54969
|
|
18
18
|
sky/adaptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
sky/adaptors/aws.py,sha256=iH55Cm6eXWwufAG0Dgk7LTQcADawNa3ELrBH1m6yuSY,7617
|
20
20
|
sky/adaptors/azure.py,sha256=r8xkjRgZZQfsSExNdguFa6c5fCLcUhZrFV8zs62VExo,21986
|
21
|
-
sky/adaptors/cloudflare.py,sha256=
|
21
|
+
sky/adaptors/cloudflare.py,sha256=BeT2kq8oZapRUK1bEdO38Gx4amwQJgfjyFUqnhjXyTI,7756
|
22
22
|
sky/adaptors/common.py,sha256=nJmuBYFokCH0vX2oFqdAJYS-84FnUSTmIPKjAi4gqzo,2877
|
23
23
|
sky/adaptors/cudo.py,sha256=WGvIQrlzJkGDe02Ve7pygA56tHwUc4kwS3XHW8kMFAA,239
|
24
24
|
sky/adaptors/do.py,sha256=dJ0BYbkQoUWVu6_9Pxq3fOu6PngjZyyCQzgjnODXLCA,777
|
@@ -47,18 +47,18 @@ sky/client/cli.py,sha256=o1IHTY4YSJzsfkynTynaN1dB4RBPZIRZGWQ4rTnVVnQ,221956
|
|
47
47
|
sky/client/common.py,sha256=axDic7WOG1e78SdFm5XIwdhX7YNvf3g4k7INrsW3X4s,14611
|
48
48
|
sky/client/sdk.py,sha256=DL-3aV-kbK3T70_qXrEiMlaUmbiHaJk513gLp2by-6Y,68352
|
49
49
|
sky/clouds/__init__.py,sha256=OW6mJ-9hpJSBORCgt2LippLQEYZHNfnBW1mooRNNvxo,1416
|
50
|
-
sky/clouds/aws.py,sha256=
|
51
|
-
sky/clouds/azure.py,sha256=
|
52
|
-
sky/clouds/cloud.py,sha256=
|
50
|
+
sky/clouds/aws.py,sha256=T-j6Fd4QUt5gYIsXRDt7vPLKKPpHSciDnib_9ra7-eg,54301
|
51
|
+
sky/clouds/azure.py,sha256=SC2x_I0ozh8q9YdyD6--veGIfixettC0I8Iqc9CMjDA,31908
|
52
|
+
sky/clouds/cloud.py,sha256=z9cDJcIWgIAQWIkszAirAGDLWkAmrK41SjpERc6ckyA,35894
|
53
53
|
sky/clouds/cudo.py,sha256=femv17IUM1TOXuCAg6zljqyFcBGfofbXCNGckpXFHzc,13127
|
54
54
|
sky/clouds/do.py,sha256=hmksx0XML0dVHUZBMV2Wr3a5VilOsYfxX2dSBV_XK5o,11487
|
55
55
|
sky/clouds/fluidstack.py,sha256=Eb0nlfU_EwTtGtV0nPKS2ueBlB0nYiDAN9swA-jjQV0,12446
|
56
|
-
sky/clouds/gcp.py,sha256=
|
57
|
-
sky/clouds/ibm.py,sha256=
|
56
|
+
sky/clouds/gcp.py,sha256=QNbCES7CnFvKoHc-iBkpjFNVRjIWTRID1zkywhA9hNU,56938
|
57
|
+
sky/clouds/ibm.py,sha256=YRKzGja9Uad5N0f4lzlOPIF2BoPsB-TV8_Mu_fjVPws,21668
|
58
58
|
sky/clouds/kubernetes.py,sha256=u8mRd75a0NS7-uHdGXk_cqqLc4Z2vU0CedwmLJpzmZ0,36081
|
59
59
|
sky/clouds/lambda_cloud.py,sha256=ejqA_Wj5-325Y_QjQ__FY4HMO8sv_2tSRsufmaldcmI,12699
|
60
60
|
sky/clouds/nebius.py,sha256=G3v73NZjLzGoCi0ZfHj6VkOt-fs1i6DDxCpNiE88BdA,12676
|
61
|
-
sky/clouds/oci.py,sha256=
|
61
|
+
sky/clouds/oci.py,sha256=oGsM8c6f-eXYBXzpd23SgEpJNBB6THylvjg9PdLdxsY,27277
|
62
62
|
sky/clouds/paperspace.py,sha256=O7bH8YaHBLFuyj6rDz2bPDz_6OYWmNB9OLqnZH70yfY,10922
|
63
63
|
sky/clouds/runpod.py,sha256=hzYB4td6qaged83xMAVKZ96bH40oZnrHXL7a_CKxXIw,11926
|
64
64
|
sky/clouds/scp.py,sha256=bOl5icqVHXJFsr9sIKH2VHwBhupo66kn7SVCL0xajdc,15872
|
@@ -97,14 +97,14 @@ sky/clouds/service_catalog/data_fetchers/fetch_vsphere.py,sha256=Opp2r3KSzXPtwk3
|
|
97
97
|
sky/clouds/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
98
98
|
sky/clouds/utils/aws_utils.py,sha256=W5BRC-2F_VY4BymRA1kS6-MufsI3V8cfY_hv--4gJBU,1986
|
99
99
|
sky/clouds/utils/azure_utils.py,sha256=NToRBnhEyuUvb-nBnsKTxjhOBRkMcrelL8LK4w6s4t8,3555
|
100
|
-
sky/clouds/utils/gcp_utils.py,sha256=
|
100
|
+
sky/clouds/utils/gcp_utils.py,sha256=YtuS4EoAMvcRnGPgE_WLENPOPWIdvhp7dLceTw_zfas,7114
|
101
101
|
sky/clouds/utils/oci_utils.py,sha256=KbmwTWlEO3stcjM4jN2agSFi2w9WNc2NYA9Gr5jMAvE,6385
|
102
102
|
sky/clouds/utils/scp_utils.py,sha256=r4lhRLtNgoz5nmkfN2ctAXYugF_-Et8TYH6ZlbbFfo8,15791
|
103
103
|
sky/data/__init__.py,sha256=Nhaf1NURisXpZuwWANa2IuCyppIuc720FRwqSE2oEwY,184
|
104
104
|
sky/data/data_transfer.py,sha256=wixC4_3_JaeJFdGKOp-O5ulcsMugDSgrCR0SnPpugGc,8946
|
105
105
|
sky/data/data_utils.py,sha256=HjcgMDuWRR_fNQ9gjuROi9GgPVvTGApiJwxGtdb2_UU,28860
|
106
106
|
sky/data/mounting_utils.py,sha256=i79Y-DZXVR88fjG_MBPB8EgsZBnHdpf1LGnJSm_VhAg,16063
|
107
|
-
sky/data/storage.py,sha256=
|
107
|
+
sky/data/storage.py,sha256=bENPzQGJCb_4wE6OpLryB8Ny-FVxA2vPcq9ZAFDmaro,207657
|
108
108
|
sky/data/storage_utils.py,sha256=zB99nRTJjh8isU0UmqERmlwwRNgfig91IwrwVH8CcNw,12383
|
109
109
|
sky/jobs/__init__.py,sha256=qoI53-xXE0-SOkrLWigvhgFXjk7dWE0OTqGPYIk-kmM,1458
|
110
110
|
sky/jobs/constants.py,sha256=1XiIqdR5dEgGgepLKWkZCRT3MYSsMBR-dO7N4RTsjwg,3088
|
@@ -154,9 +154,9 @@ sky/provision/fluidstack/config.py,sha256=hDqesKEVjIhXLTWej3fDdpbHtKBXoybxFGgC6T
|
|
154
154
|
sky/provision/fluidstack/fluidstack_utils.py,sha256=dYEHRRY86nCxQtZ_GIV6WhkNvvnkIuqDDKJqf1CouKY,5729
|
155
155
|
sky/provision/fluidstack/instance.py,sha256=TCGLojd5mEuEaUQ1BnmRvXMOSSBjltyf7dhPG3OLdgQ,13787
|
156
156
|
sky/provision/gcp/__init__.py,sha256=zlgjR2JoaGD7sStGStMRu9bJ62f-8NKEIyb-bFHBlzM,528
|
157
|
-
sky/provision/gcp/config.py,sha256=
|
158
|
-
sky/provision/gcp/constants.py,sha256=
|
159
|
-
sky/provision/gcp/instance.py,sha256=
|
157
|
+
sky/provision/gcp/config.py,sha256=kU357o4tCTuQ2e0Gind5q_tC0kFRW2tch-NQ2DnwN9Q,33319
|
158
|
+
sky/provision/gcp/constants.py,sha256=KbnAupsKCp_mNNOas62-yiCJcqYoaer7iMljFq-CPfk,7739
|
159
|
+
sky/provision/gcp/instance.py,sha256=47jDHLbIAI5M1MZIQTCiKGfwc9QzPOyjApkShqBRczE,25035
|
160
160
|
sky/provision/gcp/instance_utils.py,sha256=T0AVT8lMn128snPp3MvqmhXOihlZSC8-c1QpgYT4_FA,71377
|
161
161
|
sky/provision/gcp/mig_utils.py,sha256=oFpcFZoapHMILSE4iIm8V5bxP1RhbMHRF7cciqq8qAk,7883
|
162
162
|
sky/provision/kubernetes/__init__.py,sha256=y6yVfii81WYG3ROxv4hiIj-ydinS5-xGxLvXnARVQoI,719
|
@@ -165,7 +165,7 @@ sky/provision/kubernetes/constants.py,sha256=dZCUV8FOO9Gct80sdqeubKnxeW3CGl-u5mx
|
|
165
165
|
sky/provision/kubernetes/instance.py,sha256=oag17OtuiqU-1RjkgW9NvEpxSGUFIYdI7M61S-YmPu8,50503
|
166
166
|
sky/provision/kubernetes/network.py,sha256=AtcOM8wPs_-UlQJhGEQGP6Lh4HIgdx63Y0iWEhP5jyc,12673
|
167
167
|
sky/provision/kubernetes/network_utils.py,sha256=Bwy5ZQb62ejC7ZHM4htjzhs86UNACK7AXN-NfQ9IJrE,11454
|
168
|
-
sky/provision/kubernetes/utils.py,sha256=
|
168
|
+
sky/provision/kubernetes/utils.py,sha256=Ugy_FaD6rBw5SsbYShc0nlmXZZrWgNaQwU45rtkILe0,124207
|
169
169
|
sky/provision/kubernetes/manifests/smarter-device-manager-configmap.yaml,sha256=AMzYzlY0JIlfBWj5eX054Rc1XDW2thUcLSOGMJVhIdA,229
|
170
170
|
sky/provision/kubernetes/manifests/smarter-device-manager-daemonset.yaml,sha256=RtTq4F1QUmR2Uunb6zuuRaPhV7hpesz4saHjn3Ncsb4,2010
|
171
171
|
sky/provision/lambda_cloud/__init__.py,sha256=6EEvSgtUeEiup9ivIFevHmgv0GqleroO2X0K7TRa2nE,612
|
@@ -217,7 +217,7 @@ sky/serve/constants.py,sha256=H_cVwI49HkS4JRg2k6TWje1vJtfAAnOivRtVrh8qjwQ,4806
|
|
217
217
|
sky/serve/controller.py,sha256=jtzWHsLHnVPQ727ZpDZTUpGTtIOssbnQpXeWOyAuW_s,11886
|
218
218
|
sky/serve/load_balancer.py,sha256=2nkMPRvy-h7hJL4Qq__tkT8nIAVC_nmjyXf8mMGYEFk,13658
|
219
219
|
sky/serve/load_balancing_policies.py,sha256=XVj76qBgqh7h6wfx53RKQFzBefDWTE4TCdCEtFLLtI4,5398
|
220
|
-
sky/serve/replica_managers.py,sha256=
|
220
|
+
sky/serve/replica_managers.py,sha256=nf5T6npBbgeWbTVLFXw1IF1eEYbWn__vJdlr_CVWSJY,58160
|
221
221
|
sky/serve/serve_state.py,sha256=Do-MITtijw1z8dDUyJZMAGnjZCgdUFtJ2nwhhcjpOGI,20056
|
222
222
|
sky/serve/serve_utils.py,sha256=o8ZgAA72-1_PMfTftmF3SChi9NmbLap5A6AOnMGkvNU,41747
|
223
223
|
sky/serve/service.py,sha256=9sx9oDgHoAZYAo6yTL01sUaa6d6cqpJaHc2cd-SCSGY,12519
|
@@ -316,7 +316,7 @@ sky/utils/common.py,sha256=P4oVXFATUYgkruHX92cN12SJBtfb8DiOOYZtbN1kvP0,1927
|
|
316
316
|
sky/utils/common_utils.py,sha256=vsikxAnRZYTbn0OWENuMSv1JWYUr2hRnPxqWSct6N7I,31357
|
317
317
|
sky/utils/config_utils.py,sha256=VQ2E3DQ2XysD-kul-diSrxn_pXWsDMfKAev91OiJQ1Q,9041
|
318
318
|
sky/utils/control_master_utils.py,sha256=iD4M0onjYOdZ2RuxjwMBl4KhafHXJzuHjvqlBUnu-VE,1450
|
319
|
-
sky/utils/controller_utils.py,sha256=
|
319
|
+
sky/utils/controller_utils.py,sha256=UTiKU7mzX1_MiYZk9JiUPDa-kLcRLgROQywzIdsYdcg,49672
|
320
320
|
sky/utils/dag_utils.py,sha256=sAus0aL1wtuuFZSDnpO4LY-6WK4u5iJY952oWQzHo3Y,7532
|
321
321
|
sky/utils/db_utils.py,sha256=K2-OHPg0FeHCarevMdWe0IWzm6wWumViEeYeJuGoFUE,3747
|
322
322
|
sky/utils/env_options.py,sha256=aaD6GoYK0LaZIqjOEZ-R7eccQuiRriW3EuLWtOI5En8,1578
|
@@ -344,12 +344,12 @@ sky/utils/kubernetes/generate_kubeconfig.sh,sha256=MBvXJio0PeujZSCXiRKE_pa6HCTiU
|
|
344
344
|
sky/utils/kubernetes/gpu_labeler.py,sha256=4px7FyfsukacPEvKwTLUNb3WwacMIUrHWjP93qTi3kE,6998
|
345
345
|
sky/utils/kubernetes/k8s_gpu_labeler_job.yaml,sha256=k0TBoQ4zgf79-sVkixKSGYFHQ7ZWF5gdVIZPupCCo9A,1224
|
346
346
|
sky/utils/kubernetes/k8s_gpu_labeler_setup.yaml,sha256=VLKT2KKimZu1GDg_4AIlIt488oMQvhRZWwsj9vBbPUg,3812
|
347
|
-
sky/utils/kubernetes/kubernetes_deploy_utils.py,sha256=
|
347
|
+
sky/utils/kubernetes/kubernetes_deploy_utils.py,sha256=jVRySB1Dme9yI_hFqkgKhYco19fDpyDpHusa3gnl8UY,10167
|
348
348
|
sky/utils/kubernetes/rsync_helper.sh,sha256=h4YwrPFf9727CACnMJvF3EyK_0OeOYKKt4su_daKekw,1256
|
349
349
|
sky/utils/kubernetes/ssh_jump_lifecycle_manager.py,sha256=Kq1MDygF2IxFmu9FXpCxqucXLmeUrvs6OtRij6XTQbo,6554
|
350
|
-
skypilot_nightly-1.0.0.
|
351
|
-
skypilot_nightly-1.0.0.
|
352
|
-
skypilot_nightly-1.0.0.
|
353
|
-
skypilot_nightly-1.0.0.
|
354
|
-
skypilot_nightly-1.0.0.
|
355
|
-
skypilot_nightly-1.0.0.
|
350
|
+
skypilot_nightly-1.0.0.dev20250320.dist-info/licenses/LICENSE,sha256=emRJAvE7ngL6x0RhQvlns5wJzGI3NEQ_WMjNmd9TZc4,12170
|
351
|
+
skypilot_nightly-1.0.0.dev20250320.dist-info/METADATA,sha256=8VHM4tb2L9CQ4Hd1deeEyY2O0qzxQOFgkJ4Qv_MUGBk,17941
|
352
|
+
skypilot_nightly-1.0.0.dev20250320.dist-info/WHEEL,sha256=tTnHoFhvKQHCh4jz3yCn0WPTYIy7wXx3CJtJ7SJGV7c,91
|
353
|
+
skypilot_nightly-1.0.0.dev20250320.dist-info/entry_points.txt,sha256=StA6HYpuHj-Y61L2Ze-hK2IcLWgLZcML5gJu8cs6nU4,36
|
354
|
+
skypilot_nightly-1.0.0.dev20250320.dist-info/top_level.txt,sha256=qA8QuiNNb6Y1OF-pCUtPEr6sLEwy2xJX06Bd_CrtrHY,4
|
355
|
+
skypilot_nightly-1.0.0.dev20250320.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|