fix: use explicit durable bridge entrypoint
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
import { startServer } from "./server.mjs";
|
||||
|
||||
startServer();
|
||||
@@ -1,11 +1,10 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { createHash, createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
||||
import { mkdtempSync, readFileSync, realpathSync, rmSync } from "node:fs";
|
||||
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
||||
import { mkdir, open, readFile, readdir, rename, stat, unlink } from "node:fs/promises";
|
||||
import { createServer } from "node:http";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
export function createGithubSyncHandler(config) {
|
||||
const controller = config.controller ?? createDurableSyncController(config);
|
||||
@@ -1358,14 +1357,3 @@ function positiveIntegerEnv(name) {
|
||||
if (!Number.isFinite(value) || value < 1) throw new Error(`invalid positive integer env ${name}`);
|
||||
return value;
|
||||
}
|
||||
|
||||
export function isMainModule(argvPath = process.argv[1], moduleUrl = import.meta.url) {
|
||||
if (!argvPath) return false;
|
||||
try {
|
||||
return pathToFileURL(realpathSync(argvPath)).href === pathToFileURL(realpathSync(new URL(moduleUrl))).href;
|
||||
} catch {
|
||||
return pathToFileURL(argvPath).href === moduleUrl;
|
||||
}
|
||||
}
|
||||
|
||||
if (isMainModule()) startServer();
|
||||
|
||||
@@ -5,14 +5,12 @@ import { existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync
|
||||
import { createServer } from "node:http";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import test from "node:test";
|
||||
import {
|
||||
createGithubSyncHandler,
|
||||
createDurableInboxStore,
|
||||
createDurableSyncController,
|
||||
createSyncCoordinator,
|
||||
isMainModule,
|
||||
run,
|
||||
runResult,
|
||||
syncRepository,
|
||||
@@ -20,17 +18,21 @@ import {
|
||||
|
||||
const zeroDelay = async () => {};
|
||||
|
||||
test("main module detection follows Kubernetes ConfigMap symlinks", () => {
|
||||
test("explicit entrypoint starts through Kubernetes ConfigMap symlinks", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "gitea-sync-main-"));
|
||||
try {
|
||||
const dataDirectory = join(root, "..data");
|
||||
const source = join(dataDirectory, "server.mjs");
|
||||
const mounted = join(root, "server.mjs");
|
||||
const serverSource = join(dataDirectory, "server.mjs");
|
||||
const entrypointSource = join(dataDirectory, "entrypoint.mjs");
|
||||
const marker = join(root, "started");
|
||||
mkdirSync(dataDirectory);
|
||||
writeFileSync(source, "export {};\n", { flag: "wx" });
|
||||
symlinkSync(join("..data", "server.mjs"), mounted);
|
||||
writeFileSync(serverSource, `import { writeFileSync } from "node:fs";\nexport function startServer() { writeFileSync(${JSON.stringify(marker)}, "started\\n"); }\n`, { flag: "wx" });
|
||||
writeFileSync(entrypointSource, 'import { startServer } from "./server.mjs";\nstartServer();\n', { flag: "wx" });
|
||||
symlinkSync(join("..data", "server.mjs"), join(root, "server.mjs"));
|
||||
symlinkSync(join("..data", "entrypoint.mjs"), join(root, "entrypoint.mjs"));
|
||||
|
||||
assert.equal(isMainModule(mounted, pathToFileURL(source).href), true);
|
||||
execFileSync(process.execPath, [join(root, "entrypoint.mjs")], { stdio: "pipe" });
|
||||
assert.equal(existsSync(marker), true);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
@@ -60,7 +60,9 @@ test("owning YAML renders one child Application and the complete durable bridge
|
||||
expect(manifest).toContain("argocd.argoproj.io/hook: PreSync");
|
||||
expect(manifest).toContain('argocd.argoproj.io/sync-wave: "-2"');
|
||||
expect(manifest).toContain('argocd.argoproj.io/sync-wave: "-1"');
|
||||
expect(manifest).toContain("node /etc/gitea-github-sync-candidate/server.mjs &");
|
||||
expect(manifest).toContain("node /etc/gitea-github-sync-candidate/entrypoint.mjs &");
|
||||
expect(manifest).toContain('import { startServer } from "./server.mjs";');
|
||||
expect(manifest).toContain("- /etc/gitea-github-sync/entrypoint.mjs");
|
||||
expect(manifest).toContain("mountPath: /etc/gitea-github-sync-candidate");
|
||||
expect(manifest).toContain("name: candidate-inbox\n emptyDir: {}");
|
||||
expect(manifest).toContain('gate: "gitea-github-sync-candidate-startup"');
|
||||
|
||||
@@ -25,6 +25,7 @@ const configFile = rootPath("config", "platform-infra", "gitea.yaml");
|
||||
const configLabel = "config/platform-infra/gitea.yaml";
|
||||
const remoteScriptFile = rootPath("scripts", "src", "platform-infra-gitea-remote.sh");
|
||||
const githubSyncServerFile = rootPath("scripts", "src", "platform-infra-gitea-github-sync-server.mjs");
|
||||
const githubSyncEntrypointFile = rootPath("scripts", "src", "platform-infra-gitea-github-sync-entrypoint.mjs");
|
||||
const statusEvaluatorFile = rootPath("scripts", "src", "platform_infra_gitea_status_evaluator.py");
|
||||
const fieldManager = "unidesk-platform-infra-gitea";
|
||||
const y = createYamlFieldReader(configLabel);
|
||||
@@ -1288,7 +1289,8 @@ function renderGithubSyncManifest(gitea: GiteaConfig, target: GiteaTarget): stri
|
||||
app.kubernetes.io/managed-by: unidesk`;
|
||||
const reposJson = JSON.stringify(repositoriesForTarget(gitea, target).map(remoteRepoSpec), null, 2);
|
||||
const serverSource = readFileSync(githubSyncServerFile, "utf8");
|
||||
const configHash = createHash("sha256").update(reposJson).update("\0").update(serverSource).digest("hex").slice(0, 16);
|
||||
const entrypointSource = readFileSync(githubSyncEntrypointFile, "utf8");
|
||||
const configHash = createHash("sha256").update(reposJson).update("\0").update(serverSource).update("\0").update(entrypointSource).digest("hex").slice(0, 16);
|
||||
const gate = sync.bridge.candidateGate;
|
||||
const candidateManifest = gate.enabled ? `---
|
||||
apiVersion: v1
|
||||
@@ -1307,6 +1309,8 @@ data:
|
||||
${indentBlock(reposJson, 4)}
|
||||
server.mjs: |
|
||||
${indentBlock(serverSource, 4)}
|
||||
entrypoint.mjs: |
|
||||
${indentBlock(entrypointSource, 4)}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
@@ -1341,7 +1345,7 @@ spec:
|
||||
- -eu
|
||||
- -c
|
||||
- |
|
||||
node /etc/gitea-github-sync-candidate/server.mjs &
|
||||
node /etc/gitea-github-sync-candidate/entrypoint.mjs &
|
||||
server_pid=$!
|
||||
trap 'kill "$server_pid" 2>/dev/null || true' EXIT INT TERM
|
||||
node --input-type=module - ${gate.healthTimeoutMs} ${gate.pollIntervalMs} <<'NODE'
|
||||
@@ -1455,6 +1459,8 @@ data:
|
||||
${indentBlock(reposJson, 4)}
|
||||
server.mjs: |
|
||||
${indentBlock(serverSource, 4)}
|
||||
entrypoint.mjs: |
|
||||
${indentBlock(entrypointSource, 4)}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
@@ -1525,7 +1531,7 @@ spec:
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- node
|
||||
- /etc/gitea-github-sync/server.mjs
|
||||
- /etc/gitea-github-sync/entrypoint.mjs
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: ${sync.bridge.httpPort}
|
||||
|
||||
Reference in New Issue
Block a user