skypilot-nightly 1.0.0.dev20250101__py3-none-any.whl → 1.0.0.dev20250103__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/do.py +20 -0
- sky/backends/backend_utils.py +1 -0
- sky/backends/cloud_vm_ray_backend.py +1 -0
- sky/clouds/__init__.py +2 -0
- sky/clouds/do.py +303 -0
- sky/clouds/service_catalog/constants.py +1 -1
- sky/clouds/service_catalog/do_catalog.py +111 -0
- sky/clouds/utils/oci_utils.py +6 -2
- sky/provision/do/__init__.py +11 -0
- sky/provision/do/config.py +14 -0
- sky/provision/do/constants.py +10 -0
- sky/provision/do/instance.py +287 -0
- sky/provision/do/utils.py +306 -0
- sky/provision/docker_utils.py +14 -8
- sky/provision/provisioner.py +0 -1
- sky/setup_files/dependencies.py +1 -0
- sky/templates/do-ray.yml.j2 +98 -0
- {skypilot_nightly-1.0.0.dev20250101.dist-info → skypilot_nightly-1.0.0.dev20250103.dist-info}/METADATA +8 -1
- {skypilot_nightly-1.0.0.dev20250101.dist-info → skypilot_nightly-1.0.0.dev20250103.dist-info}/RECORD +24 -15
- {skypilot_nightly-1.0.0.dev20250101.dist-info → skypilot_nightly-1.0.0.dev20250103.dist-info}/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250101.dist-info → skypilot_nightly-1.0.0.dev20250103.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20250101.dist-info → skypilot_nightly-1.0.0.dev20250103.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250101.dist-info → skypilot_nightly-1.0.0.dev20250103.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 = '6a6d6671958c9fce56ffa314144daa1156a43342'
|
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.dev20250103'
|
39
39
|
__root_dir__ = os.path.dirname(os.path.abspath(__file__))
|
40
40
|
|
41
41
|
|
sky/adaptors/do.py
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
"""Digital Ocean cloud adaptors"""
|
2
|
+
|
3
|
+
# pylint: disable=import-outside-toplevel
|
4
|
+
|
5
|
+
from sky.adaptors import common
|
6
|
+
|
7
|
+
_IMPORT_ERROR_MESSAGE = ('Failed to import dependencies for DO. '
|
8
|
+
'Try pip install "skypilot[do]"')
|
9
|
+
pydo = common.LazyImport('pydo', import_error_message=_IMPORT_ERROR_MESSAGE)
|
10
|
+
azure = common.LazyImport('azure', import_error_message=_IMPORT_ERROR_MESSAGE)
|
11
|
+
_LAZY_MODULES = (pydo, azure)
|
12
|
+
|
13
|
+
|
14
|
+
# `pydo`` inherits Azure exceptions. See:
|
15
|
+
# https://github.com/digitalocean/pydo/blob/7b01498d99eb0d3a772366b642e5fab3d6fc6aa2/examples/poc_droplets_volumes_sshkeys.py#L6
|
16
|
+
@common.load_lazy_modules(modules=_LAZY_MODULES)
|
17
|
+
def exceptions():
|
18
|
+
"""Azure exceptions."""
|
19
|
+
from azure.core import exceptions as azure_exceptions
|
20
|
+
return azure_exceptions
|
sky/backends/backend_utils.py
CHANGED
@@ -1000,6 +1000,7 @@ def _add_auth_to_cluster_config(cloud: clouds.Cloud, cluster_config_file: str):
|
|
1000
1000
|
clouds.Cudo,
|
1001
1001
|
clouds.Paperspace,
|
1002
1002
|
clouds.Azure,
|
1003
|
+
clouds.DO,
|
1003
1004
|
)):
|
1004
1005
|
config = auth.configure_ssh_info(config)
|
1005
1006
|
elif isinstance(cloud, clouds.GCP):
|
@@ -178,6 +178,7 @@ def _get_cluster_config_template(cloud):
|
|
178
178
|
clouds.SCP: 'scp-ray.yml.j2',
|
179
179
|
clouds.OCI: 'oci-ray.yml.j2',
|
180
180
|
clouds.Paperspace: 'paperspace-ray.yml.j2',
|
181
|
+
clouds.DO: 'do-ray.yml.j2',
|
181
182
|
clouds.RunPod: 'runpod-ray.yml.j2',
|
182
183
|
clouds.Kubernetes: 'kubernetes-ray.yml.j2',
|
183
184
|
clouds.Vsphere: 'vsphere-ray.yml.j2',
|
sky/clouds/__init__.py
CHANGED
@@ -15,6 +15,7 @@ from sky.clouds.cloud_registry import CLOUD_REGISTRY
|
|
15
15
|
from sky.clouds.aws import AWS
|
16
16
|
from sky.clouds.azure import Azure
|
17
17
|
from sky.clouds.cudo import Cudo
|
18
|
+
from sky.clouds.do import DO
|
18
19
|
from sky.clouds.fluidstack import Fluidstack
|
19
20
|
from sky.clouds.gcp import GCP
|
20
21
|
from sky.clouds.ibm import IBM
|
@@ -34,6 +35,7 @@ __all__ = [
|
|
34
35
|
'Cudo',
|
35
36
|
'GCP',
|
36
37
|
'Lambda',
|
38
|
+
'DO',
|
37
39
|
'Paperspace',
|
38
40
|
'SCP',
|
39
41
|
'RunPod',
|
sky/clouds/do.py
ADDED
@@ -0,0 +1,303 @@
|
|
1
|
+
""" Digital Ocean Cloud. """
|
2
|
+
|
3
|
+
import json
|
4
|
+
import typing
|
5
|
+
from typing import Dict, Iterator, List, Optional, Tuple, Union
|
6
|
+
|
7
|
+
from sky import clouds
|
8
|
+
from sky.adaptors import do
|
9
|
+
from sky.clouds import service_catalog
|
10
|
+
from sky.provision.do import utils as do_utils
|
11
|
+
from sky.utils import resources_utils
|
12
|
+
|
13
|
+
if typing.TYPE_CHECKING:
|
14
|
+
from sky import resources as resources_lib
|
15
|
+
|
16
|
+
_CREDENTIAL_FILE = 'config.yaml'
|
17
|
+
|
18
|
+
|
19
|
+
@clouds.CLOUD_REGISTRY.register(aliases=['digitalocean'])
|
20
|
+
class DO(clouds.Cloud):
|
21
|
+
"""Digital Ocean Cloud"""
|
22
|
+
|
23
|
+
_REPR = 'DO'
|
24
|
+
_CLOUD_UNSUPPORTED_FEATURES = {
|
25
|
+
clouds.CloudImplementationFeatures.CLONE_DISK_FROM_CLUSTER:
|
26
|
+
'Migrating '
|
27
|
+
f'disk is not supported in {_REPR}.',
|
28
|
+
clouds.CloudImplementationFeatures.SPOT_INSTANCE:
|
29
|
+
'Spot instances are '
|
30
|
+
f'not supported in {_REPR}.',
|
31
|
+
clouds.CloudImplementationFeatures.CUSTOM_DISK_TIER:
|
32
|
+
'Custom disk tiers'
|
33
|
+
f' is not supported in {_REPR}.',
|
34
|
+
}
|
35
|
+
# DO maximum node name length defined as <= 255
|
36
|
+
# https://docs.digitalocean.com/reference/api/api-reference/#operation/droplets_create
|
37
|
+
# 255 - 8 = 247 characters since
|
38
|
+
# our provisioner adds additional `-worker`.
|
39
|
+
_MAX_CLUSTER_NAME_LEN_LIMIT = 247
|
40
|
+
_regions: List[clouds.Region] = []
|
41
|
+
|
42
|
+
# Using the latest SkyPilot provisioner API to provision and check status.
|
43
|
+
PROVISIONER_VERSION = clouds.ProvisionerVersion.SKYPILOT
|
44
|
+
STATUS_VERSION = clouds.StatusVersion.SKYPILOT
|
45
|
+
|
46
|
+
@classmethod
|
47
|
+
def _unsupported_features_for_resources(
|
48
|
+
cls, resources: 'resources_lib.Resources'
|
49
|
+
) -> Dict[clouds.CloudImplementationFeatures, str]:
|
50
|
+
"""The features not supported based on the resources provided.
|
51
|
+
|
52
|
+
This method is used by check_features_are_supported() to check if the
|
53
|
+
cloud implementation supports all the requested features.
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
A dict of {feature: reason} for the features not supported by the
|
57
|
+
cloud implementation.
|
58
|
+
"""
|
59
|
+
del resources # unused
|
60
|
+
return cls._CLOUD_UNSUPPORTED_FEATURES
|
61
|
+
|
62
|
+
@classmethod
|
63
|
+
def _max_cluster_name_length(cls) -> Optional[int]:
|
64
|
+
return cls._MAX_CLUSTER_NAME_LEN_LIMIT
|
65
|
+
|
66
|
+
@classmethod
|
67
|
+
def regions_with_offering(
|
68
|
+
cls,
|
69
|
+
instance_type: str,
|
70
|
+
accelerators: Optional[Dict[str, int]],
|
71
|
+
use_spot: bool,
|
72
|
+
region: Optional[str],
|
73
|
+
zone: Optional[str],
|
74
|
+
) -> List[clouds.Region]:
|
75
|
+
assert zone is None, 'DO does not support zones.'
|
76
|
+
del accelerators, zone # unused
|
77
|
+
if use_spot:
|
78
|
+
return []
|
79
|
+
regions = service_catalog.get_region_zones_for_instance_type(
|
80
|
+
instance_type, use_spot, 'DO')
|
81
|
+
if region is not None:
|
82
|
+
regions = [r for r in regions if r.name == region]
|
83
|
+
return regions
|
84
|
+
|
85
|
+
@classmethod
|
86
|
+
def get_vcpus_mem_from_instance_type(
|
87
|
+
cls,
|
88
|
+
instance_type: str,
|
89
|
+
) -> Tuple[Optional[float], Optional[float]]:
|
90
|
+
return service_catalog.get_vcpus_mem_from_instance_type(instance_type,
|
91
|
+
clouds='DO')
|
92
|
+
|
93
|
+
@classmethod
|
94
|
+
def zones_provision_loop(
|
95
|
+
cls,
|
96
|
+
*,
|
97
|
+
region: str,
|
98
|
+
num_nodes: int,
|
99
|
+
instance_type: str,
|
100
|
+
accelerators: Optional[Dict[str, int]] = None,
|
101
|
+
use_spot: bool = False,
|
102
|
+
) -> Iterator[None]:
|
103
|
+
del num_nodes # unused
|
104
|
+
regions = cls.regions_with_offering(instance_type,
|
105
|
+
accelerators,
|
106
|
+
use_spot,
|
107
|
+
region=region,
|
108
|
+
zone=None)
|
109
|
+
for r in regions:
|
110
|
+
assert r.zones is None, r
|
111
|
+
yield r.zones
|
112
|
+
|
113
|
+
def instance_type_to_hourly_cost(
|
114
|
+
self,
|
115
|
+
instance_type: str,
|
116
|
+
use_spot: bool,
|
117
|
+
region: Optional[str] = None,
|
118
|
+
zone: Optional[str] = None,
|
119
|
+
) -> float:
|
120
|
+
return service_catalog.get_hourly_cost(
|
121
|
+
instance_type,
|
122
|
+
use_spot=use_spot,
|
123
|
+
region=region,
|
124
|
+
zone=zone,
|
125
|
+
clouds='DO',
|
126
|
+
)
|
127
|
+
|
128
|
+
def accelerators_to_hourly_cost(
|
129
|
+
self,
|
130
|
+
accelerators: Dict[str, int],
|
131
|
+
use_spot: bool,
|
132
|
+
region: Optional[str] = None,
|
133
|
+
zone: Optional[str] = None,
|
134
|
+
) -> float:
|
135
|
+
"""Returns the hourly cost of the accelerators, in dollars/hour."""
|
136
|
+
# the acc price is include in the instance price.
|
137
|
+
del accelerators, use_spot, region, zone # unused
|
138
|
+
return 0.0
|
139
|
+
|
140
|
+
def get_egress_cost(self, num_gigabytes: float) -> float:
|
141
|
+
return 0.0
|
142
|
+
|
143
|
+
def __repr__(self):
|
144
|
+
return self._REPR
|
145
|
+
|
146
|
+
@classmethod
|
147
|
+
def get_default_instance_type(
|
148
|
+
cls,
|
149
|
+
cpus: Optional[str] = None,
|
150
|
+
memory: Optional[str] = None,
|
151
|
+
disk_tier: Optional[resources_utils.DiskTier] = None,
|
152
|
+
) -> Optional[str]:
|
153
|
+
"""Returns the default instance type for DO."""
|
154
|
+
return service_catalog.get_default_instance_type(cpus=cpus,
|
155
|
+
memory=memory,
|
156
|
+
disk_tier=disk_tier,
|
157
|
+
clouds='DO')
|
158
|
+
|
159
|
+
@classmethod
|
160
|
+
def get_accelerators_from_instance_type(
|
161
|
+
cls, instance_type: str) -> Optional[Dict[str, Union[int, float]]]:
|
162
|
+
return service_catalog.get_accelerators_from_instance_type(
|
163
|
+
instance_type, clouds='DO')
|
164
|
+
|
165
|
+
@classmethod
|
166
|
+
def get_zone_shell_cmd(cls) -> Optional[str]:
|
167
|
+
return None
|
168
|
+
|
169
|
+
def make_deploy_resources_variables(
|
170
|
+
self,
|
171
|
+
resources: 'resources_lib.Resources',
|
172
|
+
cluster_name: resources_utils.ClusterName,
|
173
|
+
region: 'clouds.Region',
|
174
|
+
zones: Optional[List['clouds.Zone']],
|
175
|
+
num_nodes: int,
|
176
|
+
dryrun: bool = False) -> Dict[str, Optional[str]]:
|
177
|
+
del zones, dryrun, cluster_name
|
178
|
+
|
179
|
+
r = resources
|
180
|
+
acc_dict = self.get_accelerators_from_instance_type(r.instance_type)
|
181
|
+
if acc_dict is not None:
|
182
|
+
custom_resources = json.dumps(acc_dict, separators=(',', ':'))
|
183
|
+
else:
|
184
|
+
custom_resources = None
|
185
|
+
image_id = None
|
186
|
+
if (resources.image_id is not None and
|
187
|
+
resources.extract_docker_image() is None):
|
188
|
+
if None in resources.image_id:
|
189
|
+
image_id = resources.image_id[None]
|
190
|
+
else:
|
191
|
+
assert region.name in resources.image_id
|
192
|
+
image_id = resources.image_id[region.name]
|
193
|
+
return {
|
194
|
+
'instance_type': resources.instance_type,
|
195
|
+
'custom_resources': custom_resources,
|
196
|
+
'region': region.name,
|
197
|
+
**({
|
198
|
+
'image_id': image_id
|
199
|
+
} if image_id else {})
|
200
|
+
}
|
201
|
+
|
202
|
+
def _get_feasible_launchable_resources(
|
203
|
+
self, resources: 'resources_lib.Resources'
|
204
|
+
) -> resources_utils.FeasibleResources:
|
205
|
+
"""Returns a list of feasible resources for the given resources."""
|
206
|
+
if resources.use_spot:
|
207
|
+
# TODO: Add hints to all return values in this method to help
|
208
|
+
# users understand why the resources are not launchable.
|
209
|
+
return resources_utils.FeasibleResources([], [], None)
|
210
|
+
if resources.instance_type is not None:
|
211
|
+
assert resources.is_launchable(), resources
|
212
|
+
resources = resources.copy(accelerators=None)
|
213
|
+
return resources_utils.FeasibleResources([resources], [], None)
|
214
|
+
|
215
|
+
def _make(instance_list):
|
216
|
+
resource_list = []
|
217
|
+
for instance_type in instance_list:
|
218
|
+
r = resources.copy(
|
219
|
+
cloud=DO(),
|
220
|
+
instance_type=instance_type,
|
221
|
+
accelerators=None,
|
222
|
+
cpus=None,
|
223
|
+
)
|
224
|
+
resource_list.append(r)
|
225
|
+
return resource_list
|
226
|
+
|
227
|
+
# Currently, handle a filter on accelerators only.
|
228
|
+
accelerators = resources.accelerators
|
229
|
+
if accelerators is None:
|
230
|
+
# Return a default instance type
|
231
|
+
default_instance_type = DO.get_default_instance_type(
|
232
|
+
cpus=resources.cpus,
|
233
|
+
memory=resources.memory,
|
234
|
+
disk_tier=resources.disk_tier)
|
235
|
+
return resources_utils.FeasibleResources(
|
236
|
+
_make([default_instance_type]), [], None)
|
237
|
+
|
238
|
+
assert len(accelerators) == 1, resources
|
239
|
+
acc, acc_count = list(accelerators.items())[0]
|
240
|
+
(instance_list, fuzzy_candidate_list) = (
|
241
|
+
service_catalog.get_instance_type_for_accelerator(
|
242
|
+
acc,
|
243
|
+
acc_count,
|
244
|
+
use_spot=resources.use_spot,
|
245
|
+
cpus=resources.cpus,
|
246
|
+
memory=resources.memory,
|
247
|
+
region=resources.region,
|
248
|
+
zone=resources.zone,
|
249
|
+
clouds='DO',
|
250
|
+
))
|
251
|
+
if instance_list is None:
|
252
|
+
return resources_utils.FeasibleResources([], fuzzy_candidate_list,
|
253
|
+
None)
|
254
|
+
return resources_utils.FeasibleResources(_make(instance_list),
|
255
|
+
fuzzy_candidate_list, None)
|
256
|
+
|
257
|
+
@classmethod
|
258
|
+
def check_credentials(cls) -> Tuple[bool, Optional[str]]:
|
259
|
+
"""Verify that the user has valid credentials for DO."""
|
260
|
+
try:
|
261
|
+
# attempt to make a CURL request for listing instances
|
262
|
+
do_utils.client().droplets.list()
|
263
|
+
except do.exceptions().HttpResponseError as err:
|
264
|
+
return False, str(err)
|
265
|
+
except do_utils.DigitalOceanError as err:
|
266
|
+
return False, str(err)
|
267
|
+
|
268
|
+
return True, None
|
269
|
+
|
270
|
+
def get_credential_file_mounts(self) -> Dict[str, str]:
|
271
|
+
try:
|
272
|
+
do_utils.client()
|
273
|
+
return {
|
274
|
+
f'~/.config/doctl/{_CREDENTIAL_FILE}': do_utils.CREDENTIALS_PATH
|
275
|
+
}
|
276
|
+
except do_utils.DigitalOceanError:
|
277
|
+
return {}
|
278
|
+
|
279
|
+
@classmethod
|
280
|
+
def get_current_user_identity(cls) -> Optional[List[str]]:
|
281
|
+
# NOTE: used for very advanced SkyPilot functionality
|
282
|
+
# Can implement later if desired
|
283
|
+
return None
|
284
|
+
|
285
|
+
@classmethod
|
286
|
+
def get_image_size(cls, image_id: str, region: Optional[str]) -> float:
|
287
|
+
del region
|
288
|
+
try:
|
289
|
+
response = do_utils.client().images.get(image_id=image_id)
|
290
|
+
return response['image']['size_gigabytes']
|
291
|
+
except do.exceptions().HttpResponseError as err:
|
292
|
+
raise do_utils.DigitalOceanError(
|
293
|
+
'HTTP error while retrieving size of '
|
294
|
+
f'image_id {response}: {err.error.message}') from err
|
295
|
+
except KeyError as err:
|
296
|
+
raise do_utils.DigitalOceanError(
|
297
|
+
f'No image_id `{image_id}` found') from err
|
298
|
+
|
299
|
+
def instance_type_exists(self, instance_type: str) -> bool:
|
300
|
+
return service_catalog.instance_type_exists(instance_type, 'DO')
|
301
|
+
|
302
|
+
def validate_region_zone(self, region: Optional[str], zone: Optional[str]):
|
303
|
+
return service_catalog.validate_region_zone(region, zone, clouds='DO')
|
@@ -0,0 +1,111 @@
|
|
1
|
+
"""Digital ocean service catalog.
|
2
|
+
|
3
|
+
This module loads the service catalog file and can be used to
|
4
|
+
query instance types and pricing information for digital ocean.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import typing
|
8
|
+
from typing import Dict, List, Optional, Tuple, Union
|
9
|
+
|
10
|
+
from sky.clouds.service_catalog import common
|
11
|
+
from sky.utils import ux_utils
|
12
|
+
|
13
|
+
if typing.TYPE_CHECKING:
|
14
|
+
from sky.clouds import cloud
|
15
|
+
|
16
|
+
_df = common.read_catalog('do/vms.csv')
|
17
|
+
|
18
|
+
|
19
|
+
def instance_type_exists(instance_type: str) -> bool:
|
20
|
+
return common.instance_type_exists_impl(_df, instance_type)
|
21
|
+
|
22
|
+
|
23
|
+
def validate_region_zone(
|
24
|
+
region: Optional[str],
|
25
|
+
zone: Optional[str]) -> Tuple[Optional[str], Optional[str]]:
|
26
|
+
if zone is not None:
|
27
|
+
with ux_utils.print_exception_no_traceback():
|
28
|
+
raise ValueError('DO does not support zones.')
|
29
|
+
return common.validate_region_zone_impl('DO', _df, region, zone)
|
30
|
+
|
31
|
+
|
32
|
+
def get_hourly_cost(
|
33
|
+
instance_type: str,
|
34
|
+
use_spot: bool = False,
|
35
|
+
region: Optional[str] = None,
|
36
|
+
zone: Optional[str] = None,
|
37
|
+
) -> float:
|
38
|
+
"""Returns the cost, or the cheapest cost among all zones for spot."""
|
39
|
+
if zone is not None:
|
40
|
+
with ux_utils.print_exception_no_traceback():
|
41
|
+
raise ValueError('DO does not support zones.')
|
42
|
+
return common.get_hourly_cost_impl(_df, instance_type, use_spot, region,
|
43
|
+
zone)
|
44
|
+
|
45
|
+
|
46
|
+
def get_vcpus_mem_from_instance_type(
|
47
|
+
instance_type: str,) -> Tuple[Optional[float], Optional[float]]:
|
48
|
+
return common.get_vcpus_mem_from_instance_type_impl(_df, instance_type)
|
49
|
+
|
50
|
+
|
51
|
+
def get_default_instance_type(
|
52
|
+
cpus: Optional[str] = None,
|
53
|
+
memory: Optional[str] = None,
|
54
|
+
disk_tier: Optional[str] = None,
|
55
|
+
) -> Optional[str]:
|
56
|
+
# NOTE: After expanding catalog to multiple entries, you may
|
57
|
+
# want to specify a default instance type or family.
|
58
|
+
del disk_tier # unused
|
59
|
+
return common.get_instance_type_for_cpus_mem_impl(_df, cpus, memory)
|
60
|
+
|
61
|
+
|
62
|
+
def get_accelerators_from_instance_type(
|
63
|
+
instance_type: str) -> Optional[Dict[str, Union[int, float]]]:
|
64
|
+
return common.get_accelerators_from_instance_type_impl(_df, instance_type)
|
65
|
+
|
66
|
+
|
67
|
+
def get_instance_type_for_accelerator(
|
68
|
+
acc_name: str,
|
69
|
+
acc_count: int,
|
70
|
+
cpus: Optional[str] = None,
|
71
|
+
memory: Optional[str] = None,
|
72
|
+
use_spot: bool = False,
|
73
|
+
region: Optional[str] = None,
|
74
|
+
zone: Optional[str] = None,
|
75
|
+
) -> Tuple[Optional[List[str]], List[str]]:
|
76
|
+
"""Returns a list of instance types that have the given accelerator."""
|
77
|
+
if zone is not None:
|
78
|
+
with ux_utils.print_exception_no_traceback():
|
79
|
+
raise ValueError('DO does not support zones.')
|
80
|
+
return common.get_instance_type_for_accelerator_impl(
|
81
|
+
df=_df,
|
82
|
+
acc_name=acc_name,
|
83
|
+
acc_count=acc_count,
|
84
|
+
cpus=cpus,
|
85
|
+
memory=memory,
|
86
|
+
use_spot=use_spot,
|
87
|
+
region=region,
|
88
|
+
zone=zone,
|
89
|
+
)
|
90
|
+
|
91
|
+
|
92
|
+
def get_region_zones_for_instance_type(instance_type: str,
|
93
|
+
use_spot: bool) -> List['cloud.Region']:
|
94
|
+
df = _df[_df['InstanceType'] == instance_type]
|
95
|
+
return common.get_region_zones(df, use_spot)
|
96
|
+
|
97
|
+
|
98
|
+
def list_accelerators(
|
99
|
+
gpus_only: bool,
|
100
|
+
name_filter: Optional[str],
|
101
|
+
region_filter: Optional[str],
|
102
|
+
quantity_filter: Optional[int],
|
103
|
+
case_sensitive: bool = True,
|
104
|
+
all_regions: bool = False,
|
105
|
+
require_price: bool = True,
|
106
|
+
) -> Dict[str, List[common.InstanceTypeInfo]]:
|
107
|
+
"""Returns all instance types in DO offering GPUs."""
|
108
|
+
del require_price # unused
|
109
|
+
return common.list_accelerators_impl('DO', _df, gpus_only, name_filter,
|
110
|
+
region_filter, quantity_filter,
|
111
|
+
case_sensitive, all_regions)
|
sky/clouds/utils/oci_utils.py
CHANGED
@@ -6,6 +6,10 @@ History:
|
|
6
6
|
configuration.
|
7
7
|
- Hysun He (hysun.he@oracle.com) @ Nov.12, 2024: Add the constant
|
8
8
|
SERVICE_PORT_RULE_TAG
|
9
|
+
- Hysun He (hysun.he@oracle.com) @ Jan.01, 2025: Set the default image
|
10
|
+
from ubuntu 20.04 to ubuntu 22.04, including:
|
11
|
+
- GPU: skypilot:gpu-ubuntu-2004 -> skypilot:gpu-ubuntu-2204
|
12
|
+
- CPU: skypilot:cpu-ubuntu-2004 -> skypilot:cpu-ubuntu-2204
|
9
13
|
"""
|
10
14
|
import os
|
11
15
|
|
@@ -117,7 +121,7 @@ class OCIConfig:
|
|
117
121
|
# the sky's user-config file (if not specified, use the hardcode one at
|
118
122
|
# last)
|
119
123
|
return skypilot_config.get_nested(('oci', 'default', 'image_tag_gpu'),
|
120
|
-
'skypilot:gpu-ubuntu-
|
124
|
+
'skypilot:gpu-ubuntu-2204')
|
121
125
|
|
122
126
|
@classmethod
|
123
127
|
def get_default_image_tag(cls) -> str:
|
@@ -125,7 +129,7 @@ class OCIConfig:
|
|
125
129
|
# set the default image tag in the sky's user-config file. (if not
|
126
130
|
# specified, use the hardcode one at last)
|
127
131
|
return skypilot_config.get_nested(
|
128
|
-
('oci', 'default', 'image_tag_general'), 'skypilot:cpu-ubuntu-
|
132
|
+
('oci', 'default', 'image_tag_general'), 'skypilot:cpu-ubuntu-2204')
|
129
133
|
|
130
134
|
@classmethod
|
131
135
|
def get_sky_user_config_file(cls) -> str:
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"""DO provisioner for SkyPilot."""
|
2
|
+
|
3
|
+
from sky.provision.do.config import bootstrap_instances
|
4
|
+
from sky.provision.do.instance import cleanup_ports
|
5
|
+
from sky.provision.do.instance import get_cluster_info
|
6
|
+
from sky.provision.do.instance import open_ports
|
7
|
+
from sky.provision.do.instance import query_instances
|
8
|
+
from sky.provision.do.instance import run_instances
|
9
|
+
from sky.provision.do.instance import stop_instances
|
10
|
+
from sky.provision.do.instance import terminate_instances
|
11
|
+
from sky.provision.do.instance import wait_instances
|
@@ -0,0 +1,14 @@
|
|
1
|
+
"""Paperspace configuration bootstrapping."""
|
2
|
+
|
3
|
+
from sky import sky_logging
|
4
|
+
from sky.provision import common
|
5
|
+
|
6
|
+
logger = sky_logging.init_logger(__name__)
|
7
|
+
|
8
|
+
|
9
|
+
def bootstrap_instances(
|
10
|
+
region: str, cluster_name: str,
|
11
|
+
config: common.ProvisionConfig) -> common.ProvisionConfig:
|
12
|
+
"""Bootstraps instances for the given cluster."""
|
13
|
+
del region, cluster_name
|
14
|
+
return config
|