import { defineCommand } from "citty"; import { apiRequest, type ApiRequestInit } from "../lib/api"; import { ctx } from "../lib/context"; import { toTable } from "../lib/format"; import { getComposeS3Claims, type S3Claim } from "../lib/storage"; const GARAGE_UI_URL = "http://garage-ui.garage-system.svc.cluster.local"; export type S3ApiRequest = ( path: string, init?: ApiRequestInit, ) => Promise; export function getRemoteS3Credentials( project: string, claim: S3Claim, request: S3ApiRequest = apiRequest, ): Promise> { return request>( `/workspaces/${encodeURIComponent(project)}/storage/credentials`, { method: "POST", json: { claim } }, ); } export function getS3UiUrl(bucket: string): string { return `${GARAGE_UI_URL}/buckets/${encodeURIComponent(bucket)}/objects`; } async function getServiceClaim(service: string): Promise { const claim = getComposeS3Claims(await ctx().compose()).find( (entry) => entry.service === service, ); if (!claim) { throw new Error(`Service ${service} does not declare a managed S3 volume.`); } return claim; } const list = defineCommand({ meta: { name: "ls", description: "List managed S3 claims", }, async run() { const claims = getComposeS3Claims(await ctx().compose()); if (claims.length === 0) { console.log("No managed S3 volumes declared"); return; } console.log( toTable( claims.map((claim) => ({ service: claim.service, key: claim.key, bucket: claim.bucket, })), ), ); }, }); const creds = defineCommand({ meta: { name: "creds", description: "Print S3 environment variables for a service", }, async run({ args }) { const service = args._[0]; if (!service) throw new Error("Service name is required"); const credentials = await getRemoteS3Credentials( ctx().project, await getServiceClaim(service), ); for (const [name, value] of Object.entries(credentials)) { console.log(`${name}=${value}`); } }, }); const ui = defineCommand({ meta: { name: "ui", description: "Print the Garage UI URL for a service bucket", }, async run({ args }) { const service = args._[0]; if (!service) throw new Error("Service name is required"); console.log(getS3UiUrl((await getServiceClaim(service)).bucket)); }, }); export const s3 = defineCommand({ meta: { name: "s3", description: "Inspect managed S3 storage", }, subCommands: { creds, ls: list, ui, }, });