fix(api): показать частичные отказы каталога контейнеров

This commit is contained in:
Denozordec committed 2026-10-01 10:39:37 +07:00
1 parent 1e0fc4cd2d
commit 644ddb64b3
10 files changed
+191 -5

No files matched your search

+4
View File
@@ -57,6 +57,10 @@
"./statistics": {
"types": "./dist/statistics.d.ts",
"default": "./dist/statistics.js"
},
"./containers": {
"types": "./dist/containers.d.ts",
"default": "./dist/containers.js"
}
},
"dependencies": {
+37
View File
@@ -0,0 +1,37 @@
import { z } from "zod"
const serverId = z.number().int().positive().safe()
const time = z.string().datetime({ offset: true })
export const containerStateRowSchema = z.object({
id: z.string().min(1), rosId: z.string().min(1), name: z.string().min(1),
serverId: z.string().regex(/^[1-9]\d*$/),
image: z.string(), tag: z.string(), status: z.enum(["running", "stopped", "error", "unknown"]),
envs: z.array(z.object({ key: z.string().min(1), value: z.string() })),
mounts: z.array(z.object({ dst: z.string().min(1), src: z.string().optional() })),
interfaces: z.array(z.string().min(1)), cmd: z.string().optional(),
startOnBoot: z.boolean().nullable(), comment: z.string(), uptime: z.string().optional(),
cpu: z.number().finite().min(0).max(100).optional(), memMb: z.number().finite().nonnegative().optional(),
})
export const containerServerStateSchema = z.object({
serverId, collectedAt: time, availability: z.enum(["available", "unsupported", "error"]),
containers: z.array(containerStateRowSchema),
failures: z.array(z.object({ resource: z.enum(["containers", "envs", "mounts"]), error: z.string().min(1) })),
}).superRefine((value, ctx) => {
const ids = new Set<string>()
for (const row of value.containers) {
if (row.serverId !== String(value.serverId) || row.id !== value.serverId + "-" + row.rosId || ids.has(row.rosId)) ctx.addIssue({ code: "custom", message: "Контейнеры не соответствуют устройству или содержат дубли" })
ids.add(row.rosId)
}
const resources = value.failures.map(f => f.resource)
if (new Set(resources).size !== resources.length) ctx.addIssue({ code: "custom", message: "Дубли ошибок ресурсов" })
if (value.availability !== "available" && value.containers.length) ctx.addIssue({ code: "custom", message: "Неуспешная загрузка содержит контейнеры" })
if (value.availability === "error" && !resources.includes("containers") || value.availability === "available" && resources.includes("containers") || value.availability === "unsupported" && resources.length) ctx.addIssue({ code: "custom", message: "Состояние не соответствует ошибкам" })
})
export const containersStateSchema = z.object({
collectedAt: time, servers: z.array(containerServerStateSchema),
}).superRefine((value, ctx) => {
if (new Set(value.servers.map(s => s.serverId)).size !== value.servers.length) ctx.addIssue({ code: "custom", message: "Дубли устройств" })
})
export type ContainerStateRow = z.infer<typeof containerStateRowSchema>
export type ContainerServerState = z.infer<typeof containerServerStateSchema>
export type ContainersState = z.infer<typeof containersStateSchema>