@jacebenson/jsn 4.3.7-dev.23 → 4.3.7-dev.25
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
|
@@ -250,17 +250,15 @@ export function midserversCmd(wrap) {
|
|
|
250
250
|
]
|
|
251
251
|
: dockerStatus.installed && dockerStatus.compose
|
|
252
252
|
? [
|
|
253
|
-
{ name: '
|
|
253
|
+
{ name: 'Prepare files now, run Docker later', value: 'prepare' },
|
|
254
254
|
{ name: 'Direct install (not available yet)', value: 'direct' },
|
|
255
255
|
]
|
|
256
256
|
: [
|
|
257
|
-
{ name: '
|
|
257
|
+
{ name: 'Prepare files now, run Docker later', value: 'prepare' },
|
|
258
258
|
{ name: 'Direct install (not available yet)', value: 'direct' },
|
|
259
259
|
],
|
|
260
260
|
});
|
|
261
261
|
if (installMethod === 'direct') throw new Error('Direct MID Server installation is not implemented yet. Choose Docker.');
|
|
262
|
-
if (installMethod === 'docker-unavailable') throw new Error('Docker is installed, but this user cannot access the Docker daemon. Start Docker and grant this user access to /var/run/docker.sock, then run this command again.');
|
|
263
|
-
if (installMethod === 'install-docker') throw new Error('Automatic Docker installation is not implemented yet. Install Docker and Compose, then run this command again.');
|
|
264
262
|
|
|
265
263
|
const installation = await installDockerMidServer({
|
|
266
264
|
instanceURL: app.getEffectiveInstance(),
|
|
@@ -269,7 +267,12 @@ export function midserversCmd(wrap) {
|
|
|
269
267
|
name,
|
|
270
268
|
releaseName: credentials.releaseName,
|
|
271
269
|
directory: argv.directory,
|
|
270
|
+
runNow: installMethod !== 'prepare',
|
|
272
271
|
});
|
|
272
|
+
if (installation.prepared) {
|
|
273
|
+
app.ok(installation, { summary: `Prepared MID Server files in ${installation.installDir}. Run: ${installation.runCommand}` });
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
273
276
|
let record;
|
|
274
277
|
try {
|
|
275
278
|
record = await waitForMidServerUp(app, installation.name, Math.max(1, argv['wait-timeout']), Math.max(500, argv['wait-interval']));
|
package/src/midserver-install.js
CHANGED
|
@@ -28,7 +28,8 @@ export function normalizeMidName(name) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export function buildMidRecipeUrl(releaseName) {
|
|
31
|
-
const
|
|
31
|
+
const matches = [...String(releaseName).matchAll(/(\d{4})-(\d{2})-(\d{2})|(\d{2})-(\d{2})-(\d{4})/g)];
|
|
32
|
+
const match = matches.at(-1);
|
|
32
33
|
if (!match) throw new Error(`MID release name has no build date: ${releaseName}`);
|
|
33
34
|
const year = match[1] || match[6];
|
|
34
35
|
const month = match[2] || match[4];
|
|
@@ -77,7 +78,16 @@ export function dockerComposeAvailable(run = defaultRun) {
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
function composeFile({ serviceName }) {
|
|
80
|
-
return `services:\n ${serviceName}:\n container_name: ${serviceName}\n image: ${serviceName}:\${MID_RELEASE}\n restart: unless-stopped\n volumes:\n - ./export:/opt/snc_mid_server/agent/export\n environment:\n MID_INSTANCE_URL: \${MID_INSTANCE_URL}\n MID_INSTANCE_USERNAME: \${MID_INSTANCE_USERNAME}\n MID_INSTANCE_PASSWORD: \${MID_INSTANCE_PASSWORD}\n MID_SERVER_NAME: \${MID_SERVER_NAME}\n`;
|
|
81
|
+
return `services:\n ${serviceName}:\n container_name: ${serviceName}\n build: ./recipe\n image: ${serviceName}:\${MID_RELEASE}\n restart: unless-stopped\n volumes:\n - ./export:/opt/snc_mid_server/agent/export\n environment:\n MID_INSTANCE_URL: \${MID_INSTANCE_URL}\n MID_INSTANCE_USERNAME: \${MID_INSTANCE_USERNAME}\n MID_INSTANCE_PASSWORD: \${MID_INSTANCE_PASSWORD}\n MID_SERVER_NAME: \${MID_SERVER_NAME}\n`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function envFile({ instanceURL, username, password, displayName, releaseName }) {
|
|
85
|
+
return `MID_RELEASE=${releaseName}\nMID_INSTANCE_URL=${String(instanceURL).replace(/\/$/, '')}/\nMID_INSTANCE_USERNAME=${username}\nMID_INSTANCE_PASSWORD=${password}\nMID_SERVER_NAME=${displayName}\n`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function instanceName(instanceURL) {
|
|
89
|
+
const hostname = new URL(instanceURL).hostname;
|
|
90
|
+
return hostname.replace(/\.service-now\.com$|\.servicenowservices\.com$/i, '').replace(/[^A-Za-z0-9._-]/g, '_');
|
|
81
91
|
}
|
|
82
92
|
|
|
83
93
|
export async function installDockerMidServer({
|
|
@@ -87,17 +97,17 @@ export async function installDockerMidServer({
|
|
|
87
97
|
name,
|
|
88
98
|
directory,
|
|
89
99
|
releaseName: suppliedReleaseName,
|
|
100
|
+
runNow = true,
|
|
90
101
|
fetchImpl = fetch,
|
|
91
102
|
run = defaultRun,
|
|
92
103
|
}) {
|
|
93
|
-
|
|
94
|
-
throw new Error('Docker and Docker Compose are required for Docker MID Server installation');
|
|
95
|
-
}
|
|
104
|
+
const dockerAvailable = detectDocker(run).available;
|
|
96
105
|
const shortName = normalizeMidName(name);
|
|
97
106
|
const displayName = `mid.server.${shortName}`;
|
|
98
107
|
const releaseName = suppliedReleaseName || (await validateMidCredentials(instanceURL, username, password, fetchImpl)).releaseName;
|
|
99
108
|
const recipeURL = buildMidRecipeUrl(releaseName);
|
|
100
|
-
const
|
|
109
|
+
const serviceNowInstance = instanceName(instanceURL);
|
|
110
|
+
const installDir = directory || path.join(os.homedir(), '.servicenow', 'mids', serviceNowInstance, shortName);
|
|
101
111
|
fs.mkdirSync(installDir, { recursive: true, mode: 0o700 });
|
|
102
112
|
const exportDir = path.join(installDir, 'export');
|
|
103
113
|
fs.mkdirSync(exportDir, { recursive: true, mode: 0o700 });
|
|
@@ -110,9 +120,8 @@ export async function installDockerMidServer({
|
|
|
110
120
|
fs.mkdirSync(recipeDir, { recursive: true, mode: 0o700 });
|
|
111
121
|
run('unzip', ['-q', archive, '-d', recipeDir]);
|
|
112
122
|
const composePath = path.join(installDir, 'docker-compose.yaml');
|
|
123
|
+
const persistedRecipeDir = path.join(installDir, 'recipe');
|
|
113
124
|
const serviceName = `jsn_mid_${shortName.replace(/[^A-Za-z0-9_.-]/g, '_')}`;
|
|
114
|
-
run('docker', ['build', '--tag', `${serviceName}:${releaseName}`, recipeDir]);
|
|
115
|
-
fs.writeFileSync(composePath, composeFile({ serviceName, instanceURL, displayName }), { mode: 0o600 });
|
|
116
125
|
const env = {
|
|
117
126
|
MID_RELEASE: releaseName,
|
|
118
127
|
MID_INSTANCE_URL: `${String(instanceURL).replace(/\/$/, '')}/`,
|
|
@@ -120,6 +129,25 @@ export async function installDockerMidServer({
|
|
|
120
129
|
MID_INSTANCE_PASSWORD: password,
|
|
121
130
|
MID_SERVER_NAME: displayName,
|
|
122
131
|
};
|
|
132
|
+
fs.rmSync(persistedRecipeDir, { recursive: true, force: true });
|
|
133
|
+
fs.cpSync(recipeDir, persistedRecipeDir, { recursive: true });
|
|
134
|
+
fs.writeFileSync(composePath, composeFile({ serviceName }), { mode: 0o600 });
|
|
135
|
+
fs.chmodSync(composePath, 0o600);
|
|
136
|
+
const envPath = path.join(installDir, '.env');
|
|
137
|
+
fs.writeFileSync(envPath, envFile({ instanceURL, username, password, displayName, releaseName }), { mode: 0o600 });
|
|
138
|
+
fs.chmodSync(envPath, 0o600);
|
|
139
|
+
if (!dockerAvailable || !runNow) {
|
|
140
|
+
return {
|
|
141
|
+
name: displayName,
|
|
142
|
+
releaseName,
|
|
143
|
+
installDir,
|
|
144
|
+
composePath,
|
|
145
|
+
serviceName,
|
|
146
|
+
prepared: true,
|
|
147
|
+
runCommand: `docker compose -f ${composePath} up -d`,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
run('docker', ['build', '--tag', `${serviceName}:${releaseName}`, persistedRecipeDir]);
|
|
123
151
|
run('docker', ['compose', '-f', composePath, 'up', '-d'], { cwd: installDir, env });
|
|
124
152
|
return {
|
|
125
153
|
name: displayName,
|