Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions apps/hub/src/provisioners/process.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { describe, expect, test } from "bun:test";
import { createProcessSidecarProvisioner, readProcessProvisionerConfig } from "./process";
import { createFakeSidecarProcessRunner } from "./fake-process-runner";

function fingerprint(role: "deployment" | "probe", port: number, dataDir: string, entry: string) {
return createProcessSidecarProvisioner({
role,
runner: createFakeSidecarProcessRunner(),
config: readProcessProvisionerConfig({
env: {
PROCESS_PROVISIONER_SIDECAR_ENTRY: entry,
SIDECAR_CREDENTIAL_ENCRYPTION_KEY: "k".repeat(32),
},
dataDir,
hubWebSocketUrl: `ws://127.0.0.1:${port}/api/sidecars/ws`,
}),
}).bindingFingerprint;
}

describe("process provisioner binding fingerprint", () => {
test("is stable across hub restarts that change the port or install path", () => {
expect(fingerprint("deployment", 3000, "/srv/a/data", "/srv/a/sidecar.ts")).toBe(
fingerprint("deployment", 4123, "/srv/b/data", "/srv/b/sidecar.ts"),
);
});

test("still distinguishes roles", () => {
expect(fingerprint("deployment", 3000, "/srv/a", "/srv/a/s.ts")).not.toBe(
fingerprint("probe", 3000, "/srv/a", "/srv/a/s.ts"),
);
});
});
13 changes: 6 additions & 7 deletions apps/hub/src/provisioners/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ export type ProcessProvisionerConfig = {
readonly allocationsDir: string;
/** Where the shared allocation state store keeps generation fences. */
readonly stateFilePath: string;
/** The ws(s):// URL provisioned sidecars dial back on; part of the
* binding fingerprint, since a hub moved to a new address is a
* different backend binding even with the same entry point. */
/** The ws(s):// URL provisioned sidecars dial back on. */
readonly hubWebSocketUrl: string;
/** The operator key every spawned sidecar seals its at-rest credentials under. */
readonly sidecarCredentialEncryptionKey: string;
Expand Down Expand Up @@ -448,9 +446,10 @@ export type CreateProcessSidecarProvisionerOpts = {
};

/**
* The binding fingerprint pins entry point and hub URL: a change to either
* is a different backend binding, so allocations bound to the old one
* aren't silently treated as current.
* The binding fingerprint names the backend kind and role only. Hub port,
* install path, and sidecar entry location change across restarts without
* changing what the backend can host; pinning them strands every existing
* allocation, which the reconciler can neither release nor replace.
*/
export function createProcessSidecarProvisioner(
opts: CreateProcessSidecarProvisionerOpts,
Expand All @@ -462,7 +461,7 @@ export function createProcessSidecarProvisioner(
return createSidecarProvisioner({
id: PROCESS_PROVISIONER_ID,
apiVersion: PROVISIONER_API_VERSION,
bindingFingerprint: `process:v1:${opts.role}:${config.sidecarEntryPath}:${config.hubWebSocketUrl}`,
bindingFingerprint: `process:v1:${opts.role}`,
capabilities: sidecarCapabilityDeclarations("process"),
backend: createProcessBackend(runner, config),
store,
Expand Down
Loading