skypilot-nightly 1.0.0.dev20250405__py3-none-any.whl → 1.0.0.dev20250407__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/clouds/lambda_cloud.py +0 -1
- sky/provision/lambda_cloud/instance.py +101 -16
- sky/provision/lambda_cloud/lambda_utils.py +84 -0
- {skypilot_nightly-1.0.0.dev20250405.dist-info → skypilot_nightly-1.0.0.dev20250407.dist-info}/METADATA +1 -1
- {skypilot_nightly-1.0.0.dev20250405.dist-info → skypilot_nightly-1.0.0.dev20250407.dist-info}/RECORD +10 -10
- {skypilot_nightly-1.0.0.dev20250405.dist-info → skypilot_nightly-1.0.0.dev20250407.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20250405.dist-info → skypilot_nightly-1.0.0.dev20250407.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250405.dist-info → skypilot_nightly-1.0.0.dev20250407.dist-info}/licenses/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250405.dist-info → skypilot_nightly-1.0.0.dev20250407.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 = 'c5039370280815a3f347e76622dc154ede36d6c3'
|
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.dev20250407'
|
39
39
|
__root_dir__ = os.path.dirname(os.path.abspath(__file__))
|
40
40
|
|
41
41
|
|
sky/clouds/lambda_cloud.py
CHANGED
@@ -43,7 +43,6 @@ class Lambda(clouds.Cloud):
|
|
43
43
|
clouds.CloudImplementationFeatures.SPOT_INSTANCE: f'Spot instances are not supported in {_REPR}.',
|
44
44
|
clouds.CloudImplementationFeatures.IMAGE_ID: f'Specifying image ID is not supported in {_REPR}.',
|
45
45
|
clouds.CloudImplementationFeatures.CUSTOM_DISK_TIER: f'Custom disk tiers are not supported in {_REPR}.',
|
46
|
-
clouds.CloudImplementationFeatures.OPEN_PORTS: f'Opening ports is currently not supported on {_REPR}.',
|
47
46
|
clouds.CloudImplementationFeatures.HOST_CONTROLLERS: f'Host controllers are not supported in {_REPR}.',
|
48
47
|
}
|
49
48
|
|
@@ -1,12 +1,13 @@
|
|
1
|
-
"""Lambda instance provisioning."""
|
1
|
+
"""Lambda Cloud instance provisioning."""
|
2
2
|
|
3
3
|
import time
|
4
4
|
from typing import Any, Dict, List, Optional
|
5
5
|
|
6
6
|
from sky import sky_logging
|
7
7
|
from sky.provision import common
|
8
|
-
|
8
|
+
from sky.provision.lambda_cloud import lambda_utils
|
9
9
|
from sky.utils import common_utils
|
10
|
+
from sky.utils import resources_utils
|
10
11
|
from sky.utils import status_lib
|
11
12
|
from sky.utils import ux_utils
|
12
13
|
|
@@ -248,18 +249,102 @@ def query_instances(
|
|
248
249
|
return statuses
|
249
250
|
|
250
251
|
|
251
|
-
def open_ports(
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
ports:
|
262
|
-
|
263
|
-
|
264
|
-
|
252
|
+
def open_ports(cluster_name_on_cloud: str,
|
253
|
+
ports: List[str],
|
254
|
+
provider_config: Optional[Dict[str, Any]] = None) -> None:
|
255
|
+
"""Open firewall ports for Lambda Cloud.
|
256
|
+
|
257
|
+
Args:
|
258
|
+
cluster_name_on_cloud: Cluster name on Lambda Cloud.
|
259
|
+
ports: List of ports to open.
|
260
|
+
provider_config: Lambda Cloud provider config. Contains the API key.
|
261
|
+
"""
|
262
|
+
if not ports:
|
263
|
+
return
|
264
|
+
|
265
|
+
# Skip port opening for us-south-1 region where it's not supported
|
266
|
+
region = None
|
267
|
+
if provider_config is not None:
|
268
|
+
region = provider_config.get('region')
|
269
|
+
|
270
|
+
# Skip port opening for us-south-1, as it's not supported by Lambda Cloud
|
271
|
+
# https://cloud.lambda.ai/api/v1/docs#get-/api/v1/firewall-rules
|
272
|
+
if region == 'us-south-1':
|
273
|
+
logger.warning(
|
274
|
+
f'Skipping port opening for cluster {cluster_name_on_cloud} in '
|
275
|
+
f'us-south-1 region, as firewall rules are not supported there.')
|
276
|
+
return
|
277
|
+
|
278
|
+
del provider_config, cluster_name_on_cloud # No longer needed
|
279
|
+
|
280
|
+
lambda_client = lambda_utils.LambdaCloudClient()
|
281
|
+
|
282
|
+
# Get existing rules to avoid duplicates
|
283
|
+
existing_rules = lambda_client.list_firewall_rules()
|
284
|
+
existing_ports = set()
|
285
|
+
for rule in existing_rules:
|
286
|
+
port_range = rule.get('port_range')
|
287
|
+
if rule.get('protocol') == 'tcp' and port_range is not None:
|
288
|
+
if len(port_range) == 1:
|
289
|
+
# For single ports
|
290
|
+
existing_ports.add(port_range[0])
|
291
|
+
elif len(port_range) == 2:
|
292
|
+
# For port ranges, add all ports in the range
|
293
|
+
existing_ports.update(range(port_range[0], port_range[1] + 1))
|
294
|
+
|
295
|
+
# Convert port strings to a set of individual ports
|
296
|
+
ports_to_open = resources_utils.port_ranges_to_set(ports)
|
297
|
+
|
298
|
+
# Remove ports that are already open
|
299
|
+
ports_to_open = ports_to_open - existing_ports
|
300
|
+
|
301
|
+
# If no ports need to be opened, return early
|
302
|
+
if not ports_to_open:
|
303
|
+
return
|
304
|
+
|
305
|
+
# Convert individual ports to consolidated ranges
|
306
|
+
port_ranges = resources_utils.port_set_to_ranges(ports_to_open)
|
307
|
+
|
308
|
+
# Open port ranges
|
309
|
+
for port_range in port_ranges:
|
310
|
+
if '-' in port_range:
|
311
|
+
# Handle range (e.g., "1000-1010")
|
312
|
+
start, end = map(int, port_range.split('-'))
|
313
|
+
logger.debug(f'Opening port range {port_range}/tcp')
|
314
|
+
try:
|
315
|
+
lambda_client.create_firewall_rule(port_range=[start, end],
|
316
|
+
protocol='tcp')
|
317
|
+
except lambda_utils.LambdaCloudError as e:
|
318
|
+
logger.warning(f'Failed to open port range {port_range}: {e}')
|
319
|
+
else:
|
320
|
+
# Handle single port
|
321
|
+
port = int(port_range)
|
322
|
+
logger.debug(f'Opening port {port}/tcp')
|
323
|
+
try:
|
324
|
+
lambda_client.create_firewall_rule(port_range=[port, port],
|
325
|
+
protocol='tcp')
|
326
|
+
except lambda_utils.LambdaCloudError as e:
|
327
|
+
logger.warning(f'Failed to open port {port}: {e}')
|
328
|
+
|
329
|
+
|
330
|
+
def cleanup_ports(cluster_name_on_cloud: str,
|
331
|
+
ports: List[str],
|
332
|
+
provider_config: Optional[Dict[str, Any]] = None) -> None:
|
333
|
+
"""Skip cleanup of firewall rules.
|
334
|
+
|
335
|
+
Lambda Cloud firewall rules are global to the account, not cluster-specific.
|
336
|
+
We skip cleanup because rules may be used by other clusters.
|
337
|
+
|
338
|
+
TODO(zhwu): the firewall rules may accumulate over time, and we may need
|
339
|
+
to add a way to automatically clean them up.
|
340
|
+
|
341
|
+
Args:
|
342
|
+
cluster_name_on_cloud: Unused.
|
343
|
+
ports: Unused.
|
344
|
+
provider_config: Unused.
|
345
|
+
"""
|
265
346
|
del cluster_name_on_cloud, ports, provider_config # Unused.
|
347
|
+
|
348
|
+
# Break the long line by splitting it
|
349
|
+
logger.info('Skipping cleanup of Lambda Cloud firewall rules '
|
350
|
+
'as they are account-wide.')
|
@@ -112,6 +112,8 @@ def _try_request_with_backoff(method: str,
|
|
112
112
|
response = requests.get(url, headers=headers)
|
113
113
|
elif method == 'post':
|
114
114
|
response = requests.post(url, headers=headers, data=data)
|
115
|
+
elif method == 'put':
|
116
|
+
response = requests.put(url, headers=headers, data=data)
|
115
117
|
else:
|
116
118
|
raise ValueError(f'Unsupported requests method: {method}')
|
117
119
|
# If rate limited, wait and try again
|
@@ -249,4 +251,86 @@ class LambdaCloudClient:
|
|
249
251
|
response = _try_request_with_backoff('get',
|
250
252
|
f'{API_ENDPOINT}/instance-types',
|
251
253
|
headers=self.headers)
|
254
|
+
return response.json().get('data', {})
|
255
|
+
|
256
|
+
def list_firewall_rules(self) -> List[Dict[str, Any]]:
|
257
|
+
"""List firewall rules."""
|
258
|
+
response = _try_request_with_backoff('get',
|
259
|
+
f'{API_ENDPOINT}/firewall-rules',
|
260
|
+
headers=self.headers)
|
252
261
|
return response.json().get('data', [])
|
262
|
+
|
263
|
+
def create_firewall_rule(self,
|
264
|
+
port_range: List[int],
|
265
|
+
protocol: str = 'tcp',
|
266
|
+
description: str = '') -> Dict[str, Any]:
|
267
|
+
"""Create a firewall rule.
|
268
|
+
|
269
|
+
Args:
|
270
|
+
port_range: Port range as [min_port, max_port]. For a single port,
|
271
|
+
use [port, port].
|
272
|
+
protocol: Protocol ('tcp', 'udp', 'icmp', or 'all').
|
273
|
+
description: Description for the rule.
|
274
|
+
|
275
|
+
Returns:
|
276
|
+
The created firewall rule.
|
277
|
+
"""
|
278
|
+
# First, get all existing rules
|
279
|
+
existing_rules = self.list_firewall_rules()
|
280
|
+
|
281
|
+
# Convert existing rules to the format expected by the API
|
282
|
+
rule_list = []
|
283
|
+
for rule in existing_rules:
|
284
|
+
if rule.get('protocol') and rule.get('source_network'):
|
285
|
+
api_rule = {
|
286
|
+
'protocol': rule.get('protocol'),
|
287
|
+
'source_network': rule.get('source_network'),
|
288
|
+
'description': rule.get('description', '')
|
289
|
+
}
|
290
|
+
|
291
|
+
# Add port_range for non-icmp protocols
|
292
|
+
if rule.get('protocol') != 'icmp' and rule.get('port_range'):
|
293
|
+
api_rule['port_range'] = rule.get('port_range')
|
294
|
+
|
295
|
+
rule_list.append(api_rule)
|
296
|
+
|
297
|
+
# Add our new rule
|
298
|
+
new_rule: Dict[str, Any] = {
|
299
|
+
'protocol': protocol,
|
300
|
+
'source_network': '0.0.0.0/0', # Allow from any IP address
|
301
|
+
'description': description or
|
302
|
+
('SkyPilot auto-generated rule for port '
|
303
|
+
f'{port_range[0]}-{port_range[1]}/{protocol}')
|
304
|
+
}
|
305
|
+
|
306
|
+
# Add port_range for non-icmp protocols
|
307
|
+
if protocol != 'icmp':
|
308
|
+
new_rule['port_range'] = port_range
|
309
|
+
|
310
|
+
# Check if this rule already exists to avoid duplicates
|
311
|
+
rule_exists = False
|
312
|
+
for rule in rule_list:
|
313
|
+
if (rule.get('protocol') == protocol and
|
314
|
+
rule.get('source_network') == '0.0.0.0/0'):
|
315
|
+
if protocol != 'icmp':
|
316
|
+
if rule.get('port_range') == port_range:
|
317
|
+
rule_exists = True
|
318
|
+
break
|
319
|
+
else:
|
320
|
+
rule_exists = True
|
321
|
+
break
|
322
|
+
|
323
|
+
# Only add the rule if it doesn't already exist
|
324
|
+
if not rule_exists:
|
325
|
+
rule_list.append(new_rule)
|
326
|
+
|
327
|
+
# Create a data structure that matches the API schema
|
328
|
+
data = json.dumps({'data': rule_list})
|
329
|
+
|
330
|
+
response = _try_request_with_backoff(
|
331
|
+
'put', # Using PUT instead of POST as per API documentation
|
332
|
+
f'{API_ENDPOINT}/firewall-rules',
|
333
|
+
data=data,
|
334
|
+
headers=self.headers,
|
335
|
+
)
|
336
|
+
return response.json().get('data', {})
|
{skypilot_nightly-1.0.0.dev20250405.dist-info → skypilot_nightly-1.0.0.dev20250407.dist-info}/RECORD
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
sky/__init__.py,sha256
|
1
|
+
sky/__init__.py,sha256=-f-rcPq-1NRczFhvTmgyY0eGeL4xNdnjClhgY-sPx5I,6428
|
2
2
|
sky/admin_policy.py,sha256=hPo02f_A32gCqhUueF0QYy1fMSSKqRwYEg_9FxScN_s,3248
|
3
3
|
sky/authentication.py,sha256=ND011K_-Ud1dVZF37A9KrwYir_ihJXcHc7iDWmuBc8Q,22872
|
4
4
|
sky/check.py,sha256=PPNQnaaZBA9_aogJpN4gnG4XWnTqkd74c-rBYDkDRDY,16101
|
@@ -56,7 +56,7 @@ sky/clouds/fluidstack.py,sha256=jIqW1MLe55MVME1PATZm8e6_FsiTnJawW7OdytPW0aM,1266
|
|
56
56
|
sky/clouds/gcp.py,sha256=sUJ9LXUnMxYm6OYZ5P-z1dJHxgVILuC3OW3eFSTNCv8,56919
|
57
57
|
sky/clouds/ibm.py,sha256=XtuPN8QgrwJdb1qb_b-7KwAE2tf_N9wh9eEfi2tcg-s,22013
|
58
58
|
sky/clouds/kubernetes.py,sha256=SNRilcl_JYvaMDoYw0jnMtfaSi7FKQycCiJVmX6-4f4,36216
|
59
|
-
sky/clouds/lambda_cloud.py,sha256=
|
59
|
+
sky/clouds/lambda_cloud.py,sha256=H32vd30OfjXriH9SibVATrJZfZcCBTiWAXHfliGeMZk,12804
|
60
60
|
sky/clouds/nebius.py,sha256=4D7C2NQYI-BNhXWNOyAXNAZj7-5nN33VQW1sxfSGt9w,14662
|
61
61
|
sky/clouds/oci.py,sha256=YO4kjSsHBmAVH4z1TuVP72zfmC0BXte4E0xIyZir9N4,27622
|
62
62
|
sky/clouds/paperspace.py,sha256=s_sZcGqmABEqzu0MTus8__NuHo5hIUvq2FqVZCRkTzE,11070
|
@@ -171,8 +171,8 @@ sky/provision/kubernetes/manifests/smarter-device-manager-configmap.yaml,sha256=
|
|
171
171
|
sky/provision/kubernetes/manifests/smarter-device-manager-daemonset.yaml,sha256=RtTq4F1QUmR2Uunb6zuuRaPhV7hpesz4saHjn3Ncsb4,2010
|
172
172
|
sky/provision/lambda_cloud/__init__.py,sha256=6EEvSgtUeEiup9ivIFevHmgv0GqleroO2X0K7TRa2nE,612
|
173
173
|
sky/provision/lambda_cloud/config.py,sha256=jq1iLzp4Up61r4JGxvtpVbJlgXnea3LHYQhCQyyl7ik,272
|
174
|
-
sky/provision/lambda_cloud/instance.py,sha256=
|
175
|
-
sky/provision/lambda_cloud/lambda_utils.py,sha256=
|
174
|
+
sky/provision/lambda_cloud/instance.py,sha256=zenKFaAS9bAJxXM5_-Vnz7Fm7sSf3KSIlXhKUL4n6l8,12726
|
175
|
+
sky/provision/lambda_cloud/lambda_utils.py,sha256=G1dciGF8U3OGYk0-1pc3IDsT8AyA8AceujOkQy4fqho,13284
|
176
176
|
sky/provision/nebius/__init__.py,sha256=30I3181mu0W5g9fNvaWMPoBJZoGZ9RibuTpBH9P2pDg,558
|
177
177
|
sky/provision/nebius/config.py,sha256=LK9kTDp2w6zZrn3vNdcSGgsgS-dL_j63Nh4_u3pqNiA,321
|
178
178
|
sky/provision/nebius/instance.py,sha256=kfpZqwh56XV7h6XsX5dGJYilsVdRhC1EUgk0flaCo_E,11889
|
@@ -350,9 +350,9 @@ sky/utils/kubernetes/k8s_gpu_labeler_setup.yaml,sha256=VLKT2KKimZu1GDg_4AIlIt488
|
|
350
350
|
sky/utils/kubernetes/kubernetes_deploy_utils.py,sha256=HPVgNt-wbCVPd9dpDFiA7t2mzQLpjXHJ61eiwRbEr-c,10378
|
351
351
|
sky/utils/kubernetes/rsync_helper.sh,sha256=h4YwrPFf9727CACnMJvF3EyK_0OeOYKKt4su_daKekw,1256
|
352
352
|
sky/utils/kubernetes/ssh_jump_lifecycle_manager.py,sha256=Kq1MDygF2IxFmu9FXpCxqucXLmeUrvs6OtRij6XTQbo,6554
|
353
|
-
skypilot_nightly-1.0.0.
|
354
|
-
skypilot_nightly-1.0.0.
|
355
|
-
skypilot_nightly-1.0.0.
|
356
|
-
skypilot_nightly-1.0.0.
|
357
|
-
skypilot_nightly-1.0.0.
|
358
|
-
skypilot_nightly-1.0.0.
|
353
|
+
skypilot_nightly-1.0.0.dev20250407.dist-info/licenses/LICENSE,sha256=emRJAvE7ngL6x0RhQvlns5wJzGI3NEQ_WMjNmd9TZc4,12170
|
354
|
+
skypilot_nightly-1.0.0.dev20250407.dist-info/METADATA,sha256=hqvdfiv3pR-AR3iUrwYaDHD9U1Qra2EFlv8mwLdtAmk,18552
|
355
|
+
skypilot_nightly-1.0.0.dev20250407.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
356
|
+
skypilot_nightly-1.0.0.dev20250407.dist-info/entry_points.txt,sha256=StA6HYpuHj-Y61L2Ze-hK2IcLWgLZcML5gJu8cs6nU4,36
|
357
|
+
skypilot_nightly-1.0.0.dev20250407.dist-info/top_level.txt,sha256=qA8QuiNNb6Y1OF-pCUtPEr6sLEwy2xJX06Bd_CrtrHY,4
|
358
|
+
skypilot_nightly-1.0.0.dev20250407.dist-info/RECORD,,
|
{skypilot_nightly-1.0.0.dev20250405.dist-info → skypilot_nightly-1.0.0.dev20250407.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|