skypilot-nightly 1.0.0.dev20251029__py3-none-any.whl → 1.0.0.dev20251101__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of skypilot-nightly might be problematic. Click here for more details.

Files changed (68) hide show
  1. sky/__init__.py +2 -2
  2. sky/adaptors/aws.py +25 -7
  3. sky/client/cli/command.py +47 -23
  4. sky/clouds/aws.py +59 -11
  5. sky/dashboard/out/404.html +1 -1
  6. sky/dashboard/out/_next/static/chunks/2755.d6dc6d530fed0b61.js +26 -0
  7. sky/dashboard/out/_next/static/chunks/{webpack-485984ca04e021d0.js → webpack-e38d5319cd10a3a0.js} +1 -1
  8. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  9. sky/dashboard/out/clusters/[cluster].html +1 -1
  10. sky/dashboard/out/clusters.html +1 -1
  11. sky/dashboard/out/config.html +1 -1
  12. sky/dashboard/out/index.html +1 -1
  13. sky/dashboard/out/infra/[context].html +1 -1
  14. sky/dashboard/out/infra.html +1 -1
  15. sky/dashboard/out/jobs/[job].html +1 -1
  16. sky/dashboard/out/jobs/pools/[pool].html +1 -1
  17. sky/dashboard/out/jobs.html +1 -1
  18. sky/dashboard/out/users.html +1 -1
  19. sky/dashboard/out/volumes.html +1 -1
  20. sky/dashboard/out/workspace/new.html +1 -1
  21. sky/dashboard/out/workspaces/[name].html +1 -1
  22. sky/dashboard/out/workspaces.html +1 -1
  23. sky/data/mounting_utils.py +32 -2
  24. sky/jobs/constants.py +2 -0
  25. sky/jobs/controller.py +62 -67
  26. sky/jobs/file_content_utils.py +80 -0
  27. sky/jobs/log_gc.py +201 -0
  28. sky/jobs/scheduler.py +15 -2
  29. sky/jobs/server/core.py +85 -13
  30. sky/jobs/server/server.py +12 -11
  31. sky/jobs/server/utils.py +28 -10
  32. sky/jobs/state.py +216 -40
  33. sky/jobs/utils.py +60 -22
  34. sky/metrics/utils.py +18 -0
  35. sky/schemas/api/responses.py +1 -0
  36. sky/schemas/db/spot_jobs/004_job_file_contents.py +42 -0
  37. sky/schemas/db/spot_jobs/005_logs_gc.py +38 -0
  38. sky/schemas/generated/managed_jobsv1_pb2.py +39 -35
  39. sky/schemas/generated/managed_jobsv1_pb2.pyi +21 -5
  40. sky/serve/server/server.py +8 -7
  41. sky/server/common.py +21 -15
  42. sky/server/constants.py +1 -1
  43. sky/server/daemons.py +23 -17
  44. sky/server/requests/executor.py +7 -3
  45. sky/server/requests/request_names.py +80 -0
  46. sky/server/server.py +103 -35
  47. sky/skylet/constants.py +6 -1
  48. sky/skylet/events.py +7 -0
  49. sky/skylet/services.py +18 -7
  50. sky/ssh_node_pools/server.py +5 -4
  51. sky/task.py +4 -42
  52. sky/templates/kubernetes-ray.yml.j2 +1 -1
  53. sky/templates/websocket_proxy.py +140 -12
  54. sky/users/permission.py +4 -1
  55. sky/utils/db/migration_utils.py +1 -1
  56. sky/utils/resource_checker.py +4 -1
  57. sky/utils/schemas.py +23 -4
  58. sky/volumes/server/server.py +4 -3
  59. sky/workspaces/server.py +7 -6
  60. {skypilot_nightly-1.0.0.dev20251029.dist-info → skypilot_nightly-1.0.0.dev20251101.dist-info}/METADATA +36 -36
  61. {skypilot_nightly-1.0.0.dev20251029.dist-info → skypilot_nightly-1.0.0.dev20251101.dist-info}/RECORD +67 -62
  62. sky/dashboard/out/_next/static/chunks/2755.a239c652bf8684dd.js +0 -26
  63. /sky/dashboard/out/_next/static/{DabuSAKsc_y0wyJxpTIdQ → 8ixeA0NVQJN8HUdijid8b}/_buildManifest.js +0 -0
  64. /sky/dashboard/out/_next/static/{DabuSAKsc_y0wyJxpTIdQ → 8ixeA0NVQJN8HUdijid8b}/_ssgManifest.js +0 -0
  65. {skypilot_nightly-1.0.0.dev20251029.dist-info → skypilot_nightly-1.0.0.dev20251101.dist-info}/WHEEL +0 -0
  66. {skypilot_nightly-1.0.0.dev20251029.dist-info → skypilot_nightly-1.0.0.dev20251101.dist-info}/entry_points.txt +0 -0
  67. {skypilot_nightly-1.0.0.dev20251029.dist-info → skypilot_nightly-1.0.0.dev20251101.dist-info}/licenses/LICENSE +0 -0
  68. {skypilot_nightly-1.0.0.dev20251029.dist-info → skypilot_nightly-1.0.0.dev20251101.dist-info}/top_level.txt +0 -0
@@ -11,15 +11,23 @@ This script is useful for users who do not have local Kubernetes credentials.
11
11
  import asyncio
12
12
  from http.cookiejar import MozillaCookieJar
13
13
  import os
14
+ import struct
14
15
  import sys
15
- from typing import Dict
16
+ import time
17
+ from typing import Dict, Optional
16
18
  from urllib.request import Request
17
19
 
20
+ import requests
18
21
  import websockets
19
22
  from websockets.asyncio.client import ClientConnection
20
23
  from websockets.asyncio.client import connect
21
24
 
25
+ from sky.server import constants
26
+ from sky.server.server import KubernetesSSHMessageType
27
+ from sky.skylet import constants as skylet_constants
28
+
22
29
  BUFFER_SIZE = 2**16 # 64KB
30
+ HEARTBEAT_INTERVAL_SECONDS = 10
23
31
 
24
32
  # Environment variable for a file path to the API cookie file.
25
33
  # Keep in sync with server/constants.py
@@ -28,6 +36,8 @@ API_COOKIE_FILE_ENV_VAR = 'SKYPILOT_API_COOKIE_FILE'
28
36
  # Keep in sync with server/constants.py
29
37
  API_COOKIE_FILE_DEFAULT_LOCATION = '~/.sky/cookies.txt'
30
38
 
39
+ MAX_UNANSWERED_PINGS = 100
40
+
31
41
 
32
42
  def _get_cookie_header(url: str) -> Dict[str, str]:
33
43
  """Extract Cookie header value from a cookie jar for a specific URL"""
@@ -49,7 +59,7 @@ def _get_cookie_header(url: str) -> Dict[str, str]:
49
59
  return {'Cookie': cookie_header}
50
60
 
51
61
 
52
- async def main(url: str) -> None:
62
+ async def main(url: str, timestamps_supported: bool) -> None:
53
63
  cookie_header = _get_cookie_header(url)
54
64
  async with connect(url,
55
65
  ping_interval=None,
@@ -75,45 +85,149 @@ async def main(url: str) -> None:
75
85
  asyncio.streams.FlowControlMixin, sys.stdout) # type: ignore
76
86
  stdout_writer = asyncio.StreamWriter(transport, protocol, None,
77
87
  loop)
88
+ # Dictionary to store last ping time for latency measurement
89
+ last_ping_time_dict: Optional[Dict[int, float]] = None
90
+ if timestamps_supported:
91
+ last_ping_time_dict = {}
92
+
93
+ # Use an Event to signal when websocket is closed
94
+ websocket_closed_event = asyncio.Event()
95
+ websocket_lock = asyncio.Lock()
78
96
 
79
- await asyncio.gather(stdin_to_websocket(stdin_reader, websocket),
80
- websocket_to_stdout(websocket, stdout_writer))
97
+ await asyncio.gather(
98
+ stdin_to_websocket(stdin_reader, websocket,
99
+ timestamps_supported, websocket_closed_event,
100
+ websocket_lock),
101
+ websocket_to_stdout(websocket, stdout_writer,
102
+ timestamps_supported, last_ping_time_dict,
103
+ websocket_closed_event, websocket_lock),
104
+ latency_monitor(websocket, last_ping_time_dict,
105
+ websocket_closed_event, websocket_lock),
106
+ return_exceptions=True)
81
107
  finally:
82
108
  if old_settings:
83
109
  termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN,
84
110
  old_settings)
85
111
 
86
112
 
113
+ async def latency_monitor(websocket: ClientConnection,
114
+ last_ping_time_dict: Optional[dict],
115
+ websocket_closed_event: asyncio.Event,
116
+ websocket_lock: asyncio.Lock):
117
+ """Periodically send PING messages (type 1) to measure latency."""
118
+ if last_ping_time_dict is None:
119
+ return
120
+ next_id = 0
121
+ while not websocket_closed_event.is_set():
122
+ try:
123
+ await asyncio.sleep(HEARTBEAT_INTERVAL_SECONDS)
124
+ if len(last_ping_time_dict) >= MAX_UNANSWERED_PINGS:
125
+ # We are not getting responses, clear the dictionary so
126
+ # as not to grow unbounded.
127
+ last_ping_time_dict.clear()
128
+ ping_time = time.time()
129
+ next_id += 1
130
+ last_ping_time_dict[next_id] = ping_time
131
+ message_header_bytes = struct.pack(
132
+ '!BI', KubernetesSSHMessageType.PINGPONG.value, next_id)
133
+ try:
134
+ async with websocket_lock:
135
+ await websocket.send(message_header_bytes)
136
+ except websockets.exceptions.ConnectionClosed as e:
137
+ # Websocket is already closed.
138
+ print(f'Failed to send PING message: {e}', file=sys.stderr)
139
+ break
140
+ except Exception as e:
141
+ print(f'Error in latency_monitor: {e}', file=sys.stderr)
142
+ websocket_closed_event.set()
143
+ raise e
144
+
145
+
87
146
  async def stdin_to_websocket(reader: asyncio.StreamReader,
88
- websocket: ClientConnection):
147
+ websocket: ClientConnection,
148
+ timestamps_supported: bool,
149
+ websocket_closed_event: asyncio.Event,
150
+ websocket_lock: asyncio.Lock):
89
151
  try:
90
- while True:
152
+ while not websocket_closed_event.is_set():
91
153
  # Read at most BUFFER_SIZE bytes, this not affect
92
154
  # responsiveness since it will return as soon as
93
155
  # there is at least one byte.
94
156
  # The BUFFER_SIZE is chosen to be large enough to improve
95
157
  # throughput.
96
158
  data = await reader.read(BUFFER_SIZE)
159
+
97
160
  if not data:
98
161
  break
99
- await websocket.send(data)
162
+ if timestamps_supported:
163
+ # Send message with type 0 to indicate data.
164
+ message_type_bytes = struct.pack(
165
+ '!B', KubernetesSSHMessageType.REGULAR_DATA.value)
166
+ data = message_type_bytes + data
167
+ async with websocket_lock:
168
+ await websocket.send(data)
169
+
100
170
  except Exception as e: # pylint: disable=broad-except
101
171
  print(f'Error in stdin_to_websocket: {e}', file=sys.stderr)
102
172
  finally:
103
- await websocket.close()
173
+ async with websocket_lock:
174
+ await websocket.close()
175
+ websocket_closed_event.set()
104
176
 
105
177
 
106
178
  async def websocket_to_stdout(websocket: ClientConnection,
107
- writer: asyncio.StreamWriter):
179
+ writer: asyncio.StreamWriter,
180
+ timestamps_supported: bool,
181
+ last_ping_time_dict: Optional[dict],
182
+ websocket_closed_event: asyncio.Event,
183
+ websocket_lock: asyncio.Lock):
108
184
  try:
109
- while True:
185
+ while not websocket_closed_event.is_set():
110
186
  message = await websocket.recv()
187
+ if (timestamps_supported and len(message) > 0 and
188
+ last_ping_time_dict is not None):
189
+ message_type = struct.unpack('!B', message[:1])[0]
190
+ if message_type == KubernetesSSHMessageType.REGULAR_DATA.value:
191
+ # Regular data - strip type byte and write to stdout
192
+ message = message[1:]
193
+ elif message_type == KubernetesSSHMessageType.PINGPONG.value:
194
+ # PONG response - calculate latency and send measurement
195
+ if not len(message) == struct.calcsize('!BI'):
196
+ raise ValueError(
197
+ f'Invalid PONG message length: {len(message)}')
198
+ pong_id = struct.unpack('!I', message[1:5])[0]
199
+ pong_time = time.time()
200
+
201
+ ping_time = last_ping_time_dict.pop(pong_id, None)
202
+
203
+ if ping_time is None:
204
+ continue
205
+
206
+ latency_seconds = pong_time - ping_time
207
+ latency_ms = int(latency_seconds * 1000)
208
+
209
+ # Send latency measurement (type 2)
210
+ message_type_bytes = struct.pack(
211
+ '!B',
212
+ KubernetesSSHMessageType.LATENCY_MEASUREMENT.value)
213
+ latency_bytes = struct.pack('!Q', latency_ms)
214
+ message = message_type_bytes + latency_bytes
215
+ # Send to server.
216
+ async with websocket_lock:
217
+ await websocket.send(message)
218
+ continue
219
+ # No timestamps support, write directly
111
220
  writer.write(message)
112
221
  await writer.drain()
113
222
  except websockets.exceptions.ConnectionClosed:
114
223
  print('WebSocket connection closed', file=sys.stderr)
115
224
  except Exception as e: # pylint: disable=broad-except
116
225
  print(f'Error in websocket_to_stdout: {e}', file=sys.stderr)
226
+ raise e
227
+ finally:
228
+ async with websocket_lock:
229
+ await websocket.close()
230
+ websocket_closed_event.set()
117
231
 
118
232
 
119
233
  if __name__ == '__main__':
@@ -123,11 +237,25 @@ if __name__ == '__main__':
123
237
  # TODO(aylei): Remove this after 0.10.0
124
238
  server_url = f'http://{server_url}'
125
239
 
240
+ health_url = f'{server_url}/api/health'
241
+ health_response = requests.get(health_url)
242
+ health_data = health_response.json()
243
+ timestamps_are_supported = int(health_data['api_version']) > 21
244
+ disable_latency_measurement = os.environ.get(
245
+ skylet_constants.SSH_DISABLE_LATENCY_MEASUREMENT_ENV_VAR, '0') == '1'
246
+ timestamps_are_supported = (timestamps_are_supported and
247
+ not disable_latency_measurement)
248
+
126
249
  server_proto, server_fqdn = server_url.split('://')
127
250
  websocket_proto = 'ws'
128
251
  if server_proto == 'https':
129
252
  websocket_proto = 'wss'
130
253
  server_url = f'{websocket_proto}://{server_fqdn}'
254
+
255
+ client_version_str = (f'&client_version={constants.API_VERSION}'
256
+ if timestamps_are_supported else '')
257
+
131
258
  websocket_url = (f'{server_url}/kubernetes-pod-ssh-proxy'
132
- f'?cluster_name={sys.argv[2]}')
133
- asyncio.run(main(websocket_url))
259
+ f'?cluster_name={sys.argv[2]}'
260
+ f'{client_version_str}')
261
+ asyncio.run(main(websocket_url, timestamps_are_supported))
sky/users/permission.py CHANGED
@@ -43,7 +43,6 @@ class PermissionService:
43
43
  with _policy_lock():
44
44
  global _enforcer_instance
45
45
  if _enforcer_instance is None:
46
- _enforcer_instance = self
47
46
  engine = global_user_state.initialize_and_get_db()
48
47
  db_utils.add_all_tables_to_db_sqlalchemy(
49
48
  sqlalchemy_adapter.Base.metadata, engine)
@@ -53,6 +52,10 @@ class PermissionService:
53
52
  'model.conf')
54
53
  enforcer = casbin.Enforcer(model_path, adapter)
55
54
  self.enforcer = enforcer
55
+ # Only set the enforcer instance once the enforcer
56
+ # is successfully initialized, if we change it and then fail
57
+ # we will set it to None and all subsequent calls will fail.
58
+ _enforcer_instance = self
56
59
  self._maybe_initialize_policies()
57
60
  self._maybe_initialize_basic_auth_user()
58
61
  else:
@@ -22,7 +22,7 @@ GLOBAL_USER_STATE_VERSION = '010'
22
22
  GLOBAL_USER_STATE_LOCK_PATH = f'~/.sky/locks/.{GLOBAL_USER_STATE_DB_NAME}.lock'
23
23
 
24
24
  SPOT_JOBS_DB_NAME = 'spot_jobs_db'
25
- SPOT_JOBS_VERSION = '003'
25
+ SPOT_JOBS_VERSION = '005'
26
26
  SPOT_JOBS_LOCK_PATH = f'~/.sky/locks/.{SPOT_JOBS_DB_NAME}.lock'
27
27
 
28
28
  SERVE_DB_NAME = 'serve_db'
@@ -278,7 +278,10 @@ def _get_active_resources(
278
278
  from sky.jobs.server import core as managed_jobs_core
279
279
  try:
280
280
  filtered_jobs, _, _, _ = managed_jobs_core.queue_v2(
281
- refresh=False, skip_finished=True, all_users=True)
281
+ refresh=False,
282
+ skip_finished=True,
283
+ all_users=True,
284
+ fields=['job_id', 'user_hash', 'workspace'])
282
285
  return filtered_jobs
283
286
  except exceptions.ClusterNotUpError:
284
287
  logger.warning('All jobs should be finished.')
sky/utils/schemas.py CHANGED
@@ -1190,7 +1190,13 @@ def get_config_schema():
1190
1190
  'consolidation_mode': {
1191
1191
  'type': 'boolean',
1192
1192
  'default': False,
1193
- }
1193
+ },
1194
+ 'controller_logs_gc_retention_hours': {
1195
+ 'type': 'integer',
1196
+ },
1197
+ 'task_logs_gc_retention_hours': {
1198
+ 'type': 'integer',
1199
+ },
1194
1200
  },
1195
1201
  },
1196
1202
  'bucket': {
@@ -1592,10 +1598,10 @@ def get_config_schema():
1592
1598
 
1593
1599
  allowed_workspace_cloud_names = list(constants.ALL_CLOUDS) + ['cloudflare']
1594
1600
  # Create pattern for not supported clouds, i.e.
1595
- # all clouds except gcp, kubernetes, ssh
1601
+ # all clouds except aws, gcp, kubernetes, ssh, nebius
1596
1602
  not_supported_clouds = [
1597
1603
  cloud for cloud in allowed_workspace_cloud_names
1598
- if cloud.lower() not in ['gcp', 'kubernetes', 'ssh', 'nebius']
1604
+ if cloud.lower() not in ['aws', 'gcp', 'kubernetes', 'ssh', 'nebius']
1599
1605
  ]
1600
1606
  not_supported_cloud_regex = '|'.join(not_supported_clouds)
1601
1607
  workspaces_schema = {
@@ -1606,7 +1612,8 @@ def get_config_schema():
1606
1612
  'type': 'object',
1607
1613
  'additionalProperties': False,
1608
1614
  'patternProperties': {
1609
- # Pattern for non-GCP clouds - only allows 'disabled' property
1615
+ # Pattern for clouds with no workspace-specific config -
1616
+ # only allow 'disabled' property.
1610
1617
  f'^({not_supported_cloud_regex})$': {
1611
1618
  'type': 'object',
1612
1619
  'additionalProperties': False,
@@ -1641,6 +1648,18 @@ def get_config_schema():
1641
1648
  },
1642
1649
  'additionalProperties': False,
1643
1650
  },
1651
+ 'aws': {
1652
+ 'type': 'object',
1653
+ 'properties': {
1654
+ 'profile': {
1655
+ 'type': 'string'
1656
+ },
1657
+ 'disabled': {
1658
+ 'type': 'boolean'
1659
+ },
1660
+ },
1661
+ 'additionalProperties': False,
1662
+ },
1644
1663
  'ssh': {
1645
1664
  'type': 'object',
1646
1665
  'required': [],
@@ -7,6 +7,7 @@ from sky import exceptions
7
7
  from sky import sky_logging
8
8
  from sky.server.requests import executor
9
9
  from sky.server.requests import payloads
10
+ from sky.server.requests import request_names
10
11
  from sky.server.requests import requests as requests_lib
11
12
  from sky.utils import registry
12
13
  from sky.utils import volume as volume_utils
@@ -27,7 +28,7 @@ async def volume_list(request: fastapi.Request) -> None:
27
28
  request_body = payloads.RequestBody(**auth_user_env_vars_kwargs)
28
29
  await executor.schedule_request_async(
29
30
  request_id=request.state.request_id,
30
- request_name='volume_list',
31
+ request_name=request_names.RequestName.VOLUME_LIST,
31
32
  request_body=request_body,
32
33
  func=core.volume_list,
33
34
  schedule_type=requests_lib.ScheduleType.SHORT,
@@ -40,7 +41,7 @@ async def volume_delete(request: fastapi.Request,
40
41
  """Deletes a volume."""
41
42
  await executor.schedule_request_async(
42
43
  request_id=request.state.request_id,
43
- request_name='volume_delete',
44
+ request_name=request_names.RequestName.VOLUME_DELETE,
44
45
  request_body=volume_delete_body,
45
46
  func=core.volume_delete,
46
47
  schedule_type=requests_lib.ScheduleType.LONG,
@@ -114,7 +115,7 @@ async def volume_apply(request: fastapi.Request,
114
115
  detail='Runpod network volume is only supported on Runpod')
115
116
  await executor.schedule_request_async(
116
117
  request_id=request.state.request_id,
117
- request_name='volume_apply',
118
+ request_name=request_names.RequestName.VOLUME_APPLY,
118
119
  request_body=volume_apply_body,
119
120
  func=core.volume_apply,
120
121
  schedule_type=requests_lib.ScheduleType.LONG,
sky/workspaces/server.py CHANGED
@@ -4,6 +4,7 @@ import fastapi
4
4
 
5
5
  from sky.server.requests import executor
6
6
  from sky.server.requests import payloads
7
+ from sky.server.requests import request_names
7
8
  from sky.server.requests import requests as api_requests
8
9
  from sky.workspaces import core
9
10
 
@@ -24,7 +25,7 @@ async def get(request: fastapi.Request) -> None:
24
25
 
25
26
  await executor.schedule_request_async(
26
27
  request_id=request.state.request_id,
27
- request_name='workspaces.get',
28
+ request_name=request_names.RequestName.WORKSPACES_GET,
28
29
  request_body=request_body,
29
30
  func=core.get_workspaces,
30
31
  schedule_type=api_requests.ScheduleType.SHORT,
@@ -37,7 +38,7 @@ async def update(request: fastapi.Request,
37
38
  """Updates a specific workspace configuration."""
38
39
  await executor.schedule_request_async(
39
40
  request_id=request.state.request_id,
40
- request_name='workspaces.update',
41
+ request_name=request_names.RequestName.WORKSPACES_UPDATE,
41
42
  request_body=update_workspace_body,
42
43
  func=core.update_workspace,
43
44
  schedule_type=api_requests.ScheduleType.SHORT,
@@ -50,7 +51,7 @@ async def create(request: fastapi.Request,
50
51
  """Creates a new workspace configuration."""
51
52
  await executor.schedule_request_async(
52
53
  request_id=request.state.request_id,
53
- request_name='workspaces.create',
54
+ request_name=request_names.RequestName.WORKSPACES_CREATE,
54
55
  request_body=create_workspace_body,
55
56
  func=core.create_workspace,
56
57
  schedule_type=api_requests.ScheduleType.SHORT,
@@ -63,7 +64,7 @@ async def delete(request: fastapi.Request,
63
64
  """Deletes a workspace configuration."""
64
65
  await executor.schedule_request_async(
65
66
  request_id=request.state.request_id,
66
- request_name='workspaces.delete',
67
+ request_name=request_names.RequestName.WORKSPACES_DELETE,
67
68
  request_body=delete_workspace_body,
68
69
  func=core.delete_workspace,
69
70
  schedule_type=api_requests.ScheduleType.SHORT,
@@ -80,7 +81,7 @@ async def get_config(request: fastapi.Request) -> None:
80
81
  get_config_body = payloads.GetConfigBody(**auth_user_env_vars_kwargs)
81
82
  await executor.schedule_request_async(
82
83
  request_id=request.state.request_id,
83
- request_name='workspaces.get_config',
84
+ request_name=request_names.RequestName.WORKSPACES_GET_CONFIG,
84
85
  request_body=get_config_body,
85
86
  func=core.get_config,
86
87
  schedule_type=api_requests.ScheduleType.SHORT,
@@ -93,7 +94,7 @@ async def update_config(request: fastapi.Request,
93
94
  """Updates the entire SkyPilot configuration."""
94
95
  await executor.schedule_request_async(
95
96
  request_id=request.state.request_id,
96
- request_name='workspaces.update_config',
97
+ request_name=request_names.RequestName.WORKSPACES_UPDATE_CONFIG,
97
98
  request_body=update_config_body,
98
99
  func=core.update_config,
99
100
  schedule_type=api_requests.ScheduleType.SHORT,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skypilot-nightly
3
- Version: 1.0.0.dev20251029
3
+ Version: 1.0.0.dev20251101
4
4
  Summary: SkyPilot: Run AI on Any Infra — Unified, Faster, Cheaper.
5
5
  Author: SkyPilot Team
6
6
  License: Apache 2.0
@@ -387,51 +387,51 @@ Requires-Dist: protobuf<7.0.0,>=5.26.1; extra == "shadeform"
387
387
  Requires-Dist: aiosqlite; extra == "shadeform"
388
388
  Requires-Dist: greenlet; extra == "shadeform"
389
389
  Provides-Extra: all
390
- Requires-Dist: msgraph-sdk; extra == "all"
391
- Requires-Dist: ibm-cloud-sdk-core; extra == "all"
392
- Requires-Dist: ibm-vpc; extra == "all"
390
+ Requires-Dist: azure-cli>=2.65.0; extra == "all"
391
+ Requires-Dist: aiohttp; extra == "all"
392
+ Requires-Dist: google-api-python-client>=2.69.0; extra == "all"
393
393
  Requires-Dist: azure-core>=1.31.0; extra == "all"
394
- Requires-Dist: awscli>=1.27.10; extra == "all"
395
- Requires-Dist: sqlalchemy_adapter; extra == "all"
394
+ Requires-Dist: botocore>=1.29.10; extra == "all"
395
+ Requires-Dist: colorama<0.4.5; extra == "all"
396
+ Requires-Dist: docker; extra == "all"
397
+ Requires-Dist: protobuf<7.0.0,>=5.26.1; extra == "all"
398
+ Requires-Dist: runpod>=1.6.1; extra == "all"
396
399
  Requires-Dist: azure-mgmt-network>=27.0.0; extra == "all"
397
- Requires-Dist: azure-identity>=1.19.0; extra == "all"
398
- Requires-Dist: ray[default]>=2.6.1; extra == "all"
400
+ Requires-Dist: ibm-vpc; extra == "all"
401
+ Requires-Dist: sqlalchemy_adapter; extra == "all"
402
+ Requires-Dist: awscli>=1.27.10; extra == "all"
403
+ Requires-Dist: anyio; extra == "all"
404
+ Requires-Dist: kubernetes!=32.0.0,>=20.0.0; extra == "all"
405
+ Requires-Dist: pydo>=0.3.0; extra == "all"
406
+ Requires-Dist: grpcio>=1.63.0; extra == "all"
407
+ Requires-Dist: tomli; python_version < "3.11" and extra == "all"
408
+ Requires-Dist: passlib; extra == "all"
399
409
  Requires-Dist: nebius>=0.2.47; extra == "all"
400
- Requires-Dist: google-api-python-client>=2.69.0; extra == "all"
410
+ Requires-Dist: azure-core>=1.24.0; extra == "all"
411
+ Requires-Dist: ibm-cloud-sdk-core; extra == "all"
401
412
  Requires-Dist: vastai-sdk>=0.1.12; extra == "all"
402
- Requires-Dist: casbin; extra == "all"
403
- Requires-Dist: grpcio>=1.63.0; extra == "all"
413
+ Requires-Dist: ibm-platform-services>=0.48.0; extra == "all"
414
+ Requires-Dist: pyjwt; extra == "all"
415
+ Requires-Dist: cudo-compute>=0.1.10; extra == "all"
416
+ Requires-Dist: ray[default]>=2.6.1; extra == "all"
404
417
  Requires-Dist: aiosqlite; extra == "all"
418
+ Requires-Dist: oci; extra == "all"
419
+ Requires-Dist: ibm-cos-sdk; extra == "all"
405
420
  Requires-Dist: pyopenssl<24.3.0,>=23.2.0; extra == "all"
406
- Requires-Dist: runpod>=1.6.1; extra == "all"
421
+ Requires-Dist: ecsapi>=0.2.0; extra == "all"
422
+ Requires-Dist: msgraph-sdk; extra == "all"
423
+ Requires-Dist: boto3>=1.26.1; extra == "all"
424
+ Requires-Dist: casbin; extra == "all"
407
425
  Requires-Dist: greenlet; extra == "all"
408
- Requires-Dist: azure-common; extra == "all"
409
- Requires-Dist: colorama<0.4.5; extra == "all"
426
+ Requires-Dist: pyvmomi==8.0.1.0.2; extra == "all"
427
+ Requires-Dist: python-dateutil; extra == "all"
428
+ Requires-Dist: azure-storage-blob>=12.23.1; extra == "all"
429
+ Requires-Dist: azure-identity>=1.19.0; extra == "all"
410
430
  Requires-Dist: google-cloud-storage; extra == "all"
431
+ Requires-Dist: msrestazure; extra == "all"
432
+ Requires-Dist: azure-common; extra == "all"
411
433
  Requires-Dist: websockets; extra == "all"
412
434
  Requires-Dist: azure-mgmt-compute>=33.0.0; extra == "all"
413
- Requires-Dist: msrestazure; extra == "all"
414
- Requires-Dist: tomli; python_version < "3.11" and extra == "all"
415
- Requires-Dist: ecsapi>=0.2.0; extra == "all"
416
- Requires-Dist: python-dateutil; extra == "all"
417
- Requires-Dist: passlib; extra == "all"
418
- Requires-Dist: kubernetes!=32.0.0,>=20.0.0; extra == "all"
419
- Requires-Dist: docker; extra == "all"
420
- Requires-Dist: anyio; extra == "all"
421
- Requires-Dist: ibm-cos-sdk; extra == "all"
422
- Requires-Dist: pyvmomi==8.0.1.0.2; extra == "all"
423
- Requires-Dist: pyjwt; extra == "all"
424
- Requires-Dist: oci; extra == "all"
425
- Requires-Dist: azure-storage-blob>=12.23.1; extra == "all"
426
- Requires-Dist: cudo-compute>=0.1.10; extra == "all"
427
- Requires-Dist: azure-core>=1.24.0; extra == "all"
428
- Requires-Dist: aiohttp; extra == "all"
429
- Requires-Dist: protobuf<7.0.0,>=5.26.1; extra == "all"
430
- Requires-Dist: botocore>=1.29.10; extra == "all"
431
- Requires-Dist: azure-cli>=2.65.0; extra == "all"
432
- Requires-Dist: boto3>=1.26.1; extra == "all"
433
- Requires-Dist: pydo>=0.3.0; extra == "all"
434
- Requires-Dist: ibm-platform-services>=0.48.0; extra == "all"
435
435
  Provides-Extra: remote
436
436
  Requires-Dist: grpcio>=1.63.0; extra == "remote"
437
437
  Requires-Dist: protobuf<7.0.0,>=5.26.1; extra == "remote"