@nocobase/app-installer 0.0.0-stage → 0.1.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +199 -2
- package/bin/run.js +43 -0
- package/dist/cli.js +168 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/install.js +319 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/rollback.js +284 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/status.js +132 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/upgrade.js +549 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/lib/app-cli.js +89 -0
- package/dist/lib/app-cli.js.map +1 -0
- package/dist/lib/backup.js +167 -0
- package/dist/lib/backup.js.map +1 -0
- package/dist/lib/confirm.js +36 -0
- package/dist/lib/confirm.js.map +1 -0
- package/dist/lib/current-link.js +22 -0
- package/dist/lib/current-link.js.map +1 -0
- package/dist/lib/ecosystem.js +82 -0
- package/dist/lib/ecosystem.js.map +1 -0
- package/dist/lib/env-file.js +87 -0
- package/dist/lib/env-file.js.map +1 -0
- package/dist/lib/errors.js +32 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/health.js +55 -0
- package/dist/lib/health.js.map +1 -0
- package/dist/lib/initial-admin.js +39 -0
- package/dist/lib/initial-admin.js.map +1 -0
- package/dist/lib/interrupt.js +50 -0
- package/dist/lib/interrupt.js.map +1 -0
- package/dist/lib/invocation.js +33 -0
- package/dist/lib/invocation.js.map +1 -0
- package/dist/lib/layout.js +48 -0
- package/dist/lib/layout.js.map +1 -0
- package/dist/lib/lock.js +59 -0
- package/dist/lib/lock.js.map +1 -0
- package/dist/lib/mount-path.js +34 -0
- package/dist/lib/mount-path.js.map +1 -0
- package/dist/lib/output.js +61 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/pm2.js +92 -0
- package/dist/lib/pm2.js.map +1 -0
- package/dist/lib/prechecks.js +199 -0
- package/dist/lib/prechecks.js.map +1 -0
- package/dist/lib/registry.js +9 -0
- package/dist/lib/registry.js.map +1 -0
- package/dist/lib/release.js +173 -0
- package/dist/lib/release.js.map +1 -0
- package/dist/lib/run-command.js +108 -0
- package/dist/lib/run-command.js.map +1 -0
- package/dist/lib/service.js +100 -0
- package/dist/lib/service.js.map +1 -0
- package/dist/lib/source.js +44 -0
- package/dist/lib/source.js.map +1 -0
- package/dist/lib/state.js +84 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/version.js +51 -0
- package/dist/lib/version.js.map +1 -0
- package/package.json +51 -3
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { mkdir, readdir, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Args, Flags } from '@oclif/core';
|
|
4
|
+
import { runAppCli } from "../lib/app-cli.js";
|
|
5
|
+
import { switchCurrent } from "../lib/current-link.js";
|
|
6
|
+
import { buildEcosystemConfig, buildLauncher } from "../lib/ecosystem.js";
|
|
7
|
+
import { quoteForShell } from '@nocobase/cli-envelope';
|
|
8
|
+
import { buildAppEnv, endpointsOf, healthUrl, mountPathOf, readAppEnv, } from "../lib/env-file.js";
|
|
9
|
+
import { EXIT_INVALID, InstallerError } from "../lib/errors.js";
|
|
10
|
+
import { pm2StartFailed, waitForHealthy } from "../lib/health.js";
|
|
11
|
+
import { readInitialAdmin } from "../lib/initial-admin.js";
|
|
12
|
+
import { layoutOf, releaseLinkTarget } from "../lib/layout.js";
|
|
13
|
+
import { acquireLock } from "../lib/lock.js";
|
|
14
|
+
import { assertFixedMountPath, parseBasePathFlag } from "../lib/mount-path.js";
|
|
15
|
+
import { checkEnvVariables, checkPlatform, checkPm2, checkPm2NameFree, checkPortFree, checkTargetEmpty, } from "../lib/prechecks.js";
|
|
16
|
+
import { defaultRegistry, normalizeRegistry, } from "../lib/registry.js";
|
|
17
|
+
import { DIALECTS, assertStorageOutsideRelease, checkArchiveDriver, unpackRelease, } from "../lib/release.js";
|
|
18
|
+
import { runCommand } from "../lib/run-command.js";
|
|
19
|
+
import { errorLogCommandLine, errorLogTail, startAdvice, } from "../lib/service.js";
|
|
20
|
+
import { resolveArchivePath } from "../lib/source.js";
|
|
21
|
+
import { writeState } from "../lib/state.js";
|
|
22
|
+
export const INSTALL_ARGS = {
|
|
23
|
+
directory: Args.string({
|
|
24
|
+
description: 'Directory to install into. Must be new or empty. --dir names it too.',
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
export const INSTALL_FLAGS = {
|
|
28
|
+
dir: Flags.string({
|
|
29
|
+
description: 'Directory to install into, as the other commands name it; the same as the DIRECTORY argument.',
|
|
30
|
+
}),
|
|
31
|
+
archive: Flags.string({
|
|
32
|
+
description: 'Deployment archive to install, as `pnpm build --tar` writes it to storage/exports/dist.tar.gz. Build it for this machine with --target and --node-version.',
|
|
33
|
+
}),
|
|
34
|
+
origin: Flags.string({
|
|
35
|
+
description: 'Public origin the application is reached at, without its base path, e.g. https://apps.example.com. Defaults to http://HOST:PORT.',
|
|
36
|
+
}),
|
|
37
|
+
'base-path': Flags.string({
|
|
38
|
+
description: "Path the application is mounted at, e.g. /crm, or / for the origin root. Written to app.env as APP_BASE_PATH; without it the server's default applies. An archive from before relocatable builds runs only at the path it was built for.",
|
|
39
|
+
}),
|
|
40
|
+
host: Flags.string({
|
|
41
|
+
default: '127.0.0.1',
|
|
42
|
+
description: 'Address the application listens on. Keep the loopback default behind a reverse proxy.',
|
|
43
|
+
}),
|
|
44
|
+
port: Flags.integer({
|
|
45
|
+
default: 13000,
|
|
46
|
+
min: 1,
|
|
47
|
+
max: 65535,
|
|
48
|
+
description: 'Port the application listens on. It must be free; give each installation on a machine its own.',
|
|
49
|
+
}),
|
|
50
|
+
dialect: Flags.string({
|
|
51
|
+
default: 'sqlite',
|
|
52
|
+
options: [...DIALECTS],
|
|
53
|
+
description: 'Database. Anything but SQLite needs --set for its connection; an archive must carry its driver.',
|
|
54
|
+
}),
|
|
55
|
+
set: Flags.string({
|
|
56
|
+
multiple: true,
|
|
57
|
+
description: 'A config.yml setting as key=value, applied with `nocobase config set`, e.g. database.connections.main.host=db.internal. Values are YAML scalars: quote text that looks like a number or boolean, as in key=\'"0123"\'.',
|
|
58
|
+
}),
|
|
59
|
+
'set-from-env': Flags.string({
|
|
60
|
+
multiple: true,
|
|
61
|
+
description: 'A setting read from an environment variable, as key=VARIABLE, e.g. database.connections.main.password=DB_PASSWORD.',
|
|
62
|
+
}),
|
|
63
|
+
registry: Flags.string({
|
|
64
|
+
description: 'npm registry for the installer commands suggested later.',
|
|
65
|
+
}),
|
|
66
|
+
name: Flags.string({
|
|
67
|
+
description: 'pm2 process name. Defaults to nocobase- followed by the directory name, so each installation on a machine has its own.',
|
|
68
|
+
}),
|
|
69
|
+
start: Flags.boolean({
|
|
70
|
+
allowNo: true,
|
|
71
|
+
default: true,
|
|
72
|
+
description: 'Start the application with pm2 once it is installed.',
|
|
73
|
+
}),
|
|
74
|
+
'health-timeout': Flags.integer({
|
|
75
|
+
default: 180,
|
|
76
|
+
min: 1,
|
|
77
|
+
description: 'Seconds to wait for the application to answer its health check.',
|
|
78
|
+
}),
|
|
79
|
+
json: Flags.boolean({
|
|
80
|
+
default: false,
|
|
81
|
+
description: 'Print one JSON result on stdout; progress stays on stderr.',
|
|
82
|
+
}),
|
|
83
|
+
};
|
|
84
|
+
function parsePairs(values, flag) {
|
|
85
|
+
return (values ?? []).map((value) => {
|
|
86
|
+
const index = value.indexOf('=');
|
|
87
|
+
if (index <= 0 || index === value.length - 1) {
|
|
88
|
+
throw new InstallerError('INVALID_USAGE', `--${flag} expects key=value, got "${value}".`, { exitCode: EXIT_INVALID });
|
|
89
|
+
}
|
|
90
|
+
return [value.slice(0, index), value.slice(index + 1)];
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/** The sign-in line of the summary: who, and where the password is, never the password itself. */
|
|
94
|
+
function describeInitialAdmin(admin) {
|
|
95
|
+
const who = [admin.username, admin.email && `(${admin.email})`]
|
|
96
|
+
.filter(Boolean)
|
|
97
|
+
.join(' ') || 'the account';
|
|
98
|
+
const password = admin.defaultPassword === true
|
|
99
|
+
? `the default password from config.example.yml; change it after signing in`
|
|
100
|
+
: 'the password set there';
|
|
101
|
+
return `${who} under ${admin.key} in config.yml, with ${password}`;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Removes what a failed install wrote. The target was new or empty when the install began, so everything in it now
|
|
105
|
+
* came from this run. `created` is the topmost directory the install created, which may be a parent of the root.
|
|
106
|
+
*/
|
|
107
|
+
async function cleanUp(root, created) {
|
|
108
|
+
if (created) {
|
|
109
|
+
await rm(created, { recursive: true, force: true });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
for (const entry of await readdir(root).catch(() => [])) {
|
|
113
|
+
await rm(path.join(root, entry), { recursive: true, force: true });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export async function install(input, deps) {
|
|
117
|
+
const { flags } = input;
|
|
118
|
+
const { reporter, pm2 } = deps;
|
|
119
|
+
const run = deps.run ?? runCommand;
|
|
120
|
+
const cwd = deps.cwd ?? process.cwd();
|
|
121
|
+
const directory = input.directory ?? flags.dir;
|
|
122
|
+
if (directory === undefined) {
|
|
123
|
+
throw new InstallerError('INVALID_USAGE', 'Name the directory to install into, as an argument or with --dir.', { exitCode: EXIT_INVALID });
|
|
124
|
+
}
|
|
125
|
+
if (input.directory !== undefined &&
|
|
126
|
+
flags.dir !== undefined &&
|
|
127
|
+
path.resolve(cwd, input.directory) !== path.resolve(cwd, flags.dir)) {
|
|
128
|
+
throw new InstallerError('INVALID_USAGE', `The DIRECTORY argument (${input.directory}) and --dir (${flags.dir}) name different directories; give one of them.`, { exitCode: EXIT_INVALID });
|
|
129
|
+
}
|
|
130
|
+
if (flags.archive === undefined) {
|
|
131
|
+
throw new InstallerError('INVALID_USAGE', 'Name what to install: --archive with a deployment archive built by `pnpm build --tar`.', { exitCode: EXIT_INVALID });
|
|
132
|
+
}
|
|
133
|
+
const requestedBasePath = parseBasePathFlag(flags['base-path']);
|
|
134
|
+
const root = path.resolve(cwd, directory);
|
|
135
|
+
const layout = layoutOf(root);
|
|
136
|
+
const name = flags.name ?? `nocobase-${path.basename(root)}`;
|
|
137
|
+
const dialect = flags.dialect;
|
|
138
|
+
const registry = normalizeRegistry(flags.registry ?? defaultRegistry());
|
|
139
|
+
const origin = (flags.origin ?? `http://${flags.host}:${flags.port}`).replace(/\/+$/u, '');
|
|
140
|
+
const sets = parsePairs(flags.set, 'set');
|
|
141
|
+
const setsFromEnv = parsePairs(flags['set-from-env'], 'set-from-env');
|
|
142
|
+
if (!/^https?:\/\/[^/]+$/u.test(origin)) {
|
|
143
|
+
throw new InstallerError('INVALID_USAGE', `--origin must be a protocol and host without a path, such as https://apps.example.com; got "${origin}".`, { exitCode: EXIT_INVALID });
|
|
144
|
+
}
|
|
145
|
+
// Everything that can be checked is checked before the first write, so a failed precheck leaves nothing behind.
|
|
146
|
+
checkPlatform();
|
|
147
|
+
await checkTargetEmpty(root);
|
|
148
|
+
checkEnvVariables(setsFromEnv.map(([, variable]) => variable));
|
|
149
|
+
const archive = resolveArchivePath(cwd, flags.archive);
|
|
150
|
+
if (flags.start) {
|
|
151
|
+
await checkPm2(pm2);
|
|
152
|
+
await checkPm2NameFree(pm2, name);
|
|
153
|
+
}
|
|
154
|
+
await checkPortFree(flags.host, flags.port, { suggestPort: true });
|
|
155
|
+
if (!flags.origin) {
|
|
156
|
+
reporter.warn(`No --origin given; the application will build links for ${origin}. Pass --origin with the public address before exposing it.`);
|
|
157
|
+
}
|
|
158
|
+
// `mkdir` returns the first directory it created, so a failure can remove parents the install made as well.
|
|
159
|
+
const created = await mkdir(root, { recursive: true });
|
|
160
|
+
let releaseLock;
|
|
161
|
+
try {
|
|
162
|
+
releaseLock = await acquireLock(layout.lockFile);
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
if (created)
|
|
166
|
+
await rm(created, { recursive: true, force: true });
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
let switched = false;
|
|
170
|
+
try {
|
|
171
|
+
reporter.progress(`Unpacking ${archive} into ${root}`);
|
|
172
|
+
const prepared = await unpackRelease({ layout, archive });
|
|
173
|
+
checkArchiveDriver(prepared.dir, dialect);
|
|
174
|
+
reporter.progress(`Installing ${prepared.appName} ${prepared.version} (${prepared.id})`);
|
|
175
|
+
// A relocatable release is mounted where the installation says, or at the server's default. An earlier release
|
|
176
|
+
// runs only at the path its client was compiled for.
|
|
177
|
+
let mountPath;
|
|
178
|
+
if (prepared.relocatable) {
|
|
179
|
+
mountPath = requestedBasePath;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
mountPath = prepared.basePath;
|
|
183
|
+
if (requestedBasePath !== undefined) {
|
|
184
|
+
assertFixedMountPath(`${prepared.appName} ${prepared.version}`, mountPath, requestedBasePath);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
await writeFile(layout.appEnv, buildAppEnv(layout, {
|
|
188
|
+
origin,
|
|
189
|
+
host: flags.host,
|
|
190
|
+
port: flags.port,
|
|
191
|
+
basePath: mountPath,
|
|
192
|
+
}));
|
|
193
|
+
const env = await readAppEnv(layout);
|
|
194
|
+
const cli = { releaseDir: prepared.dir, cwd: root, env, run };
|
|
195
|
+
reporter.progress('Writing config.yml');
|
|
196
|
+
await runAppCli(['config', 'init', '--config', layout.configFile, '--dialect', dialect], cli);
|
|
197
|
+
if (sets.length > 0) {
|
|
198
|
+
await runAppCli(['config', 'set', ...sets.map(([key, value]) => `${key}=${value}`)], cli);
|
|
199
|
+
}
|
|
200
|
+
for (const [key, variable] of setsFromEnv) {
|
|
201
|
+
await runAppCli(['config', 'set', '--from-env', `${key}=${variable}`], cli);
|
|
202
|
+
}
|
|
203
|
+
await runAppCli(['config', 'check'], cli);
|
|
204
|
+
reporter.progress('Applying database migrations');
|
|
205
|
+
await runAppCli(['db', 'apply'], cli);
|
|
206
|
+
assertStorageOutsideRelease(prepared.dir);
|
|
207
|
+
// Everything else the root needs is written first: the switch is the last write before starting, so a failure
|
|
208
|
+
// anywhere up to it leaves nothing half-installed for status and install to disagree about.
|
|
209
|
+
await mkdir(layout.logsDir, { recursive: true });
|
|
210
|
+
await writeFile(layout.ecosystemFile, buildEcosystemConfig({ name, nodePath: process.execPath }));
|
|
211
|
+
await writeFile(layout.launcherFile, buildLauncher());
|
|
212
|
+
const at = new Date().toISOString();
|
|
213
|
+
const state = {
|
|
214
|
+
schemaVersion: 1,
|
|
215
|
+
appName: prepared.appName,
|
|
216
|
+
basePath: mountPathOf(env) || '/',
|
|
217
|
+
source: { kind: 'archive' },
|
|
218
|
+
name,
|
|
219
|
+
registry,
|
|
220
|
+
dialect,
|
|
221
|
+
current: prepared.id,
|
|
222
|
+
releases: [
|
|
223
|
+
{
|
|
224
|
+
id: prepared.id,
|
|
225
|
+
version: prepared.version,
|
|
226
|
+
builtAt: prepared.builtAt,
|
|
227
|
+
installedAt: at,
|
|
228
|
+
buildTarget: prepared.buildTarget,
|
|
229
|
+
...(prepared.relocatable
|
|
230
|
+
? { relocatable: true }
|
|
231
|
+
: { basePath: prepared.basePath }),
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
history: [{ action: 'install', to: prepared.id, at }],
|
|
235
|
+
};
|
|
236
|
+
await writeState(layout, state);
|
|
237
|
+
await switchCurrent(layout, releaseLinkTarget(prepared.id));
|
|
238
|
+
switched = true;
|
|
239
|
+
const url = healthUrl(env);
|
|
240
|
+
if (flags.start) {
|
|
241
|
+
reporter.progress('Starting the application with pm2');
|
|
242
|
+
await pm2.start(layout.ecosystemFile, root);
|
|
243
|
+
const healthy = await waitForHealthy(url, {
|
|
244
|
+
timeoutMs: flags['health-timeout'] * 1000,
|
|
245
|
+
fetchImpl: deps.fetchImpl,
|
|
246
|
+
failed: pm2StartFailed(pm2, name),
|
|
247
|
+
});
|
|
248
|
+
if (!healthy) {
|
|
249
|
+
// The name was free before this install, so the process under it is the one just started.
|
|
250
|
+
await pm2.remove(name).catch(() => undefined);
|
|
251
|
+
throw new InstallerError('START_FAILED', `The application did not become healthy at ${url} (waited up to ${flags['health-timeout']}s). It is installed but not running.`, {
|
|
252
|
+
details: { log: await errorLogTail(layout) },
|
|
253
|
+
suggestions: [
|
|
254
|
+
{
|
|
255
|
+
message: 'Read the error log:',
|
|
256
|
+
run: errorLogCommandLine(layout),
|
|
257
|
+
},
|
|
258
|
+
...startAdvice(layout, 'Start it again once fixed:'),
|
|
259
|
+
],
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
await pm2.save();
|
|
263
|
+
}
|
|
264
|
+
const endpoints = endpointsOf(env);
|
|
265
|
+
const initialAdmin = await readInitialAdmin(layout.configFile, path.join(prepared.dir, 'config.example.yml'));
|
|
266
|
+
// `nextCommands` are lines for a shell, as the application CLI's are, so one may chain two commands.
|
|
267
|
+
const startCommand = `pm2 start ${quoteForShell(layout.ecosystemFile)} && pm2 save`;
|
|
268
|
+
const nextCommands = [
|
|
269
|
+
...(flags.start ? [] : [startCommand]),
|
|
270
|
+
'pm2 startup',
|
|
271
|
+
];
|
|
272
|
+
return {
|
|
273
|
+
status: 'success',
|
|
274
|
+
result: {
|
|
275
|
+
directory: root,
|
|
276
|
+
version: prepared.version,
|
|
277
|
+
releaseId: prepared.id,
|
|
278
|
+
builtAt: prepared.builtAt,
|
|
279
|
+
release: prepared.dir,
|
|
280
|
+
appName: prepared.appName,
|
|
281
|
+
basePath: mountPathOf(env) || '/',
|
|
282
|
+
dialect,
|
|
283
|
+
url: endpoints.url,
|
|
284
|
+
endpoints,
|
|
285
|
+
healthUrl: url,
|
|
286
|
+
name,
|
|
287
|
+
started: flags.start,
|
|
288
|
+
configFile: layout.configFile,
|
|
289
|
+
storageDir: layout.storageDir,
|
|
290
|
+
initialAdmin,
|
|
291
|
+
nextCommands,
|
|
292
|
+
},
|
|
293
|
+
summary: [
|
|
294
|
+
`${prepared.appName} ${prepared.version} is installed at ${root}${flags.start ? ' and running' : ''}.`,
|
|
295
|
+
` URL ${endpoints.url}`,
|
|
296
|
+
` Release ${prepared.id}`,
|
|
297
|
+
` Sign in ${describeInitialAdmin(initialAdmin)}`,
|
|
298
|
+
` Logs pm2 logs ${name}`,
|
|
299
|
+
'Next steps',
|
|
300
|
+
...(flags.start ? [] : [` Start it: ${startCommand}`]),
|
|
301
|
+
' Start pm2 at boot: run `pm2 startup` and execute the command it prints (needs sudo).',
|
|
302
|
+
` Proxy ${origin} to http://${flags.host}:${flags.port} with location /.`,
|
|
303
|
+
],
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
// Before the switch nothing is in use yet, so a retry should find the target as empty as it was.
|
|
308
|
+
// After it, the release, configuration and data are real and stay.
|
|
309
|
+
if (!switched) {
|
|
310
|
+
await releaseLock();
|
|
311
|
+
await cleanUp(root, created);
|
|
312
|
+
}
|
|
313
|
+
throw error;
|
|
314
|
+
}
|
|
315
|
+
finally {
|
|
316
|
+
await releaseLock();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { backupHasDatabase, restoreDatabase } from "../lib/backup.js";
|
|
5
|
+
import { confirm } from "../lib/confirm.js";
|
|
6
|
+
import { switchCurrent } from "../lib/current-link.js";
|
|
7
|
+
import { healthUrl, mountPathOf, readAppEnv } from "../lib/env-file.js";
|
|
8
|
+
import { assertFixedMountPath } from "../lib/mount-path.js";
|
|
9
|
+
import { EXIT_FAILED, EXIT_INVALID, EXIT_ROLLBACK_FAILED, InstallerError, } from "../lib/errors.js";
|
|
10
|
+
import { layoutOf, releaseDir, releaseLinkTarget } from "../lib/layout.js";
|
|
11
|
+
import { installerCommandLine } from "../lib/invocation.js";
|
|
12
|
+
import { acquireLock } from "../lib/lock.js";
|
|
13
|
+
import { checkPlatform, checkPm2, currentNodeMajor } from "../lib/prechecks.js";
|
|
14
|
+
import { checkPm2Ownership, errorLogCommandLine, errorLogTail, startApp, stopApp, } from "../lib/service.js";
|
|
15
|
+
import { nodeRebuildAdvice } from "../lib/source.js";
|
|
16
|
+
import { fixedMountPathOf, readState, resolveReleaseRef, writeState, } from "../lib/state.js";
|
|
17
|
+
export const ROLLBACK_FLAGS = {
|
|
18
|
+
dir: Flags.string({
|
|
19
|
+
description: 'Installation root managed by app-installer. Defaults to the current directory.',
|
|
20
|
+
}),
|
|
21
|
+
to: Flags.string({
|
|
22
|
+
description: 'Release to return to, by id or version (the newest build of it). Defaults to the one the last upgrade came from.',
|
|
23
|
+
}),
|
|
24
|
+
restore: Flags.boolean({
|
|
25
|
+
allowNo: true,
|
|
26
|
+
default: true,
|
|
27
|
+
description: 'Restore the SQLite databases backed up before the upgrade, when that upgrade migrated them.',
|
|
28
|
+
}),
|
|
29
|
+
'health-timeout': Flags.integer({
|
|
30
|
+
default: 180,
|
|
31
|
+
min: 1,
|
|
32
|
+
description: 'Seconds to wait for the release to answer its health check.',
|
|
33
|
+
}),
|
|
34
|
+
yes: Flags.boolean({
|
|
35
|
+
default: false,
|
|
36
|
+
description: 'Proceed without asking for confirmation.',
|
|
37
|
+
}),
|
|
38
|
+
json: Flags.boolean({
|
|
39
|
+
default: false,
|
|
40
|
+
description: 'Print one JSON result on stdout; progress stays on stderr.',
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
function lastUpgrade(history, matches) {
|
|
44
|
+
for (let index = history.length - 1; index >= 0; index -= 1) {
|
|
45
|
+
const entry = history[index];
|
|
46
|
+
if (entry.action === 'upgrade' &&
|
|
47
|
+
entry.outcome !== 'rolled-back' &&
|
|
48
|
+
matches(entry)) {
|
|
49
|
+
return entry;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The id of the release to return to: the interrupted operation's origin, else where the last completed upgrade came
|
|
56
|
+
* from.
|
|
57
|
+
*/
|
|
58
|
+
export function defaultRollbackTarget(state) {
|
|
59
|
+
// An interrupted upgrade is undone; an interrupted rollback is finished.
|
|
60
|
+
if (state.pending) {
|
|
61
|
+
return state.pending.action === 'upgrade'
|
|
62
|
+
? state.pending.from
|
|
63
|
+
: state.pending.to;
|
|
64
|
+
}
|
|
65
|
+
return lastUpgrade(state.history, (entry) => entry.to === state.current)
|
|
66
|
+
?.from;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The backup that holds the databases as they were on `target`, and whether they need restoring: only when the upgrade
|
|
70
|
+
* away from `target` applied migrations.
|
|
71
|
+
*
|
|
72
|
+
* An interrupted upgrade may have migrated once it moved `current`, and how far it got is unknown, so it counts as
|
|
73
|
+
* migrated from then on; before that it had only stopped the application. An interrupted rollback restores what it set
|
|
74
|
+
* out to.
|
|
75
|
+
*/
|
|
76
|
+
export function backupFor(state, target) {
|
|
77
|
+
const pending = state.pending;
|
|
78
|
+
if (pending?.action === 'upgrade' && pending.from === target) {
|
|
79
|
+
return { backup: pending.backup, migrated: pending.switched === true };
|
|
80
|
+
}
|
|
81
|
+
if (pending?.action === 'rollback' && pending.to === target) {
|
|
82
|
+
return {
|
|
83
|
+
backup: pending.restoreFrom,
|
|
84
|
+
migrated: pending.restoreFrom !== undefined,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const upgrade = lastUpgrade(state.history, (entry) => entry.from === target && entry.to === state.current);
|
|
88
|
+
return {
|
|
89
|
+
backup: upgrade?.backup,
|
|
90
|
+
migrated: (upgrade?.migrations ?? 0) > 0,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export async function rollback(input, deps) {
|
|
94
|
+
const { flags } = input;
|
|
95
|
+
const { reporter, pm2 } = deps;
|
|
96
|
+
const root = path.resolve(deps.cwd ?? process.cwd(), flags.dir ?? '.');
|
|
97
|
+
const layout = layoutOf(root);
|
|
98
|
+
const releaseLock = await acquireLock(layout.lockFile);
|
|
99
|
+
try {
|
|
100
|
+
// Read under the lock: a run that waited on it must see what the previous one wrote.
|
|
101
|
+
const state = await readState(layout);
|
|
102
|
+
checkPlatform();
|
|
103
|
+
const from = state.current;
|
|
104
|
+
const interrupted = state.pending;
|
|
105
|
+
const requested = flags.to ?? defaultRollbackTarget(state);
|
|
106
|
+
if (requested === undefined) {
|
|
107
|
+
throw new InstallerError('NOTHING_TO_ROLL_BACK', `No upgrade led to ${from}, so there is no earlier release to return to.`, {
|
|
108
|
+
exitCode: EXIT_INVALID,
|
|
109
|
+
suggestions: [
|
|
110
|
+
{ message: 'Name a release on disk with --to; status lists them.' },
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const record = resolveReleaseRef(state, requested);
|
|
115
|
+
const target = record?.id ?? requested;
|
|
116
|
+
if (target === from && !interrupted) {
|
|
117
|
+
return {
|
|
118
|
+
status: 'success-noop',
|
|
119
|
+
result: { directory: root, current: from, rolledBack: false },
|
|
120
|
+
summary: [`The application is already on ${from}.`],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (!record || !existsSync(releaseDir(layout, record.id))) {
|
|
124
|
+
throw new InstallerError('RELEASE_MISSING', `${requested} is not on disk; only releases app-installer kept can be returned to.`, {
|
|
125
|
+
exitCode: EXIT_INVALID,
|
|
126
|
+
suggestions: [{ message: 'status lists the releases on disk.' }],
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const machineMajor = currentNodeMajor();
|
|
130
|
+
if (record.buildTarget.nodeMajor !== machineMajor) {
|
|
131
|
+
throw new InstallerError('NODE_MISMATCH', `${target} was built for Node ${record.buildTarget.nodeMajor}, but this machine runs Node ${machineMajor}; its native modules would not load.`, {
|
|
132
|
+
exitCode: EXIT_INVALID,
|
|
133
|
+
suggestions: nodeRebuildAdvice(state, root),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const env = await readAppEnv(layout);
|
|
137
|
+
// A release built before relocatable builds runs only at the path it was built for, which app.env may have moved
|
|
138
|
+
// away from since.
|
|
139
|
+
const fixedMountPath = fixedMountPathOf(record, state);
|
|
140
|
+
if (fixedMountPath !== undefined) {
|
|
141
|
+
assertFixedMountPath(target, fixedMountPath, mountPathOf(env));
|
|
142
|
+
}
|
|
143
|
+
const service = {
|
|
144
|
+
layout,
|
|
145
|
+
pm2,
|
|
146
|
+
name: state.name,
|
|
147
|
+
healthUrl: healthUrl(env),
|
|
148
|
+
fetchImpl: deps.fetchImpl,
|
|
149
|
+
};
|
|
150
|
+
await checkPm2(pm2);
|
|
151
|
+
await checkPm2Ownership(service);
|
|
152
|
+
// Restore only from a backup that actually holds the database: an external database is never in one, and an
|
|
153
|
+
// upgrade interrupted before its copy finished never records one.
|
|
154
|
+
const { backup, migrated } = backupFor(state, target);
|
|
155
|
+
const restoreFrom = flags.restore &&
|
|
156
|
+
migrated &&
|
|
157
|
+
backup !== undefined &&
|
|
158
|
+
backupHasDatabase(layout, backup)
|
|
159
|
+
? backup
|
|
160
|
+
: undefined;
|
|
161
|
+
if (flags.restore && migrated && restoreFrom === undefined) {
|
|
162
|
+
reporter.warn(`The databases may have been migrated past ${target}, and app-installer holds no copy of them from before (an external database, or a backup that was cut short). Restore them from your own backup if ${target} misbehaves.`);
|
|
163
|
+
}
|
|
164
|
+
await confirm([
|
|
165
|
+
`Roll the application at ${root} back from ${from} to ${target}.`,
|
|
166
|
+
'The application stops while the release switches.',
|
|
167
|
+
restoreFrom
|
|
168
|
+
? `The SQLite databases are restored from ${restoreFrom}: whatever was written since that upgrade is lost.`
|
|
169
|
+
: 'The databases are left as they are; rolling back does not undo migrations.',
|
|
170
|
+
], { yes: flags.yes, json: flags.json });
|
|
171
|
+
state.pending = {
|
|
172
|
+
action: 'rollback',
|
|
173
|
+
from,
|
|
174
|
+
to: target,
|
|
175
|
+
startedAt: new Date().toISOString(),
|
|
176
|
+
...(restoreFrom ? { restoreFrom } : {}),
|
|
177
|
+
};
|
|
178
|
+
await writeState(layout, state);
|
|
179
|
+
reporter.progress(`Stopping ${from}`);
|
|
180
|
+
try {
|
|
181
|
+
await stopApp(service);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
// Nothing was restored or switched: put back what was pending before this run, if anything.
|
|
185
|
+
if (interrupted)
|
|
186
|
+
state.pending = interrupted;
|
|
187
|
+
else
|
|
188
|
+
delete state.pending;
|
|
189
|
+
await writeState(layout, state);
|
|
190
|
+
throw new InstallerError('ROLLBACK_ABORTED', `Stopping ${from} failed: ${error instanceof Error ? error.message : String(error)}. Nothing was restored or switched.`, { exitCode: EXIT_FAILED, cause: error });
|
|
191
|
+
}
|
|
192
|
+
let restored = false;
|
|
193
|
+
let switched = false;
|
|
194
|
+
let healthy = false;
|
|
195
|
+
let failure;
|
|
196
|
+
try {
|
|
197
|
+
if (restoreFrom) {
|
|
198
|
+
reporter.progress(`Restoring the databases from ${restoreFrom}`);
|
|
199
|
+
await restoreDatabase(layout, restoreFrom);
|
|
200
|
+
restored = true;
|
|
201
|
+
}
|
|
202
|
+
await switchCurrent(layout, releaseLinkTarget(target));
|
|
203
|
+
switched = true;
|
|
204
|
+
// The link and installer.json agree from here, whatever happens next.
|
|
205
|
+
state.current = target;
|
|
206
|
+
await writeState(layout, state);
|
|
207
|
+
reporter.progress(`Starting ${target}`);
|
|
208
|
+
healthy = await startApp({
|
|
209
|
+
...service,
|
|
210
|
+
timeoutMs: flags['health-timeout'] * 1000,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
failure = error;
|
|
215
|
+
}
|
|
216
|
+
if (!healthy) {
|
|
217
|
+
// The rollback stays pending, so running it again retries it — restore included — once the cause is fixed.
|
|
218
|
+
await writeState(layout, state);
|
|
219
|
+
const reason = failure instanceof Error ? ` (${failure.message})` : '';
|
|
220
|
+
throw new InstallerError('ROLLBACK_FAILED', switched
|
|
221
|
+
? `${target} did not come back${reason}. The application is down.`
|
|
222
|
+
: `${restoreFrom && !restored ? 'Restoring the databases' : 'Switching to ' + target} failed${reason}; the application is stopped and still on ${from}.`, {
|
|
223
|
+
exitCode: EXIT_ROLLBACK_FAILED,
|
|
224
|
+
details: {
|
|
225
|
+
log: await errorLogTail(layout),
|
|
226
|
+
databaseRestored: restored,
|
|
227
|
+
},
|
|
228
|
+
suggestions: [
|
|
229
|
+
{
|
|
230
|
+
message: 'Read the error log:',
|
|
231
|
+
run: errorLogCommandLine(layout),
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
message: 'Once the cause is fixed, run the rollback again:',
|
|
235
|
+
run: installerCommandLine(['rollback', '--dir', root], {
|
|
236
|
+
registry: state.registry,
|
|
237
|
+
}),
|
|
238
|
+
},
|
|
239
|
+
...(switched
|
|
240
|
+
? [
|
|
241
|
+
{
|
|
242
|
+
message: `Or go back to ${from}:`,
|
|
243
|
+
run: installerCommandLine(['rollback', '--dir', root, '--to', from, '--no-restore'], { registry: state.registry }),
|
|
244
|
+
},
|
|
245
|
+
]
|
|
246
|
+
: []),
|
|
247
|
+
],
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
delete state.pending;
|
|
251
|
+
state.history.push({
|
|
252
|
+
action: 'rollback',
|
|
253
|
+
from,
|
|
254
|
+
to: target,
|
|
255
|
+
at: new Date().toISOString(),
|
|
256
|
+
databaseRestored: restored,
|
|
257
|
+
});
|
|
258
|
+
await writeState(layout, state);
|
|
259
|
+
return {
|
|
260
|
+
status: 'success',
|
|
261
|
+
result: {
|
|
262
|
+
directory: root,
|
|
263
|
+
from,
|
|
264
|
+
to: target,
|
|
265
|
+
rolledBack: true,
|
|
266
|
+
recovered: interrupted ? interrupted.action : null,
|
|
267
|
+
databaseRestored: restored,
|
|
268
|
+
backup: restoreFrom ?? null,
|
|
269
|
+
},
|
|
270
|
+
summary: [
|
|
271
|
+
interrupted
|
|
272
|
+
? `Recovered from the interrupted ${interrupted.action} (${interrupted.from} to ${interrupted.to}); the application runs ${target}.`
|
|
273
|
+
: `Rolled the application back from ${from} to ${target}.`,
|
|
274
|
+
restored
|
|
275
|
+
? ` Databases restored from ${restoreFrom}`
|
|
276
|
+
: ' Databases left as they were',
|
|
277
|
+
],
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
finally {
|
|
281
|
+
await releaseLock();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=rollback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/commands/rollback.ts"],"names":[],"mappings":"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"}
|