50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
import type { FastifyInstance } from "fastify";
|
|
import { z } from "zod";
|
|
import { createDatabase, createDatabaseUser, deleteDatabase, deleteDatabaseUser } from "../services/do";
|
|
import { addCustomerToPool, removeCustomerFromPool } from "../services/pgbouncer";
|
|
import { addCustomerChart, removeCustomerChart } from "../services/git";
|
|
import { setupCustomerDatabase, teardownCustomerDatabase } from "../services/db";
|
|
|
|
const ProvisionSchema = z.object({
|
|
name: z.string().min(2).max(32).regex(/^[a-z0-9-]+$/, "lowercase letters, numbers, and hyphens only"),
|
|
appVersion: z.string().default("latest"),
|
|
});
|
|
|
|
export async function customerRoutes(app: FastifyInstance) {
|
|
app.post("/customers", async (req, reply) => {
|
|
const body = ProvisionSchema.parse(req.body);
|
|
const slug = body.name;
|
|
|
|
app.log.info({ slug }, "provisioning customer");
|
|
|
|
const [, user] = await Promise.all([
|
|
createDatabase(slug),
|
|
createDatabaseUser(slug),
|
|
]);
|
|
|
|
await setupCustomerDatabase(slug, user.name);
|
|
await addCustomerToPool(slug, user.password);
|
|
addCustomerChart(slug, body.appVersion);
|
|
|
|
app.log.info({ slug }, "customer provisioned");
|
|
return reply.code(201).send({ slug, status: "provisioned" });
|
|
});
|
|
|
|
app.delete("/customers/:slug", async (req, reply) => {
|
|
const { slug } = req.params as { slug: string };
|
|
|
|
app.log.info({ slug }, "deprovisioning customer");
|
|
|
|
removeCustomerChart(slug);
|
|
await removeCustomerFromPool(slug);
|
|
await teardownCustomerDatabase(slug, slug);
|
|
await Promise.all([
|
|
deleteDatabase(slug),
|
|
deleteDatabaseUser(slug),
|
|
]);
|
|
|
|
app.log.info({ slug }, "customer deprovisioned");
|
|
return reply.code(204).send();
|
|
});
|
|
}
|