Skip to content

Commit 4fa172d

Browse files
committed
agent restart command
1 parent e261da0 commit 4fa172d

12 files changed

Lines changed: 550 additions & 0 deletions

File tree

src/PolykeyAgent.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,25 @@ class PolykeyAgent {
712712
this.logger.info(`Destroyed ${this.constructor.name}`);
713713
}
714714

715+
public async restart({
716+
password,
717+
networkConfig = {},
718+
fresh = false,
719+
}: {
720+
password: string;
721+
networkConfig?: NetworkConfig;
722+
fresh?: boolean;
723+
}) {
724+
this.logger.info(`Restarting ${this.constructor.name}`);
725+
await this.stop();
726+
await this.start({
727+
password,
728+
networkConfig,
729+
fresh,
730+
});
731+
this.logger.info(`Restarted ${this.constructor.name}`);
732+
}
733+
715734
public setWorkerManager(workerManager: PolykeyWorkerManagerInterface) {
716735
this.db.setWorkerManager(workerManager);
717736
this.keyManager.setWorkerManager(workerManager);

src/bin/agent/CommandAgent.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import CommandLock from './CommandLock';
22
import CommandLockAll from './CommandLockAll';
3+
import CommandRestart from './CommandRestart';
34
import CommandStart from './CommandStart';
45
import CommandStatus from './CommandStatus';
56
import CommandStop from './CommandStop';
@@ -13,6 +14,7 @@ class CommandAgent extends CommandPolykey {
1314
this.description('Agent Operations');
1415
this.addCommand(new CommandLock(...args));
1516
this.addCommand(new CommandLockAll(...args));
17+
this.addCommand(new CommandRestart(...args));
1618
this.addCommand(new CommandStart(...args));
1719
this.addCommand(new CommandStatus(...args));
1820
this.addCommand(new CommandStop(...args));

src/bin/agent/CommandRestart.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import type PolykeyClient from '../../PolykeyClient';
2+
import CommandPolykey from '../CommandPolykey';
3+
import * as binUtils from '../utils';
4+
import * as binOptions from '../utils/options';
5+
import * as binProcessors from '../utils/processors';
6+
import * as binErrors from '../errors';
7+
import config from '../../config';
8+
9+
class CommandRestart extends CommandPolykey {
10+
constructor(...args: ConstructorParameters<typeof CommandPolykey>) {
11+
super(...args);
12+
this.name('restart');
13+
this.description('Restart the Polykey Agent');
14+
this.addOption(binOptions.nodeId);
15+
this.addOption(binOptions.clientHost);
16+
this.addOption(binOptions.clientPort);
17+
this.addOption(binOptions.ingressHost);
18+
this.addOption(binOptions.ingressPort);
19+
this.addOption(binOptions.fresh);
20+
this.action(async (options) => {
21+
const { default: PolykeyClient } = await import('../../PolykeyClient');
22+
const agentPB = await import('../../proto/js/polykey/v1/agent/agent_pb');
23+
const clientStatus = await binProcessors.processClientStatus(
24+
options.nodePath,
25+
options.nodeId,
26+
options.clientHost,
27+
options.clientPort,
28+
this.fs,
29+
this.logger.getChild(binProcessors.processClientOptions.name),
30+
);
31+
const statusInfo = clientStatus.statusInfo;
32+
if (statusInfo?.status === 'DEAD') {
33+
this.logger.info('Agent is already dead');
34+
return;
35+
} else if (statusInfo?.status === 'STOPPING') {
36+
this.logger.info('Agent is already stopping');
37+
return;
38+
} else if (statusInfo?.status === 'STARTING') {
39+
throw new binErrors.ErrorCLIStatusStarting();
40+
}
41+
const meta = await binProcessors.processAuthentication(
42+
options.passwordFile,
43+
this.fs,
44+
);
45+
const password = await binProcessors.processPassword(
46+
options.passwordFile,
47+
this.fs,
48+
);
49+
// Either the statusInfo is undefined or LIVE
50+
// Either way, the connection parameters now exist
51+
let pkClient: PolykeyClient;
52+
this.exitHandlers.handlers.push(async () => {
53+
if (pkClient != null) await pkClient.stop();
54+
});
55+
try {
56+
pkClient = await PolykeyClient.createPolykeyClient({
57+
nodePath: options.nodePath,
58+
nodeId: clientStatus.nodeId!,
59+
host: clientStatus.clientHost!,
60+
port: clientStatus.clientPort!,
61+
logger: this.logger.getChild(PolykeyClient.name),
62+
});
63+
const restartMessage = new agentPB.RestartMessage();
64+
restartMessage.setPassword(password);
65+
restartMessage.setClientHost(
66+
options.clientHost ?? config.defaults.networkConfig.clientHost,
67+
);
68+
restartMessage.setClientPort(
69+
options.clientPort ?? config.defaults.networkConfig.clientPort,
70+
);
71+
restartMessage.setIngressHost(options.ingressHost);
72+
restartMessage.setIngressPort(options.ingressPort);
73+
restartMessage.setFresh(options.fresh);
74+
await binUtils.retryAuthentication(
75+
(auth) => pkClient.grpcClient.agentRestart(restartMessage, auth),
76+
meta,
77+
);
78+
this.logger.info('Restarting Agent');
79+
} finally {
80+
if (pkClient! != null) await pkClient.stop();
81+
}
82+
});
83+
}
84+
}
85+
86+
export default CommandRestart;

src/client/GRPCClientClient.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ class GRPCClientClient extends GRPCClient<ClientServiceClient> {
119119
)(...args);
120120
}
121121

122+
@ready(new clientErrors.ErrorClientClientDestroyed())
123+
public agentRestart(...args) {
124+
return grpcUtils.promisifyUnaryCall<utilsPB.EmptyMessage>(
125+
this.client,
126+
this.client.agentRestart,
127+
)(...args);
128+
}
129+
122130
@ready(new clientErrors.ErrorClientClientDestroyed())
123131
public vaultsList(
124132
...args

src/client/service/agentRestart.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { Host, Port } from '../../network/types';
2+
import type * as grpc from '@grpc/grpc-js';
3+
import type { Authenticate } from '../types';
4+
import type PolykeyAgent from '../../PolykeyAgent';
5+
import type * as agentPB from '../../proto/js/polykey/v1/agent/agent_pb';
6+
import * as grpcUtils from '../../grpc/utils';
7+
import * as utilsPB from '../../proto/js/polykey/v1/utils/utils_pb';
8+
9+
function agentRestart({
10+
authenticate,
11+
pkAgent,
12+
}: {
13+
authenticate: Authenticate;
14+
pkAgent: PolykeyAgent;
15+
}) {
16+
return async (
17+
call: grpc.ServerUnaryCall<agentPB.RestartMessage, utilsPB.EmptyMessage>,
18+
callback: grpc.sendUnaryData<utilsPB.EmptyMessage>,
19+
): Promise<void> => {
20+
const response = new utilsPB.EmptyMessage();
21+
try {
22+
const metadata = await authenticate(call.metadata);
23+
call.sendMetadata(metadata);
24+
// Respond first to close the GRPC connection
25+
callback(null, response);
26+
} catch (err) {
27+
callback(grpcUtils.fromError(err), null);
28+
return;
29+
}
30+
const password = call.request.getPassword();
31+
const networkConfig = {
32+
clientHost: call.request.getClientHost() as Host,
33+
clientPort: call.request.getClientPort() as Port,
34+
ingressHost: call.request.getIngressHost() as Host,
35+
ingressPort: call.request.getIngressPort() as Port,
36+
};
37+
const fresh = call.request.getFresh();
38+
await pkAgent.restart({
39+
password,
40+
networkConfig,
41+
fresh,
42+
});
43+
return;
44+
};
45+
}
46+
47+
export default agentRestart;

src/client/service/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type { IClientServiceServer } from '../../proto/js/polykey/v1/client_serv
1919
import type { FileSystem } from '../../types';
2020
import Logger from '@matrixai/logger';
2121
import agentLockAll from './agentLockAll';
22+
import agentRestart from './agentRestart';
2223
import agentStatus from './agentStatus';
2324
import agentStop from './agentStop';
2425
import agentUnlock from './agentUnlock';
@@ -122,6 +123,7 @@ function createService({
122123
};
123124
const service: IClientServiceServer = {
124125
agentLockAll: agentLockAll(container),
126+
agentRestart: agentRestart(container),
125127
agentStatus: agentStatus(container),
126128
agentStop: agentStop(container),
127129
agentUnlock: agentUnlock(container),

src/proto/js/polykey/v1/agent/agent_pb.d.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,38 @@ export namespace InfoMessage {
6767
rootCertChainPem: string,
6868
}
6969
}
70+
71+
export class RestartMessage extends jspb.Message {
72+
getPassword(): string;
73+
setPassword(value: string): RestartMessage;
74+
getClientHost(): string;
75+
setClientHost(value: string): RestartMessage;
76+
getClientPort(): number;
77+
setClientPort(value: number): RestartMessage;
78+
getIngressHost(): string;
79+
setIngressHost(value: string): RestartMessage;
80+
getIngressPort(): number;
81+
setIngressPort(value: number): RestartMessage;
82+
getFresh(): boolean;
83+
setFresh(value: boolean): RestartMessage;
84+
85+
serializeBinary(): Uint8Array;
86+
toObject(includeInstance?: boolean): RestartMessage.AsObject;
87+
static toObject(includeInstance: boolean, msg: RestartMessage): RestartMessage.AsObject;
88+
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
89+
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
90+
static serializeBinaryToWriter(message: RestartMessage, writer: jspb.BinaryWriter): void;
91+
static deserializeBinary(bytes: Uint8Array): RestartMessage;
92+
static deserializeBinaryFromReader(message: RestartMessage, reader: jspb.BinaryReader): RestartMessage;
93+
}
94+
95+
export namespace RestartMessage {
96+
export type AsObject = {
97+
password: string,
98+
clientHost: string,
99+
clientPort: number,
100+
ingressHost: string,
101+
ingressPort: number,
102+
fresh: boolean,
103+
}
104+
}

0 commit comments

Comments
 (0)