fix(ui): показывать достоверный снимок контейнера
This commit is contained in:
1 parent
c419a46955
commit
3ceb8c038c
14 files changed
+117
-141
No files matched your search
@@ -4,7 +4,7 @@ import { MikrotikError } from "./mikrotik.js"
|
||||
import { containersStateSchema } from "@mmapp/contracts/containers"
|
||||
|
||||
const server = { id: 1, name: "Router" } as Parameters<typeof readContainerServerState>[0]
|
||||
const row = { ".id": "*A", name: "nginx", "remote-image": "nginx:alpine", interface: "veth1", envlist: "e", mounts: "m", status: "running", "start-on-boot": "yes", cpu: "0", "memory-high": "0" }
|
||||
const row = { ".id": "*A", name: "nginx", "remote-image": "nginx:alpine", interface: "veth1", envlist: "e", mounts: "m", status: "running", "start-on-boot": "yes", cpu: "0", "memory-current": "0", "memory-high": "52428800" }
|
||||
const read = async (path: string): Promise<unknown> => path === "/container" ? [row] : path === "/container/envs" ? [{name:"e",key:"A",value:"B"}] : [{name:"m",src:"/disk",dst:"/data"}]
|
||||
const good = await readContainerServerState(server, read)
|
||||
assert.equal(good.availability, "available"); assert.equal(good.containers[0].status,"running")
|
||||
@@ -32,3 +32,6 @@ for (const value of [
|
||||
{...aggregate,servers:[{...unsupported,failures:[{resource:"envs",error:"x"}]}]},
|
||||
]) assert.equal(containersStateSchema.safeParse(value).success,false)
|
||||
console.log("Containers state: independent devices, malformed/duplicate IDs, unknown status/boot, known empty, missing package, partial dependencies, zeros and envelope validation; no DB/RouterOS")
|
||||
|
||||
const limitOnly=await readContainerServerState(server,async path=>path==="/container"?[{".id":"*C","memory-high":"52428800"}]:[]);assert.equal(limitOnly.containers[0].memMb,undefined)
|
||||
const modern=await readContainerServerState(server,async path=>path==="/container"?[{...row,envlist:"e,e2",mounts:undefined,mountlists:"m"}]:path==="/container/envs"?[{list:"e",key:"A",value:"1"},{list:"e2",key:"B",value:"2"}]:[{list:"m",src:"/disk",dst:"/data"}]);assert.equal(modern.containers[0].envs.length,2);assert.equal(modern.containers[0].mounts.length,1)
|
||||
@@ -7,14 +7,14 @@ type ServerRow = Parameters<typeof mapContainerRow>[0]
|
||||
type Reader = (path: string) => Promise<unknown>
|
||||
const rawSchema = z.array(z.object({
|
||||
".id": z.string().min(1), name: z.string().optional(), tag: z.string().optional(), "remote-image": z.string().optional(),
|
||||
interface: z.string().optional(), envlist: z.string().optional(), mounts: z.string().optional(),
|
||||
interface: z.string().optional(), envlist: z.string().optional(), mounts: z.string().optional(), mountlists: z.string().optional(),
|
||||
cmd: z.string().optional(), "start-on-boot": z.string().optional(), comment: z.string().optional(),
|
||||
status: z.string().optional(), "memory-high": z.string().optional(), cpu: z.string().optional(),
|
||||
status: z.string().optional(), "memory-high": z.string().optional(), "memory-current": z.string().optional(), cpu: z.string().optional(),
|
||||
})).superRefine((rows, ctx) => {
|
||||
if (new Set(rows.map(r => r[".id"])).size !== rows.length) ctx.addIssue({ code: "custom", message: "Дубли RouterOS ID" })
|
||||
})
|
||||
const envSchema = z.array(z.object({ name: z.string().optional(), key: z.string().optional(), value: z.string().optional() }))
|
||||
const mountSchema = z.array(z.object({ name: z.string().optional(), src: z.string().optional(), dst: z.string().optional() }))
|
||||
const envSchema = z.array(z.object({ name: z.string().optional(), list: z.string().optional(), key: z.string().min(1), value: z.string() }).refine(row => !!(row.list || row.name), "Отсутствует список env"))
|
||||
const mountSchema = z.array(z.object({ name: z.string().optional(), list: z.string().optional(), src: z.string().optional(), dst: z.string().min(1) }).refine(row => !!(row.list || row.name), "Отсутствует список mounts"))
|
||||
const errorMessage = (error: unknown) => error instanceof z.ZodError ? "Некорректный ответ RouterOS" : (error instanceof Error ? error.message.slice(0, 500) : "Ошибка RouterOS")
|
||||
function missingPackage(error: unknown) {
|
||||
return error instanceof MikrotikError && (error.statusCode === 404 || /no such command|unknown command/i.test(error.body))
|
||||
@@ -36,10 +36,14 @@ export async function readContainerServerState(server: ServerRow, read: Reader):
|
||||
if (envs.status === "rejected") failures.push({ resource: "envs", error: errorMessage(envs.reason) })
|
||||
if (mounts.status === "rejected") failures.push({ resource: "mounts", error: errorMessage(mounts.reason) })
|
||||
const containers = raw.map((row, index) => {
|
||||
const mapped = mapContainerRow(server, row, envs.status === "fulfilled" ? envs.value : [], mounts.status === "fulfilled" ? mounts.value : [], index)
|
||||
const envRows = envs.status === "fulfilled" ? envs.value : []
|
||||
const mountRows = mounts.status === "fulfilled" ? mounts.value : []
|
||||
const mapped = mapContainerRow(server, { ...row, mounts: row.mountlists ?? row.mounts }, envRows.map(item => ({ ...item, name: item.list ?? item.name })), mountRows.map(item => ({ ...item, name: item.list ?? item.name })), index)
|
||||
const envLists = new Set((row.envlist ?? "").split(",").map(name => name.trim()).filter(Boolean))
|
||||
mapped.envs = envRows.filter(item => envLists.has(item.list ?? item.name ?? "")).map(item => ({ key: item.key, value: item.value }))
|
||||
const status = (row.status ?? "").toLowerCase()
|
||||
const boot = row["start-on-boot"]
|
||||
const mem = Number.parseInt(row["memory-high"] ?? "", 10)
|
||||
const mem = Number(row["memory-current"]?.trim() || NaN)
|
||||
return { ...mapped, image: row["remote-image"] ? mapped.image : "", tag: row["remote-image"] ? mapped.tag : "",
|
||||
status: status === "running" || status === "stopped" ? status : status === "error" || status === "failed" ? "error" : "unknown",
|
||||
startOnBoot: boot === "true" || boot === "yes" ? true : boot === "false" || boot === "no" ? false : null,
|
||||
|
||||
Reference in new issue
Block a user