Files
MikrotikManager/packages/contracts/src/containers.ts
T

40 lines
2.8 KiB
TypeScript

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>
export const containerMutationAckSchema = z.object({ ok: z.literal(true) })