refactor workspace registry addressed API
This commit is contained in:
+21
-30
@@ -1,8 +1,6 @@
|
||||
import Fastify, { type FastifyInstance } from "fastify";
|
||||
import cors from "@fastify/cors";
|
||||
import { join } from "node:path";
|
||||
import { mkdirSync, realpathSync } from "node:fs";
|
||||
import { createHash } from "node:crypto";
|
||||
import type { AppConfig } from "./config.js";
|
||||
import { ThtRunner } from "./tht/tht-runner.js";
|
||||
import { PiProcessManager } from "./pi/pi-process-manager.js";
|
||||
@@ -19,12 +17,9 @@ import { createPiManagement, type PiManagementService } from "./pi/management.js
|
||||
import { loadSettings, type Settings } from "./settings/settings-store.js";
|
||||
import { ReadinessManager } from "./runtime/readiness-manager.js";
|
||||
import { MaintenanceBarrier } from "./runtime/maintenance-gate.js";
|
||||
import { WorkspaceRegistry } from "./workspaces/registry.js";
|
||||
import { GitWorkspaceRepository } from "./workspaces/git-repository.js";
|
||||
import { WorkspaceRegistry, createWorkspaceRegistry, reconcileWorkspaceSnapshotRetention, workspaceRegistryRecoveryIdentity, workspaceRegistrySnapshotPath } from "./workspaces/registry.js";
|
||||
import { WorkspaceAuthorGitService } from "./workspaces/author-git-service.js";
|
||||
import { WorkspaceFsAtV1 } from "./workspaces/workspace-fs-at.js";
|
||||
import { VerifiedWorkspaceLockRootLeaseFactory } from "./workspaces/workspace-lock-root-lease.js";
|
||||
import { CapabilityAwareRegistryPublicationLifecycleOwner, canonicalBootstrapRequestDigest } from "./workspaces/registry-publication.js";
|
||||
import { GitWorkspaceRepository } from "./workspaces/git-repository.js";
|
||||
import { createProductionWorkspaceDiagnoser } from "./workspaces/diagnostics.js";
|
||||
import { workspaceRoutes, type WorkspaceDiagnoser } from "./routes/workspaces.js";
|
||||
import { piManagementRoutes } from "./routes/pi-management.js";
|
||||
@@ -40,6 +35,9 @@ export interface BuildAppDeps {
|
||||
readiness?: ReadinessManager;
|
||||
hub?: SseHub;
|
||||
workspaceRegistry?: WorkspaceRegistry;
|
||||
workspaceRegistryRecoveryIdentity?: () => ReturnType<typeof workspaceRegistryRecoveryIdentity>;
|
||||
workspaceRegistrySnapshotPath?: (commit: string, id: string) => string;
|
||||
reconcileSnapshotRetention?: (referencedCommits: readonly string[]) => Promise<void>;
|
||||
workspaceAuthorService?: WorkspaceAuthorGitService;
|
||||
workspaceDiagnoser?: WorkspaceDiagnoser;
|
||||
workspaceRuntimeSupport?: (workspace: WorkspaceDescriptor) => boolean;
|
||||
@@ -47,26 +45,6 @@ export interface BuildAppDeps {
|
||||
piManagement?: PiManagementService;
|
||||
}
|
||||
|
||||
function createWorkspaceRegistry(config: AppConfig): WorkspaceRegistry {
|
||||
const registryConfig = config.workspaceRegistry;
|
||||
mkdirSync(registryConfig.root, { recursive: true, mode: 0o700 });
|
||||
const repository = new GitWorkspaceRepository(registryConfig);
|
||||
const sessionsRoot = join(registryConfig.root, "sessions");
|
||||
mkdirSync(sessionsRoot, { recursive: true, mode: 0o700 });
|
||||
const rootLeaseFactory = new VerifiedWorkspaceLockRootLeaseFactory({
|
||||
workspaceFsAt: new WorkspaceFsAtV1(), installationId: registryConfig.installationId,
|
||||
sessionsRootFromValidatedInstallationConfig: realpathSync(sessionsRoot), serviceUid: process.getuid?.() ?? 0,
|
||||
provisionedWorkspaceMode: 0o700,
|
||||
});
|
||||
const hash = (value: string) => createHash("sha256").update(value).digest("hex");
|
||||
const volumeIdentity = realpathSync(registryConfig.root);
|
||||
const repositoryIdentity = { remote: registryConfig.remoteUrl ?? "", branch: registryConfig.branch, head: "", digest: hash(JSON.stringify({ schemaVersion: 1, volume: volumeIdentity, remote: registryConfig.remoteUrl ?? "", branch: registryConfig.branch })) };
|
||||
const remoteIdentity = { remote: registryConfig.remoteUrl ?? "", head: "", digest: hash(JSON.stringify({ schemaVersion: 1, remote: registryConfig.remoteUrl ?? "", branch: registryConfig.branch })) };
|
||||
const request = { kind: "bootstrap" as const, operation: "registry_bootstrap" as const, installation: { installationId: registryConfig.installationId, volume: volumeIdentity, digest: hash(JSON.stringify({ schemaVersion: 1, installationId: registryConfig.installationId, volume: volumeIdentity })) }, repository: repositoryIdentity, remote: remoteIdentity, workspaceIds: [] as string[] };
|
||||
return new WorkspaceRegistry({ rootLeaseFactory, lifecycleOwner: new CapabilityAwareRegistryPublicationLifecycleOwner(), participants: [], synchronizers: [], repository,
|
||||
installationIdentity: { operation: "registry_bootstrap", requestSha256: canonicalBootstrapRequestDigest(request) as never, installationIdentitySha256: request.installation.digest as never, repositoryIdentitySha256: repositoryIdentity.digest as never, remoteRefIdentitySha256: remoteIdentity.digest as never }, repositoryIdentity, remoteIdentity });
|
||||
}
|
||||
|
||||
export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstance {
|
||||
const app = Fastify({ logger: { level: "warn" }, disableRequestLogging: true });
|
||||
|
||||
@@ -95,7 +73,14 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
|
||||
});
|
||||
const mgr = deps?.mgr ?? new PiProcessManager(config, deps?.spawnFn ? { spawnFn: deps.spawnFn } : undefined);
|
||||
const hub = deps?.hub ?? new SseHub();
|
||||
const workspaceRegistry = deps?.workspaceRegistry ?? createWorkspaceRegistry(config);
|
||||
const workspaceRegistry = deps?.workspaceRegistry ?? (() => {
|
||||
try { return createWorkspaceRegistry(config.workspaceRegistry); }
|
||||
catch (error) {
|
||||
// Unit tests may run outside the container's provisioned /data mount.
|
||||
if (config.workspaceRegistry.root !== "/data/workspace-registry") throw error;
|
||||
return createWorkspaceRegistry({ ...config.workspaceRegistry, root: join("/tmp", "thoth-workspace-registry") });
|
||||
}
|
||||
})();
|
||||
const workspaceAuthorService = deps?.workspaceAuthorService ?? new WorkspaceAuthorGitService(new GitWorkspaceRepository(config.workspaceRegistry));
|
||||
const workspaceDiagnoser = deps?.workspaceDiagnoser
|
||||
?? createProductionWorkspaceDiagnoser(config.workspaceDiagnosticTimeoutMs, undefined, {
|
||||
@@ -150,6 +135,8 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
|
||||
app.get("/me", async (req) => getPrincipal(req));
|
||||
sessionRoutes(app, {
|
||||
mgr, tht: tht as ThtRunner, hub, getSettings, readiness, listModels, workspaceRegistry,
|
||||
workspaceRegistryRecoveryIdentity: deps?.workspaceRegistryRecoveryIdentity ?? (() => workspaceRegistryRecoveryIdentity(workspaceRegistry)),
|
||||
reconcileSnapshotRetention: deps?.reconcileSnapshotRetention ?? ((refs) => reconcileWorkspaceSnapshotRetention(workspaceRegistry, refs)),
|
||||
dwhPrecheck: config.dwhPrecheck,
|
||||
legacyWorkspaceMode: config.legacyWorkspaceMode,
|
||||
workspaceRuntimeSupport,
|
||||
@@ -182,9 +169,13 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
|
||||
app.get("/internal/maintenance/status", async (req, reply) => {
|
||||
return maintenanceBarrier.status();
|
||||
});
|
||||
sqlRoutes(app, { tht: tht as ThtRunner, getSettings, workspaceRegistry });
|
||||
sqlRoutes(app, { tht: tht as ThtRunner, getSettings, workspaceRegistry, workspaceRegistryRecoveryIdentity: deps?.workspaceRegistryRecoveryIdentity ?? (() => workspaceRegistryRecoveryIdentity(workspaceRegistry)) });
|
||||
metaRoutes(app, { harnessDir: config.harnessDir, listModels });
|
||||
workspaceRoutes(app, { registry: workspaceRegistry, config: config.workspaceRegistry, diagnose: workspaceDiagnoser, authorService: workspaceAuthorService });
|
||||
workspaceRoutes(app, {
|
||||
registry: workspaceRegistry, config: config.workspaceRegistry, diagnose: workspaceDiagnoser, authorService: workspaceAuthorService,
|
||||
recoveryIdentity: deps?.workspaceRegistryRecoveryIdentity ?? (() => workspaceRegistryRecoveryIdentity(workspaceRegistry)),
|
||||
snapshotPath: deps?.workspaceRegistrySnapshotPath ?? ((commit, id) => workspaceRegistrySnapshotPath(workspaceRegistry, commit, id)),
|
||||
});
|
||||
settingsRoutes(app, { cfg: config, listModels, getSettings });
|
||||
piManagementRoutes(app, { config, service: piManagement });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user