diff --git a/src/routes/customers.ts b/src/routes/customers.ts index 1b34a3b..42d1f18 100644 --- a/src/routes/customers.ts +++ b/src/routes/customers.ts @@ -140,7 +140,7 @@ export async function customerRoutes(app: FastifyInstance) { await createCustomerDnsRecord(slug); await setStep("dns", "done"); - addCustomerChart(slug, body.appVersion); + await addCustomerChart(slug, body.appVersion); await setStep("chart", "done"); await db`UPDATE customers SET status = 'provisioned', updated_at = NOW() WHERE slug = ${slug}`; @@ -299,7 +299,7 @@ export async function customerRoutes(app: FastifyInstance) { const dbUrl = new URL(secrets["database-url"]); await addCustomerToPool(slug, dbUrl.password); - addCustomerChart(slug, "*"); + await addCustomerChart(slug, "*"); await db`UPDATE customers SET status = 'provisioned', updated_at = NOW() WHERE slug = ${slug}`; app.log.info({ slug }, "customer reactivated"); return reply.code(200).send({ slug, status: "provisioned" }); diff --git a/src/services/cloudflare.ts b/src/services/cloudflare.ts index 1f42c58..f15e2ea 100644 --- a/src/services/cloudflare.ts +++ b/src/services/cloudflare.ts @@ -44,7 +44,7 @@ export async function getCustomerDnsRecord(slug: string): Promise<{ exists: bool export async function checkCustomerHealth(slug: string): Promise<{ reachable: boolean; status: number | null }> { try { - const res = await fetch(`https://${slug}.lunarfront.tech/health`, { + const res = await fetch(`https://${slug}.lunarfront.tech/api/health`, { signal: AbortSignal.timeout(5000), }); return { reachable: res.ok, status: res.status }; diff --git a/src/services/git.ts b/src/services/git.ts index cb792a8..5883af1 100644 --- a/src/services/git.ts +++ b/src/services/git.ts @@ -4,6 +4,23 @@ import { tmpdir } from "os"; import { join } from "path"; import { config } from "../lib/config"; +async function getLatestChartVersion(): Promise { + const res = await fetch("https://api.digitalocean.com/v2/registry/lunarfront/repositories/lunarfront/tags?page=1&per_page=100", { + headers: { Authorization: `Bearer ${config.doToken}` }, + }); + const data = await res.json() as { tags: { tag: string }[] }; + const versions = (data.tags ?? []) + .map(t => t.tag) + .filter(t => /^\d+\.\d+\.\d+$/.test(t)) + .sort((a, b) => { + const [aMaj, aMin, aPat] = a.split(".").map(Number); + const [bMaj, bMin, bPat] = b.split(".").map(Number); + return bMaj - aMaj || bMin - aMin || bPat - aPat; + }); + if (!versions.length) throw new Error("No chart versions found in DOCR"); + return versions[0]; +} + function withRepo(fn: (dir: string, env: NodeJS.ProcessEnv) => T): T { const keyPath = join(tmpdir(), `manager-ssh-key-${Date.now()}`); const dir = join(tmpdir(), `lunarfront-charts-${Date.now()}`); @@ -30,9 +47,10 @@ function withRepo(fn: (dir: string, env: NodeJS.ProcessEnv) => T): T { } } -export function addCustomerChart(slug: string, appVersion: string) { +export async function addCustomerChart(slug: string, appVersion: string) { + const version = (appVersion === "*" || appVersion === "latest") ? await getLatestChartVersion() : appVersion; withRepo((dir, env) => { - const manifest = buildArgoCDApp(slug, appVersion); + const manifest = buildArgoCDApp(slug, version); writeFileSync(join(dir, "customers", `${slug}.yaml`), manifest); execSync(`git -C ${dir} add customers/${slug}.yaml`, { env }); execSync(`git -C ${dir} commit -m "feat: provision customer ${slug}"`, { env }); @@ -50,8 +68,8 @@ export function removeCustomerChart(slug: string) { }); } -function buildArgoCDApp(slug: string, appVersion: string): string { - const revision = appVersion === "*" || appVersion === "latest" ? ">=0.0.1" : appVersion; +function buildArgoCDApp(slug: string, version: string): string { + const revision = version; return `apiVersion: argoproj.io/v1alpha1 kind: Application metadata: