Skip to content

Commit 2df87bb

Browse files
committed
The processClientStatus and processClientOptions only reads status if none of the client options are set
The client options of `--node-id`, `--client-host`, `--client-port` are required connection parameters When partially set, the values are no longer defaulted to the values in status
1 parent 8ef8b28 commit 2df87bb

5 files changed

Lines changed: 117 additions & 82 deletions

File tree

src/bin/agent/CommandStop.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ class CommandStop extends CommandPolykey {
3232
this.logger.info('Agent is already stopping');
3333
return;
3434
} else if (statusInfo?.status === 'STARTING') {
35-
throw new binErrors.ErrorCLIStatusStarting();
35+
throw new binErrors.ErrorCLIPolykeyAgentStatus(
36+
'agent is starting'
37+
);
3638
}
3739
const meta = await binProcessors.processAuthentication(
3840
options.passwordFile,

src/bin/errors.ts

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,15 @@ class ErrorCLINodePath extends ErrorCLI {
88
exitCode = sysexits.USAGE;
99
}
1010

11-
class ErrorCLIStatusMissing extends ErrorCLI {
11+
class ErrorCLIClientOptions extends ErrorCLI {
1212
description =
13-
'Could not resolve nodeId, clientHost or clientPort from non-existent Status';
13+
'Missing required client options';
1414
exitCode = sysexits.USAGE;
1515
}
1616

17-
class ErrorCLIStatusNotLive extends ErrorCLI {
18-
description =
19-
'Could not resolve nodeId, clientHost or clientPort from Status';
20-
exitCode = sysexits.USAGE;
21-
}
22-
23-
class ErrorCLIStatusStarting extends ErrorCLI {
24-
description = 'Agent is starting';
25-
exitCode = sysexits.TEMPFAIL;
26-
}
27-
28-
class ErrorCLIPolykeyAgentProcess extends ErrorCLI {
29-
description = 'PolykeyAgent process could not be started';
30-
exitCode = sysexits.OSERR;
31-
}
32-
3317
class ErrorCLIPasswordMissing extends ErrorCLI {
3418
description =
35-
'Password is necessary, provide it via PK_PASSWORD, --password-file or when prompted';
19+
'Password is necessary, provide it via --password-file, PK_PASSWORD or when prompted';
3620
exitCode = sysexits.USAGE;
3721
}
3822

@@ -51,6 +35,16 @@ class ErrorCLIFileRead extends ErrorCLI {
5135
exitCode = sysexits.NOINPUT;
5236
}
5337

38+
class ErrorCLIPolykeyAgentStatus extends ErrorCLI {
39+
description = 'PolykeyAgent agent status';
40+
exitCode = sysexits.TEMPFAIL;
41+
}
42+
43+
class ErrorCLIPolykeyAgentProcess extends ErrorCLI {
44+
description = 'PolykeyAgent process could not be started';
45+
exitCode = sysexits.OSERR;
46+
}
47+
5448
class ErrorNodeFindFailed extends ErrorCLI {
5549
description = 'Failed to find the node in the DHT';
5650
exitCode = 1;
@@ -64,14 +58,13 @@ class ErrorNodePingFailed extends ErrorCLI {
6458
export {
6559
ErrorCLI,
6660
ErrorCLINodePath,
61+
ErrorCLIClientOptions,
6762
ErrorCLIPasswordMissing,
68-
ErrorCLIStatusMissing,
69-
ErrorCLIStatusStarting,
70-
ErrorCLIStatusNotLive,
71-
ErrorCLIPolykeyAgentProcess,
7263
ErrorCLIPasswordFileRead,
7364
ErrorCLIRecoveryCodeFileRead,
7465
ErrorCLIFileRead,
66+
ErrorCLIPolykeyAgentStatus,
67+
ErrorCLIPolykeyAgentProcess,
7568
ErrorNodeFindFailed,
7669
ErrorNodePingFailed,
7770
};

src/bin/utils/processors.ts

Lines changed: 90 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ import path from 'path';
1313
import prompts from 'prompts';
1414
import * as grpc from '@grpc/grpc-js';
1515
import Logger from '@matrixai/logger';
16-
import * as binErrors from '../errors';
16+
import Status from '../../status/Status';
1717
import * as clientUtils from '../../client/utils';
18-
import { Status } from '../../status';
18+
import * as binErrors from '../errors';
19+
import { arrayZip } from '../../utils';
1920
import config from '../../config';
2021

2122
/**
@@ -185,7 +186,7 @@ async function processRecoveryCode(
185186
* 1. Reads --node-id, --client-host, --client-port
186187
* 2. Reads PK_NODE_ID, PK_CLIENT_HOST, PK_CLIENT_PORT
187188
* 3. Command-specific defaults
188-
* 4. Reads Status
189+
* 4. If no options are set, reads Status
189190
* Step 2 is done during option construction
190191
* Step 3 is done in CommandPolykey classes
191192
*/
@@ -201,7 +202,13 @@ async function processClientOptions(
201202
clientHost: Host;
202203
clientPort: Port;
203204
}> {
204-
if (nodeId == null || clientHost == null || clientPort == null) {
205+
if (nodeId != null && clientHost != null && clientPort != null) {
206+
return {
207+
nodeId,
208+
clientHost,
209+
clientPort,
210+
};
211+
} else if (nodeId == null && clientHost == null && clientPort == null) {
205212
const statusPath = path.join(nodePath, config.defaults.statusBase);
206213
const statusLockPath = path.join(nodePath, config.defaults.statusLockBase);
207214
const status = new Status({
@@ -212,24 +219,39 @@ async function processClientOptions(
212219
});
213220
const statusInfo = await status.readStatus();
214221
if (statusInfo === undefined || statusInfo.status !== 'LIVE') {
215-
throw new binErrors.ErrorCLIStatusNotLive();
222+
throw new binErrors.ErrorCLIPolykeyAgentStatus(
223+
'agent is not live'
224+
);
216225
}
217-
if (nodeId == null) nodeId = statusInfo.data.nodeId;
218-
if (clientHost == null) clientHost = statusInfo.data.clientHost;
219-
if (clientPort == null) clientPort = statusInfo.data.clientPort;
226+
return {
227+
nodeId: statusInfo.data.nodeId,
228+
clientHost: statusInfo.data.clientHost,
229+
clientPort: statusInfo.data.clientPort,
230+
};
231+
} else {
232+
const errorMsg = arrayZip(
233+
[nodeId, clientHost, clientPort],
234+
[
235+
'missing node ID, provide it with --node-id or PK_NODE_ID',
236+
'missing client host, provide it with --client-host or PK_CLIENT_HOST',
237+
'missing client port, provide it with --client-port or PK_CLIENT_PORT'
238+
]
239+
).flatMap(([option, msg]) => {
240+
if (option == null) {
241+
return [msg];
242+
} else {
243+
return [];
244+
}
245+
}).join('; ');
246+
throw new binErrors.ErrorCLIClientOptions(errorMsg);
220247
}
221-
return {
222-
nodeId,
223-
clientHost,
224-
clientPort,
225-
};
226248
}
227249

228250
/**
229251
* Process client status
230252
* Options are used for connecting PolykeyClient
231253
* Variant of processClientOptions
232-
* Use this when you need always need the status info
254+
* Use this when you need always need the status info when reading the status
233255
*/
234256
async function processClientStatus(
235257
nodePath: string,
@@ -261,7 +283,6 @@ async function processClientStatus(
261283
clientPort: Port;
262284
}
263285
> {
264-
// If all parameters are set, no status and no statusInfo is used
265286
if (nodeId != null && clientHost != null && clientPort != null) {
266287
return {
267288
statusInfo: undefined,
@@ -270,40 +291,61 @@ async function processClientStatus(
270291
clientHost,
271292
clientPort,
272293
};
294+
} else if (nodeId == null && clientHost == null && clientPort == null) {
295+
const statusPath = path.join(nodePath, config.defaults.statusBase);
296+
const statusLockPath = path.join(nodePath, config.defaults.statusLockBase);
297+
const status = new Status({
298+
statusPath,
299+
statusLockPath,
300+
fs,
301+
logger: logger.getChild(Status.name),
302+
});
303+
const statusInfo = await status.readStatus();
304+
if (statusInfo == null) {
305+
return {
306+
statusInfo: { status: 'DEAD', data: {} },
307+
status,
308+
nodeId: undefined,
309+
clientHost: undefined,
310+
clientPort: undefined,
311+
};
312+
} else if (statusInfo.status === 'LIVE') {
313+
nodeId = statusInfo.data.nodeId;
314+
clientHost = statusInfo.data.clientHost;
315+
clientPort = statusInfo.data.clientPort;
316+
return {
317+
statusInfo,
318+
status,
319+
nodeId,
320+
clientHost,
321+
clientPort,
322+
};
323+
} else {
324+
return {
325+
statusInfo,
326+
status,
327+
nodeId: undefined,
328+
clientHost: undefined,
329+
clientPort: undefined,
330+
};
331+
}
332+
} else {
333+
const errorMsg = arrayZip(
334+
[nodeId, clientHost, clientPort],
335+
[
336+
'missing node ID, provide it with --node-id or PK_NODE_ID',
337+
'missing client host, provide it with --client-host or PK_CLIENT_HOST',
338+
'missing client port, provide it with --client-port or PK_CLIENT_PORT'
339+
]
340+
).flatMap(([option, msg]) => {
341+
if (option == null) {
342+
return [msg];
343+
} else {
344+
return [];
345+
}
346+
}).join('; ');
347+
throw new binErrors.ErrorCLIClientOptions(errorMsg);
273348
}
274-
const statusPath = path.join(nodePath, config.defaults.statusBase);
275-
const statusLockPath = path.join(nodePath, config.defaults.statusLockBase);
276-
const status = new Status({
277-
statusPath,
278-
statusLockPath,
279-
fs,
280-
logger: logger.getChild(Status.name),
281-
});
282-
const statusInfo = await status.readStatus();
283-
// If not all parameters are set, and that the status doesn't exist
284-
// Then this an exception
285-
if (statusInfo == null) {
286-
throw new binErrors.ErrorCLIStatusMissing();
287-
}
288-
if (statusInfo.status === 'LIVE') {
289-
if (nodeId == null) nodeId = statusInfo.data.nodeId;
290-
if (clientHost == null) clientHost = statusInfo.data.clientHost;
291-
if (clientPort == null) clientPort = statusInfo.data.clientPort;
292-
return {
293-
statusInfo,
294-
status,
295-
nodeId,
296-
clientHost,
297-
clientPort,
298-
};
299-
}
300-
return {
301-
statusInfo,
302-
status,
303-
nodeId,
304-
clientHost,
305-
clientPort,
306-
};
307349
}
308350

309351
/**

tests/bin/agent/status.test.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ import path from 'path';
33
import fs from 'fs';
44
import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
55
import Status from '@/status/Status';
6-
import config from '@/config';
76
import * as nodesUtils from '@/nodes/utils';
8-
import * as binErrors from '@/bin/errors';
7+
import config from '@/config';
98
import * as testBinUtils from '../utils';
109
import * as testUtils from '../../utils';
1110

@@ -113,17 +112,16 @@ describe('status', () => {
113112
global.defaultTimeout * 2,
114113
);
115114
test('status on missing agent', async () => {
116-
const { exitCode, stderr } = await testBinUtils.pkStdio(
117-
['agent', 'status', '--verbose'],
115+
const { exitCode, stdout } = await testBinUtils.pkStdio(
116+
['agent', 'status', '--format', 'json'],
118117
{
119118
PK_NODE_PATH: path.join(dataDir, 'polykey'),
120119
},
121120
);
122-
testBinUtils.expectProcessError(
123-
exitCode,
124-
stderr,
125-
new binErrors.ErrorCLIStatusMissing(),
126-
);
121+
expect(exitCode).toBe(0);
122+
expect(JSON.parse(stdout)).toMatchObject({
123+
status: 'DEAD',
124+
});
127125
});
128126
describe('status with global agent', () => {
129127
let globalAgentDir;

tests/bin/agent/stop.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ describe('stop', () => {
206206
testBinUtils.expectProcessError(
207207
exitCode,
208208
stderr,
209-
new binErrors.ErrorCLIStatusStarting(),
209+
new binErrors.ErrorCLIPolykeyAgentStatus('agent is starting'),
210210
);
211211
await status.waitFor('LIVE');
212212
await testBinUtils.pkStdio(

0 commit comments

Comments
 (0)