Files
kuber/command/s3.ts
T
2026-10-07 10:33:21 +00:00

108 lines
2.6 KiB
TypeScript

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 = <T>(
path: string,
init?: ApiRequestInit,
) => Promise<T>;
export function getRemoteS3Credentials(
project: string,
claim: S3Claim,
request: S3ApiRequest = apiRequest,
): Promise<Record<string, string>> {
return request<Record<string, string>>(
`/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<S3Claim> {
const claim = getComposeS3Claims(await ctx().compose()).find(
(entry) => entry.service === service,
);
if (!claim) {
throw new Error(
`Service ${service} does not declare an object storage volume.`,
);
}
return claim;
}
const list = defineCommand({
meta: {
name: "ls",
description: "List object storage volumes used by this project",
},
async run() {
const claims = getComposeS3Claims(await ctx().compose());
if (claims.length === 0) {
console.log("No object storage 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 object storage 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 object storage browser 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: "View project object storage settings",
},
subCommands: {
creds,
ls: list,
ui,
},
});