@jacebenson/jsn 4.3.7-dev.27 → 4.3.7-dev.29
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/package.json +1 -1
- package/src/commands/midservers.js +74 -10
- package/src/midserver-install.js +5 -4
package/package.json
CHANGED
|
@@ -195,12 +195,14 @@ async function waitForMidServerUp(app, name, timeoutMs, intervalMs) {
|
|
|
195
195
|
function removeLocalMidServer(instanceURL, name) {
|
|
196
196
|
const installDir = midInstallDirectory(instanceURL, name);
|
|
197
197
|
const composePath = path.join(installDir, 'docker-compose.yaml');
|
|
198
|
+
const envPath = path.join(installDir, '.env');
|
|
198
199
|
if (!fs.existsSync(composePath)) return false;
|
|
200
|
+
const composeArgs = ['compose', ...(fs.existsSync(envPath) ? ['--env-file', envPath] : []), '-f', composePath, 'down'];
|
|
199
201
|
try {
|
|
200
|
-
defaultRun('docker',
|
|
202
|
+
defaultRun('docker', composeArgs, { cwd: installDir });
|
|
201
203
|
} catch {
|
|
202
204
|
defaultRun('sudo', ['systemctl', 'start', 'docker']);
|
|
203
|
-
defaultRun('sudo', ['docker',
|
|
205
|
+
defaultRun('sudo', ['docker', ...composeArgs], { cwd: installDir });
|
|
204
206
|
}
|
|
205
207
|
try {
|
|
206
208
|
fs.rmSync(installDir, { recursive: true, force: true });
|
|
@@ -210,6 +212,21 @@ function removeLocalMidServer(instanceURL, name) {
|
|
|
210
212
|
return true;
|
|
211
213
|
}
|
|
212
214
|
|
|
215
|
+
function showMidServerLogs(app, identifier, argv) {
|
|
216
|
+
const installDir = midInstallDirectory(app.getEffectiveInstance(), identifier);
|
|
217
|
+
const composePath = path.join(installDir, 'docker-compose.yaml');
|
|
218
|
+
const envPath = path.join(installDir, '.env');
|
|
219
|
+
if (!fs.existsSync(composePath)) throw new Error(`No local Compose installation found for MID Server '${identifier}'`);
|
|
220
|
+
const args = ['compose', ...(fs.existsSync(envPath) ? ['--env-file', envPath] : []), '-f', composePath, 'logs', '--tail', String(argv.tail)];
|
|
221
|
+
if (argv.follow) args.push('--follow');
|
|
222
|
+
try {
|
|
223
|
+
defaultRun('docker', args, { cwd: installDir });
|
|
224
|
+
} catch {
|
|
225
|
+
defaultRun('sudo', ['systemctl', 'start', 'docker']);
|
|
226
|
+
defaultRun('sudo', ['docker', ...args], { cwd: installDir });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
213
230
|
export function midserversCmd(wrap) {
|
|
214
231
|
return {
|
|
215
232
|
command: 'midservers [subcommand]',
|
|
@@ -238,6 +255,26 @@ export function midserversCmd(wrap) {
|
|
|
238
255
|
app.ok(record, { summary: `MID Server: ${getStringField(record, 'name') || argv.identifier}` });
|
|
239
256
|
}),
|
|
240
257
|
})
|
|
258
|
+
.command({
|
|
259
|
+
command: 'logs <identifier>',
|
|
260
|
+
describe: 'Show local Docker Compose logs for a MID Server',
|
|
261
|
+
builder: (b) => b
|
|
262
|
+
.option('tail', { type: 'number', default: 100, describe: 'Number of log lines' })
|
|
263
|
+
.option('follow', { type: 'boolean', default: false, describe: 'Follow the logs' }),
|
|
264
|
+
handler: wrap(async (argv, app) => {
|
|
265
|
+
showMidServerLogs(app, argv.identifier, argv);
|
|
266
|
+
}),
|
|
267
|
+
})
|
|
268
|
+
.command({
|
|
269
|
+
command: '<identifier> logs',
|
|
270
|
+
describe: 'Show local Docker Compose logs for a MID Server',
|
|
271
|
+
builder: (b) => b
|
|
272
|
+
.option('tail', { type: 'number', default: 100, describe: 'Number of log lines' })
|
|
273
|
+
.option('follow', { type: 'boolean', default: false, describe: 'Follow the logs' }),
|
|
274
|
+
handler: wrap(async (argv, app) => {
|
|
275
|
+
showMidServerLogs(app, argv.identifier, argv);
|
|
276
|
+
}),
|
|
277
|
+
})
|
|
241
278
|
.command({
|
|
242
279
|
command: 'add',
|
|
243
280
|
describe: 'Install and verify a MID Server',
|
|
@@ -246,7 +283,7 @@ export function midserversCmd(wrap) {
|
|
|
246
283
|
.option('username', { type: 'string', describe: 'MID Server username (password is always prompted)' })
|
|
247
284
|
.option('install-method', { type: 'string', choices: ['docker', 'direct'], describe: 'Installation method (prompted when omitted)' })
|
|
248
285
|
.option('directory', { type: 'string', describe: 'Docker installation directory' })
|
|
249
|
-
.option('wait-timeout', { type: 'number', default:
|
|
286
|
+
.option('wait-timeout', { type: 'number', default: 300000, describe: 'How long to wait for the MID Server to report Up' })
|
|
250
287
|
.option('wait-interval', { type: 'number', default: 3000, describe: 'MID Server status polling interval in milliseconds' }),
|
|
251
288
|
handler: wrap(async (argv, app) => {
|
|
252
289
|
app.requireInstance();
|
|
@@ -292,13 +329,14 @@ export function midserversCmd(wrap) {
|
|
|
292
329
|
});
|
|
293
330
|
if (installMethod === 'sudo') {
|
|
294
331
|
defaultRun('sudo', ['systemctl', 'start', 'docker']);
|
|
295
|
-
defaultRun('sudo', ['docker', 'compose', '-f', installation.composePath, 'up', '-d'], { cwd: installation.installDir });
|
|
332
|
+
defaultRun('sudo', ['docker', 'compose', '--env-file', path.join(installation.installDir, '.env'), '-f', installation.composePath, 'up', '-d'], { cwd: installation.installDir });
|
|
296
333
|
installation.prepared = false;
|
|
297
334
|
}
|
|
298
335
|
if (installation.prepared) {
|
|
299
336
|
app.ok(installation, { summary: `Prepared MID Server files in ${installation.installDir}. Run: ${installation.runCommand}` });
|
|
300
337
|
return;
|
|
301
338
|
}
|
|
339
|
+
console.log('MID Server container started. ServiceNow may take a few minutes to register it and report Up.');
|
|
302
340
|
let record;
|
|
303
341
|
try {
|
|
304
342
|
record = await waitForMidServerUp(app, installation.name, Math.max(1, argv['wait-timeout']), Math.max(500, argv['wait-interval']));
|
|
@@ -359,22 +397,48 @@ export function midserversCmd(wrap) {
|
|
|
359
397
|
}),
|
|
360
398
|
})
|
|
361
399
|
.command({
|
|
362
|
-
command: 'execute
|
|
400
|
+
command: 'execute [identifier]',
|
|
363
401
|
describe: 'Execute a shell command through a MID Server',
|
|
364
402
|
builder: (b) => b
|
|
365
|
-
.option('command', { alias: 'c', type: 'string',
|
|
403
|
+
.option('command', { alias: 'c', type: 'string', describe: 'Command line to execute on the MID Server host' })
|
|
366
404
|
.option('timeout', { type: 'number', default: DEFAULT_TIMEOUT, describe: 'Response timeout in milliseconds' })
|
|
367
405
|
.option('interval', { type: 'number', default: DEFAULT_INTERVAL, describe: 'Polling interval in milliseconds' }),
|
|
368
406
|
handler: wrap(async (argv, app) => {
|
|
369
|
-
|
|
407
|
+
let record;
|
|
408
|
+
if (argv.identifier) {
|
|
409
|
+
record = await resolveMidServer(app.sdk, argv.identifier);
|
|
410
|
+
} else {
|
|
411
|
+
if (!canPrompt() || app.output.getFormat() !== FormatAuto) {
|
|
412
|
+
throw new Error('An identifier and --command are required outside an interactive terminal');
|
|
413
|
+
}
|
|
414
|
+
record = await interactiveList({
|
|
415
|
+
app,
|
|
416
|
+
table: AGENT_TABLE,
|
|
417
|
+
singular: 'MID Server',
|
|
418
|
+
columns: LIST_FIELDS,
|
|
419
|
+
limit: 50,
|
|
420
|
+
labelField: 'name',
|
|
421
|
+
message: 'Select a MID Server to execute on',
|
|
422
|
+
formatLabel: (candidate) => {
|
|
423
|
+
const name = getStringField(candidate, 'name') || getStringField(candidate, 'sys_id');
|
|
424
|
+
const status = getStringField(candidate, 'status');
|
|
425
|
+
return status ? `${name} [${status}]` : name;
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
if (!record) return;
|
|
429
|
+
}
|
|
430
|
+
const command = argv.command || await input({
|
|
431
|
+
message: 'Command to execute:',
|
|
432
|
+
validate: value => value.trim() ? true : 'Command is required',
|
|
433
|
+
});
|
|
370
434
|
assertMidServerUp(record);
|
|
371
435
|
const agent = agentName(record);
|
|
372
436
|
const output = await app.sdk.create(QUEUE_TABLE, {
|
|
373
437
|
agent,
|
|
374
438
|
topic: 'Command',
|
|
375
439
|
queue: 'output',
|
|
376
|
-
name:
|
|
377
|
-
payload: buildCommandPayload(
|
|
440
|
+
name: command,
|
|
441
|
+
payload: buildCommandPayload(command),
|
|
378
442
|
});
|
|
379
443
|
const outputSysId = unwrapSysId(output);
|
|
380
444
|
if (!outputSysId) throw new Error('ServiceNow did not return the ECC Queue sys_id for the command');
|
|
@@ -384,7 +448,7 @@ export function midserversCmd(wrap) {
|
|
|
384
448
|
const result = parseCommandResult(queueValue(response.payload));
|
|
385
449
|
app.ok({
|
|
386
450
|
mid_server: getStringField(record, 'name'),
|
|
387
|
-
command
|
|
451
|
+
command,
|
|
388
452
|
output: { sys_id: outputSysId, ...output },
|
|
389
453
|
response: { ...response, ...result },
|
|
390
454
|
}, { summary: `Executed command on MID Server '${getStringField(record, 'name')}'` });
|
package/src/midserver-install.js
CHANGED
|
@@ -114,7 +114,8 @@ export async function installDockerMidServer({
|
|
|
114
114
|
const installDir = directory || midInstallDirectory(instanceURL, name);
|
|
115
115
|
fs.mkdirSync(installDir, { recursive: true, mode: 0o700 });
|
|
116
116
|
const exportDir = path.join(installDir, 'export');
|
|
117
|
-
fs.mkdirSync(exportDir, { recursive: true, mode:
|
|
117
|
+
fs.mkdirSync(exportDir, { recursive: true, mode: 0o777 });
|
|
118
|
+
fs.chmodSync(exportDir, 0o777);
|
|
118
119
|
const workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'jsn-mid-'));
|
|
119
120
|
const filename = path.basename(recipeURL);
|
|
120
121
|
const archive = path.join(workDir, filename);
|
|
@@ -148,18 +149,18 @@ export async function installDockerMidServer({
|
|
|
148
149
|
composePath,
|
|
149
150
|
serviceName,
|
|
150
151
|
prepared: true,
|
|
151
|
-
runCommand: `docker compose -f ${composePath} up -d`,
|
|
152
|
+
runCommand: `docker compose --env-file ${envPath} -f ${composePath} up -d`,
|
|
152
153
|
};
|
|
153
154
|
}
|
|
154
155
|
run('docker', ['build', '--tag', `${serviceName}:${releaseName}`, persistedRecipeDir]);
|
|
155
|
-
run('docker', ['compose', '-f', composePath, 'up', '-d'], { cwd: installDir, env });
|
|
156
|
+
run('docker', ['compose', '--env-file', envPath, '-f', composePath, 'up', '-d'], { cwd: installDir, env });
|
|
156
157
|
return {
|
|
157
158
|
name: displayName,
|
|
158
159
|
releaseName,
|
|
159
160
|
installDir,
|
|
160
161
|
composePath,
|
|
161
162
|
serviceName,
|
|
162
|
-
rollback: () => run('docker', ['compose', '-f', composePath, 'down'], { cwd: installDir, env }),
|
|
163
|
+
rollback: () => run('docker', ['compose', '--env-file', envPath, '-f', composePath, 'down'], { cwd: installDir, env }),
|
|
163
164
|
};
|
|
164
165
|
} finally {
|
|
165
166
|
fs.rmSync(workDir, { recursive: true, force: true });
|