From 39d75031ba3a536e2e37f2a93a40e974b25c6fbf Mon Sep 17 00:00:00 2001 From: JOLIMAITRE Matthieu Date: Sat, 13 Jan 2024 18:31:39 +0100 Subject: [PATCH] add docker support and udp proto in redirs --- instance/control.ts | 4 ++-- instance/local/.gitignore | 1 + instance/src/lib.ts | 1 + instance/src/lib/config.ts | 30 +++++++++++++++++++++++++----- instance/src/lib/nspawn.ts | 8 ++++++-- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/instance/control.ts b/instance/control.ts index 0bdd825..0942da3 100755 --- a/instance/control.ts +++ b/instance/control.ts @@ -1,7 +1,7 @@ #!/bin/env -S deno run -A --unstable import { daemon_send, new_cmd_disable, new_cmd_enable, new_cmd_status, new_cmd_stop } from "./src/lib.ts"; -import { load_all_configs, new_container_config, save_container_config } from "./src/lib/config.ts"; +import { load_all_container_configs, new_container_config, save_container_config } from "./src/lib/config.ts"; import { load_base, new_container_context } from "./src/lib/create.ts"; import { container_paths, socket_path } from "./src/lib/paths.ts"; import { log_from, run } from "./src/lib/utils.ts"; @@ -78,7 +78,7 @@ Commands: export async function create(name: string, base_name: string) { log("loading base", base_name); const base = await load_base(base_name); - const known_containers = await load_all_configs(); + const known_containers = await load_all_container_configs(); const paths = container_paths(name); await Deno.mkdir(paths.base); diff --git a/instance/local/.gitignore b/instance/local/.gitignore index 33f9f5e..5375a10 100644 --- a/instance/local/.gitignore +++ b/instance/local/.gitignore @@ -1,2 +1,3 @@ /containers/* +/config.json /state.json diff --git a/instance/src/lib.ts b/instance/src/lib.ts index be1c432..c63c2e3 100644 --- a/instance/src/lib.ts +++ b/instance/src/lib.ts @@ -78,6 +78,7 @@ export function start_runner(config: ContainerConfig) { stdin: "null", stdout: "null", }, + syscall_filter: ["add_key", "keyctl", "bpf"], }); const container_loop = loop_process(command, { on_start: () => log("container", name, "started"), diff --git a/instance/src/lib/config.ts b/instance/src/lib/config.ts index 4d411ff..166b584 100644 --- a/instance/src/lib/config.ts +++ b/instance/src/lib/config.ts @@ -1,10 +1,10 @@ -import { container_paths, containers_path } from "./paths.ts"; +import { container_paths, containers_path, state_config_path } from "./paths.ts"; import { exists, log_from } from "./utils.ts"; +import { z } from "https://deno.land/x/zod@v3.22.4/mod.ts"; const log = log_from("config"); -export type ContainerConfig = ReturnType; -export function new_container_config(name: string) { +export function new_container_config(name: string): ContainerConfig { return { name, version: 0, @@ -12,12 +12,32 @@ export function new_container_config(name: string) { }; } +export type ContainerConfig = ReturnType; +export function parse_container_config(json: string) { + return z.object({ + name: z.string(), + version: z.number(), + redirects: z.array( + z + .tuple([ + z.number(), + z.number(), + ]) + .or(z.tuple([ + z.number(), + z.number(), + z.literal("tcp").or(z.literal("udp")), + ])), + ), + }).parse(JSON.parse(json)); +} + export async function load_container_config(name: string) { const config_path = container_paths(name).configuration; log("loading config for", name); if (!exists(config_path)) return null; const content = await Deno.readTextFile(config_path); - const read = JSON.parse(content); + const read = parse_container_config(content); const default_ = new_container_config(name); if (read.version < default_.version) throw new Error("read conf version is outdated"); return { ...default_, ...read } as ContainerConfig; @@ -30,7 +50,7 @@ export async function save_container_config(config: ContainerConfig) { await Deno.writeTextFile(config_path, serialized); } -export async function load_all_configs() { +export async function load_all_container_configs() { const names = Array.from(Deno.readDirSync(containers_path())) .filter((e) => e.isDirectory) .map((e) => e.name); diff --git a/instance/src/lib/nspawn.ts b/instance/src/lib/nspawn.ts index eb7527f..491f486 100644 --- a/instance/src/lib/nspawn.ts +++ b/instance/src/lib/nspawn.ts @@ -7,8 +7,9 @@ const log = log_from("nspawn"); export function container_command(name: string, directory: string, opts?: { veth?: boolean; boot?: boolean; - ports?: [number, number][]; + ports?: ([number, number] | [number, number, "tcp" | "udp"])[]; cmd_opts?: Deno.CommandOptions; + syscall_filter?: string[]; }) { const args = [ `--machine=${name}`, @@ -16,7 +17,10 @@ export function container_command(name: string, directory: string, opts?: { ]; if (opts?.veth ?? false) args.push("--network-veth"); if (opts?.boot ?? false) args.push("--boot"); - for (const [from, to] of opts?.ports ?? []) args.push(`--port=${from}:${to}`); + for (const [from, to, proto] of opts?.ports ?? []) { + args.push(proto === undefined ? `--port=${from}:${to}` : `--port=${proto}:${from}:${to}`); + } + for (const call of opts?.syscall_filter ?? []) args.push(`--system-call-filter=${call}`); const command = new Deno.Command("systemd-nspawn", { ...opts?.cmd_opts, args }); return command; }