@jacebenson/jsn 4.3.7-dev.27 → 4.3.7-dev.28

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jacebenson/jsn",
3
- "version": "4.3.7-dev.27",
3
+ "version": "4.3.7-dev.28",
4
4
  "description": "A command-line interface for ServiceNow that follows the Unix philosophy: simple, composable, and scriptable.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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', ['compose', '-f', composePath, 'down'], { cwd: installDir });
202
+ defaultRun('docker', composeArgs, { cwd: installDir });
201
203
  } catch {
202
204
  defaultRun('sudo', ['systemctl', 'start', 'docker']);
203
- defaultRun('sudo', ['docker', 'compose', '-f', composePath, 'down'], { cwd: installDir });
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: 120000, describe: 'How long to wait for the MID Server to report Up' })
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']));
@@ -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: 0o700 });
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 });