skypilot-nightly 1.0.0.dev20250624__py3-none-any.whl → 1.0.0.dev20250625__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 (145) hide show
  1. sky/__init__.py +2 -2
  2. sky/backends/backend_utils.py +26 -11
  3. sky/backends/cloud_vm_ray_backend.py +16 -5
  4. sky/client/cli/command.py +222 -4
  5. sky/client/sdk.py +110 -82
  6. sky/clouds/aws.py +10 -7
  7. sky/clouds/azure.py +10 -7
  8. sky/clouds/cloud.py +2 -0
  9. sky/clouds/cudo.py +2 -0
  10. sky/clouds/do.py +10 -7
  11. sky/clouds/fluidstack.py +2 -0
  12. sky/clouds/gcp.py +10 -7
  13. sky/clouds/hyperbolic.py +10 -7
  14. sky/clouds/ibm.py +2 -0
  15. sky/clouds/kubernetes.py +26 -9
  16. sky/clouds/lambda_cloud.py +10 -7
  17. sky/clouds/nebius.py +10 -7
  18. sky/clouds/oci.py +10 -7
  19. sky/clouds/paperspace.py +10 -7
  20. sky/clouds/runpod.py +10 -7
  21. sky/clouds/scp.py +10 -7
  22. sky/clouds/vast.py +10 -7
  23. sky/clouds/vsphere.py +2 -0
  24. sky/core.py +1 -0
  25. sky/dag.py +14 -0
  26. sky/dashboard/out/404.html +1 -1
  27. sky/dashboard/out/_next/static/ZWdSYkqVe3WjnFR8ocqoG/_buildManifest.js +1 -0
  28. sky/dashboard/out/_next/static/chunks/230-d6e363362017ff3a.js +1 -0
  29. sky/dashboard/out/_next/static/chunks/310.2671028c20e892c7.js +16 -0
  30. sky/dashboard/out/_next/static/chunks/{37-4650f214e2119168.js → 37-1f1e94f5a561202a.js} +2 -2
  31. sky/dashboard/out/_next/static/chunks/42.bc85e5b1a4debf22.js +6 -0
  32. sky/dashboard/out/_next/static/chunks/470-92dd1614396389be.js +1 -0
  33. sky/dashboard/out/_next/static/chunks/544.110e53813fb98e2e.js +1 -0
  34. sky/dashboard/out/_next/static/chunks/645.961f08e39b8ce447.js +1 -0
  35. sky/dashboard/out/_next/static/chunks/66-66ae330df2d3c1c7.js +1 -0
  36. sky/dashboard/out/_next/static/chunks/682.00e56a220dd26fe1.js +6 -0
  37. sky/dashboard/out/_next/static/chunks/697.6460bf72e760addd.js +20 -0
  38. sky/dashboard/out/_next/static/chunks/{856-bfddc18e16f3873c.js → 856-cdf66268ec878d0c.js} +1 -1
  39. sky/dashboard/out/_next/static/chunks/pages/{_app-ce31493da9747ef4.js → _app-0ef7418d1a3822f3.js} +1 -1
  40. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-aff040d7bc5d0086.js +6 -0
  41. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-32ce4f49f2261f55.js +6 -0
  42. sky/dashboard/out/_next/static/chunks/pages/clusters-4aa031d1f42723d8.js +1 -0
  43. sky/dashboard/out/_next/static/chunks/pages/config-3102d02a188f04b3.js +1 -0
  44. sky/dashboard/out/_next/static/chunks/pages/infra/[context]-6f1e02e31eecb5ce.js +1 -0
  45. sky/dashboard/out/_next/static/chunks/pages/infra-fd5dc8a91bd9169a.js +1 -0
  46. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-e4b23128db0774cd.js +16 -0
  47. sky/dashboard/out/_next/static/chunks/pages/jobs-26da173e20af16e4.js +1 -0
  48. sky/dashboard/out/_next/static/chunks/pages/users-ce29e7420385563d.js +1 -0
  49. sky/dashboard/out/_next/static/chunks/pages/volumes-476b670ef33d1ecd.js +1 -0
  50. sky/dashboard/out/_next/static/chunks/pages/workspace/new-09ae0f6f972aa871.js +1 -0
  51. sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-ecc5a7003776cfa7.js → [name]-0b4c662a25e4747a.js} +1 -1
  52. sky/dashboard/out/_next/static/chunks/pages/workspaces-862b120406461b10.js +1 -0
  53. sky/dashboard/out/_next/static/chunks/webpack-6133dc1e928bd0b5.js +1 -0
  54. sky/dashboard/out/_next/static/css/b23cb0257bf96c51.css +3 -0
  55. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  56. sky/dashboard/out/clusters/[cluster].html +1 -1
  57. sky/dashboard/out/clusters.html +1 -1
  58. sky/dashboard/out/config.html +1 -1
  59. sky/dashboard/out/index.html +1 -1
  60. sky/dashboard/out/infra/[context].html +1 -1
  61. sky/dashboard/out/infra.html +1 -1
  62. sky/dashboard/out/jobs/[job].html +1 -1
  63. sky/dashboard/out/jobs.html +1 -1
  64. sky/dashboard/out/users.html +1 -1
  65. sky/dashboard/out/volumes.html +1 -0
  66. sky/dashboard/out/workspace/new.html +1 -1
  67. sky/dashboard/out/workspaces/[name].html +1 -1
  68. sky/dashboard/out/workspaces.html +1 -1
  69. sky/data/storage_utils.py +2 -4
  70. sky/exceptions.py +15 -0
  71. sky/execution.py +5 -0
  72. sky/global_user_state.py +129 -0
  73. sky/jobs/client/sdk.py +13 -11
  74. sky/jobs/server/core.py +4 -0
  75. sky/models.py +16 -0
  76. sky/provision/__init__.py +26 -0
  77. sky/provision/kubernetes/__init__.py +3 -0
  78. sky/provision/kubernetes/instance.py +38 -77
  79. sky/provision/kubernetes/utils.py +52 -2
  80. sky/provision/kubernetes/volume.py +147 -0
  81. sky/resources.py +20 -76
  82. sky/serve/client/sdk.py +13 -13
  83. sky/serve/server/core.py +5 -1
  84. sky/server/common.py +40 -5
  85. sky/server/constants.py +5 -1
  86. sky/server/metrics.py +105 -0
  87. sky/server/requests/executor.py +30 -14
  88. sky/server/requests/payloads.py +16 -0
  89. sky/server/requests/requests.py +35 -1
  90. sky/server/rest.py +152 -0
  91. sky/server/server.py +66 -16
  92. sky/server/state.py +20 -0
  93. sky/server/stream_utils.py +8 -3
  94. sky/server/uvicorn.py +153 -13
  95. sky/setup_files/dependencies.py +2 -0
  96. sky/skylet/constants.py +14 -3
  97. sky/task.py +141 -18
  98. sky/templates/kubernetes-ray.yml.j2 +30 -1
  99. sky/users/permission.py +2 -0
  100. sky/utils/context.py +3 -1
  101. sky/utils/resources_utils.py +66 -0
  102. sky/utils/rich_utils.py +6 -0
  103. sky/utils/schemas.py +146 -3
  104. sky/utils/status_lib.py +10 -0
  105. sky/utils/validator.py +11 -1
  106. sky/volumes/__init__.py +0 -0
  107. sky/volumes/client/__init__.py +0 -0
  108. sky/volumes/client/sdk.py +64 -0
  109. sky/volumes/server/__init__.py +0 -0
  110. sky/volumes/server/core.py +199 -0
  111. sky/volumes/server/server.py +85 -0
  112. sky/volumes/utils.py +158 -0
  113. sky/volumes/volume.py +198 -0
  114. {skypilot_nightly-1.0.0.dev20250624.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/METADATA +2 -1
  115. {skypilot_nightly-1.0.0.dev20250624.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/RECORD +123 -108
  116. sky/dashboard/out/_next/static/chunks/350.9e123a4551f68b0d.js +0 -1
  117. sky/dashboard/out/_next/static/chunks/42.2273cc2415291ceb.js +0 -6
  118. sky/dashboard/out/_next/static/chunks/470-1494c899266cf5c9.js +0 -1
  119. sky/dashboard/out/_next/static/chunks/641.c8e452bc5070a630.js +0 -1
  120. sky/dashboard/out/_next/static/chunks/682.4dd5dc116f740b5f.js +0 -6
  121. sky/dashboard/out/_next/static/chunks/760-a89d354797ce7af5.js +0 -1
  122. sky/dashboard/out/_next/static/chunks/901-b424d293275e1fd7.js +0 -1
  123. sky/dashboard/out/_next/static/chunks/984.ae8c08791d274ca0.js +0 -50
  124. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-4e065c812a52460b.js +0 -6
  125. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-520ec1ab65e2f2a4.js +0 -6
  126. sky/dashboard/out/_next/static/chunks/pages/clusters-7e9736af1c6345a6.js +0 -1
  127. sky/dashboard/out/_next/static/chunks/pages/config-e4f473661889e7cd.js +0 -1
  128. sky/dashboard/out/_next/static/chunks/pages/infra/[context]-00fd23b9577492ca.js +0 -1
  129. sky/dashboard/out/_next/static/chunks/pages/infra-8a4bf7370d4d9bb7.js +0 -1
  130. sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-171c27f4ca94861c.js +0 -16
  131. sky/dashboard/out/_next/static/chunks/pages/jobs-55e5bcb16d563231.js +0 -1
  132. sky/dashboard/out/_next/static/chunks/pages/users-c9f4d785cdaa52d8.js +0 -1
  133. sky/dashboard/out/_next/static/chunks/pages/workspace/new-31aa8bdcb7592635.js +0 -1
  134. sky/dashboard/out/_next/static/chunks/pages/workspaces-f00cba35691483b1.js +0 -1
  135. sky/dashboard/out/_next/static/chunks/webpack-c85998e6a5722f21.js +0 -1
  136. sky/dashboard/out/_next/static/css/6ab927686b492a4a.css +0 -3
  137. sky/dashboard/out/_next/static/zsALxITkbP8J8NVwSDwMo/_buildManifest.js +0 -1
  138. /sky/dashboard/out/_next/static/{zsALxITkbP8J8NVwSDwMo → ZWdSYkqVe3WjnFR8ocqoG}/_ssgManifest.js +0 -0
  139. /sky/dashboard/out/_next/static/chunks/{843-bde186946d353355.js → 843-07d25a7e64462fd8.js} +0 -0
  140. /sky/dashboard/out/_next/static/chunks/{938-ce7991c156584b06.js → 938-068520cc11738deb.js} +0 -0
  141. /sky/dashboard/out/_next/static/chunks/{973-56412c7976b4655b.js → 973-5b5019ba333e8d62.js} +0 -0
  142. {skypilot_nightly-1.0.0.dev20250624.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/WHEEL +0 -0
  143. {skypilot_nightly-1.0.0.dev20250624.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/entry_points.txt +0 -0
  144. {skypilot_nightly-1.0.0.dev20250624.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/licenses/LICENSE +0 -0
  145. {skypilot_nightly-1.0.0.dev20250624.dist-info → skypilot_nightly-1.0.0.dev20250625.dist-info}/top_level.txt +0 -0
sky/volumes/utils.py ADDED
@@ -0,0 +1,158 @@
1
+ """Volume utils."""
2
+ import abc
3
+ from datetime import datetime
4
+ from typing import Any, Dict, List, Optional
5
+
6
+ import prettytable
7
+
8
+ from sky import sky_logging
9
+ from sky.utils import log_utils
10
+ from sky.volumes import volume
11
+
12
+ logger = sky_logging.init_logger(__name__)
13
+
14
+
15
+ def _get_infra_str(cloud: Optional[str], region: Optional[str],
16
+ zone: Optional[str]) -> str:
17
+ """Get the infrastructure string for the volume."""
18
+ infra = ''
19
+ if cloud:
20
+ infra += cloud
21
+ if region:
22
+ infra += f'/{region}'
23
+ if zone:
24
+ infra += f'/{zone}'
25
+ return infra
26
+
27
+
28
+ class VolumeTable(abc.ABC):
29
+ """The volume table."""
30
+
31
+ @abc.abstractmethod
32
+ def format(self) -> str:
33
+ """Format the volume table for display."""
34
+ pass
35
+
36
+
37
+ class PVCVolumeTable(VolumeTable):
38
+ """The PVC volume table."""
39
+
40
+ def __init__(self, volumes: List[Dict[str, Any]], show_all: bool = False):
41
+ super().__init__()
42
+ self.table = self._create_table(show_all)
43
+ self._add_rows(volumes, show_all)
44
+
45
+ def _create_table(self, show_all: bool = False) -> prettytable.PrettyTable:
46
+ """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
+ # If show_all is False, show the table with the columns:
51
+ # NAME, TYPE, INFRA, SIZE, USER, WORKSPACE,
52
+ # AGE, LAST_USE, STATUS, NAME_ON_CLOUD,
53
+ # STORAGE_CLASS, ACCESS_MODE
54
+
55
+ if show_all:
56
+ columns = [
57
+ 'NAME',
58
+ 'TYPE',
59
+ 'INFRA',
60
+ 'SIZE',
61
+ 'USER',
62
+ 'WORKSPACE',
63
+ 'AGE',
64
+ 'STATUS',
65
+ 'LAST_USE',
66
+ 'NAME_ON_CLOUD',
67
+ 'STORAGE_CLASS',
68
+ 'ACCESS_MODE',
69
+ ]
70
+ else:
71
+ columns = [
72
+ 'NAME',
73
+ 'TYPE',
74
+ 'INFRA',
75
+ 'SIZE',
76
+ 'USER',
77
+ 'WORKSPACE',
78
+ 'AGE',
79
+ 'STATUS',
80
+ 'LAST_USE',
81
+ ]
82
+
83
+ table = log_utils.create_table(columns)
84
+ return table
85
+
86
+ def _add_rows(self,
87
+ volumes: List[Dict[str, Any]],
88
+ show_all: bool = False) -> None:
89
+ """Add rows to the PVC volume table."""
90
+ for row in volumes:
91
+ # Convert last_attached_at timestamp to human readable string
92
+ last_attached_at = row.get('last_attached_at')
93
+ if last_attached_at is not None:
94
+ last_attached_at_str = datetime.fromtimestamp(
95
+ last_attached_at).strftime('%Y-%m-%d %H:%M:%S')
96
+ else:
97
+ last_attached_at_str = '-'
98
+ size = row.get('size', '')
99
+ if size:
100
+ size = f'{size}Gi'
101
+ infra = _get_infra_str(row.get('cloud'), row.get('region'),
102
+ row.get('zone'))
103
+ table_row = [
104
+ row.get('name', ''),
105
+ row.get('type', ''),
106
+ infra,
107
+ size,
108
+ row.get('user_name', '-'),
109
+ row.get('workspace', '-'),
110
+ log_utils.readable_time_duration(row.get('launched_at', 0)),
111
+ row.get('status', ''),
112
+ last_attached_at_str,
113
+ ]
114
+ if show_all:
115
+ table_row.append(row.get('name_on_cloud', ''))
116
+ table_row.append(
117
+ row.get('config', {}).get('storage_class_name', '-'))
118
+ table_row.append(row.get('config', {}).get('access_mode', ''))
119
+
120
+ self.table.add_row(table_row)
121
+
122
+ def format(self) -> str:
123
+ """Format the PVC volume table for display."""
124
+ return str(self.table)
125
+
126
+
127
+ def format_volume_table(volumes: List[Dict[str, Any]],
128
+ show_all: bool = False) -> str:
129
+ """Format the volume table for display.
130
+
131
+ Args:
132
+ volume_table (dict): The volume table.
133
+
134
+ Returns:
135
+ str: The formatted volume table.
136
+ """
137
+ volumes_per_type: Dict[str, List[Dict[str, Any]]] = {}
138
+ supported_volume_types = [
139
+ volume_type.value for volume_type in volume.VolumeType
140
+ ]
141
+ for row in volumes:
142
+ volume_type = row.get('type', '')
143
+ if volume_type in supported_volume_types:
144
+ if volume_type not in volumes_per_type:
145
+ volumes_per_type[volume_type] = []
146
+ volumes_per_type[volume_type].append(row)
147
+ else:
148
+ logger.warning(f'Unknown volume type: {volume_type}')
149
+ continue
150
+ table_str = ''
151
+ for volume_type, volume_list in volumes_per_type.items():
152
+ if volume_type == volume.VolumeType.PVC.value:
153
+ table = PVCVolumeTable(volume_list, show_all)
154
+ table_str += table.format()
155
+ if table_str:
156
+ return table_str
157
+ else:
158
+ return 'No existing volumes.'
sky/volumes/volume.py ADDED
@@ -0,0 +1,198 @@
1
+ """Volume types and access modes."""
2
+ import enum
3
+ import time
4
+ from typing import Any, Dict, Optional
5
+
6
+ from sky import exceptions
7
+ from sky import global_user_state
8
+ from sky import models
9
+ from sky.utils import common_utils
10
+ from sky.utils import infra_utils
11
+ from sky.utils import resources_utils
12
+ from sky.utils import schemas
13
+ from sky.utils import status_lib
14
+
15
+
16
+ class VolumeType(enum.Enum):
17
+ """Volume type."""
18
+ PVC = 'k8s-pvc'
19
+
20
+
21
+ class VolumeAccessMode(enum.Enum):
22
+ """Volume access mode."""
23
+ READ_WRITE_ONCE = 'ReadWriteOnce'
24
+ READ_WRITE_ONCE_POD = 'ReadWriteOncePod'
25
+ READ_WRITE_MANY = 'ReadWriteMany'
26
+ READ_ONLY_MANY = 'ReadOnlyMany'
27
+
28
+
29
+ class VolumeMount:
30
+ """Volume mount specification."""
31
+
32
+ def __init__(self, path: str, volume_name: str,
33
+ volume_config: models.VolumeConfig):
34
+ self.path: str = path
35
+ self.volume_name: str = volume_name
36
+ self.volume_config: models.VolumeConfig = volume_config
37
+
38
+ def pre_mount(self) -> None:
39
+ """Update the volume status before actual mounting."""
40
+ # TODO(aylei): for ReadWriteOnce volume, we also need to queue the
41
+ # mount request if the target volume is already mounted to another
42
+ # cluster. For now, we only support ReadWriteMany volume.
43
+ global_user_state.update_volume(self.volume_name,
44
+ last_attached_at=int(time.time()),
45
+ status=status_lib.VolumeStatus.IN_USE)
46
+
47
+ @classmethod
48
+ def resolve(cls, path: str, volume_name: str) -> 'VolumeMount':
49
+ """Resolve the volume mount by populating metadata of volume."""
50
+ record = global_user_state.get_volume_by_name(volume_name)
51
+ if record is None:
52
+ raise exceptions.VolumeNotFoundError(
53
+ f'Volume {volume_name} not found.')
54
+ assert 'handle' in record, 'Volume handle is None.'
55
+ volume_config: models.VolumeConfig = record['handle']
56
+ return cls(path, volume_name, volume_config)
57
+
58
+ @classmethod
59
+ def from_yaml_config(cls, config: Dict[str, Any]) -> 'VolumeMount':
60
+ common_utils.validate_schema(config, schemas.get_volume_mount_schema(),
61
+ 'Invalid volume mount config: ')
62
+
63
+ path = config.pop('path', None)
64
+ volume_name = config.pop('volume_name', None)
65
+ volume_config: models.VolumeConfig = models.VolumeConfig.model_validate(
66
+ config.pop('volume_config', None))
67
+ return cls(path, volume_name, volume_config)
68
+
69
+ def to_yaml_config(self) -> Dict[str, Any]:
70
+ return {
71
+ 'path': self.path,
72
+ 'volume_name': self.volume_name,
73
+ 'volume_config': self.volume_config.model_dump(),
74
+ }
75
+
76
+ def __repr__(self):
77
+ return (f'VolumeMount('
78
+ f'\n\tpath={self.path},'
79
+ f'\n\tvolume_name={self.volume_name},'
80
+ f'\n\tvolume_config={self.volume_config})')
81
+
82
+
83
+ class Volume:
84
+ """Volume specification."""
85
+
86
+ def __init__(
87
+ self,
88
+ name: Optional[str] = None,
89
+ type: Optional[str] = None, # pylint: disable=redefined-builtin
90
+ infra: Optional[str] = None,
91
+ size: Optional[str] = None,
92
+ resource_name: Optional[str] = None,
93
+ config: Optional[Dict[str, Any]] = None):
94
+ """Initialize a Volume instance.
95
+
96
+ Args:
97
+ name: Volume name
98
+ type: Volume type (e.g., 'k8s-pvc')
99
+ infra: Infrastructure specification
100
+ size: Volume size
101
+ config: Additional configuration
102
+ """
103
+ self.name = name
104
+ self.type = type
105
+ self.infra = infra
106
+ self.size = size
107
+ self.resource_name = resource_name
108
+ self.config = config or {}
109
+
110
+ self.cloud: Optional[str] = None
111
+ self.region: Optional[str] = None
112
+ self.zone: Optional[str] = None
113
+
114
+ @classmethod
115
+ def from_dict(cls, config_dict: Dict[str, Any]) -> 'Volume':
116
+ """Create a Volume instance from a dictionary."""
117
+ return cls(name=config_dict.get('name'),
118
+ type=config_dict.get('type'),
119
+ infra=config_dict.get('infra'),
120
+ size=config_dict.get('size'),
121
+ resource_name=config_dict.get('resource_name'),
122
+ config=config_dict.get('config', {}))
123
+
124
+ def to_dict(self) -> Dict[str, Any]:
125
+ """Convert the Volume to a dictionary."""
126
+ return {
127
+ 'name': self.name,
128
+ 'type': self.type,
129
+ 'infra': self.infra,
130
+ 'size': self.size,
131
+ 'resource_name': self.resource_name,
132
+ 'config': self.config,
133
+ 'cloud': self.cloud,
134
+ 'region': self.region,
135
+ 'zone': self.zone,
136
+ }
137
+
138
+ def normalize_config(
139
+ self,
140
+ name: Optional[str] = None,
141
+ infra: Optional[str] = None,
142
+ type: Optional[str] = None, # pylint: disable=redefined-builtin
143
+ size: Optional[str] = None) -> None:
144
+ """Override the volume config with CLI options,
145
+ adjust and validate the config.
146
+
147
+ Args:
148
+ name: Volume name to override
149
+ infra: Infrastructure to override
150
+ type: Volume type to override
151
+ size: Volume size to override
152
+ """
153
+ if name is not None:
154
+ self.name = name
155
+ if infra is not None:
156
+ self.infra = infra
157
+ if type is not None:
158
+ self.type = type
159
+ if size is not None:
160
+ self.size = size
161
+
162
+ # Validate schema
163
+ common_utils.validate_schema(self.to_dict(),
164
+ schemas.get_volume_schema(),
165
+ 'Invalid volumes config: ')
166
+
167
+ # Adjust the volume config (e.g., parse size)
168
+ self._adjust_config()
169
+
170
+ # Validate the volume config
171
+ self._validate_config()
172
+
173
+ # Resolve the infrastructure options to cloud, region, zone
174
+ infra_info = infra_utils.InfraInfo.from_str(self.infra)
175
+ self.cloud = infra_info.cloud
176
+ self.region = infra_info.region
177
+ self.zone = infra_info.zone
178
+
179
+ def _adjust_config(self) -> None:
180
+ """Adjust the volume config (e.g., parse size)."""
181
+ if self.size is None:
182
+ return
183
+ try:
184
+ size = resources_utils.parse_memory_resource(self.size,
185
+ 'size',
186
+ allow_rounding=True)
187
+ if size == '0':
188
+ raise ValueError('Size must be no less than 1Gi')
189
+ self.size = size
190
+ except ValueError as e:
191
+ raise ValueError(f'Invalid size {self.size}: {e}') from e
192
+
193
+ def _validate_config(self) -> None:
194
+ """Validate the volume config."""
195
+ if not self.resource_name and not self.size:
196
+ raise ValueError('Size is required for new volumes. '
197
+ 'Please specify the size in the YAML file or '
198
+ 'use the --size flag.')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skypilot-nightly
3
- Version: 1.0.0.dev20250624
3
+ Version: 1.0.0.dev20250625
4
4
  Summary: SkyPilot: Run AI on Any Infra — Unified, Faster, Cheaper.
5
5
  Author: SkyPilot Team
6
6
  License: Apache 2.0
@@ -51,6 +51,7 @@ Requires-Dist: sqlalchemy
51
51
  Requires-Dist: psycopg2-binary
52
52
  Requires-Dist: casbin
53
53
  Requires-Dist: sqlalchemy_adapter
54
+ Requires-Dist: prometheus_client>=0.8.0
54
55
  Requires-Dist: passlib
55
56
  Provides-Extra: aws
56
57
  Requires-Dist: awscli>=1.27.10; extra == "aws"