Skip to content

Commit ac29b53

Browse files
committed
replace shell curl to node-fetch
1 parent 6f4849b commit ac29b53

File tree

10 files changed

+408
-282
lines changed

10 files changed

+408
-282
lines changed

package-lock.json

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"debug": "^4.3.4",
4747
"execa": "^5.1.1",
4848
"gunzip-maybe": "^1.4.2",
49+
"https-proxy-agent": "^7.0.1",
4950
"node-fetch": "^2.6.12",
5051
"tar-fs": "^3.0.4"
5152
},

src/constants.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
export const DISABLE_PROXY = {
2-
env: { http_proxy: undefined, https_proxy: undefined, all_proxy: undefined },
3-
};
4-
51
export enum Artifacts {
62
ES = 'https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch',
73
OS = 'https://artifacts.opensearch.org/releases/bundle/opensearch',

src/engine.ts

Lines changed: 26 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import execa from 'execa';
2-
import { download, getError, platform, waitForLocalhost } from './utils';
2+
import { download, getEngineBinaryURL, waitForLocalhost } from './utils';
33
import { execSync } from 'child_process';
44
import path from 'path';
55
import { debug } from './debug';
6-
import { Artifacts, DISABLE_PROXY, EngineType } from './constants';
6+
import { EngineType } from './constants';
77
import { startZinc } from './zinc';
8+
import { createClient, EngineClient } from './engineClient';
89

9-
type IndexBody = { name: string; body?: unknown; mappings?: unknown };
10+
export type IndexBody = { name: string; body?: unknown; mappings?: unknown };
1011
export type EngineOptions = {
1112
engine: EngineType;
1213
version: string;
@@ -22,53 +23,17 @@ export type ConfiguredOptions = Omit<EngineOptions, 'binaryLocation'> & { binary
2223

2324
let server: execa.ExecaChildProcess;
2425
let engineOptions: ConfiguredOptions;
26+
let engineClient: EngineClient;
2527

26-
const getEngineResourceURL = async (engine: EngineType, version: string) => {
27-
const { sysName, arch } = await platform();
28-
const engines: {
29-
[engineType: string]: () => string;
30-
} = {
31-
[EngineType.ELASTICSEARCH]: () =>
32-
parseInt(version.charAt(0)) >= 7
33-
? `${Artifacts.ES}-${version}-${sysName}-${arch}.tar.gz`
34-
: `${Artifacts.ES}-${version}.tar.gz`,
35-
[EngineType.OPENSEARCH]: () =>
36-
`${Artifacts.OS}/${version}/opensearch-${version}-linux-${arch.replace('86_', '')}.tar.gz`,
37-
[EngineType.ZINCSEARCH]: () =>
38-
`${Artifacts.ZINC}/v${version}/zincsearch_${version}_${sysName}_${arch}.tar.gz`,
39-
};
40-
41-
return engines[engine]();
42-
};
4328
const prepareEngine = async (engine: EngineType, version: string, binaryLocation: string) => {
44-
const url = await getEngineResourceURL(engine, version);
29+
const url = await getEngineBinaryURL(engine, version);
4530

4631
return await download(url, binaryLocation, engine, version);
4732
};
4833

4934
const createIndexes = async () => {
50-
const { indexes, port, engine } = engineOptions;
51-
52-
const curlCommands: {
53-
[engineType: string]: (indexItem: IndexBody) => string;
54-
} = {
55-
[EngineType.ELASTICSEARCH]: ({ name, body }: IndexBody) =>
56-
`curl -XPUT "http://localhost:${port}/${name}" -H "Content-Type: application/json" -d'${JSON.stringify(
57-
body
58-
)}'`,
59-
[EngineType.OPENSEARCH]: ({ name, body }: IndexBody) =>
60-
`curl -XPUT "http://localhost:${port}/${name}" -H "Content-Type: application/json" -d'${JSON.stringify(
61-
body
62-
)}'`,
63-
[EngineType.ZINCSEARCH]: (index: IndexBody) =>
64-
`curl -XPUT "http://localhost:${port}/api/index" -u ${engineOptions.zincAdmin}:${
65-
engineOptions.zincPassword
66-
} -H "Content-Type: application/json" -d'${JSON.stringify(index)}'`,
67-
};
68-
debug('creating indexes');
69-
await Promise.all(
70-
indexes.map(async (index) => await execSync(curlCommands[engine](index), DISABLE_PROXY))
71-
);
35+
const { indexes } = engineOptions;
36+
await Promise.all(indexes.map(async (index) => await engineClient.createIndex(index)));
7237
};
7338

7439
const start = async () => {
@@ -96,9 +61,9 @@ const start = async () => {
9661
debug(`failed to start engine emit error: ${JSON.stringify(err)}`);
9762
throw new Error('failed to start engine emit error');
9863
});
99-
64+
debug(`checking the local ${engine}:${port} startup`);
10065
try {
101-
await waitForLocalhost(engine, port);
66+
await waitForLocalhost(engineClient);
10267
} catch (error) {
10368
await killProcess();
10469
throw error;
@@ -111,43 +76,24 @@ const start = async () => {
11176
};
11277

11378
const cleanupIndices = async (): Promise<void> => {
114-
const { engine, port, indexes, zincAdmin, zincPassword } = engineOptions;
79+
const { indexes } = engineOptions;
11580
debug(' deleting indexes');
116-
if (indexes.length <= 0) return;
117-
const result = execSync(
118-
engine === EngineType.ZINCSEARCH
119-
? `curl -s -X DELETE http://localhost:${port}/api/index/* -u ${zincAdmin}:${zincPassword}`
120-
: `curl -s -X DELETE http://localhost:${port}/${indexes.map(({ name }) => name).join(',')}`,
121-
DISABLE_PROXY
122-
);
123-
124-
const error = getError(result);
125-
126-
if (error) {
127-
throw new Error(`Failed to remove index: ${error.reason}`);
128-
}
81+
82+
await Promise.all(indexes.map(async (index) => await engineClient.deleteIndex(index)));
12983

13084
debug('Removed all indexes');
13185
};
13286

13387
const killProcess = async (): Promise<void> => {
13488
try {
135-
const closeEmit = new Promise((resolve, reject) => {
136-
server.on('exit', (code, signal) =>
137-
signal === 'SIGKILL'
138-
? reject(`killed: code:${code}, signal:${signal}`)
139-
: resolve(`exit: code:${code}, signal:${signal}`)
140-
);
141-
server.on('error', (err) => reject(`error: ${err}`));
142-
});
143-
14489
server.kill('SIGTERM', { forceKillAfterTimeout: 10000 });
14590

146-
const result = await Promise.race([
147-
closeEmit,
148-
new Promise((resolve) => setTimeout(() => resolve('timout'), 15000)),
149-
]);
150-
debug(`close result: ${result}`);
91+
for (let i = 0; i < 50; i++) {
92+
if (server.killed && server.exitCode !== null) {
93+
return;
94+
}
95+
await new Promise((resolve) => setTimeout(() => resolve(0), 1000));
96+
}
15197
} catch (e) {
15298
debug(`Could not stop ${engineOptions.engine},error: ${e} killing system wide`);
15399
execSync(`pkill -f ${engineOptions.engine}`);
@@ -178,6 +124,13 @@ export const startEngine = async ({
178124
zincAdmin,
179125
zincPassword,
180126
};
127+
const authorization =
128+
zincAdmin && zincPassword
129+
? `Basic ${Buffer.from(zincAdmin + ':' + zincPassword).toString('base64')}`
130+
: undefined;
131+
132+
engineClient = createClient(port, engine, authorization);
133+
181134
// start engine
182135
await start();
183136
};

src/engineClient.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import fetch from 'node-fetch';
2+
import { EngineType } from './constants';
3+
import { debug } from './debug';
4+
import { IndexBody } from './engine';
5+
6+
export interface EngineClient {
7+
heartbeat: () => Promise<number>;
8+
createIndex: (index: IndexBody) => Promise<void>;
9+
deleteIndex: (index: IndexBody) => Promise<void>;
10+
}
11+
12+
const host = 'http://localhost';
13+
export const createClient = (
14+
port: number,
15+
engine: EngineType,
16+
authorization = ''
17+
): EngineClient => {
18+
const headers = { 'Content-Type': 'application/json', authorization };
19+
const get = async <T>(path: string): Promise<{ status: number; data: T }> => {
20+
const res = await fetch(`${host}:${port}${path}`, { headers });
21+
const data = await res.json();
22+
23+
return { status: res.status, data };
24+
};
25+
26+
const post = async <T>(path: string, body?: unknown): Promise<{ status: number; data: T }> => {
27+
const res = await fetch(`${host}:${port}${path}`, {
28+
method: 'POST',
29+
headers,
30+
body: JSON.stringify(body),
31+
});
32+
const data = await res.json();
33+
return { status: res.status, data };
34+
};
35+
const del = async (path: string): Promise<{ status: number; data: unknown }> => {
36+
const res = await fetch(`${host}:${port}${path}`, { method: 'DELETE', headers });
37+
const data = await res.json();
38+
return { status: res.status, data };
39+
};
40+
const heartbeat = async (): Promise<number> => {
41+
try {
42+
const { status } = await get(engine === EngineType.ZINCSEARCH ? `/es` : '');
43+
return status;
44+
} catch (error) {
45+
debug(`heartbeat error: ${error}`);
46+
return 0;
47+
}
48+
};
49+
const createIndex = async ({ name, body, mappings }: IndexBody) => {
50+
debug(`creating index: ${name}`);
51+
const { status, data } = await post(
52+
engine === EngineType.ZINCSEARCH ? '/api/index' : `/${name}`,
53+
engine === EngineType.ZINCSEARCH ? { name, mappings } : body
54+
);
55+
if (status !== 200) {
56+
throw new Error(`failed to create index: ${name}, status: ${status}, data: ${data}`);
57+
}
58+
};
59+
const deleteIndex = async ({ name }: IndexBody) => {
60+
debug(`deleting index: ${name}`);
61+
const { status, data } = await del(
62+
engine === EngineType.ZINCSEARCH ? `/api/index/${name}` : `/${name}`
63+
);
64+
if (status !== 200) {
65+
throw new Error(`failed to delete index: ${name}, status: ${status}, response: ${data}`);
66+
}
67+
};
68+
return { heartbeat, createIndex, deleteIndex };
69+
};

0 commit comments

Comments
 (0)