feat: move code queue to d601
This commit is contained in:
+69
-9
@@ -19,7 +19,7 @@ export interface ContainerStatus {
|
||||
ports: string;
|
||||
}
|
||||
|
||||
const rebuildableServices = ["backend-core", "frontend", "provider-gateway", "todo-note", "code-queue", "project-manager", "baidu-netdisk", "oa-event-flow"] as const;
|
||||
const rebuildableServices = ["backend-core", "frontend", "provider-gateway", "todo-note", "project-manager", "baidu-netdisk", "oa-event-flow"] as const;
|
||||
export type RebuildableService = typeof rebuildableServices[number];
|
||||
|
||||
export function isRebuildableService(value: string | undefined): value is RebuildableService {
|
||||
@@ -60,7 +60,7 @@ export function writeComposeEnv(config: UniDeskConfig, freshLogPrefix: boolean):
|
||||
const previousValue = (key: string): string => previousRaw.match(new RegExp(`^${key}=(.*)$`, "m"))?.[1]?.replace(/^"|"$/g, "") ?? "";
|
||||
const runtimeSecret = (key: string): string => process.env[key] ?? previousValue(key);
|
||||
const runtimeSecretWithDefault = (key: string, defaultValue: string, legacyDefault = ""): string => {
|
||||
if (process.env[key] !== undefined) return process.env[key] ?? defaultValue;
|
||||
if (process.env[key] !== undefined) return process.env[key] || defaultValue;
|
||||
const previous = previousValue(key);
|
||||
if (previous.length > 0 && previous !== legacyDefault) return previous;
|
||||
return defaultValue;
|
||||
@@ -86,11 +86,13 @@ export function writeComposeEnv(config: UniDeskConfig, freshLogPrefix: boolean):
|
||||
chmodSync(join(logRoot, logDay), 0o777);
|
||||
const labels = JSON.stringify(config.providerGateway.labels);
|
||||
const microservices = JSON.stringify(config.microservices);
|
||||
const restrictedHostBind = config.network.restrictedHostAccess?.bindHost || "127.0.0.1";
|
||||
const lines = {
|
||||
UNIDESK_PUBLIC_HOST: config.network.publicHost,
|
||||
UNIDESK_CORE_PORT: String(config.network.core.port),
|
||||
UNIDESK_FRONTEND_PORT: String(config.network.frontend.port),
|
||||
UNIDESK_DATABASE_PORT: String(config.network.database.port),
|
||||
UNIDESK_DATABASE_BIND_HOST: runtimeSecretWithDefault("UNIDESK_DATABASE_BIND_HOST", restrictedHostBind, "127.0.0.1"),
|
||||
UNIDESK_PROVIDER_INGRESS_PORT: String(config.network.providerIngress.port),
|
||||
UNIDESK_DATABASE_USER: config.database.user,
|
||||
UNIDESK_DATABASE_PASSWORD: config.database.password,
|
||||
@@ -147,6 +149,8 @@ export function writeComposeEnv(config: UniDeskConfig, freshLogPrefix: boolean):
|
||||
UNIDESK_CODE_QUEUE_DEV_CONTAINER_IMAGE: runtimeSecret("UNIDESK_CODE_QUEUE_DEV_CONTAINER_IMAGE"),
|
||||
UNIDESK_CODE_QUEUE_DEV_CONTAINER_WORKDIR: runtimeSecret("UNIDESK_CODE_QUEUE_DEV_CONTAINER_WORKDIR") || "/home/ubuntu",
|
||||
UNIDESK_OA_EVENT_FLOW_BASE_URL: runtimeSecret("UNIDESK_OA_EVENT_FLOW_BASE_URL") || "http://oa-event-flow:4255",
|
||||
UNIDESK_OA_EVENT_FLOW_PORT: runtimeSecret("UNIDESK_OA_EVENT_FLOW_PORT") || "4255",
|
||||
UNIDESK_OA_EVENT_FLOW_BIND_HOST: runtimeSecretWithDefault("UNIDESK_OA_EVENT_FLOW_BIND_HOST", restrictedHostBind, "127.0.0.1"),
|
||||
UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED: runtimeSecret("UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED") || "true",
|
||||
UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_BASE_URL: runtimeSecret("UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_BASE_URL") || "http://backend-core:8080/api/microservices/claudeqq/proxy",
|
||||
UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_TARGET_TYPE: runtimeSecret("UNIDESK_CODE_QUEUE_NOTIFY_CLAUDEQQ_TARGET_TYPE") || "private",
|
||||
@@ -182,7 +186,12 @@ export function startStack(config: UniDeskConfig): unknown {
|
||||
throw new Error(`Fixed UniDesk port is occupied before start: ${occupiedPorts.map((p) => `${p.name}:${p.port}`).join(", ")}`);
|
||||
}
|
||||
const upCommand = [...compose, "up", "-d", "--build", "--remove-orphans"];
|
||||
const command = ["bash", "-lc", composeLockedScript(`set -euo pipefail; ${shellJoin(upCommand)}`)];
|
||||
const script = [
|
||||
"set -euo pipefail",
|
||||
restrictedHostAccessScript(config),
|
||||
shellJoin(upCommand),
|
||||
].filter((line) => line.length > 0).join("\n");
|
||||
const command = ["bash", "-lc", composeLockedScript(script)];
|
||||
const job = startJob("server_start", command, "Build and start UniDesk services without tearing down running queue containers");
|
||||
return { job, runtimeEnv, command, ports: fixedPorts(config) };
|
||||
}
|
||||
@@ -246,14 +255,14 @@ export function rebuildService(config: UniDeskConfig, service: RebuildableServic
|
||||
const script = [
|
||||
"set -euo pipefail",
|
||||
`echo ${shellJoin(["rebuild_service", service, "build_first_then_force_recreate_with_validation"])}`,
|
||||
restrictedHostAccessScript(config),
|
||||
shellJoin(buildCommand),
|
||||
`nohup bash -lc ${shellQuote(watchdogScript)} >/dev/null 2>&1 &`,
|
||||
shellJoin(upCommand),
|
||||
validateScript,
|
||||
].join("\n");
|
||||
const command = ["bash", "-lc", composeLockedScript(script)];
|
||||
const jobRunner = service === "code-queue" ? { runner: "docker" as const, dockerImage: "unidesk-code-queue:latest" } : {};
|
||||
const job = startJob("server_rebuild", command, `Rebuild and validate UniDesk ${service} with serialized Docker Compose mutation`, jobRunner);
|
||||
const job = startJob("server_rebuild", command, `Rebuild and validate UniDesk ${service} with serialized Docker Compose mutation`);
|
||||
return {
|
||||
job,
|
||||
runtimeEnv,
|
||||
@@ -268,7 +277,7 @@ export function rebuildService(config: UniDeskConfig, service: RebuildableServic
|
||||
noDeps: true,
|
||||
forceRecreate: true,
|
||||
composeMutationLock: rootPath(".state", "locks", "server-compose.lock"),
|
||||
jobRunner: service === "code-queue" ? "docker" : "local",
|
||||
jobRunner: "local",
|
||||
postUpValidation: true,
|
||||
namedVolumesPreserved: true,
|
||||
},
|
||||
@@ -282,6 +291,36 @@ function fixedPorts(config: UniDeskConfig): Array<{ name: string; port: number;
|
||||
];
|
||||
}
|
||||
|
||||
function restrictedHostAccessScript(config: UniDeskConfig): string {
|
||||
const access = config.network.restrictedHostAccess;
|
||||
if (access === undefined || access.bindHost === "127.0.0.1") return "";
|
||||
const ports = [
|
||||
{ name: "database", containerPort: config.network.database.containerPort },
|
||||
{ name: "oa-event-flow", containerPort: 4255 },
|
||||
];
|
||||
return [
|
||||
"iptables -N DOCKER-USER 2>/dev/null || true",
|
||||
...ports.flatMap((port) => [
|
||||
...access.allowedSourceCidrs.map((source) => [
|
||||
`iptables -C DOCKER-USER -s ${shellQuote(source)} -p tcp --dport ${port.containerPort} -j ACCEPT 2>/dev/null`,
|
||||
` || iptables -I DOCKER-USER 1 -s ${shellQuote(source)} -p tcp --dport ${port.containerPort} -j ACCEPT`,
|
||||
].join(" \\\n")),
|
||||
[
|
||||
`iptables -C DOCKER-USER -p tcp --dport ${port.containerPort} -j DROP 2>/dev/null`,
|
||||
" || {",
|
||||
" return_line=$(iptables -L DOCKER-USER --line-numbers | awk '$2==\"RETURN\" {print $1; exit}')",
|
||||
" if [ -n \"$return_line\" ]; then",
|
||||
` iptables -I DOCKER-USER "$return_line" -p tcp --dport ${port.containerPort} -j DROP`,
|
||||
" else",
|
||||
` iptables -A DOCKER-USER -p tcp --dport ${port.containerPort} -j DROP`,
|
||||
" fi",
|
||||
" }",
|
||||
].join("\n"),
|
||||
`echo ${shellJoin(["restricted_host_access", port.name, String(port.containerPort), access.allowedSourceCidrs.join(",")])}`,
|
||||
]),
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function shellJoin(args: string[]): string {
|
||||
return args.map(shellQuote).join(" ");
|
||||
}
|
||||
@@ -366,6 +405,11 @@ function dockerExec(config: UniDeskConfig, container: string, command: string[])
|
||||
|
||||
export async function stackStatus(config: UniDeskConfig): Promise<unknown> {
|
||||
const runtimeEnv = writeComposeEnv(config, false);
|
||||
const runtimeRaw = existsSync(runtimeEnv.envFile) ? readFileSync(runtimeEnv.envFile, "utf8") : "";
|
||||
const runtimeValue = (key: string): string => runtimeRaw.match(new RegExp(`^${key}=(.*)$`, "m"))?.[1]?.replace(/^"|"$/g, "") ?? "";
|
||||
const databaseBindHost = runtimeValue("UNIDESK_DATABASE_BIND_HOST") || "127.0.0.1";
|
||||
const oaEventFlowBindHost = runtimeValue("UNIDESK_OA_EVENT_FLOW_BIND_HOST") || "127.0.0.1";
|
||||
const oaEventFlowPort = Number(runtimeValue("UNIDESK_OA_EVENT_FLOW_PORT") || "4255");
|
||||
const coreHealth = dockerExecJson("unidesk-backend-core", "fetch('http://127.0.0.1:8080/health').then(r=>r.json()).then(j=>console.log(JSON.stringify({ok:true,status:200,body:j}))).catch(e=>{console.log(JSON.stringify({ok:false,error:String(e)}));process.exit(1)})");
|
||||
const overview = dockerExecJson("unidesk-backend-core", "fetch('http://127.0.0.1:8080/api/overview').then(r=>r.json()).then(j=>console.log(JSON.stringify({ok:true,status:200,body:j}))).catch(e=>{console.log(JSON.stringify({ok:false,error:String(e)}));process.exit(1)})");
|
||||
return {
|
||||
@@ -373,12 +417,28 @@ export async function stackStatus(config: UniDeskConfig): Promise<unknown> {
|
||||
publicPorts: fixedPorts(config),
|
||||
blockedPublicPorts: [
|
||||
{ name: "backend-core-rest", port: config.network.core.port, listening: isPortListening(config.network.core.port), expected: "not-listening" },
|
||||
{ name: "database", port: config.network.database.port, listening: isPortListening(config.network.database.port), expected: "not-listening" },
|
||||
],
|
||||
restrictedHostPorts: [
|
||||
{
|
||||
name: "database",
|
||||
bindHost: databaseBindHost,
|
||||
hostPort: config.network.database.port,
|
||||
containerPort: config.network.database.containerPort,
|
||||
listening: isPortListening(config.network.database.port),
|
||||
expected: databaseBindHost === "127.0.0.1" ? "local-only" : "restricted-to-code-queue-provider",
|
||||
},
|
||||
{
|
||||
name: "oa-event-flow",
|
||||
bindHost: oaEventFlowBindHost,
|
||||
hostPort: oaEventFlowPort,
|
||||
containerPort: 4255,
|
||||
listening: isPortListening(oaEventFlowPort),
|
||||
expected: oaEventFlowBindHost === "127.0.0.1" ? "local-only" : "restricted-to-code-queue-provider",
|
||||
},
|
||||
],
|
||||
internalPorts: [
|
||||
{ name: "backend-core", containerPort: config.network.core.containerPort, hostPort: null },
|
||||
{ name: "database", containerPort: config.network.database.containerPort, hostPort: null },
|
||||
{ name: "code-queue", containerPort: 4222, hostPort: null },
|
||||
{ name: "project-manager", containerPort: 4233, hostPort: null },
|
||||
{ name: "baidu-netdisk", containerPort: 4244, hostPort: null },
|
||||
{ name: "oa-event-flow", containerPort: 4255, hostPort: null },
|
||||
@@ -419,7 +479,7 @@ export function stackLogs(config: UniDeskConfig, tailBytes: number): unknown {
|
||||
const currentFiles = allFiles.filter((path) => basename(path).startsWith(runtimeEnv.logPrefix));
|
||||
const selectedFiles = (currentFiles.length > 0 ? currentFiles : allFiles.slice(-12)).slice(-12);
|
||||
const files = selectedFiles.map((path) => ({ path, name: basename(path), tail: tailFile(path, tailBytes) }));
|
||||
const containerNames = ["unidesk-database", "unidesk-backend-core", "unidesk-frontend", "unidesk-provider-gateway-main", "todo-note-backend", "code-queue-backend", "project-manager-backend", "baidu-netdisk-backend", "oa-event-flow-backend"];
|
||||
const containerNames = ["unidesk-database", "unidesk-backend-core", "unidesk-frontend", "unidesk-provider-gateway-main", "todo-note-backend", "project-manager-backend", "baidu-netdisk-backend", "oa-event-flow-backend"];
|
||||
const docker = containerNames.map((name) => {
|
||||
const result = runCommand(["docker", "logs", "--tail", "40", name], repoRoot);
|
||||
return { name, exitCode: result.exitCode, stdoutTail: result.stdout.slice(-tailBytes), stderrTail: result.stderr.slice(-tailBytes) };
|
||||
|
||||
Reference in New Issue
Block a user