dockercomposefile 0.1.0__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.
- dockercomposefile/__init__.py +13 -0
- dockercomposefile/builder.py +58 -0
- dockercomposefile/exporter.py +83 -0
- dockercomposefile/models/__init__.py +97 -0
- dockercomposefile/models/build.py +123 -0
- dockercomposefile/models/common.py +412 -0
- dockercomposefile/models/compose.py +58 -0
- dockercomposefile/models/config.py +45 -0
- dockercomposefile/models/deploy.py +117 -0
- dockercomposefile/models/develop.py +33 -0
- dockercomposefile/models/model.py +20 -0
- dockercomposefile/models/network.py +67 -0
- dockercomposefile/models/secret.py +42 -0
- dockercomposefile/models/service.py +598 -0
- dockercomposefile/models/volume.py +73 -0
- dockercomposefile-0.1.0.dist-info/METADATA +143 -0
- dockercomposefile-0.1.0.dist-info/RECORD +20 -0
- dockercomposefile-0.1.0.dist-info/WHEEL +5 -0
- dockercomposefile-0.1.0.dist-info/licenses/LICENSE +201 -0
- dockercomposefile-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Network models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pydantic import Field, field_validator
|
|
6
|
+
|
|
7
|
+
from .common import ComposeBaseModel, _parse_external, _parse_list_or_dict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class IPAMConfig(ComposeBaseModel):
|
|
11
|
+
"""IPAM configuration entry."""
|
|
12
|
+
|
|
13
|
+
subnet: str | None = None
|
|
14
|
+
ip_range: str | None = None
|
|
15
|
+
gateway: str | None = None
|
|
16
|
+
aux_addresses: dict[str, str] | None = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class IPAM(ComposeBaseModel):
|
|
20
|
+
"""IP Address Management configuration."""
|
|
21
|
+
|
|
22
|
+
driver: str | None = None
|
|
23
|
+
config: list[IPAMConfig] | None = None
|
|
24
|
+
options: dict[str, str] | None = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Network(ComposeBaseModel):
|
|
28
|
+
"""Top-level network definition."""
|
|
29
|
+
|
|
30
|
+
driver: str | None = None
|
|
31
|
+
driver_opts: dict[str, str | int] | None = None
|
|
32
|
+
attachable: bool | None = None
|
|
33
|
+
enable_ipv4: bool | None = None
|
|
34
|
+
enable_ipv6: bool | None = None
|
|
35
|
+
ipam: IPAM | None = None
|
|
36
|
+
internal: bool | None = None
|
|
37
|
+
labels: dict[str, str] | list[str] | None = Field(
|
|
38
|
+
default=None, validate_default=True
|
|
39
|
+
)
|
|
40
|
+
external: bool | dict[str, str] | None = Field(
|
|
41
|
+
default=None, validate_default=True
|
|
42
|
+
)
|
|
43
|
+
name: str | None = None
|
|
44
|
+
|
|
45
|
+
@field_validator("labels", mode="before")
|
|
46
|
+
@staticmethod
|
|
47
|
+
def _labels(v):
|
|
48
|
+
return _parse_list_or_dict(v) if v is not None else None
|
|
49
|
+
|
|
50
|
+
@field_validator("external", mode="before")
|
|
51
|
+
@staticmethod
|
|
52
|
+
def _external(v):
|
|
53
|
+
return _parse_external(v) if v is not None else None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class ServiceNetworkConfig(ComposeBaseModel):
|
|
57
|
+
"""Service-level network attachment configuration."""
|
|
58
|
+
|
|
59
|
+
aliases: list[str] | None = None
|
|
60
|
+
ipv4_address: str | None = None
|
|
61
|
+
ipv6_address: str | None = None
|
|
62
|
+
link_local_ips: list[str] | None = None
|
|
63
|
+
mac_address: str | None = None
|
|
64
|
+
driver_opts: dict[str, str | int] | None = None
|
|
65
|
+
priority: int | None = None
|
|
66
|
+
gw_priority: int | None = None
|
|
67
|
+
interface_name: str | None = None
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Secret models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pydantic import Field, field_validator
|
|
6
|
+
|
|
7
|
+
from .common import ComposeBaseModel, _parse_external, _parse_list_or_dict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Secret(ComposeBaseModel):
|
|
11
|
+
"""Top-level secret definition."""
|
|
12
|
+
|
|
13
|
+
file: str | None = None
|
|
14
|
+
environment: str | None = None
|
|
15
|
+
external: bool | dict[str, str] | None = Field(
|
|
16
|
+
default=None, validate_default=True
|
|
17
|
+
)
|
|
18
|
+
name: str | None = None
|
|
19
|
+
labels: dict[str, str] | list[str] | None = Field(
|
|
20
|
+
default=None, validate_default=True
|
|
21
|
+
)
|
|
22
|
+
template_driver: str | None = None
|
|
23
|
+
|
|
24
|
+
@field_validator("labels", mode="before")
|
|
25
|
+
@staticmethod
|
|
26
|
+
def _labels(v):
|
|
27
|
+
return _parse_list_or_dict(v) if v is not None else None
|
|
28
|
+
|
|
29
|
+
@field_validator("external", mode="before")
|
|
30
|
+
@staticmethod
|
|
31
|
+
def _external(v):
|
|
32
|
+
return _parse_external(v) if v is not None else None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ServiceSecret(ComposeBaseModel):
|
|
36
|
+
"""Service-level secret reference."""
|
|
37
|
+
|
|
38
|
+
source: str
|
|
39
|
+
target: str | None = None
|
|
40
|
+
uid: str | None = None
|
|
41
|
+
gid: str | None = None
|
|
42
|
+
mode: str | None = None
|
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
"""Service model and sub-models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic import Field, field_validator
|
|
8
|
+
|
|
9
|
+
from .build import BuildConfig
|
|
10
|
+
from .config import ServiceConfig
|
|
11
|
+
from .common import (
|
|
12
|
+
ComposeBaseModel,
|
|
13
|
+
_parse_annotations,
|
|
14
|
+
_parse_command,
|
|
15
|
+
_parse_devices,
|
|
16
|
+
_parse_dns,
|
|
17
|
+
_parse_environment,
|
|
18
|
+
_parse_extra_hosts,
|
|
19
|
+
_parse_labels,
|
|
20
|
+
_parse_port,
|
|
21
|
+
_parse_service_volume,
|
|
22
|
+
_parse_tmpfs,
|
|
23
|
+
_parse_ulimits,
|
|
24
|
+
_parse_volumes_from,
|
|
25
|
+
validate_byte_value,
|
|
26
|
+
validate_duration,
|
|
27
|
+
)
|
|
28
|
+
from .deploy import DeployConfig
|
|
29
|
+
from .develop import DevelopConfig
|
|
30
|
+
from .model import ServiceModelConfig
|
|
31
|
+
from .network import ServiceNetworkConfig
|
|
32
|
+
from .secret import ServiceSecret
|
|
33
|
+
from .volume import VolumeMount
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class BlkioLimit(ComposeBaseModel):
|
|
37
|
+
"""Block IO limit for a specific device."""
|
|
38
|
+
|
|
39
|
+
path: str
|
|
40
|
+
rate: str | int
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class BlkioWeight(ComposeBaseModel):
|
|
44
|
+
"""Block IO weight for a specific device."""
|
|
45
|
+
|
|
46
|
+
path: str
|
|
47
|
+
weight: int
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class BlkioConfig(ComposeBaseModel):
|
|
51
|
+
"""Block IO configuration."""
|
|
52
|
+
|
|
53
|
+
weight: int | None = None
|
|
54
|
+
weight_device: list[BlkioWeight] | None = None
|
|
55
|
+
device_read_bps: list[BlkioLimit] | None = None
|
|
56
|
+
device_read_iops: list[BlkioLimit] | None = None
|
|
57
|
+
device_write_bps: list[BlkioLimit] | None = None
|
|
58
|
+
device_write_iops: list[BlkioLimit] | None = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class Healthcheck(ComposeBaseModel):
|
|
62
|
+
"""Healthcheck configuration."""
|
|
63
|
+
|
|
64
|
+
test: str | list[str] | None = None
|
|
65
|
+
interval: str | None = Field(default=None, validate_default=True)
|
|
66
|
+
timeout: str | None = Field(default=None, validate_default=True)
|
|
67
|
+
retries: int | None = None
|
|
68
|
+
start_period: str | None = Field(default=None, validate_default=True)
|
|
69
|
+
start_interval: str | None = Field(default=None, validate_default=True)
|
|
70
|
+
disable: bool | None = None
|
|
71
|
+
|
|
72
|
+
@field_validator("interval", "timeout", "start_period", "start_interval", mode="before")
|
|
73
|
+
@staticmethod
|
|
74
|
+
def _validate_duration(v: Any) -> str | None:
|
|
75
|
+
return validate_duration(v) if v is not None else None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class Logging(ComposeBaseModel):
|
|
79
|
+
"""Logging configuration."""
|
|
80
|
+
|
|
81
|
+
driver: str | None = None
|
|
82
|
+
options: dict[str, str] | None = None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class PortConfig(ComposeBaseModel):
|
|
86
|
+
"""Port configuration (long syntax)."""
|
|
87
|
+
|
|
88
|
+
target: int
|
|
89
|
+
published: str | None = None
|
|
90
|
+
host_ip: str | None = None
|
|
91
|
+
protocol: str | None = None
|
|
92
|
+
app_protocol: str | None = None
|
|
93
|
+
mode: str | None = None
|
|
94
|
+
name: str | None = None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Ulimit(ComposeBaseModel):
|
|
98
|
+
"""Ulimit configuration."""
|
|
99
|
+
|
|
100
|
+
soft: int
|
|
101
|
+
hard: int
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class CredentialSpec(ComposeBaseModel):
|
|
105
|
+
"""Credential specification for Windows containers."""
|
|
106
|
+
|
|
107
|
+
file: str | None = None
|
|
108
|
+
registry: str | None = None
|
|
109
|
+
config: str | None = None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class DependsOnConfig(ComposeBaseModel):
|
|
113
|
+
"""Long-form depends_on entry."""
|
|
114
|
+
|
|
115
|
+
condition: str | None = None
|
|
116
|
+
restart: bool | None = None
|
|
117
|
+
required: bool | None = None
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class ExtendsConfig(ComposeBaseModel):
|
|
121
|
+
"""Extends configuration."""
|
|
122
|
+
|
|
123
|
+
service: str
|
|
124
|
+
file: str | None = None
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class EnvFileEntry(ComposeBaseModel):
|
|
128
|
+
"""Environment file entry with options."""
|
|
129
|
+
|
|
130
|
+
path: str
|
|
131
|
+
required: bool = True
|
|
132
|
+
format: str | None = None
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class PostStartHook(ComposeBaseModel):
|
|
136
|
+
"""Post-start lifecycle hook."""
|
|
137
|
+
|
|
138
|
+
command: str | list[str]
|
|
139
|
+
user: str | None = None
|
|
140
|
+
privileged: bool | None = None
|
|
141
|
+
working_dir: str | None = None
|
|
142
|
+
environment: dict[str, str] | list[str] | None = None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class ProviderConfig(ComposeBaseModel):
|
|
146
|
+
"""Provider configuration for delegated services."""
|
|
147
|
+
|
|
148
|
+
type: str
|
|
149
|
+
options: dict[str, Any] | None = None
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class GpuConfig(ComposeBaseModel):
|
|
153
|
+
"""GPU configuration."""
|
|
154
|
+
|
|
155
|
+
driver: str | None = None
|
|
156
|
+
count: int | str | None = None
|
|
157
|
+
device_ids: list[str] | None = None
|
|
158
|
+
capabilities: list[str] | None = None
|
|
159
|
+
options: dict[str, Any] | None = None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class Service(ComposeBaseModel):
|
|
163
|
+
"""Service definition in a Compose file."""
|
|
164
|
+
|
|
165
|
+
# Core & Image
|
|
166
|
+
image: str | None = None
|
|
167
|
+
build: "BuildConfig | str | None" = Field(default=None, validate_default=True)
|
|
168
|
+
command: str | list[str] | None = Field(default=None, validate_default=True)
|
|
169
|
+
entrypoint: str | list[str] | None = Field(default=None, validate_default=True)
|
|
170
|
+
|
|
171
|
+
# Environment
|
|
172
|
+
environment: dict[str, str | None] | None = Field(
|
|
173
|
+
default=None, validate_default=True
|
|
174
|
+
)
|
|
175
|
+
env_file: list[EnvFileEntry] | list[str] | str | None = Field(
|
|
176
|
+
default=None, validate_default=True
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Networking
|
|
180
|
+
ports: list[PortConfig] | list[str] | None = Field(
|
|
181
|
+
default=None, validate_default=True
|
|
182
|
+
)
|
|
183
|
+
expose: list[str] | None = None
|
|
184
|
+
networks: dict[str, "ServiceNetworkConfig"] | list[str] | None = None
|
|
185
|
+
network_mode: str | None = None
|
|
186
|
+
hostname: str | None = None
|
|
187
|
+
domainname: str | None = None
|
|
188
|
+
mac_address: str | None = None
|
|
189
|
+
extra_hosts: dict[str, str] | list[str] | None = Field(
|
|
190
|
+
default=None, validate_default=True
|
|
191
|
+
)
|
|
192
|
+
dns: str | list[str] | None = Field(default=None, validate_default=True)
|
|
193
|
+
dns_search: str | list[str] | None = Field(default=None, validate_default=True)
|
|
194
|
+
dns_opt: list[str] | None = None
|
|
195
|
+
external_links: list[str] | None = None
|
|
196
|
+
links: list[str] | None = None
|
|
197
|
+
|
|
198
|
+
# Storage
|
|
199
|
+
volumes: list["VolumeMount"] | list[str] | None = Field(
|
|
200
|
+
default=None, validate_default=True
|
|
201
|
+
)
|
|
202
|
+
volumes_from: list[str] | None = Field(default=None, validate_default=True)
|
|
203
|
+
tmpfs: list[str] | None = Field(default=None, validate_default=True)
|
|
204
|
+
working_dir: str | None = None
|
|
205
|
+
|
|
206
|
+
# Runtime
|
|
207
|
+
user: str | None = None
|
|
208
|
+
privileged: bool | None = None
|
|
209
|
+
read_only: bool | None = None
|
|
210
|
+
stdin_open: bool | None = None
|
|
211
|
+
tty: bool | None = None
|
|
212
|
+
init: bool | None = None
|
|
213
|
+
restart: str | None = None
|
|
214
|
+
stop_grace_period: str | None = Field(default=None, validate_default=True)
|
|
215
|
+
stop_signal: str | None = None
|
|
216
|
+
runtime: str | None = None
|
|
217
|
+
platform: str | None = None
|
|
218
|
+
ipc: str | None = None
|
|
219
|
+
pid: str | None = None
|
|
220
|
+
uts: str | None = None
|
|
221
|
+
cgroup: str | None = None
|
|
222
|
+
cgroup_parent: str | None = None
|
|
223
|
+
isolation: str | None = None
|
|
224
|
+
userns_mode: str | None = None
|
|
225
|
+
oom_kill_disable: bool | None = None
|
|
226
|
+
oom_score_adj: int | None = None
|
|
227
|
+
pids_limit: int | None = None
|
|
228
|
+
|
|
229
|
+
# Resources
|
|
230
|
+
cpu_count: int | None = None
|
|
231
|
+
cpu_percent: int | None = None
|
|
232
|
+
cpu_shares: int | None = None
|
|
233
|
+
cpu_period: int | None = None
|
|
234
|
+
cpu_quota: int | None = None
|
|
235
|
+
cpu_rt_runtime: str | int | None = None
|
|
236
|
+
cpu_rt_period: str | int | None = None
|
|
237
|
+
cpus: float | None = None
|
|
238
|
+
cpuset: str | None = None
|
|
239
|
+
mem_limit: str | int | None = Field(default=None, validate_default=True)
|
|
240
|
+
mem_reservation: str | int | None = Field(default=None, validate_default=True)
|
|
241
|
+
mem_swappiness: int | None = None
|
|
242
|
+
memswap_limit: str | int | None = Field(default=None, validate_default=True)
|
|
243
|
+
shm_size: str | int | None = Field(default=None, validate_default=True)
|
|
244
|
+
storage_opt: dict[str, str] | None = None
|
|
245
|
+
ulimits: dict[str, int | dict[str, int]] | None = Field(
|
|
246
|
+
default=None, validate_default=True
|
|
247
|
+
)
|
|
248
|
+
sysctls: dict[str, str | int] | list[str] | None = Field(
|
|
249
|
+
default=None, validate_default=True
|
|
250
|
+
)
|
|
251
|
+
blkio_config: BlkioConfig | None = Field(default=None, validate_default=True)
|
|
252
|
+
|
|
253
|
+
# Capabilities & Security
|
|
254
|
+
cap_add: list[str] | None = None
|
|
255
|
+
cap_drop: list[str] | None = None
|
|
256
|
+
security_opt: list[str] | None = None
|
|
257
|
+
device_cgroup_rules: list[str] | None = None
|
|
258
|
+
devices: list[str] | None = Field(default=None, validate_default=True)
|
|
259
|
+
group_add: list[str] | None = None
|
|
260
|
+
|
|
261
|
+
# Health & Logging
|
|
262
|
+
healthcheck: Healthcheck | None = None
|
|
263
|
+
logging: Logging | None = None
|
|
264
|
+
|
|
265
|
+
# Dependencies
|
|
266
|
+
depends_on: dict[str, DependsOnConfig] | list[str] | None = Field(
|
|
267
|
+
default=None, validate_default=True
|
|
268
|
+
)
|
|
269
|
+
links: list[str] | None = None
|
|
270
|
+
external_links: list[str] | None = None
|
|
271
|
+
|
|
272
|
+
# Configs & Secrets
|
|
273
|
+
configs: list["ServiceConfig"] | list[str] | None = Field(
|
|
274
|
+
default=None, validate_default=True
|
|
275
|
+
)
|
|
276
|
+
secrets: list["ServiceSecret"] | list[str] | None = Field(
|
|
277
|
+
default=None, validate_default=True
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# Metadata
|
|
281
|
+
container_name: str | None = None
|
|
282
|
+
labels: dict[str, str] | list[str] | None = Field(
|
|
283
|
+
default=None, validate_default=True
|
|
284
|
+
)
|
|
285
|
+
annotations: dict[str, str] | list[str] | None = Field(
|
|
286
|
+
default=None, validate_default=True
|
|
287
|
+
)
|
|
288
|
+
label_file: str | list[str] | None = Field(default=None, validate_default=True)
|
|
289
|
+
|
|
290
|
+
# Profiles & Scaling
|
|
291
|
+
profiles: list[str] | None = None
|
|
292
|
+
scale: int | None = None
|
|
293
|
+
|
|
294
|
+
# Build & Deploy
|
|
295
|
+
deploy: "DeployConfig | None" = None
|
|
296
|
+
develop: "DevelopConfig | None" = None
|
|
297
|
+
|
|
298
|
+
# Pull policy
|
|
299
|
+
pull_policy: str | None = None
|
|
300
|
+
|
|
301
|
+
# Credentials
|
|
302
|
+
credential_spec: CredentialSpec | None = None
|
|
303
|
+
|
|
304
|
+
# Extends
|
|
305
|
+
extends: ExtendsConfig | None = None
|
|
306
|
+
|
|
307
|
+
# Lifecycle hooks
|
|
308
|
+
post_start: list[PostStartHook] | None = None
|
|
309
|
+
pre_stop: list[PostStartHook] | None = None
|
|
310
|
+
|
|
311
|
+
# GPU
|
|
312
|
+
gpus: list[GpuConfig] | str | None = None
|
|
313
|
+
|
|
314
|
+
# Models
|
|
315
|
+
models: list[str] | dict[str, "ServiceModelConfig"] | None = None
|
|
316
|
+
|
|
317
|
+
# Provider
|
|
318
|
+
provider: ProviderConfig | None = None
|
|
319
|
+
|
|
320
|
+
# API socket
|
|
321
|
+
use_api_socket: bool | None = None
|
|
322
|
+
|
|
323
|
+
# Attach
|
|
324
|
+
attach: bool | None = None
|
|
325
|
+
|
|
326
|
+
# ------------------------------------------------------------------
|
|
327
|
+
# Validators
|
|
328
|
+
# ------------------------------------------------------------------
|
|
329
|
+
|
|
330
|
+
@field_validator("build", mode="before")
|
|
331
|
+
@staticmethod
|
|
332
|
+
def _build(v: Any) -> dict[str, Any] | str | None:
|
|
333
|
+
if v is None or isinstance(v, (str, dict)):
|
|
334
|
+
return v
|
|
335
|
+
return None
|
|
336
|
+
|
|
337
|
+
@field_validator("command", mode="before")
|
|
338
|
+
@staticmethod
|
|
339
|
+
def _command(v: Any) -> str | list[str] | None:
|
|
340
|
+
return _parse_command(v)
|
|
341
|
+
|
|
342
|
+
@field_validator("entrypoint", mode="before")
|
|
343
|
+
@staticmethod
|
|
344
|
+
def _entrypoint(v: Any) -> str | list[str] | None:
|
|
345
|
+
return _parse_command(v)
|
|
346
|
+
|
|
347
|
+
@field_validator("environment", mode="before")
|
|
348
|
+
@staticmethod
|
|
349
|
+
def _environment(v: Any) -> dict[str, str | None] | None:
|
|
350
|
+
return _parse_environment(v)
|
|
351
|
+
|
|
352
|
+
@field_validator("env_file", mode="before")
|
|
353
|
+
@staticmethod
|
|
354
|
+
def _env_file(v: Any) -> list[EnvFileEntry] | list[str] | str | None:
|
|
355
|
+
if v is None:
|
|
356
|
+
return None
|
|
357
|
+
if isinstance(v, str):
|
|
358
|
+
return v
|
|
359
|
+
if isinstance(v, list):
|
|
360
|
+
result: list[EnvFileEntry | str] = []
|
|
361
|
+
for item in v:
|
|
362
|
+
if isinstance(item, str):
|
|
363
|
+
result.append(item)
|
|
364
|
+
elif isinstance(item, dict):
|
|
365
|
+
result.append(EnvFileEntry.model_validate(item))
|
|
366
|
+
return result
|
|
367
|
+
return None
|
|
368
|
+
|
|
369
|
+
@field_validator("ports", mode="before")
|
|
370
|
+
@staticmethod
|
|
371
|
+
def _ports(v: Any) -> list[PortConfig] | list[str] | None:
|
|
372
|
+
if v is None:
|
|
373
|
+
return None
|
|
374
|
+
if isinstance(v, list):
|
|
375
|
+
result: list[PortConfig | str] = []
|
|
376
|
+
for item in v:
|
|
377
|
+
if isinstance(item, str):
|
|
378
|
+
result.append(PortConfig.model_validate(_parse_port(item)))
|
|
379
|
+
elif isinstance(item, dict):
|
|
380
|
+
result.append(PortConfig.model_validate(item))
|
|
381
|
+
elif isinstance(item, int):
|
|
382
|
+
result.append(PortConfig.model_validate({"target": item}))
|
|
383
|
+
return result
|
|
384
|
+
return None
|
|
385
|
+
|
|
386
|
+
@field_validator("extra_hosts", mode="before")
|
|
387
|
+
@staticmethod
|
|
388
|
+
def _extra_hosts(v: Any) -> dict[str, str] | list[str] | None:
|
|
389
|
+
return _parse_extra_hosts(v)
|
|
390
|
+
|
|
391
|
+
@field_validator("dns", mode="before")
|
|
392
|
+
@staticmethod
|
|
393
|
+
def _dns(v: Any) -> str | list[str] | None:
|
|
394
|
+
return _parse_dns(v)
|
|
395
|
+
|
|
396
|
+
@field_validator("dns_search", mode="before")
|
|
397
|
+
@staticmethod
|
|
398
|
+
def _dns_search(v: Any) -> str | list[str] | None:
|
|
399
|
+
return _parse_dns(v)
|
|
400
|
+
|
|
401
|
+
@field_validator("volumes", mode="before")
|
|
402
|
+
@staticmethod
|
|
403
|
+
def _volumes(v: Any) -> list[VolumeMount] | list[str] | None:
|
|
404
|
+
if v is None:
|
|
405
|
+
return None
|
|
406
|
+
if isinstance(v, list):
|
|
407
|
+
from .volume import VolumeMount
|
|
408
|
+
result: list[VolumeMount | str] = []
|
|
409
|
+
for item in v:
|
|
410
|
+
if isinstance(item, str):
|
|
411
|
+
result.append(VolumeMount.model_validate(_parse_service_volume(item)))
|
|
412
|
+
elif isinstance(item, dict):
|
|
413
|
+
result.append(VolumeMount.model_validate(item))
|
|
414
|
+
return result
|
|
415
|
+
return None
|
|
416
|
+
|
|
417
|
+
@field_validator("volumes_from", mode="before")
|
|
418
|
+
@staticmethod
|
|
419
|
+
def _volumes_from(v: Any) -> list[str] | None:
|
|
420
|
+
return _parse_volumes_from(v)
|
|
421
|
+
|
|
422
|
+
@field_validator("tmpfs", mode="before")
|
|
423
|
+
@staticmethod
|
|
424
|
+
def _tmpfs(v: Any) -> list[str] | None:
|
|
425
|
+
return _parse_tmpfs(v)
|
|
426
|
+
|
|
427
|
+
@field_validator("stop_grace_period", mode="before")
|
|
428
|
+
@staticmethod
|
|
429
|
+
def _stop_grace_period(v: Any) -> str | None:
|
|
430
|
+
return validate_duration(v) if v is not None else None
|
|
431
|
+
|
|
432
|
+
@field_validator("mem_limit", mode="before")
|
|
433
|
+
@staticmethod
|
|
434
|
+
def _mem_limit(v: Any) -> str | int | None:
|
|
435
|
+
return validate_byte_value(v)
|
|
436
|
+
|
|
437
|
+
@field_validator("mem_reservation", mode="before")
|
|
438
|
+
@staticmethod
|
|
439
|
+
def _mem_reservation(v: Any) -> str | int | None:
|
|
440
|
+
return validate_byte_value(v)
|
|
441
|
+
|
|
442
|
+
@field_validator("memswap_limit", mode="before")
|
|
443
|
+
@staticmethod
|
|
444
|
+
def _memswap_limit(v: Any) -> str | int | None:
|
|
445
|
+
return validate_byte_value(v)
|
|
446
|
+
|
|
447
|
+
@field_validator("shm_size", mode="before")
|
|
448
|
+
@staticmethod
|
|
449
|
+
def _shm_size(v: Any) -> str | int | None:
|
|
450
|
+
return validate_byte_value(v)
|
|
451
|
+
|
|
452
|
+
@field_validator("ulimits", mode="before")
|
|
453
|
+
@staticmethod
|
|
454
|
+
def _ulimits(v: Any) -> dict[str, int | dict[str, int]] | None:
|
|
455
|
+
return _parse_ulimits(v)
|
|
456
|
+
|
|
457
|
+
@field_validator("sysctls", mode="before")
|
|
458
|
+
@staticmethod
|
|
459
|
+
def _sysctls(v: Any) -> dict[str, str | int] | list[str] | None:
|
|
460
|
+
if v is None:
|
|
461
|
+
return None
|
|
462
|
+
if isinstance(v, dict):
|
|
463
|
+
return {str(k): v for k, v in v.items()}
|
|
464
|
+
if isinstance(v, list):
|
|
465
|
+
return [str(item) for item in v]
|
|
466
|
+
return None
|
|
467
|
+
|
|
468
|
+
@field_validator("blkio_config", mode="before")
|
|
469
|
+
@staticmethod
|
|
470
|
+
def _blkio_config(v: Any) -> BlkioConfig | None:
|
|
471
|
+
if v is None:
|
|
472
|
+
return None
|
|
473
|
+
if isinstance(v, dict):
|
|
474
|
+
return BlkioConfig.model_validate(v)
|
|
475
|
+
return None
|
|
476
|
+
|
|
477
|
+
@field_validator("devices", mode="before")
|
|
478
|
+
@staticmethod
|
|
479
|
+
def _devices(v: Any) -> list[str] | None:
|
|
480
|
+
return _parse_devices(v)
|
|
481
|
+
|
|
482
|
+
@field_validator("depends_on", mode="before")
|
|
483
|
+
@staticmethod
|
|
484
|
+
def _depends_on(v: Any) -> dict[str, DependsOnConfig] | list[str] | None:
|
|
485
|
+
if v is None:
|
|
486
|
+
return None
|
|
487
|
+
if isinstance(v, list):
|
|
488
|
+
return [str(item) for item in v]
|
|
489
|
+
if isinstance(v, dict):
|
|
490
|
+
result: dict[str, DependsOnConfig] = {}
|
|
491
|
+
for k, val in v.items():
|
|
492
|
+
if isinstance(val, str):
|
|
493
|
+
result[str(k)] = DependsOnConfig(condition=val)
|
|
494
|
+
elif isinstance(val, dict):
|
|
495
|
+
result[str(k)] = DependsOnConfig.model_validate(val)
|
|
496
|
+
elif isinstance(val, bool):
|
|
497
|
+
result[str(k)] = DependsOnConfig()
|
|
498
|
+
return result
|
|
499
|
+
return None
|
|
500
|
+
|
|
501
|
+
@field_validator("configs", mode="before")
|
|
502
|
+
@staticmethod
|
|
503
|
+
def _configs(v: Any) -> list[ServiceConfig] | list[str] | None:
|
|
504
|
+
if v is None:
|
|
505
|
+
return None
|
|
506
|
+
from .config import ServiceConfig
|
|
507
|
+
if isinstance(v, list):
|
|
508
|
+
result: list[ServiceConfig | str] = []
|
|
509
|
+
for item in v:
|
|
510
|
+
if isinstance(item, str):
|
|
511
|
+
result.append(item)
|
|
512
|
+
elif isinstance(item, dict):
|
|
513
|
+
result.append(ServiceConfig.model_validate(item))
|
|
514
|
+
return result
|
|
515
|
+
return None
|
|
516
|
+
|
|
517
|
+
@field_validator("secrets", mode="before")
|
|
518
|
+
@staticmethod
|
|
519
|
+
def _secrets(v: Any) -> list[ServiceSecret] | list[str] | None:
|
|
520
|
+
if v is None:
|
|
521
|
+
return None
|
|
522
|
+
from .secret import ServiceSecret
|
|
523
|
+
if isinstance(v, list):
|
|
524
|
+
result: list[ServiceSecret | str] = []
|
|
525
|
+
for item in v:
|
|
526
|
+
if isinstance(item, str):
|
|
527
|
+
result.append(item)
|
|
528
|
+
elif isinstance(item, dict):
|
|
529
|
+
result.append(ServiceSecret.model_validate(item))
|
|
530
|
+
return result
|
|
531
|
+
return None
|
|
532
|
+
|
|
533
|
+
@field_validator("labels", mode="before")
|
|
534
|
+
@staticmethod
|
|
535
|
+
def _labels(v: Any) -> dict[str, str] | list[str] | None:
|
|
536
|
+
return _parse_labels(v)
|
|
537
|
+
|
|
538
|
+
@field_validator("annotations", mode="before")
|
|
539
|
+
@staticmethod
|
|
540
|
+
def _annotations(v: Any) -> dict[str, str] | list[str] | None:
|
|
541
|
+
return _parse_annotations(v)
|
|
542
|
+
|
|
543
|
+
@field_validator("label_file", mode="before")
|
|
544
|
+
@staticmethod
|
|
545
|
+
def _label_file(v: Any) -> str | list[str] | None:
|
|
546
|
+
if v is None:
|
|
547
|
+
return None
|
|
548
|
+
if isinstance(v, str):
|
|
549
|
+
return v
|
|
550
|
+
if isinstance(v, list):
|
|
551
|
+
return [str(item) for item in v]
|
|
552
|
+
return None
|
|
553
|
+
|
|
554
|
+
@field_validator("networks", mode="before")
|
|
555
|
+
@staticmethod
|
|
556
|
+
def _networks(v: Any) -> dict[str, "ServiceNetworkConfig"] | list[str] | None:
|
|
557
|
+
if v is None:
|
|
558
|
+
return None
|
|
559
|
+
from .network import ServiceNetworkConfig
|
|
560
|
+
if isinstance(v, list):
|
|
561
|
+
return [str(item) for item in v]
|
|
562
|
+
if isinstance(v, dict):
|
|
563
|
+
result: dict[str, ServiceNetworkConfig] = {}
|
|
564
|
+
for k, val in v.items():
|
|
565
|
+
if val is None or val == {}:
|
|
566
|
+
result[str(k)] = ServiceNetworkConfig()
|
|
567
|
+
elif isinstance(val, dict):
|
|
568
|
+
result[str(k)] = ServiceNetworkConfig.model_validate(val)
|
|
569
|
+
return result
|
|
570
|
+
return None
|
|
571
|
+
|
|
572
|
+
@field_validator("gpus", mode="before")
|
|
573
|
+
@staticmethod
|
|
574
|
+
def _gpus(v: Any) -> list[GpuConfig] | str | None:
|
|
575
|
+
if v is None:
|
|
576
|
+
return None
|
|
577
|
+
if isinstance(v, str):
|
|
578
|
+
return v
|
|
579
|
+
if isinstance(v, list):
|
|
580
|
+
result: list[GpuConfig] = []
|
|
581
|
+
for item in v:
|
|
582
|
+
if isinstance(item, dict):
|
|
583
|
+
result.append(GpuConfig.model_validate(item))
|
|
584
|
+
return result
|
|
585
|
+
return None
|
|
586
|
+
|
|
587
|
+
@field_validator("models", mode="before")
|
|
588
|
+
@staticmethod
|
|
589
|
+
def _models(v: Any) -> list[str] | dict[str, "ServiceModelConfig"] | None:
|
|
590
|
+
if v is None:
|
|
591
|
+
return None
|
|
592
|
+
if isinstance(v, list):
|
|
593
|
+
return [str(item) for item in v]
|
|
594
|
+
if isinstance(v, dict):
|
|
595
|
+
from .model import ServiceModelConfig
|
|
596
|
+
return {str(k): ServiceModelConfig.model_validate(val) if isinstance(val, dict) else ServiceModelConfig() for k, val in v.items()}
|
|
597
|
+
return None
|
|
598
|
+
|