forktex-cloud 0.2.3__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.
- forktex_cloud/__init__.py +92 -0
- forktex_cloud/bridge/__init__.py +24 -0
- forktex_cloud/bridge/local_compose.py +295 -0
- forktex_cloud/bridge/log_formatter.py +62 -0
- forktex_cloud/bridge/loki.py +109 -0
- forktex_cloud/bridge/persistence_defaults.py +120 -0
- forktex_cloud/client/__init__.py +83 -0
- forktex_cloud/client/client.py +599 -0
- forktex_cloud/client/generated/__init__.py +1057 -0
- forktex_cloud/config.py +63 -0
- forktex_cloud/manifest/__init__.py +58 -0
- forktex_cloud/manifest/errors.py +34 -0
- forktex_cloud/manifest/loader.py +296 -0
- forktex_cloud/manifest/merge.py +52 -0
- forktex_cloud/manifest/schema.py +88 -0
- forktex_cloud/paths.py +297 -0
- forktex_cloud/scaffold/__init__.py +24 -0
- forktex_cloud/scaffold/templates.py +143 -0
- forktex_cloud/secrets/__init__.py +24 -0
- forktex_cloud/secrets/base.py +52 -0
- forktex_cloud/secrets/factory.py +57 -0
- forktex_cloud/secrets/fernet.py +96 -0
- forktex_cloud/secrets/resolver.py +59 -0
- forktex_cloud/templates/observability/loki.yml +55 -0
- forktex_cloud/templates/observability/promtail.yml +46 -0
- forktex_cloud-0.2.3.dist-info/METADATA +226 -0
- forktex_cloud-0.2.3.dist-info/RECORD +30 -0
- forktex_cloud-0.2.3.dist-info/WHEEL +4 -0
- forktex_cloud-0.2.3.dist-info/licenses/LICENSE +45 -0
- forktex_cloud-0.2.3.dist-info/licenses/NOTICE +23 -0
|
@@ -0,0 +1,1057 @@
|
|
|
1
|
+
# Copyright (C) 2026 FORKTEX S.R.L.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-ForkTex-Commercial
|
|
4
|
+
#
|
|
5
|
+
# This file is part of forktex-cloud.
|
|
6
|
+
#
|
|
7
|
+
# For commercial licensing -- including use in proprietary products, SaaS
|
|
8
|
+
# deployments, or any context where AGPL obligations cannot be met -- you
|
|
9
|
+
# MUST obtain a commercial license from FORKTEX S.R.L. (info@forktex.com).
|
|
10
|
+
#
|
|
11
|
+
# This program is free software: you can redistribute it and/or modify
|
|
12
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
13
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
14
|
+
# (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# This program is distributed in the hope that it will be useful,
|
|
17
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
+
# GNU Affero General Public License for more details.
|
|
20
|
+
#
|
|
21
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
22
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
23
|
+
|
|
24
|
+
"""Auto-generated Pydantic models from the ForkTex Cloud API OpenAPI spec.
|
|
25
|
+
|
|
26
|
+
DO NOT EDIT — regenerate with: make codegen
|
|
27
|
+
|
|
28
|
+
Source: GET /api/openapi.json
|
|
29
|
+
API version: 0.6.0
|
|
30
|
+
Spec hash: c9e218a6fef2b1b4
|
|
31
|
+
"""
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
SPEC_VERSION = "0.6.0"
|
|
36
|
+
SPEC_HASH = "c9e218a6fef2b1b4"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
from enum import StrEnum
|
|
40
|
+
from typing import Annotated, Any, Literal
|
|
41
|
+
from uuid import UUID
|
|
42
|
+
|
|
43
|
+
from pydantic import AwareDatetime, BaseModel, ConfigDict, EmailStr, Field
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AccessRequestCreate(BaseModel):
|
|
47
|
+
company: Annotated[str | None, Field(title="Company")] = None
|
|
48
|
+
email: Annotated[EmailStr, Field(title="Email")]
|
|
49
|
+
name: Annotated[str | None, Field(title="Name")] = None
|
|
50
|
+
use_case: Annotated[str | None, Field(title="Use Case")] = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AccessRequestRead(BaseModel):
|
|
54
|
+
company: Annotated[str | None, Field(title="Company")]
|
|
55
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
56
|
+
email: Annotated[str, Field(title="Email")]
|
|
57
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
58
|
+
name: Annotated[str | None, Field(title="Name")]
|
|
59
|
+
status: Annotated[str, Field(title="Status")]
|
|
60
|
+
use_case: Annotated[str | None, Field(title="Use Case")]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ApiKeyCreate(BaseModel):
|
|
64
|
+
expires_at: Annotated[AwareDatetime | None, Field(title="Expires At")] = None
|
|
65
|
+
label: Annotated[str, Field(title="Label")]
|
|
66
|
+
rate_limit_rpm: Annotated[int | None, Field(title="Rate Limit Rpm")] = None
|
|
67
|
+
scopes: Annotated[list[str] | None, Field(title="Scopes")] = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ApiKeyCreated(BaseModel):
|
|
71
|
+
"""
|
|
72
|
+
Returned only at creation time — includes the raw key.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
76
|
+
expires_at: Annotated[AwareDatetime | None, Field(title="Expires At")] = None
|
|
77
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
78
|
+
is_active: Annotated[bool, Field(title="Is Active")]
|
|
79
|
+
label: Annotated[str, Field(title="Label")]
|
|
80
|
+
last_used_at: Annotated[AwareDatetime | None, Field(title="Last Used At")] = None
|
|
81
|
+
org_id: Annotated[UUID, Field(title="Org Id")]
|
|
82
|
+
rate_limit_rpm: Annotated[int | None, Field(title="Rate Limit Rpm")] = None
|
|
83
|
+
raw_key: Annotated[str, Field(title="Raw Key")]
|
|
84
|
+
scopes: Annotated[list[str] | None, Field(title="Scopes")] = None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class ApiKeyRead(BaseModel):
|
|
88
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
89
|
+
expires_at: Annotated[AwareDatetime | None, Field(title="Expires At")] = None
|
|
90
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
91
|
+
is_active: Annotated[bool, Field(title="Is Active")]
|
|
92
|
+
label: Annotated[str, Field(title="Label")]
|
|
93
|
+
last_used_at: Annotated[AwareDatetime | None, Field(title="Last Used At")] = None
|
|
94
|
+
org_id: Annotated[UUID, Field(title="Org Id")]
|
|
95
|
+
rate_limit_rpm: Annotated[int | None, Field(title="Rate Limit Rpm")] = None
|
|
96
|
+
scopes: Annotated[list[str] | None, Field(title="Scopes")] = None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class ArchitectureSnapshot(BaseModel):
|
|
100
|
+
"""
|
|
101
|
+
A C4 architecture snapshot pushed by the forktex CLI.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
description: Annotated[str | None, Field(title="Description")] = ""
|
|
105
|
+
external_systems: Annotated[
|
|
106
|
+
list[dict[str, Any]] | None, Field(title="External Systems")
|
|
107
|
+
] = None
|
|
108
|
+
generated_at: Annotated[str, Field(title="Generated At")]
|
|
109
|
+
metadata: Annotated[dict[str, Any] | None, Field(title="Metadata")] = None
|
|
110
|
+
name: Annotated[str, Field(title="Name")]
|
|
111
|
+
relationships: Annotated[
|
|
112
|
+
list[dict[str, Any]] | None, Field(title="Relationships")
|
|
113
|
+
] = None
|
|
114
|
+
systems: Annotated[list[dict[str, Any]] | None, Field(title="Systems")] = None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class AuditEventRead(BaseModel):
|
|
118
|
+
action: Annotated[str, Field(title="Action")]
|
|
119
|
+
api_key_id: Annotated[UUID | None, Field(title="Api Key Id")] = None
|
|
120
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
121
|
+
details: Annotated[str | None, Field(title="Details")] = None
|
|
122
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
123
|
+
ip_address: Annotated[str | None, Field(title="Ip Address")] = None
|
|
124
|
+
org_id: Annotated[UUID, Field(title="Org Id")]
|
|
125
|
+
resource_id: Annotated[str | None, Field(title="Resource Id")] = None
|
|
126
|
+
resource_type: Annotated[str | None, Field(title="Resource Type")] = None
|
|
127
|
+
user_id: Annotated[UUID | None, Field(title="User Id")] = None
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class BackupCreate(BaseModel):
|
|
131
|
+
backup_type: Annotated[str | None, Field(title="Backup Type")] = "full"
|
|
132
|
+
service_id: Annotated[str | None, Field(title="Service Id")] = None
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class BackupPolicyDef(BaseModel):
|
|
136
|
+
"""
|
|
137
|
+
Backup schedule + retention for persistence services.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
model_config = ConfigDict(
|
|
141
|
+
extra="forbid",
|
|
142
|
+
)
|
|
143
|
+
enabled: Annotated[bool | None, Field(title="Enabled")] = False
|
|
144
|
+
retentionDays: Annotated[int | None, Field(title="Retentiondays")] = 7
|
|
145
|
+
schedule: Annotated[str | None, Field(title="Schedule")] = "0 3 * * *"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class BackupRead(BaseModel):
|
|
149
|
+
backup_type: Annotated[str, Field(title="Backup Type")]
|
|
150
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
151
|
+
environment_id: Annotated[UUID, Field(title="Environment Id")]
|
|
152
|
+
expires_at: Annotated[AwareDatetime | None, Field(title="Expires At")] = None
|
|
153
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
154
|
+
server_id: Annotated[UUID | None, Field(title="Server Id")] = None
|
|
155
|
+
service_id: Annotated[str | None, Field(title="Service Id")] = None
|
|
156
|
+
size_bytes: Annotated[int | None, Field(title="Size Bytes")] = None
|
|
157
|
+
status: Annotated[str, Field(title="Status")]
|
|
158
|
+
storage_path: Annotated[str | None, Field(title="Storage Path")] = None
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class BackupRestoreRead(BaseModel):
|
|
162
|
+
backup_id: Annotated[UUID, Field(title="Backup Id")]
|
|
163
|
+
service_id: Annotated[str, Field(title="Service Id")]
|
|
164
|
+
status: Annotated[str, Field(title="Status")]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class CapacityOrgLimits(BaseModel):
|
|
168
|
+
max_projects: Annotated[int, Field(title="Max Projects")]
|
|
169
|
+
max_servers: Annotated[int, Field(title="Max Servers")]
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class CapacityServers(BaseModel):
|
|
173
|
+
limit: Annotated[int, Field(title="Limit")]
|
|
174
|
+
used: Annotated[int, Field(title="Used")]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class ContainerStatus(BaseModel):
|
|
178
|
+
"""
|
|
179
|
+
Container state info from Docker inspect.
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
name: Annotated[str, Field(title="Name")]
|
|
183
|
+
state: Annotated[str, Field(title="State")]
|
|
184
|
+
status: Annotated[str, Field(title="Status")]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class DeployRead(BaseModel):
|
|
188
|
+
details: Annotated[str | None, Field(title="Details")] = None
|
|
189
|
+
environment_id: Annotated[UUID | None, Field(title="Environment Id")] = None
|
|
190
|
+
finished_at: Annotated[AwareDatetime | None, Field(title="Finished At")] = None
|
|
191
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
192
|
+
manifest_version_id: Annotated[UUID | None, Field(title="Manifest Version Id")] = (
|
|
193
|
+
None
|
|
194
|
+
)
|
|
195
|
+
project_id: Annotated[UUID | None, Field(title="Project Id")] = None
|
|
196
|
+
source: Annotated[str, Field(title="Source")]
|
|
197
|
+
started_at: Annotated[AwareDatetime, Field(title="Started At")]
|
|
198
|
+
status: Annotated[str, Field(title="Status")]
|
|
199
|
+
tags: Annotated[Any, Field(title="Tags")] = None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class DeploymentDef(BaseModel):
|
|
203
|
+
model_config = ConfigDict(
|
|
204
|
+
extra="forbid",
|
|
205
|
+
)
|
|
206
|
+
drainDelaySeconds: Annotated[int | None, Field(title="Draindelayseconds")] = 5
|
|
207
|
+
gracefulStopSeconds: Annotated[int | None, Field(title="Gracefulstopseconds")] = 30
|
|
208
|
+
healthRetries: Annotated[int | None, Field(title="Healthretries")] = 30
|
|
209
|
+
imageStrategy: Annotated[str | None, Field(title="Imagestrategy")] = None
|
|
210
|
+
registry: Annotated[dict[str, Any] | None, Field(title="Registry")] = None
|
|
211
|
+
strategy: Annotated[Literal["blue-green"], Field(title="Strategy")] = "blue-green"
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class DeploymentLogRead(BaseModel):
|
|
215
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
216
|
+
deployment_id: Annotated[UUID, Field(title="Deployment Id")]
|
|
217
|
+
exit_code: Annotated[int | None, Field(title="Exit Code")] = None
|
|
218
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
219
|
+
output: Annotated[str | None, Field(title="Output")] = None
|
|
220
|
+
server_id: Annotated[UUID | None, Field(title="Server Id")] = None
|
|
221
|
+
stage: Annotated[str, Field(title="Stage")]
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class EnvironmentCreate(BaseModel):
|
|
225
|
+
is_production: Annotated[bool | None, Field(title="Is Production")] = False
|
|
226
|
+
name: Annotated[str, Field(title="Name")]
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class EnvironmentPromotionRequest(BaseModel):
|
|
230
|
+
target_name: Annotated[str | None, Field(title="Target Name")] = "production"
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class EnvironmentRead(BaseModel):
|
|
234
|
+
controller_instance: Annotated[str | None, Field(title="Controller Instance")] = (
|
|
235
|
+
None
|
|
236
|
+
)
|
|
237
|
+
controller_url: Annotated[str | None, Field(title="Controller Url")] = None
|
|
238
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
239
|
+
handoff_completed_at: Annotated[
|
|
240
|
+
AwareDatetime | None, Field(title="Handoff Completed At")
|
|
241
|
+
] = None
|
|
242
|
+
handoff_ready_at: Annotated[
|
|
243
|
+
AwareDatetime | None, Field(title="Handoff Ready At")
|
|
244
|
+
] = None
|
|
245
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
246
|
+
is_production: Annotated[bool, Field(title="Is Production")]
|
|
247
|
+
name: Annotated[str, Field(title="Name")]
|
|
248
|
+
project_id: Annotated[UUID, Field(title="Project Id")]
|
|
249
|
+
status: Annotated[str, Field(title="Status")]
|
|
250
|
+
updated_at: Annotated[AwareDatetime, Field(title="Updated At")]
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class EnvironmentServerCreate(BaseModel):
|
|
254
|
+
role: Annotated[str | None, Field(title="Role")] = "primary"
|
|
255
|
+
server_id: Annotated[UUID, Field(title="Server Id")]
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class EnvironmentServerRead(BaseModel):
|
|
259
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
260
|
+
environment_id: Annotated[UUID, Field(title="Environment Id")]
|
|
261
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
262
|
+
role: Annotated[str, Field(title="Role")]
|
|
263
|
+
server_id: Annotated[UUID, Field(title="Server Id")]
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class EnvironmentServiceRead(BaseModel):
|
|
267
|
+
active_slot: Annotated[str | None, Field(title="Active Slot")] = None
|
|
268
|
+
current_image: Annotated[str | None, Field(title="Current Image")] = None
|
|
269
|
+
environment_id: Annotated[UUID, Field(title="Environment Id")]
|
|
270
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
271
|
+
service_id: Annotated[str, Field(title="Service Id")]
|
|
272
|
+
service_type: Annotated[str, Field(title="Service Type")]
|
|
273
|
+
status: Annotated[str | None, Field(title="Status")] = None
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class EnvironmentStateExportRead(BaseModel):
|
|
277
|
+
backups: Annotated[list[dict[str, Any]], Field(title="Backups")]
|
|
278
|
+
environment: Annotated[dict[str, Any], Field(title="Environment")]
|
|
279
|
+
manifests: Annotated[list[dict[str, Any]], Field(title="Manifests")]
|
|
280
|
+
services: Annotated[list[dict[str, Any]], Field(title="Services")]
|
|
281
|
+
vault_entries: Annotated[list[dict[str, Any]], Field(title="Vault Entries")]
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class EnvironmentStateImportRequest(BaseModel):
|
|
285
|
+
state: Annotated[dict[str, Any], Field(title="State")]
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
class EventRead(BaseModel):
|
|
289
|
+
action: Annotated[str, Field(title="Action")]
|
|
290
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
291
|
+
details: Annotated[str | None, Field(title="Details")] = None
|
|
292
|
+
environment_id: Annotated[UUID | None, Field(title="Environment Id")] = None
|
|
293
|
+
id: Annotated[int, Field(title="Id")]
|
|
294
|
+
org_id: Annotated[UUID | None, Field(title="Org Id")] = None
|
|
295
|
+
project_id: Annotated[UUID | None, Field(title="Project Id")] = None
|
|
296
|
+
server_id: Annotated[UUID | None, Field(title="Server Id")] = None
|
|
297
|
+
status: Annotated[str, Field(title="Status")]
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class ExecBody(BaseModel):
|
|
301
|
+
command: Annotated[str, Field(title="Command")]
|
|
302
|
+
service: Annotated[str, Field(title="Service")]
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class ForgotPasswordRequest(BaseModel):
|
|
306
|
+
email: Annotated[EmailStr, Field(title="Email")]
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class GatewayDomain(BaseModel):
|
|
310
|
+
model_config = ConfigDict(
|
|
311
|
+
extra="forbid",
|
|
312
|
+
)
|
|
313
|
+
host: Annotated[str, Field(min_length=1, title="Host")]
|
|
314
|
+
primary: Annotated[bool | None, Field(title="Primary")] = False
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class HandoffCriterionRead(BaseModel):
|
|
318
|
+
detail: Annotated[str, Field(title="Detail")]
|
|
319
|
+
name: Annotated[str, Field(title="Name")]
|
|
320
|
+
status: Annotated[bool, Field(title="Status")]
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class HandoffReadinessRead(BaseModel):
|
|
324
|
+
controller_instance: Annotated[str | None, Field(title="Controller Instance")] = (
|
|
325
|
+
None
|
|
326
|
+
)
|
|
327
|
+
controller_url: Annotated[str | None, Field(title="Controller Url")] = None
|
|
328
|
+
criteria: Annotated[list[HandoffCriterionRead], Field(title="Criteria")]
|
|
329
|
+
handoff_completed_at: Annotated[
|
|
330
|
+
AwareDatetime | None, Field(title="Handoff Completed At")
|
|
331
|
+
] = None
|
|
332
|
+
handoff_ready_at: Annotated[
|
|
333
|
+
AwareDatetime | None, Field(title="Handoff Ready At")
|
|
334
|
+
] = None
|
|
335
|
+
ready: Annotated[bool, Field(title="Ready")]
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class InfrastructureDef(BaseModel):
|
|
339
|
+
model_config = ConfigDict(
|
|
340
|
+
extra="forbid",
|
|
341
|
+
)
|
|
342
|
+
flavour: Annotated[str, Field(min_length=1, title="Flavour")]
|
|
343
|
+
image: Annotated[str | None, Field(title="Image")] = "ubuntu-24.04"
|
|
344
|
+
provider: Annotated[str, Field(min_length=1, title="Provider")]
|
|
345
|
+
region: Annotated[str, Field(min_length=1, title="Region")]
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class JobResponse(BaseModel):
|
|
349
|
+
"""
|
|
350
|
+
Response for asynchronous pipeline operations (/up, /down, /deploy).
|
|
351
|
+
"""
|
|
352
|
+
|
|
353
|
+
deployment_id: Annotated[str | None, Field(title="Deployment Id")] = None
|
|
354
|
+
job_id: Annotated[str, Field(title="Job Id")]
|
|
355
|
+
status: Annotated[str, Field(title="Status")]
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
class LifecycleDef(BaseModel):
|
|
359
|
+
"""
|
|
360
|
+
Hooks that run at specific deployment phases.
|
|
361
|
+
|
|
362
|
+
- ``initCommand`` — first deployment only (e.g. ``createdb``)
|
|
363
|
+
- ``preDeployCommand`` — before each deploy (e.g. ``pg_dump > backup.sql``)
|
|
364
|
+
- ``postDeployCommand`` — after each deploy (e.g. ``alembic upgrade head``)
|
|
365
|
+
"""
|
|
366
|
+
|
|
367
|
+
model_config = ConfigDict(
|
|
368
|
+
extra="forbid",
|
|
369
|
+
)
|
|
370
|
+
initCommand: Annotated[str | None, Field(title="Initcommand")] = None
|
|
371
|
+
postDeployCommand: Annotated[str | None, Field(title="Postdeploycommand")] = None
|
|
372
|
+
preDeployCommand: Annotated[str | None, Field(title="Predeploycommand")] = None
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class LoginRequest(BaseModel):
|
|
376
|
+
email: Annotated[EmailStr, Field(title="Email")]
|
|
377
|
+
password: Annotated[str, Field(title="Password")]
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class LokiDef(BaseModel):
|
|
381
|
+
"""
|
|
382
|
+
Per-project Loki log aggregator config.
|
|
383
|
+
"""
|
|
384
|
+
|
|
385
|
+
model_config = ConfigDict(
|
|
386
|
+
extra="forbid",
|
|
387
|
+
)
|
|
388
|
+
enabled: Annotated[bool | None, Field(title="Enabled")] = True
|
|
389
|
+
retentionDays: Annotated[int | None, Field(title="Retentiondays")] = 14
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
class MCPInfo(BaseModel):
|
|
393
|
+
description: Annotated[str, Field(title="Description")]
|
|
394
|
+
"""
|
|
395
|
+
Human-readable summary
|
|
396
|
+
"""
|
|
397
|
+
endpoint: Annotated[str, Field(title="Endpoint")]
|
|
398
|
+
"""
|
|
399
|
+
HTTP path of the MCP JSON-RPC transport
|
|
400
|
+
"""
|
|
401
|
+
protocol: Annotated[str, Field(title="Protocol")]
|
|
402
|
+
"""
|
|
403
|
+
Protocol identifier
|
|
404
|
+
"""
|
|
405
|
+
spec_url: Annotated[str, Field(title="Spec Url")]
|
|
406
|
+
"""
|
|
407
|
+
Link to the MCP specification
|
|
408
|
+
"""
|
|
409
|
+
version: Annotated[str, Field(title="Version")]
|
|
410
|
+
"""
|
|
411
|
+
MCP protocol version this server targets
|
|
412
|
+
"""
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
class ManifestPush(BaseModel):
|
|
416
|
+
manifest_json: Annotated[dict[str, Any], Field(title="Manifest Json")]
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
class ManifestVersionRead(BaseModel):
|
|
420
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
421
|
+
deployed_at: Annotated[AwareDatetime | None, Field(title="Deployed At")] = None
|
|
422
|
+
environment_id: Annotated[UUID, Field(title="Environment Id")]
|
|
423
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
424
|
+
manifest_hash: Annotated[str, Field(title="Manifest Hash")]
|
|
425
|
+
manifest_json: Annotated[dict[str, Any], Field(title="Manifest Json")]
|
|
426
|
+
version: Annotated[int, Field(title="Version")]
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
class MetadataDef(BaseModel):
|
|
430
|
+
model_config = ConfigDict(
|
|
431
|
+
extra="forbid",
|
|
432
|
+
)
|
|
433
|
+
environment: Annotated[str | None, Field(title="Environment")] = None
|
|
434
|
+
local: Annotated[dict[str, Any] | None, Field(title="Local")] = None
|
|
435
|
+
name: Annotated[str, Field(min_length=1, title="Name")]
|
|
436
|
+
projectId: Annotated[str | None, Field(title="Projectid")] = None
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
class MetricsDef(BaseModel):
|
|
440
|
+
"""
|
|
441
|
+
Metrics subsystem — Prometheus scrapes /metrics endpoints.
|
|
442
|
+
"""
|
|
443
|
+
|
|
444
|
+
model_config = ConfigDict(
|
|
445
|
+
extra="forbid",
|
|
446
|
+
)
|
|
447
|
+
enabled: Annotated[bool | None, Field(title="Enabled")] = True
|
|
448
|
+
retentionDays: Annotated[int | None, Field(title="Retentiondays")] = 7
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
class NativeBuildSpec(BaseModel):
|
|
452
|
+
model_config = ConfigDict(
|
|
453
|
+
extra="forbid",
|
|
454
|
+
)
|
|
455
|
+
command: Annotated[str, Field(min_length=1, title="Command")]
|
|
456
|
+
outputBinary: Annotated[str, Field(min_length=1, title="Outputbinary")]
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
class OpsResponse(BaseModel):
|
|
460
|
+
"""
|
|
461
|
+
Response for server operations (restart, exec, switch, update).
|
|
462
|
+
"""
|
|
463
|
+
|
|
464
|
+
output: Annotated[str | None, Field(title="Output")] = ""
|
|
465
|
+
status: Annotated[str, Field(title="Status")]
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
class OrgBrief(BaseModel):
|
|
469
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
470
|
+
name: Annotated[str, Field(title="Name")]
|
|
471
|
+
slug: Annotated[str, Field(title="Slug")]
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
class OrgCreate(BaseModel):
|
|
475
|
+
name: Annotated[str, Field(title="Name")]
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
class OrgRead(BaseModel):
|
|
479
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
480
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
481
|
+
name: Annotated[str, Field(title="Name")]
|
|
482
|
+
slug: Annotated[str, Field(title="Slug")]
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
class ProjectCreate(BaseModel):
|
|
486
|
+
description: Annotated[str | None, Field(title="Description")] = None
|
|
487
|
+
name: Annotated[str, Field(title="Name")]
|
|
488
|
+
project_id: Annotated[str | None, Field(title="Project Id")] = None
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
class ProjectRead(BaseModel):
|
|
492
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
493
|
+
description: Annotated[str | None, Field(title="Description")] = None
|
|
494
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
495
|
+
name: Annotated[str, Field(title="Name")]
|
|
496
|
+
updated_at: Annotated[AwareDatetime, Field(title="Updated At")]
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
class RefreshRequest(BaseModel):
|
|
500
|
+
refresh_token: Annotated[str, Field(title="Refresh Token")]
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
class RegisterRequest(LoginRequest):
|
|
504
|
+
pass
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
class ResetPasswordRequest(BaseModel):
|
|
508
|
+
new_password: Annotated[str, Field(title="New Password")]
|
|
509
|
+
token: Annotated[str, Field(title="Token")]
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
class RestartBody(BaseModel):
|
|
513
|
+
service: Annotated[str | None, Field(title="Service")] = None
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
class Challenge(StrEnum):
|
|
517
|
+
dns_01 = "dns-01"
|
|
518
|
+
http_01 = "http-01"
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
class Provider(StrEnum):
|
|
522
|
+
letsencrypt = "letsencrypt"
|
|
523
|
+
custom = "custom"
|
|
524
|
+
none = "none"
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
class SSLConfig(BaseModel):
|
|
528
|
+
model_config = ConfigDict(
|
|
529
|
+
extra="forbid",
|
|
530
|
+
)
|
|
531
|
+
certPath: Annotated[str | None, Field(title="Certpath")] = None
|
|
532
|
+
challenge: Annotated[Challenge | None, Field(title="Challenge")] = "dns-01"
|
|
533
|
+
dnsProvider: Annotated[str | None, Field(title="Dnsprovider")] = None
|
|
534
|
+
email: Annotated[str | None, Field(title="Email")] = None
|
|
535
|
+
enabled: Annotated[bool | None, Field(title="Enabled")] = True
|
|
536
|
+
keyPath: Annotated[str | None, Field(title="Keypath")] = None
|
|
537
|
+
provider: Annotated[Provider | None, Field(title="Provider")] = "letsencrypt"
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
class ServerCreate(BaseModel):
|
|
541
|
+
flavour: Annotated[str | None, Field(title="Flavour")] = None
|
|
542
|
+
image: Annotated[str | None, Field(title="Image")] = None
|
|
543
|
+
location: Annotated[str | None, Field(title="Location")] = None
|
|
544
|
+
name: Annotated[str, Field(title="Name")]
|
|
545
|
+
provider: Annotated[str | None, Field(title="Provider")] = "hetzner"
|
|
546
|
+
region: Annotated[str | None, Field(title="Region")] = None
|
|
547
|
+
server_type: Annotated[str | None, Field(title="Server Type")] = None
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
class ServerDnsRead(BaseModel):
|
|
551
|
+
provider: Annotated[str, Field(title="Provider")]
|
|
552
|
+
records: Annotated[Any | None, Field(title="Records")] = None
|
|
553
|
+
server_id: Annotated[UUID, Field(title="Server Id")]
|
|
554
|
+
verified: Annotated[bool | None, Field(title="Verified")] = False
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
class ServerImport(BaseModel):
|
|
558
|
+
host: Annotated[str, Field(title="Host")]
|
|
559
|
+
name: Annotated[str, Field(title="Name")]
|
|
560
|
+
user: Annotated[str | None, Field(title="User")] = "root"
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
class ServerServiceRead(BaseModel):
|
|
564
|
+
active_slot: Annotated[str | None, Field(title="Active Slot")] = None
|
|
565
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
566
|
+
image: Annotated[str | None, Field(title="Image")] = None
|
|
567
|
+
server_id: Annotated[UUID, Field(title="Server Id")]
|
|
568
|
+
service_id: Annotated[str, Field(title="Service Id")]
|
|
569
|
+
service_type: Annotated[str, Field(title="Service Type")]
|
|
570
|
+
status: Annotated[str | None, Field(title="Status")] = None
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
class ServerSslRead(BaseModel):
|
|
574
|
+
challenge: Annotated[str | None, Field(title="Challenge")] = None
|
|
575
|
+
domain: Annotated[str | None, Field(title="Domain")] = None
|
|
576
|
+
provider: Annotated[str, Field(title="Provider")]
|
|
577
|
+
provisioned: Annotated[bool | None, Field(title="Provisioned")] = False
|
|
578
|
+
server_id: Annotated[UUID, Field(title="Server Id")]
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
class ServerStatusResponse(BaseModel):
|
|
582
|
+
"""
|
|
583
|
+
Full server status from SSH inspection.
|
|
584
|
+
"""
|
|
585
|
+
|
|
586
|
+
containers: Annotated[
|
|
587
|
+
list[ContainerStatus] | None, Field(title="Containers", validate_default=True)
|
|
588
|
+
] = []
|
|
589
|
+
health: Annotated[dict[str, str] | None, Field(title="Health")] = {}
|
|
590
|
+
server_ip: Annotated[str, Field(title="Server Ip")]
|
|
591
|
+
server_name: Annotated[str, Field(title="Server Name")]
|
|
592
|
+
system: Annotated[str | None, Field(title="System")] = None
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
class ServerUsageDetail(BaseModel):
|
|
596
|
+
cost: Annotated[float | None, Field(title="Cost")] = 0.0
|
|
597
|
+
destroyed_at: Annotated[AwareDatetime | None, Field(title="Destroyed At")] = None
|
|
598
|
+
hours: Annotated[float, Field(title="Hours")]
|
|
599
|
+
provider: Annotated[str, Field(title="Provider")]
|
|
600
|
+
provisioned_at: Annotated[AwareDatetime, Field(title="Provisioned At")]
|
|
601
|
+
server_id: Annotated[str, Field(title="Server Id")]
|
|
602
|
+
server_name: Annotated[str, Field(title="Server Name")]
|
|
603
|
+
server_type: Annotated[str | None, Field(title="Server Type")] = None
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
class LogFormat(StrEnum):
|
|
607
|
+
"""
|
|
608
|
+
Log format this service writes to stdout. 'json' enables structured field extraction in Loki (level, request_id). 'auto' (default when omitted) infers from the image name.
|
|
609
|
+
"""
|
|
610
|
+
|
|
611
|
+
json = "json"
|
|
612
|
+
plain = "plain"
|
|
613
|
+
auto = "auto"
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
class Type(StrEnum):
|
|
617
|
+
compute = "compute"
|
|
618
|
+
persistence = "persistence"
|
|
619
|
+
observability = "observability"
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
class ServiceDef(BaseModel):
|
|
623
|
+
"""
|
|
624
|
+
A single service entry under ``cloud.services[]``.
|
|
625
|
+
|
|
626
|
+
The ``type`` field selects required-field rules:
|
|
627
|
+
|
|
628
|
+
- ``compute`` → requires ``port`` and ``healthPath``
|
|
629
|
+
- ``persistence`` → requires ``port``
|
|
630
|
+
- ``observability``→ image only
|
|
631
|
+
"""
|
|
632
|
+
|
|
633
|
+
model_config = ConfigDict(
|
|
634
|
+
extra="forbid",
|
|
635
|
+
)
|
|
636
|
+
backupPolicy: BackupPolicyDef | None = None
|
|
637
|
+
build: Annotated[dict[str, Any] | None, Field(title="Build")] = None
|
|
638
|
+
command: Annotated[str | None, Field(title="Command")] = None
|
|
639
|
+
dependsOn: Annotated[list[str] | None, Field(title="Dependson")] = None
|
|
640
|
+
environment: Annotated[dict[str, str] | None, Field(title="Environment")] = None
|
|
641
|
+
environments: Annotated[list[str] | None, Field(title="Environments")] = None
|
|
642
|
+
extraPorts: Annotated[list[str] | None, Field(title="Extraports")] = None
|
|
643
|
+
"""
|
|
644
|
+
Additional host:container port mappings passed through verbatim to docker-compose. Useful for services with multiple exposed ports (e.g. MailHog: 1025 SMTP + 8025 web UI).
|
|
645
|
+
"""
|
|
646
|
+
healthPath: Annotated[str | None, Field(title="Healthpath")] = None
|
|
647
|
+
healthcheck: Annotated[dict[str, Any] | None, Field(title="Healthcheck")] = None
|
|
648
|
+
hostPort: Annotated[int | None, Field(title="Hostport")] = None
|
|
649
|
+
id: Annotated[str, Field(min_length=1, title="Id")]
|
|
650
|
+
image: Annotated[str, Field(min_length=1, title="Image")]
|
|
651
|
+
labels: Annotated[dict[str, str] | None, Field(title="Labels")] = None
|
|
652
|
+
lifecycle: LifecycleDef | None = None
|
|
653
|
+
logFormat: Annotated[LogFormat | None, Field(title="Logformat")] = None
|
|
654
|
+
"""
|
|
655
|
+
Log format this service writes to stdout. 'json' enables structured field extraction in Loki (level, request_id). 'auto' (default when omitted) infers from the image name.
|
|
656
|
+
"""
|
|
657
|
+
port: Annotated[int | None, Field(title="Port")] = None
|
|
658
|
+
resources: Annotated[dict[str, Any] | None, Field(title="Resources")] = None
|
|
659
|
+
routePrefix: Annotated[str | None, Field(title="Routeprefix")] = None
|
|
660
|
+
server: Annotated[str | None, Field(title="Server")] = None
|
|
661
|
+
"""
|
|
662
|
+
Server role for multi-server deployments. Services with the same server value are co-located on one VPS. If omitted, all services go to the default (primary) server.
|
|
663
|
+
"""
|
|
664
|
+
type: Annotated[Type, Field(title="Type")]
|
|
665
|
+
volumes: Annotated[list[str] | None, Field(title="Volumes")] = None
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
class SingleContainerSpec(BaseModel):
|
|
669
|
+
model_config = ConfigDict(
|
|
670
|
+
extra="forbid",
|
|
671
|
+
)
|
|
672
|
+
healthPath: Annotated[str, Field(min_length=1, title="Healthpath")]
|
|
673
|
+
image: Annotated[str, Field(min_length=1, title="Image")]
|
|
674
|
+
port: Annotated[int, Field(gt=0, title="Port")]
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
class SnapshotResponse(BaseModel):
|
|
678
|
+
id: Annotated[int, Field(title="Id")]
|
|
679
|
+
received_at: Annotated[str, Field(title="Received At")]
|
|
680
|
+
snapshot: ArchitectureSnapshot
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
class SnapshotSummary(BaseModel):
|
|
684
|
+
id: Annotated[int, Field(title="Id")]
|
|
685
|
+
name: Annotated[str, Field(title="Name")]
|
|
686
|
+
received_at: Annotated[str, Field(title="Received At")]
|
|
687
|
+
system_count: Annotated[int, Field(title="System Count")]
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
class StaticBuild(BaseModel):
|
|
691
|
+
model_config = ConfigDict(
|
|
692
|
+
extra="forbid",
|
|
693
|
+
)
|
|
694
|
+
command: Annotated[str, Field(min_length=1, title="Command")]
|
|
695
|
+
installCommand: Annotated[str | None, Field(title="Installcommand")] = None
|
|
696
|
+
outputDir: Annotated[str, Field(min_length=1, title="Outputdir")]
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
class Router(StrEnum):
|
|
700
|
+
spa = "spa"
|
|
701
|
+
history = "history"
|
|
702
|
+
hash = "hash"
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
class StaticServe(BaseModel):
|
|
706
|
+
model_config = ConfigDict(
|
|
707
|
+
extra="forbid",
|
|
708
|
+
)
|
|
709
|
+
router: Annotated[Router, Field(title="Router")]
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
class StatusResponse(BaseModel):
|
|
713
|
+
"""
|
|
714
|
+
Generic status response for operations that don't return data.
|
|
715
|
+
"""
|
|
716
|
+
|
|
717
|
+
status: Annotated[str, Field(title="Status")]
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
class SwitchBody(BaseModel):
|
|
721
|
+
component: Annotated[str, Field(title="Component")]
|
|
722
|
+
to_color: Annotated[str, Field(title="To Color")]
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
class TokenResponse(BaseModel):
|
|
726
|
+
access_token: Annotated[str, Field(title="Access Token")]
|
|
727
|
+
expires_in: Annotated[int | None, Field(title="Expires In")] = None
|
|
728
|
+
refresh_token: Annotated[str | None, Field(title="Refresh Token")] = None
|
|
729
|
+
token_type: Annotated[str | None, Field(title="Token Type")] = "bearer"
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
class UpdateBody(BaseModel):
|
|
733
|
+
component: Annotated[str, Field(title="Component")]
|
|
734
|
+
new_image: Annotated[str, Field(title="New Image")]
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
class UsageEstimate(BaseModel):
|
|
738
|
+
activeServers: Annotated[int, Field(title="Activeservers")]
|
|
739
|
+
currentMonthCost: Annotated[float | None, Field(title="Currentmonthcost")] = 0.0
|
|
740
|
+
currentMonthHours: Annotated[float, Field(title="Currentmonthhours")]
|
|
741
|
+
org_id: Annotated[str, Field(title="Org Id")]
|
|
742
|
+
projectedMonthCost: Annotated[float | None, Field(title="Projectedmonthcost")] = 0.0
|
|
743
|
+
projectedMonthHours: Annotated[float, Field(title="Projectedmonthhours")]
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
class UsageHistoryItem(BaseModel):
|
|
747
|
+
cost: Annotated[float | None, Field(title="Cost")] = 0.0
|
|
748
|
+
period_end: Annotated[AwareDatetime, Field(title="Period End")]
|
|
749
|
+
period_start: Annotated[AwareDatetime, Field(title="Period Start")]
|
|
750
|
+
serverCount: Annotated[int, Field(title="Servercount")]
|
|
751
|
+
vpsHours: Annotated[float, Field(title="Vpshours")]
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
class UsageSummary(BaseModel):
|
|
755
|
+
activeServerCount: Annotated[int, Field(title="Activeservercount")]
|
|
756
|
+
org_id: Annotated[str, Field(title="Org Id")]
|
|
757
|
+
period_end: Annotated[AwareDatetime, Field(title="Period End")]
|
|
758
|
+
period_start: Annotated[AwareDatetime, Field(title="Period Start")]
|
|
759
|
+
servers: Annotated[
|
|
760
|
+
list[ServerUsageDetail] | None, Field(title="Servers", validate_default=True)
|
|
761
|
+
] = []
|
|
762
|
+
totalCost: Annotated[float | None, Field(title="Totalcost")] = 0.0
|
|
763
|
+
totalVpsHours: Annotated[float, Field(title="Totalvpshours")]
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
class UserRead(BaseModel):
|
|
767
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
768
|
+
email: Annotated[str, Field(title="Email")]
|
|
769
|
+
email_verified: Annotated[bool | None, Field(title="Email Verified")] = False
|
|
770
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
771
|
+
is_active: Annotated[bool, Field(title="Is Active")]
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
class ValidateBody(BaseModel):
|
|
775
|
+
manifest_path: Annotated[str | None, Field(title="Manifest Path")] = None
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
class ValidateResponse(BaseModel):
|
|
779
|
+
"""
|
|
780
|
+
Response for manifest validation.
|
|
781
|
+
"""
|
|
782
|
+
|
|
783
|
+
path: Annotated[str, Field(title="Path")]
|
|
784
|
+
valid: Annotated[bool, Field(title="Valid")]
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
class ValidationError(BaseModel):
|
|
788
|
+
ctx: Annotated[dict[str, Any] | None, Field(title="Context")] = None
|
|
789
|
+
input: Annotated[Any | None, Field(title="Input")] = None
|
|
790
|
+
loc: Annotated[list[str | int], Field(title="Location")]
|
|
791
|
+
msg: Annotated[str, Field(title="Message")]
|
|
792
|
+
type: Annotated[str, Field(title="Error Type")]
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
class VaultGetResponse(BaseModel):
|
|
796
|
+
"""
|
|
797
|
+
Response for vault get operations.
|
|
798
|
+
"""
|
|
799
|
+
|
|
800
|
+
key: Annotated[str, Field(title="Key")]
|
|
801
|
+
value: Annotated[str, Field(title="Value")]
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
class VaultSetRequest(BaseModel):
|
|
805
|
+
environment_id: Annotated[str | None, Field(title="Environment Id")] = None
|
|
806
|
+
key: Annotated[str, Field(title="Key")]
|
|
807
|
+
value: Annotated[str, Field(title="Value")]
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
class VaultSetResponse(BaseModel):
|
|
811
|
+
"""
|
|
812
|
+
Response for vault set operations.
|
|
813
|
+
"""
|
|
814
|
+
|
|
815
|
+
key: Annotated[str, Field(title="Key")]
|
|
816
|
+
status: Annotated[str, Field(title="Status")]
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
class VerifyEmailRequest(BaseModel):
|
|
820
|
+
token: Annotated[str, Field(title="Token")]
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
class WorkspaceRead(BaseModel):
|
|
824
|
+
apiEndpoint: Annotated[str | None, Field(title="Apiendpoint")] = None
|
|
825
|
+
currentEnvironment: Annotated[str | None, Field(title="Currentenvironment")] = None
|
|
826
|
+
currentServer: Annotated[str | None, Field(title="Currentserver")] = None
|
|
827
|
+
hasAccountKey: Annotated[bool | None, Field(title="Hasaccountkey")] = False
|
|
828
|
+
projectKeyCount: Annotated[int | None, Field(title="Projectkeycount")] = 0
|
|
829
|
+
version: Annotated[int, Field(title="Version")]
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
class WorkspaceUpdate(BaseModel):
|
|
833
|
+
current_environment: Annotated[str | None, Field(title="Current Environment")] = (
|
|
834
|
+
None
|
|
835
|
+
)
|
|
836
|
+
current_server: Annotated[str | None, Field(title="Current Server")] = None
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
class CapacityReport(BaseModel):
|
|
840
|
+
limits_per_org: CapacityOrgLimits
|
|
841
|
+
region: Annotated[str, Field(title="Region")]
|
|
842
|
+
servers: CapacityServers
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
class GatewayDef(BaseModel):
|
|
846
|
+
model_config = ConfigDict(
|
|
847
|
+
extra="forbid",
|
|
848
|
+
)
|
|
849
|
+
domains: Annotated[list[GatewayDomain], Field(min_length=1, title="Domains")]
|
|
850
|
+
ssl: SSLConfig | None = None
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
class HTTPValidationError(BaseModel):
|
|
854
|
+
detail: Annotated[list[ValidationError] | None, Field(title="Detail")] = None
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
class HealthRead(BaseModel):
|
|
858
|
+
capacity: CapacityReport | None = None
|
|
859
|
+
instance: Annotated[str, Field(title="Instance")]
|
|
860
|
+
region: Annotated[str, Field(title="Region")]
|
|
861
|
+
region_url: Annotated[str, Field(title="Region Url")]
|
|
862
|
+
status: Annotated[str, Field(title="Status")]
|
|
863
|
+
version: Annotated[str, Field(title="Version")]
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
class LoggingDef(BaseModel):
|
|
867
|
+
"""
|
|
868
|
+
Logging subsystem — Promtail ships container stdout to Loki.
|
|
869
|
+
"""
|
|
870
|
+
|
|
871
|
+
model_config = ConfigDict(
|
|
872
|
+
extra="forbid",
|
|
873
|
+
)
|
|
874
|
+
enabled: Annotated[bool | None, Field(title="Enabled")] = True
|
|
875
|
+
loki: LokiDef | None = None
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
class MeResponse(BaseModel):
|
|
879
|
+
orgs: Annotated[list[OrgBrief], Field(title="Orgs")]
|
|
880
|
+
user: UserRead
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
class NativeBuild(BaseModel):
|
|
884
|
+
model_config = ConfigDict(
|
|
885
|
+
extra="forbid",
|
|
886
|
+
)
|
|
887
|
+
apiVersion: Annotated[Literal["forktex.cloud/v1beta2"], Field(title="Apiversion")]
|
|
888
|
+
build: NativeBuildSpec
|
|
889
|
+
infrastructure: InfrastructureDef | None = None
|
|
890
|
+
kind: Annotated[Literal["NativeBuild"], Field(title="Kind")]
|
|
891
|
+
metadata: MetadataDef
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
class ObservabilityDefInput(BaseModel):
|
|
895
|
+
"""
|
|
896
|
+
Opt-in monitoring stack deployed alongside the application on the VPS.
|
|
897
|
+
|
|
898
|
+
When enabled, Loki + Promtail aggregate container logs (queryable via
|
|
899
|
+
``forktex cloud logs --query``), and Prometheus scrapes metrics from
|
|
900
|
+
services that expose ``/metrics``.
|
|
901
|
+
"""
|
|
902
|
+
|
|
903
|
+
model_config = ConfigDict(
|
|
904
|
+
extra="forbid",
|
|
905
|
+
)
|
|
906
|
+
enabled: Annotated[bool | None, Field(title="Enabled")] = False
|
|
907
|
+
logging: LoggingDef | None = None
|
|
908
|
+
metrics: MetricsDef | None = None
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
class ObservabilityDefOutput(ObservabilityDefInput):
|
|
912
|
+
"""
|
|
913
|
+
Opt-in monitoring stack deployed alongside the application on the VPS.
|
|
914
|
+
|
|
915
|
+
When enabled, Loki + Promtail aggregate container logs (queryable via
|
|
916
|
+
``forktex cloud logs --query``), and Prometheus scrapes metrics from
|
|
917
|
+
services that expose ``/metrics``.
|
|
918
|
+
"""
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
class ProjectDeploymentInput(BaseModel):
|
|
922
|
+
"""
|
|
923
|
+
Multi-service single-server deployment to a single Hetzner VPS.
|
|
924
|
+
"""
|
|
925
|
+
|
|
926
|
+
model_config = ConfigDict(
|
|
927
|
+
extra="forbid",
|
|
928
|
+
)
|
|
929
|
+
apiVersion: Annotated[Literal["forktex.cloud/v1beta2"], Field(title="Apiversion")]
|
|
930
|
+
deployment: DeploymentDef | None = None
|
|
931
|
+
gateway: GatewayDef | None = None
|
|
932
|
+
infrastructure: InfrastructureDef
|
|
933
|
+
kind: Annotated[Literal["ProjectDeployment"], Field(title="Kind")]
|
|
934
|
+
metadata: MetadataDef
|
|
935
|
+
observability: ObservabilityDefInput | None = None
|
|
936
|
+
services: Annotated[list[ServiceDef], Field(min_length=1, title="Services")]
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
class ProjectDeploymentOutput(BaseModel):
|
|
940
|
+
"""
|
|
941
|
+
Multi-service single-server deployment to a single Hetzner VPS.
|
|
942
|
+
"""
|
|
943
|
+
|
|
944
|
+
model_config = ConfigDict(
|
|
945
|
+
extra="forbid",
|
|
946
|
+
)
|
|
947
|
+
apiVersion: Annotated[Literal["forktex.cloud/v1beta2"], Field(title="Apiversion")]
|
|
948
|
+
deployment: DeploymentDef | None = None
|
|
949
|
+
gateway: GatewayDef | None = None
|
|
950
|
+
infrastructure: InfrastructureDef
|
|
951
|
+
kind: Annotated[Literal["ProjectDeployment"], Field(title="Kind")]
|
|
952
|
+
metadata: MetadataDef
|
|
953
|
+
observability: ObservabilityDefOutput | None = None
|
|
954
|
+
services: Annotated[list[ServiceDef], Field(min_length=1, title="Services")]
|
|
955
|
+
|
|
956
|
+
|
|
957
|
+
class ServerRead(BaseModel):
|
|
958
|
+
created_at: Annotated[AwareDatetime, Field(title="Created At")]
|
|
959
|
+
dns: ServerDnsRead | None = None
|
|
960
|
+
id: Annotated[UUID, Field(title="Id")]
|
|
961
|
+
image: Annotated[str | None, Field(title="Image")] = None
|
|
962
|
+
ipv4: Annotated[str | None, Field(title="Ipv4")] = None
|
|
963
|
+
location: Annotated[str | None, Field(title="Location")] = None
|
|
964
|
+
name: Annotated[str, Field(title="Name")]
|
|
965
|
+
provider: Annotated[str, Field(title="Provider")]
|
|
966
|
+
provider_id: Annotated[str | None, Field(title="Provider Id")] = None
|
|
967
|
+
server_type: Annotated[str | None, Field(title="Server Type")] = None
|
|
968
|
+
services: Annotated[list[ServerServiceRead] | None, Field(title="Services")] = None
|
|
969
|
+
ssh_key_id: Annotated[str | None, Field(title="Ssh Key Id")] = None
|
|
970
|
+
ssl: ServerSslRead | None = None
|
|
971
|
+
status: Annotated[str, Field(title="Status")]
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
class SingleContainerInput(BaseModel):
|
|
975
|
+
model_config = ConfigDict(
|
|
976
|
+
extra="forbid",
|
|
977
|
+
)
|
|
978
|
+
apiVersion: Annotated[Literal["forktex.cloud/v1beta2"], Field(title="Apiversion")]
|
|
979
|
+
container: SingleContainerSpec
|
|
980
|
+
gateway: GatewayDef | None = None
|
|
981
|
+
infrastructure: InfrastructureDef | None = None
|
|
982
|
+
kind: Annotated[Literal["SingleContainer"], Field(title="Kind")]
|
|
983
|
+
metadata: MetadataDef
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
class SingleContainerOutput(SingleContainerInput):
|
|
987
|
+
pass
|
|
988
|
+
|
|
989
|
+
|
|
990
|
+
class StaticSiteInput(BaseModel):
|
|
991
|
+
model_config = ConfigDict(
|
|
992
|
+
extra="forbid",
|
|
993
|
+
)
|
|
994
|
+
apiVersion: Annotated[Literal["forktex.cloud/v1beta2"], Field(title="Apiversion")]
|
|
995
|
+
build: StaticBuild
|
|
996
|
+
gateway: GatewayDef | None = None
|
|
997
|
+
kind: Annotated[Literal["StaticSite"], Field(title="Kind")]
|
|
998
|
+
metadata: MetadataDef
|
|
999
|
+
serve: StaticServe
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
class StaticSiteOutput(StaticSiteInput):
|
|
1003
|
+
pass
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
class UpRequest(BaseModel):
|
|
1007
|
+
assets_tarball_b64: Annotated[str | None, Field(title="Assets Tarball B64")] = None
|
|
1008
|
+
env: Annotated[str | None, Field(title="Env")] = None
|
|
1009
|
+
flavour: Annotated[str | None, Field(title="Flavour")] = None
|
|
1010
|
+
manifest_data: Annotated[
|
|
1011
|
+
ProjectDeploymentInput
|
|
1012
|
+
| StaticSiteInput
|
|
1013
|
+
| SingleContainerInput
|
|
1014
|
+
| NativeBuild
|
|
1015
|
+
| None,
|
|
1016
|
+
Field(title="Manifest Data"),
|
|
1017
|
+
] = None
|
|
1018
|
+
name: Annotated[str | None, Field(title="Name")] = None
|
|
1019
|
+
region: Annotated[str | None, Field(title="Region")] = None
|
|
1020
|
+
skip_dns: Annotated[bool | None, Field(title="Skip Dns")] = False
|
|
1021
|
+
skip_ssl: Annotated[bool | None, Field(title="Skip Ssl")] = False
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
class UsageResponse(BaseModel):
|
|
1025
|
+
current: UsageSummary
|
|
1026
|
+
history: Annotated[
|
|
1027
|
+
list[UsageHistoryItem] | None, Field(title="History", validate_default=True)
|
|
1028
|
+
] = []
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
class DeployRequest(BaseModel):
|
|
1032
|
+
assets_tarball_b64: Annotated[str | None, Field(title="Assets Tarball B64")] = None
|
|
1033
|
+
environment_id: Annotated[str | None, Field(title="Environment Id")] = None
|
|
1034
|
+
manifest_data: Annotated[
|
|
1035
|
+
ProjectDeploymentInput
|
|
1036
|
+
| StaticSiteInput
|
|
1037
|
+
| SingleContainerInput
|
|
1038
|
+
| NativeBuild
|
|
1039
|
+
| None,
|
|
1040
|
+
Field(title="Manifest Data"),
|
|
1041
|
+
] = None
|
|
1042
|
+
server_id: Annotated[str, Field(title="Server Id")]
|
|
1043
|
+
service: Annotated[str | None, Field(title="Service")] = None
|
|
1044
|
+
tags: Annotated[list[str] | None, Field(title="Tags")] = None
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
class DownRequest(BaseModel):
|
|
1048
|
+
keep_dns: Annotated[bool | None, Field(title="Keep Dns")] = False
|
|
1049
|
+
manifest_data: Annotated[
|
|
1050
|
+
ProjectDeploymentInput
|
|
1051
|
+
| StaticSiteInput
|
|
1052
|
+
| SingleContainerInput
|
|
1053
|
+
| NativeBuild
|
|
1054
|
+
| None,
|
|
1055
|
+
Field(title="Manifest Data"),
|
|
1056
|
+
] = None
|
|
1057
|
+
name: Annotated[str | None, Field(title="Name")] = None
|