Merge pull request #1039 from pikasTech/fix/1017-caddy-prefix

fix(web-probe): merge sentinel caddy path routes
This commit is contained in:
Lyon
2026-06-26 21:23:05 +08:00
committed by GitHub
+53 -20
View File
@@ -622,18 +622,21 @@ function runSentinelControlPlaneConfirmed(state: SentinelCicdState, options: Ext
const startedAt = Date.now();
const command = `web-probe sentinel control-plane ${options.action}`;
const applyOnly = options.action === "apply";
const sourceMirrorSync = applyOnly ? null : runSentinelSourceMirrorSyncJob(state, options.timeoutSeconds);
const cicdWaitWarningSeconds = controlPlaneWaitWarningSeconds(state);
const deadline = startedAt + cicdWaitWarningSeconds * 1000;
const remainingCicdWaitSeconds = () => remainingSeconds(deadline, Math.min(options.timeoutSeconds, cicdWaitWarningSeconds));
const sourceMirrorSync = applyOnly ? null : runSentinelSourceMirrorSyncJob(state, remainingCicdWaitSeconds());
const publish = applyOnly
? null
: record(sourceMirrorSync).ok === true
? runSentinelPublishJob(state, true, options.timeoutSeconds)
? runSentinelPublishJob(state, true, remainingCicdWaitSeconds())
: sentinelBlockedRemoteResult("source-mirror-sync-blocked", "sentinel source mirror sync failed; publish job was not started");
const flush = !applyOnly && record(publish).ok === true
? runChildCli(["hwlab", "nodes", "git-mirror", "flush", "--node", state.spec.nodeId, "--lane", state.spec.lane, "--confirm", "--wait"], options.timeoutSeconds)
? runChildCli(["hwlab", "nodes", "git-mirror", "flush", "--node", state.spec.nodeId, "--lane", state.spec.lane, "--confirm", "--wait"], remainingCicdWaitSeconds())
: null;
const publicExposureApply = applySentinelPublicExposure(state, options.timeoutSeconds);
const argoApply = applySentinelArgoApplication(state, options.timeoutSeconds);
const observed = waitForSentinelObservedStatus(state, options.timeoutSeconds);
const publicExposureApply = applySentinelPublicExposure(state, remainingCicdWaitSeconds());
const argoApply = applySentinelArgoApplication(state, remainingCicdWaitSeconds());
const observed = waitForSentinelObservedStatus(state, remainingCicdWaitSeconds());
const observedReady = sentinelObservedReady(observed);
const targetValidation = null;
const targetValidationBlocked = false;
@@ -646,7 +649,6 @@ function runSentinelControlPlaneConfirmed(state: SentinelCicdState, options: Ext
&& record(argoApply).ok === true
&& observedReady;
const elapsedMs = Date.now() - startedAt;
const cicdWaitWarningSeconds = controlPlaneWaitWarningSeconds(state);
const blocker = ok ? null : {
code: record(sourceMirrorSync).ok === false ? "sentinel-source-mirror-sync-failed" : "sentinel-control-plane-not-ready",
reason: record(sourceMirrorSync).ok === false
@@ -753,7 +755,7 @@ function collectSentinelObservedStatus(state: SentinelCicdState, timeoutSeconds:
function waitForSentinelObservedStatus(state: SentinelCicdState, timeoutSeconds: number, expectation?: SentinelObservedExpectation): SentinelObservedStatus {
const startedAt = Date.now();
const timeoutMs = Math.max(30_000, Math.min(timeoutSeconds * 1000, controlPlaneWaitWarningSeconds(state) * 1000));
const timeoutMs = Math.max(5_000, Math.min(timeoutSeconds * 1000, controlPlaneWaitWarningSeconds(state) * 1000));
let observed = collectSentinelObservedStatus(state, timeoutSeconds, expectation);
while (!sentinelObservedReady(observed) && Date.now() - startedAt < timeoutMs) {
runCommand(["sleep", "5"], repoRoot, { timeoutMs: 6_000 });
@@ -917,7 +919,7 @@ function runSentinelSourceMirrorSyncJob(state: SentinelCicdState, timeoutSeconds
return { ok: false, phase: "create-job", jobName, payload: { ok: false, status: "create-failed", valuesRedacted: true }, create: compactCommand(created), valuesRedacted: true };
}
const startedAt = Date.now();
const timeoutMs = Math.max(30_000, Math.min(timeoutSeconds * 1000, controlPlaneWaitWarningSeconds(state) * 1000));
const timeoutMs = Math.max(5_000, Math.min(timeoutSeconds * 1000, controlPlaneWaitWarningSeconds(state) * 1000));
const warningBudgetMs = Math.max(1, Math.trunc(controlPlaneWaitWarningSeconds(state))) * 1000;
let slowWarningSent = false;
let polls = 0;
@@ -1160,7 +1162,7 @@ function runSentinelPublishJob(state: SentinelCicdState, publishGitops: boolean,
}
sentinelProgressEvent("sentinel.publish.progress", { phase: "create-job", status: "succeeded", jobName, publishGitops, node: state.spec.nodeId, lane: state.spec.lane });
const startedAt = Date.now();
const timeoutMs = Math.max(30_000, Math.min(timeoutSeconds * 1000, controlPlaneWaitWarningSeconds(state) * 1000));
const timeoutMs = Math.max(5_000, Math.min(timeoutSeconds * 1000, controlPlaneWaitWarningSeconds(state) * 1000));
const warningBudgetMs = Math.max(1, Math.trunc(controlPlaneWaitWarningSeconds(state))) * 1000;
let slowWarningSent = false;
let polls = 0;
@@ -2267,10 +2269,8 @@ function applySentinelCaddyBlock(state: SentinelCicdState, timeoutSeconds: numbe
"",
].join("\n")
: [
`${hostname} {`,
` handle_path ${routePrefix}* {`,
...proxyLines.map((line) => ` ${line}`),
" }",
`handle_path ${routePrefix}* {`,
...proxyLines.map((line) => ` ${line}`),
"}",
"",
].join("\n");
@@ -2281,6 +2281,7 @@ function applySentinelCaddyBlock(state: SentinelCicdState, timeoutSeconds: numbe
`owner=${shellQuote(owner)}`,
`config_path=${shellQuote(configPath)}`,
`service=${shellQuote(serviceName)}`,
`route_prefix=${shellQuote(routePrefix)}`,
`block_b64=${shellQuote(blockB64)}`,
"marker=\"unidesk managed $owner\"",
"tmp=$(mktemp -d)",
@@ -2289,20 +2290,52 @@ function applySentinelCaddyBlock(state: SentinelCicdState, timeoutSeconds: numbe
"next=\"$tmp/Caddyfile\"",
"printf '%s' \"$block_b64\" | base64 -d >\"$block\"",
"if [ -f \"$config_path\" ]; then cp \"$config_path\" \"$next\"; else : >\"$next\"; fi",
"python3 - \"$next\" \"$block\" \"$marker\" <<'PY' >/tmp/web-probe-sentinel-caddy-python.out 2>/tmp/web-probe-sentinel-caddy-python.err",
"python3 - \"$next\" \"$block\" \"$marker\" \"$hostname\" \"$route_prefix\" <<'PY' >/tmp/web-probe-sentinel-caddy-python.out 2>/tmp/web-probe-sentinel-caddy-python.err",
"import pathlib, re, sys",
"config = pathlib.Path(sys.argv[1])",
"block = pathlib.Path(sys.argv[2]).read_text(encoding='utf-8')",
"marker = sys.argv[3]",
"hostname = sys.argv[4]",
"route_prefix = sys.argv[5]",
"text = config.read_text(encoding='utf-8') if config.exists() else ''",
"begin = f'# BEGIN {marker}'",
"end = f'# END {marker}'",
"managed = f'{begin}\\n{block.rstrip()}\\n# END {marker}\\n'",
"pattern = re.compile(rf'(?ms)^# BEGIN {re.escape(marker)}\\n.*?\\n# END {re.escape(marker)}\\n*')",
"if pattern.search(text):",
" text = pattern.sub(managed, text)",
"else:",
"pattern = re.compile(rf'(?ms)^[ \\t]*# BEGIN {re.escape(marker)}\\n.*?^[ \\t]*# END {re.escape(marker)}\\n*')",
"text = pattern.sub('', text)",
"def site_span(src, host):",
" match = re.search(rf'(?m)^([ \\t]*){re.escape(host)}[ \\t]*\\{{[ \\t]*\\n', src)",
" if not match:",
" return None",
" depth = 1",
" index = match.end()",
" while index < len(src):",
" char = src[index]",
" if char == '{':",
" depth += 1",
" elif char == '}':",
" depth -= 1",
" if depth == 0:",
" end_index = index + 1",
" if end_index < len(src) and src[end_index] == '\\n':",
" end_index += 1",
" return match.start(), end_index, index, match.end()",
" index += 1",
" raise ValueError(f'unclosed Caddy site block for {host}')",
"if route_prefix == '/':",
" managed = f'{begin}\\n{block.rstrip()}\\n{end}\\n'",
" text = text.rstrip() + '\\n\\n' + managed",
"else:",
" handler = '\\n'.join((' ' + line) if line else '' for line in block.rstrip().splitlines())",
" managed = f' {begin}\\n{handler}\\n {end}\\n'",
" span = site_span(text, hostname)",
" if span is None:",
" text = text.rstrip() + '\\n\\n' + f'{hostname} {{\\n{managed}}}\\n'",
" else:",
" start, stop, close_index, open_end = span",
" site = text[start:stop]",
" relative_open = open_end - start",
" replacement = site[:relative_open] + managed + site[relative_open:]",
" text = text[:start] + replacement + text[stop:]",
"config.write_text(text, encoding='utf-8')",
"PY",
"python_rc=$?",