UNPKG

convex

Version:

Client for the Convex Cloud

277 lines (276 loc) 8.17 kB
"use strict"; import path from "path"; import { logFailure, logFinishedStep, logVerbose } from "../../../bundler/context.js"; import { runSystemQuery } from "../run.js"; import { deploymentStateDir, saveDeploymentConfig } from "./filePaths.js"; import { ensureBackendStopped, localDeploymentUrl, runLocalBackend } from "./run.js"; import { downloadSnapshotExport, startSnapshotExport } from "../convexExport.js"; import { deploymentFetch, logAndHandleFetchError } from "../utils/utils.js"; import { confirmImport, uploadForImport, waitForStableImportState } from "../convexImport.js"; import { promptOptions, promptYesNo } from "../utils/prompts.js"; import { recursivelyDelete } from "../fsUtils.js"; import { LocalDeploymentError } from "./errors.js"; import { ensureBackendBinaryDownloaded } from "./download.js"; export async function handlePotentialUpgrade(ctx, args) { const newConfig = { ports: args.ports, backendVersion: args.newVersion, adminKey: args.adminKey, instanceSecret: args.instanceSecret }; if (args.oldVersion === null || args.oldVersion === args.newVersion) { saveDeploymentConfig( ctx, args.deploymentKind, args.deploymentName, newConfig ); return runLocalBackend(ctx, { binaryPath: args.newBinaryPath, deploymentKind: args.deploymentKind, deploymentName: args.deploymentName, ports: args.ports, instanceSecret: args.instanceSecret, isLatestVersion: true }); } logVerbose( ctx, `Considering upgrade from ${args.oldVersion} to ${args.newVersion}` ); const confirmed = args.forceUpgrade || await promptYesNo(ctx, { message: `This deployment is using an older version of the Convex backend. Upgrade now?`, default: true }); if (!confirmed) { const { binaryPath: oldBinaryPath } = await ensureBackendBinaryDownloaded( ctx, { kind: "version", version: args.oldVersion } ); saveDeploymentConfig(ctx, args.deploymentKind, args.deploymentName, { ...newConfig, backendVersion: args.oldVersion }); return runLocalBackend(ctx, { binaryPath: oldBinaryPath, ports: args.ports, deploymentKind: args.deploymentKind, deploymentName: args.deploymentName, instanceSecret: args.instanceSecret, isLatestVersion: false }); } const choice = args.forceUpgrade ? "transfer" : await promptOptions(ctx, { message: "Transfer data from existing deployment?", default: "transfer", choices: [ { name: "transfer data", value: "transfer" }, { name: "start fresh", value: "reset" } ] }); const deploymentStatePath = deploymentStateDir( args.deploymentKind, args.deploymentName ); if (choice === "reset") { recursivelyDelete(ctx, deploymentStatePath, { force: true }); saveDeploymentConfig( ctx, args.deploymentKind, args.deploymentName, newConfig ); return runLocalBackend(ctx, { binaryPath: args.newBinaryPath, deploymentKind: args.deploymentKind, deploymentName: args.deploymentName, ports: args.ports, instanceSecret: args.instanceSecret, isLatestVersion: true }); } return handleUpgrade(ctx, { deploymentKind: args.deploymentKind, deploymentName: args.deploymentName, oldVersion: args.oldVersion, newBinaryPath: args.newBinaryPath, newVersion: args.newVersion, ports: args.ports, adminKey: args.adminKey, instanceSecret: args.instanceSecret }); } async function handleUpgrade(ctx, args) { const { binaryPath: oldBinaryPath } = await ensureBackendBinaryDownloaded( ctx, { kind: "version", version: args.oldVersion } ); logVerbose(ctx, "Running backend on old version"); const { cleanupHandle: oldCleanupHandle } = await runLocalBackend(ctx, { binaryPath: oldBinaryPath, ports: args.ports, deploymentKind: args.deploymentKind, deploymentName: args.deploymentName, instanceSecret: args.instanceSecret, isLatestVersion: false }); logVerbose(ctx, "Downloading env vars"); const deploymentUrl = localDeploymentUrl(args.ports.cloud); const envs = await runSystemQuery(ctx, { deploymentUrl, adminKey: args.adminKey, functionName: "_system/cli/queryEnvironmentVariables", componentPath: void 0, args: {} }); logVerbose(ctx, "Doing a snapshot export"); const exportPath = path.join( deploymentStateDir(args.deploymentKind, args.deploymentName), "export.zip" ); if (ctx.fs.exists(exportPath)) { ctx.fs.unlink(exportPath); } const snaphsotExportState = await startSnapshotExport(ctx, { deploymentUrl, adminKey: args.adminKey, includeStorage: true, inputPath: exportPath }); if (snaphsotExportState.state !== "completed") { return ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: "Failed to export snapshot" }); } await downloadSnapshotExport(ctx, { snapshotExportTs: snaphsotExportState.start_ts, inputPath: exportPath, adminKey: args.adminKey, deploymentUrl }); logVerbose(ctx, "Stopping the backend on the old version"); const oldCleanupFunc = ctx.removeCleanup(oldCleanupHandle); if (oldCleanupFunc) { await oldCleanupFunc(0); } await ensureBackendStopped(ctx, { ports: args.ports, maxTimeSecs: 5, deploymentName: args.deploymentName, allowOtherDeployments: false }); logVerbose(ctx, "Running backend on new version"); const { cleanupHandle } = await runLocalBackend(ctx, { binaryPath: args.newBinaryPath, ports: args.ports, deploymentKind: args.deploymentKind, deploymentName: args.deploymentName, instanceSecret: args.instanceSecret, isLatestVersion: true }); logVerbose(ctx, "Importing the env vars"); if (envs.length > 0) { const fetch = deploymentFetch(ctx, { deploymentUrl, adminKey: args.adminKey }); try { await fetch("/api/update_environment_variables", { body: JSON.stringify({ changes: envs }), method: "POST" }); } catch (e) { return await logAndHandleFetchError(ctx, e); } } logVerbose(ctx, "Doing a snapshot import"); const importId = await uploadForImport(ctx, { deploymentUrl, adminKey: args.adminKey, filePath: exportPath, importArgs: { format: "zip", mode: "replace", tableName: void 0 }, onImportFailed: async (e) => { logFailure(ctx, `Failed to import snapshot: ${e}`); } }); logVerbose(ctx, `Snapshot import started`); let status = await waitForStableImportState(ctx, { importId, deploymentUrl, adminKey: args.adminKey, onProgress: () => { return 0; } }); if (status.state !== "waiting_for_confirmation") { const message = "Error while transferring data: Failed to upload snapshot"; return ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: message, errForSentry: new LocalDeploymentError(message) }); } await confirmImport(ctx, { importId, adminKey: args.adminKey, deploymentUrl, onError: async (e) => { logFailure(ctx, `Failed to confirm import: ${e}`); } }); logVerbose(ctx, `Snapshot import confirmed`); status = await waitForStableImportState(ctx, { importId, deploymentUrl, adminKey: args.adminKey, onProgress: () => { return 0; } }); logVerbose(ctx, `Snapshot import status: ${status.state}`); if (status.state !== "completed") { const message = "Error while transferring data: Failed to import snapshot"; return ctx.crash({ exitCode: 1, errorType: "fatal", printedMessage: message, errForSentry: new LocalDeploymentError(message) }); } logFinishedStep(ctx, "Successfully upgraded to a new backend version"); saveDeploymentConfig(ctx, args.deploymentKind, args.deploymentName, { ports: args.ports, backendVersion: args.newVersion, adminKey: args.adminKey, instanceSecret: args.instanceSecret }); return { cleanupHandle }; } //# sourceMappingURL=upgrade.js.map