skypilot-nightly 1.0.0.dev20250628__py3-none-any.whl → 1.0.0.dev20250701__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.
Files changed (132) hide show
  1. sky/__init__.py +2 -2
  2. sky/adaptors/kubernetes.py +7 -0
  3. sky/backends/cloud_vm_ray_backend.py +3 -3
  4. sky/client/cli/command.py +1 -2
  5. sky/dashboard/out/404.html +1 -1
  6. sky/dashboard/out/_next/static/Md3rlE87jmL5uv7gSo8mR/_buildManifest.js +1 -0
  7. sky/dashboard/out/_next/static/chunks/1043-1b39779691bb4030.js +1 -0
  8. sky/dashboard/out/_next/static/chunks/{141-fa5a20cbf401b351.js → 1141-726e5a3f00b67185.js} +2 -2
  9. sky/dashboard/out/_next/static/chunks/1272-1ef0bf0237faccdb.js +1 -0
  10. sky/dashboard/out/_next/static/chunks/1664-d65361e92b85e786.js +1 -0
  11. sky/dashboard/out/_next/static/chunks/{691.fd9292250ab089af.js → 1691.44e378727a41f3b5.js} +2 -2
  12. sky/dashboard/out/_next/static/chunks/{871-e547295e7e21399c.js → 1871-80dea41717729fa5.js} +1 -1
  13. sky/dashboard/out/_next/static/chunks/2544.27f70672535675ed.js +1 -0
  14. sky/dashboard/out/_next/static/chunks/{875.52c962183328b3f2.js → 2875.c24c6d57dc82e436.js} +1 -1
  15. sky/dashboard/out/_next/static/chunks/3256.7257acd01b481bed.js +11 -0
  16. sky/dashboard/out/_next/static/chunks/3698-52ad1ca228faa776.js +1 -0
  17. sky/dashboard/out/_next/static/chunks/3785.b3cc2bc1d49d2c3c.js +1 -0
  18. sky/dashboard/out/_next/static/chunks/3937.d7f1c55d1916c7f2.js +1 -0
  19. sky/dashboard/out/_next/static/chunks/{947-6620842ef80ae879.js → 3947-b059261d6fa88a1f.js} +1 -1
  20. sky/dashboard/out/_next/static/chunks/{697.6460bf72e760addd.js → 4697.f5421144224da9fc.js} +1 -1
  21. sky/dashboard/out/_next/static/chunks/4725.4c849b1e05c8e9ad.js +1 -0
  22. sky/dashboard/out/_next/static/chunks/5230-df791914b54d91d9.js +1 -0
  23. sky/dashboard/out/_next/static/chunks/{491.b3d264269613fe09.js → 5491.918ffed0ba7a5294.js} +1 -1
  24. sky/dashboard/out/_next/static/chunks/5739-5ea3ffa10fc884f2.js +8 -0
  25. sky/dashboard/out/_next/static/chunks/616-162f3033ffcd3d31.js +39 -0
  26. sky/dashboard/out/_next/static/chunks/6601-fcfad0ddf92ec7ab.js +1 -0
  27. sky/dashboard/out/_next/static/chunks/6989-6ff4e45dfb49d11d.js +1 -0
  28. sky/dashboard/out/_next/static/chunks/6990-d0dc765474fa0eca.js +1 -0
  29. sky/dashboard/out/_next/static/chunks/8969-909d53833da080cb.js +1 -0
  30. sky/dashboard/out/_next/static/chunks/8982.a2e214068f30a857.js +1 -0
  31. sky/dashboard/out/_next/static/chunks/{25.76c246239df93d50.js → 9025.a7c44babfe56ce09.js} +2 -2
  32. sky/dashboard/out/_next/static/chunks/{938-0a770415b5ce4649.js → 938-044ad21de8b4626b.js} +1 -1
  33. sky/dashboard/out/_next/static/chunks/9470-21d059a1dfa03f61.js +1 -0
  34. sky/dashboard/out/_next/static/chunks/9984.739ae958a066298d.js +1 -0
  35. sky/dashboard/out/_next/static/chunks/fd9d1056-61f2257a9cd8b32b.js +1 -0
  36. sky/dashboard/out/_next/static/chunks/{framework-87d061ee6ed71b28.js → framework-efc06c2733009cd3.js} +1 -1
  37. sky/dashboard/out/_next/static/chunks/main-app-68c028b1bc5e1b72.js +1 -0
  38. sky/dashboard/out/_next/static/chunks/{main-e0e2335212e72357.js → main-c0a4f1ea606d48d2.js} +1 -1
  39. sky/dashboard/out/_next/static/chunks/pages/{_app-050a9e637b057b24.js → _app-a37b06ddb64521fd.js} +2 -2
  40. sky/dashboard/out/_next/static/chunks/pages/_error-c72a1f77a3c0be1b.js +1 -0
  41. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-8135aba0712bda37.js +6 -0
  42. sky/dashboard/out/_next/static/chunks/pages/clusters/{[cluster]-77d4816945b04793.js → [cluster]-b8e1114e6d38218c.js} +1 -1
  43. sky/dashboard/out/_next/static/chunks/pages/clusters-9744c271a1642f76.js +1 -0
  44. sky/dashboard/out/_next/static/chunks/pages/config-a2673b256b6d416f.js +1 -0
  45. sky/dashboard/out/_next/static/chunks/pages/index-927ddeebe57a8ac3.js +1 -0
  46. sky/dashboard/out/_next/static/chunks/pages/infra/[context]-8b0809f59034d509.js +1 -0
  47. sky/dashboard/out/_next/static/chunks/pages/infra-ae9d2f705ce582c9.js +1 -0
  48. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-c4d5cfac7fbc0668.js +16 -0
  49. sky/dashboard/out/_next/static/chunks/pages/jobs-5bbdc71878f0a068.js +1 -0
  50. sky/dashboard/out/_next/static/chunks/pages/users-cd43fb3c122eedde.js +1 -0
  51. sky/dashboard/out/_next/static/chunks/pages/volumes-4ebf6484f7216387.js +1 -0
  52. sky/dashboard/out/_next/static/chunks/pages/workspace/new-5629d4e551dba1ee.js +1 -0
  53. sky/dashboard/out/_next/static/chunks/pages/workspaces/[name]-7c0187f43757a548.js +1 -0
  54. sky/dashboard/out/_next/static/chunks/pages/workspaces-06bde99155fa6292.js +1 -0
  55. sky/dashboard/out/_next/static/chunks/webpack-d427db53e54de9ce.js +1 -0
  56. sky/dashboard/out/_next/static/css/0da6afe66176678a.css +3 -0
  57. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  58. sky/dashboard/out/clusters/[cluster].html +1 -1
  59. sky/dashboard/out/clusters.html +1 -1
  60. sky/dashboard/out/config.html +1 -1
  61. sky/dashboard/out/index.html +1 -1
  62. sky/dashboard/out/infra/[context].html +1 -1
  63. sky/dashboard/out/infra.html +1 -1
  64. sky/dashboard/out/jobs/[job].html +1 -1
  65. sky/dashboard/out/jobs.html +1 -1
  66. sky/dashboard/out/users.html +1 -1
  67. sky/dashboard/out/volumes.html +1 -1
  68. sky/dashboard/out/workspace/new.html +1 -1
  69. sky/dashboard/out/workspaces/[name].html +1 -1
  70. sky/dashboard/out/workspaces.html +1 -1
  71. sky/jobs/controller.py +4 -0
  72. sky/jobs/server/core.py +5 -9
  73. sky/jobs/state.py +820 -670
  74. sky/jobs/utils.py +7 -15
  75. sky/optimizer.py +46 -0
  76. sky/provision/__init__.py +14 -6
  77. sky/provision/kubernetes/constants.py +9 -0
  78. sky/provision/kubernetes/instance.py +17 -14
  79. sky/provision/kubernetes/volume.py +77 -15
  80. sky/server/common.py +1 -0
  81. sky/server/server.py +37 -15
  82. sky/setup_files/dependencies.py +2 -0
  83. sky/skylet/constants.py +1 -0
  84. sky/task.py +13 -1
  85. sky/utils/dag_utils.py +4 -2
  86. sky/utils/log_utils.py +68 -0
  87. sky/volumes/server/core.py +103 -78
  88. sky/volumes/utils.py +22 -5
  89. {skypilot_nightly-1.0.0.dev20250628.dist-info → skypilot_nightly-1.0.0.dev20250701.dist-info}/METADATA +4 -1
  90. {skypilot_nightly-1.0.0.dev20250628.dist-info → skypilot_nightly-1.0.0.dev20250701.dist-info}/RECORD +96 -94
  91. sky/dashboard/out/_next/static/ZYLkkWSYZjJhLVsObh20y/_buildManifest.js +0 -1
  92. sky/dashboard/out/_next/static/chunks/230-d6e363362017ff3a.js +0 -1
  93. sky/dashboard/out/_next/static/chunks/43-f38a531f6692f281.js +0 -1
  94. sky/dashboard/out/_next/static/chunks/470-92dd1614396389be.js +0 -1
  95. sky/dashboard/out/_next/static/chunks/544.110e53813fb98e2e.js +0 -1
  96. sky/dashboard/out/_next/static/chunks/601-111d06d9ded11d00.js +0 -1
  97. sky/dashboard/out/_next/static/chunks/616-50a620ac4a23deb4.js +0 -39
  98. sky/dashboard/out/_next/static/chunks/645.961f08e39b8ce447.js +0 -1
  99. sky/dashboard/out/_next/static/chunks/664-047bc03493fda379.js +0 -1
  100. sky/dashboard/out/_next/static/chunks/785.3446c12ffdf3d188.js +0 -1
  101. sky/dashboard/out/_next/static/chunks/798-c0525dc3f21e488d.js +0 -1
  102. sky/dashboard/out/_next/static/chunks/799-3625946b2ec2eb30.js +0 -8
  103. sky/dashboard/out/_next/static/chunks/937.72796f7afe54075b.js +0 -1
  104. sky/dashboard/out/_next/static/chunks/969-d3a0b53f728d280a.js +0 -1
  105. sky/dashboard/out/_next/static/chunks/982.d7bd80ed18cad4cc.js +0 -1
  106. sky/dashboard/out/_next/static/chunks/984.e8bac186a24e5178.js +0 -1
  107. sky/dashboard/out/_next/static/chunks/989-db34c16ad7ea6155.js +0 -1
  108. sky/dashboard/out/_next/static/chunks/990-0ad5ea1699e03ee8.js +0 -1
  109. sky/dashboard/out/_next/static/chunks/fd9d1056-2821b0f0cabcd8bd.js +0 -1
  110. sky/dashboard/out/_next/static/chunks/main-app-241eb28595532291.js +0 -1
  111. sky/dashboard/out/_next/static/chunks/pages/_error-1be831200e60c5c0.js +0 -1
  112. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-21080826c6095f21.js +0 -6
  113. sky/dashboard/out/_next/static/chunks/pages/clusters-65b2c90320b8afb8.js +0 -1
  114. sky/dashboard/out/_next/static/chunks/pages/config-6b255eae088da6a3.js +0 -1
  115. sky/dashboard/out/_next/static/chunks/pages/index-6b0d9e5031b70c58.js +0 -1
  116. sky/dashboard/out/_next/static/chunks/pages/infra/[context]-b302aea4d65766bf.js +0 -1
  117. sky/dashboard/out/_next/static/chunks/pages/infra-ee8cc4d449945d19.js +0 -1
  118. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-64bdc0b2d3a44709.js +0 -16
  119. sky/dashboard/out/_next/static/chunks/pages/jobs-df7407b5e37d3750.js +0 -1
  120. sky/dashboard/out/_next/static/chunks/pages/users-d7684eaa04c4f58f.js +0 -1
  121. sky/dashboard/out/_next/static/chunks/pages/volumes-476b670ef33d1ecd.js +0 -1
  122. sky/dashboard/out/_next/static/chunks/pages/workspace/new-5b59bce9eb208d84.js +0 -1
  123. sky/dashboard/out/_next/static/chunks/pages/workspaces/[name]-04e1b3ad4207b1e9.js +0 -1
  124. sky/dashboard/out/_next/static/chunks/pages/workspaces-c470366a6179f16e.js +0 -1
  125. sky/dashboard/out/_next/static/chunks/webpack-75a3310ef922a299.js +0 -1
  126. sky/dashboard/out/_next/static/css/605ac87514049058.css +0 -3
  127. /sky/dashboard/out/_next/static/{ZYLkkWSYZjJhLVsObh20y → Md3rlE87jmL5uv7gSo8mR}/_ssgManifest.js +0 -0
  128. /sky/dashboard/out/_next/static/chunks/{804-4c9fc53aa74bc191.js → 804-9f5e98ce84d46bdd.js} +0 -0
  129. {skypilot_nightly-1.0.0.dev20250628.dist-info → skypilot_nightly-1.0.0.dev20250701.dist-info}/WHEEL +0 -0
  130. {skypilot_nightly-1.0.0.dev20250628.dist-info → skypilot_nightly-1.0.0.dev20250701.dist-info}/entry_points.txt +0 -0
  131. {skypilot_nightly-1.0.0.dev20250628.dist-info → skypilot_nightly-1.0.0.dev20250701.dist-info}/licenses/LICENSE +0 -0
  132. {skypilot_nightly-1.0.0.dev20250628.dist-info → skypilot_nightly-1.0.0.dev20250701.dist-info}/top_level.txt +0 -0
@@ -13,7 +13,9 @@ from sky import models
13
13
  from sky import provision
14
14
  from sky import sky_logging
15
15
  from sky.utils import common_utils
16
+ from sky.utils import rich_utils
16
17
  from sky.utils import status_lib
18
+ from sky.utils import ux_utils
17
19
 
18
20
  logger = sky_logging.init_logger(__name__)
19
21
 
@@ -33,14 +35,14 @@ def volume_refresh():
33
35
  'Skipping status refresh...')
34
36
  continue
35
37
  cloud = config.cloud
36
- usedby = provision.get_volume_usedby(cloud, config)
38
+ usedby_pods, _ = provision.get_volume_usedby(cloud, config)
37
39
  with _volume_lock(volume_name):
38
40
  latest_volume = global_user_state.get_volume_by_name(volume_name)
39
41
  if latest_volume is None:
40
42
  logger.warning(f'Volume {volume_name} not found.')
41
43
  continue
42
44
  status = latest_volume.get('status')
43
- if not usedby:
45
+ if not usedby_pods:
44
46
  if status != status_lib.VolumeStatus.READY:
45
47
  logger.info(f'Update volume {volume_name} '
46
48
  f'status to READY')
@@ -49,7 +51,7 @@ def volume_refresh():
49
51
  else:
50
52
  if status != status_lib.VolumeStatus.IN_USE:
51
53
  logger.info(f'Update volume {volume_name} '
52
- f'status to IN_USE, usedby: {usedby}')
54
+ f'status to IN_USE, usedby: {usedby_pods}')
53
55
  global_user_state.update_volume_status(
54
56
  volume_name, status=status_lib.VolumeStatus.IN_USE)
55
57
 
@@ -74,42 +76,52 @@ def volume_list() -> List[Dict[str, Any]]:
74
76
  'last_attached_at': int timestamp of last attachment,
75
77
  'last_use': last command,
76
78
  'status': sky.VolumeStatus,
79
+ 'usedby_pods': List[str],
80
+ 'usedby_clusters': List[str],
77
81
  }
78
82
  ]
79
83
  """
80
- volumes = global_user_state.get_volumes()
81
- all_users = global_user_state.get_all_users()
82
- user_map = {user.id: user.name for user in all_users}
83
- records = []
84
- for volume in volumes:
85
- volume_name = volume.get('name')
86
- record = {
87
- 'name': volume_name,
88
- 'launched_at': volume.get('launched_at'),
89
- 'user_hash': volume.get('user_hash'),
90
- 'user_name': user_map.get(volume.get('user_hash'), ''),
91
- 'workspace': volume.get('workspace'),
92
- 'last_attached_at': volume.get('last_attached_at'),
93
- 'last_use': volume.get('last_use'),
94
- }
95
- status = volume.get('status')
96
- if status is not None:
97
- record['status'] = status.value
98
- else:
99
- record['status'] = ''
100
- config = volume.get('handle')
101
- if config is None:
102
- logger.warning(f'Volume {volume_name} has no handle.')
103
- continue
104
- record['type'] = config.type
105
- record['cloud'] = config.cloud
106
- record['region'] = config.region
107
- record['zone'] = config.zone
108
- record['size'] = config.size
109
- record['config'] = config.config
110
- record['name_on_cloud'] = config.name_on_cloud
111
- records.append(record)
112
- return records
84
+ with rich_utils.safe_status(ux_utils.spinner_message('Listing volumes')):
85
+ volumes = global_user_state.get_volumes()
86
+ all_users = global_user_state.get_all_users()
87
+ user_map = {user.id: user.name for user in all_users}
88
+ records = []
89
+ for volume in volumes:
90
+ volume_name = volume.get('name')
91
+ record = {
92
+ 'name': volume_name,
93
+ 'launched_at': volume.get('launched_at'),
94
+ 'user_hash': volume.get('user_hash'),
95
+ 'user_name': user_map.get(volume.get('user_hash'), ''),
96
+ 'workspace': volume.get('workspace'),
97
+ 'last_attached_at': volume.get('last_attached_at'),
98
+ 'last_use': volume.get('last_use'),
99
+ 'usedby_pods': [],
100
+ 'usedby_clusters': [],
101
+ }
102
+ status = volume.get('status')
103
+ if status is not None:
104
+ record['status'] = status.value
105
+ else:
106
+ record['status'] = ''
107
+ config = volume.get('handle')
108
+ if config is None:
109
+ logger.warning(f'Volume {volume_name} has no handle.')
110
+ continue
111
+ cloud = config.cloud
112
+ usedby_pods, usedby_clusters = provision.get_volume_usedby(
113
+ cloud, config)
114
+ record['type'] = config.type
115
+ record['cloud'] = config.cloud
116
+ record['region'] = config.region
117
+ record['zone'] = config.zone
118
+ record['size'] = config.size
119
+ record['config'] = config.config
120
+ record['name_on_cloud'] = config.name_on_cloud
121
+ record['usedby_pods'] = usedby_pods
122
+ record['usedby_clusters'] = usedby_clusters
123
+ records.append(record)
124
+ return records
113
125
 
114
126
 
115
127
  def volume_delete(names: List[str]) -> None:
@@ -122,20 +134,32 @@ def volume_delete(names: List[str]) -> None:
122
134
  ValueError: If the volume does not exist
123
135
  or is in use or has no handle.
124
136
  """
125
- for name in names:
126
- volume = global_user_state.get_volume_by_name(name)
127
- if volume is None:
128
- raise ValueError(f'Volume {name} not found.')
129
- if volume.get('status') == status_lib.VolumeStatus.IN_USE:
130
- raise ValueError(f'Volume {name} is in use.')
131
- config = volume.get('handle')
132
- if config is None:
133
- raise ValueError(f'Volume {name} has no handle.')
134
- logger.debug(f'Deleting volume {name} with config {config}')
135
- cloud = config.cloud
136
- with _volume_lock(name):
137
- provision.delete_volume(cloud, config)
138
- global_user_state.delete_volume(name)
137
+ with rich_utils.safe_status(ux_utils.spinner_message('Deleting volumes')):
138
+ for name in names:
139
+ volume = global_user_state.get_volume_by_name(name)
140
+ if volume is None:
141
+ raise ValueError(f'Volume {name} not found.')
142
+ config = volume.get('handle')
143
+ if config is None:
144
+ raise ValueError(f'Volume {name} has no handle.')
145
+ cloud = config.cloud
146
+ usedby_pods, usedby_clusters = provision.get_volume_usedby(
147
+ cloud, config)
148
+ if usedby_clusters:
149
+ usedby_clusters_str = ', '.join(usedby_clusters)
150
+ cluster_str = 'clusters' if len(
151
+ usedby_clusters) > 1 else 'cluster'
152
+ raise ValueError(f'Volume {name} is used by {cluster_str}'
153
+ f' {usedby_clusters_str}.')
154
+ if usedby_pods:
155
+ usedby_pods_str = ', '.join(usedby_pods)
156
+ pod_str = 'pods' if len(usedby_pods) > 1 else 'pod'
157
+ raise ValueError(
158
+ f'Volume {name} is used by {pod_str} {usedby_pods_str}.')
159
+ logger.debug(f'Deleting volume {name} with config {config}')
160
+ with _volume_lock(name):
161
+ provision.delete_volume(cloud, config)
162
+ global_user_state.delete_volume(name)
139
163
 
140
164
 
141
165
  def volume_apply(name: str, volume_type: str, cloud: str, region: Optional[str],
@@ -153,34 +177,35 @@ def volume_apply(name: str, volume_type: str, cloud: str, region: Optional[str],
153
177
  config: The configuration of the volume.
154
178
 
155
179
  """
156
- # Reuse the method for cluster name on cloud to
157
- # generate the storage name on cloud.
158
- cloud_obj = sky.CLOUD_REGISTRY.from_str(cloud)
159
- assert cloud_obj is not None
160
- name_uuid = str(uuid.uuid4())[:6]
161
- name_on_cloud = common_utils.make_cluster_name_on_cloud(
162
- name, max_length=cloud_obj.max_cluster_name_length())
163
- name_on_cloud += '-' + name_uuid
164
- config = models.VolumeConfig(
165
- name=name,
166
- type=volume_type,
167
- cloud=str(cloud_obj),
168
- region=region,
169
- zone=zone,
170
- size=size,
171
- config=config,
172
- name_on_cloud=name_on_cloud,
173
- )
174
- logger.debug(
175
- f'Creating volume {name} on cloud {cloud} with config {config}')
176
- with _volume_lock(name):
177
- current_volume = global_user_state.get_volume_by_name(name)
178
- if current_volume is not None:
179
- logger.info(f'Volume {name} already exists.')
180
- return
181
- config = provision.apply_volume(cloud, config)
182
- global_user_state.add_volume(name, config,
183
- status_lib.VolumeStatus.READY)
180
+ with rich_utils.safe_status(ux_utils.spinner_message('Creating volume')):
181
+ # Reuse the method for cluster name on cloud to
182
+ # generate the storage name on cloud.
183
+ cloud_obj = sky.CLOUD_REGISTRY.from_str(cloud)
184
+ assert cloud_obj is not None
185
+ name_uuid = str(uuid.uuid4())[:6]
186
+ name_on_cloud = common_utils.make_cluster_name_on_cloud(
187
+ name, max_length=cloud_obj.max_cluster_name_length())
188
+ name_on_cloud += '-' + name_uuid
189
+ config = models.VolumeConfig(
190
+ name=name,
191
+ type=volume_type,
192
+ cloud=str(cloud_obj),
193
+ region=region,
194
+ zone=zone,
195
+ size=size,
196
+ config=config,
197
+ name_on_cloud=name_on_cloud,
198
+ )
199
+ logger.debug(
200
+ f'Creating volume {name} on cloud {cloud} with config {config}')
201
+ with _volume_lock(name):
202
+ current_volume = global_user_state.get_volume_by_name(name)
203
+ if current_volume is not None:
204
+ logger.info(f'Volume {name} already exists.')
205
+ return
206
+ config = provision.apply_volume(cloud, config)
207
+ global_user_state.add_volume(name, config,
208
+ status_lib.VolumeStatus.READY)
184
209
 
185
210
 
186
211
  @contextlib.contextmanager
sky/volumes/utils.py CHANGED
@@ -6,6 +6,8 @@ from typing import Any, Dict, List, Optional
6
6
  import prettytable
7
7
 
8
8
  from sky import sky_logging
9
+ from sky.skylet import constants
10
+ from sky.utils import common_utils
9
11
  from sky.utils import log_utils
10
12
  from sky.volumes import volume
11
13
 
@@ -44,12 +46,12 @@ class PVCVolumeTable(VolumeTable):
44
46
 
45
47
  def _create_table(self, show_all: bool = False) -> prettytable.PrettyTable:
46
48
  """Create the PVC volume table."""
47
- # If show_all is True, show the table with the columns:
48
- # NAME, TYPE, INFRA, SIZE, USER, WORKSPACE,
49
- # AGE, LAST_USE, STATUS
50
49
  # If show_all is False, show the table with the columns:
51
50
  # NAME, TYPE, INFRA, SIZE, USER, WORKSPACE,
52
- # AGE, LAST_USE, STATUS, NAME_ON_CLOUD,
51
+ # AGE, STATUS, LAST_USE, USED_BY
52
+ # If show_all is True, show the table with the columns:
53
+ # NAME, TYPE, INFRA, SIZE, USER, WORKSPACE,
54
+ # AGE, STATUS, LAST_USE, USED_BY, NAME_ON_CLOUD
53
55
  # STORAGE_CLASS, ACCESS_MODE
54
56
 
55
57
  if show_all:
@@ -63,6 +65,7 @@ class PVCVolumeTable(VolumeTable):
63
65
  'AGE',
64
66
  'STATUS',
65
67
  'LAST_USE',
68
+ 'USED_BY',
66
69
  'NAME_ON_CLOUD',
67
70
  'STORAGE_CLASS',
68
71
  'ACCESS_MODE',
@@ -78,6 +81,7 @@ class PVCVolumeTable(VolumeTable):
78
81
  'AGE',
79
82
  'STATUS',
80
83
  'LAST_USE',
84
+ 'USED_BY',
81
85
  ]
82
86
 
83
87
  table = log_utils.create_table(columns)
@@ -98,6 +102,18 @@ class PVCVolumeTable(VolumeTable):
98
102
  size = row.get('size', '')
99
103
  if size:
100
104
  size = f'{size}Gi'
105
+ usedby_str = '-'
106
+ usedby_clusters = row.get('usedby_clusters')
107
+ usedby_pods = row.get('usedby_pods')
108
+ if usedby_clusters:
109
+ usedby_str = f'{", ".join(usedby_clusters)}'
110
+ elif usedby_pods:
111
+ usedby_str = f'{", ".join(usedby_pods)}'
112
+ if show_all:
113
+ usedby = usedby_str
114
+ else:
115
+ usedby = common_utils.truncate_long_string(
116
+ usedby_str, constants.USED_BY_TRUNC_LENGTH)
101
117
  infra = _get_infra_str(row.get('cloud'), row.get('region'),
102
118
  row.get('zone'))
103
119
  table_row = [
@@ -107,9 +123,10 @@ class PVCVolumeTable(VolumeTable):
107
123
  size,
108
124
  row.get('user_name', '-'),
109
125
  row.get('workspace', '-'),
110
- log_utils.readable_time_duration(row.get('launched_at', 0)),
126
+ log_utils.human_duration(row.get('launched_at', 0)),
111
127
  row.get('status', ''),
112
128
  last_attached_at_str,
129
+ usedby,
113
130
  ]
114
131
  if show_all:
115
132
  table_row.append(row.get('name_on_cloud', ''))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skypilot-nightly
3
- Version: 1.0.0.dev20250628
3
+ Version: 1.0.0.dev20250701
4
4
  Summary: SkyPilot: Run AI on Any Infra — Unified, Faster, Cheaper.
5
5
  Author: SkyPilot Team
6
6
  License: Apache 2.0
@@ -53,6 +53,7 @@ Requires-Dist: casbin
53
53
  Requires-Dist: sqlalchemy_adapter
54
54
  Requires-Dist: prometheus_client>=0.8.0
55
55
  Requires-Dist: passlib
56
+ Requires-Dist: pyjwt
56
57
  Provides-Extra: aws
57
58
  Requires-Dist: awscli>=1.27.10; extra == "aws"
58
59
  Requires-Dist: botocore>=1.29.10; extra == "aws"
@@ -126,6 +127,7 @@ Provides-Extra: server
126
127
  Requires-Dist: casbin; extra == "server"
127
128
  Requires-Dist: sqlalchemy_adapter; extra == "server"
128
129
  Requires-Dist: passlib; extra == "server"
130
+ Requires-Dist: pyjwt; extra == "server"
129
131
  Provides-Extra: all
130
132
  Requires-Dist: awscli>=1.27.10; extra == "all"
131
133
  Requires-Dist: botocore>=1.29.10; extra == "all"
@@ -178,6 +180,7 @@ Requires-Dist: colorama<0.4.5; extra == "all"
178
180
  Requires-Dist: casbin; extra == "all"
179
181
  Requires-Dist: sqlalchemy_adapter; extra == "all"
180
182
  Requires-Dist: passlib; extra == "all"
183
+ Requires-Dist: pyjwt; extra == "all"
181
184
  Dynamic: author
182
185
  Dynamic: classifier
183
186
  Dynamic: description