@bitblit/ratchet-aws
Version:
Common tools for use with AWS browser and node
114 lines • 5.01 kB
JavaScript
import { DescribeInstancesCommand, EC2Client, StartInstancesCommand, StopInstancesCommand, } from '@aws-sdk/client-ec2';
import { EC2InstanceConnectClient, SendSSHPublicKeyCommand, } from '@aws-sdk/client-ec2-instance-connect';
import { Logger } from '@bitblit/ratchet-common/logger/logger';
import { PromiseRatchet } from '@bitblit/ratchet-common/lang/promise-ratchet';
import { DurationRatchet } from '@bitblit/ratchet-common/lang/duration-ratchet';
export class Ec2Ratchet {
region;
availabilityZone;
ec2;
ec2InstanceConnect;
constructor(region = 'us-east-1', availabilityZone = 'us-east-1a') {
this.region = region;
this.availabilityZone = availabilityZone;
this.ec2 = new EC2Client({ region: region });
this.ec2InstanceConnect = new EC2InstanceConnectClient({ region: region });
}
get eC2Client() {
return this.ec2;
}
get eC2InstanceConnectClient() {
return this.ec2InstanceConnect;
}
async stopInstance(instanceId, maxWaitForShutdownMS = 0) {
let rval = true;
try {
const stopParams = {
InstanceIds: [instanceId],
DryRun: false,
};
Logger.info('About to stop instances : %j', stopParams);
await this.ec2.send(new StopInstancesCommand(stopParams));
Logger.info('Stop instance command sent, waiting on shutdown');
let status = await this.describeInstance(instanceId);
if (maxWaitForShutdownMS > 0) {
const start = new Date().getTime();
while (!!status && status.State.Code !== 16 && new Date().getTime() - start < maxWaitForShutdownMS) {
Logger.debug('Instance status is %j - waiting for 5 seconds (up to %s)', status.State, DurationRatchet.formatMsDuration(maxWaitForShutdownMS));
await PromiseRatchet.wait(5000);
status = await this.describeInstance(instanceId);
}
}
}
catch (err) {
Logger.error('Failed to stop instance %s : %s', instanceId, err, err);
rval = false;
}
return rval;
}
async launchInstance(instanceId, maxWaitForStartupMS = 0) {
let rval = true;
try {
const startParams = {
InstanceIds: [instanceId],
DryRun: false,
};
Logger.info('About to start instance : %j', startParams);
await this.ec2.send(new StartInstancesCommand(startParams));
Logger.info('Start instance command sent, waiting on startup');
let status = await this.describeInstance(instanceId);
if (maxWaitForStartupMS > 0) {
const start = new Date().getTime();
while (!!status && status.State.Code !== 16 && new Date().getTime() - start < maxWaitForStartupMS) {
Logger.debug('Instance status is %j - waiting for 5 seconds (up to %s)', status.State, DurationRatchet.formatMsDuration(maxWaitForStartupMS));
await PromiseRatchet.wait(5000);
status = await this.describeInstance(instanceId);
}
}
if (!!status && !!status.PublicIpAddress) {
Logger.info('Instance address is %s', status.PublicIpAddress);
Logger.info('SSH command : ssh -i path_to_pem_file ec2-user@%s', status.PublicIpAddress);
}
}
catch (err) {
Logger.error('Failed to start instance %s : %s', instanceId, err, err);
rval = false;
}
return rval;
}
async describeInstance(instanceId) {
const res = await this.listAllInstances([instanceId]);
return res.length === 1 ? res[0] : null;
}
async listAllInstances(instanceIds = []) {
let rval = [];
const req = {
NextToken: null,
};
if (instanceIds && instanceIds.length > 0) {
req.InstanceIds = instanceIds;
}
do {
Logger.debug('Pulling instances... (%j)', req);
const res = await this.ec2.send(new DescribeInstancesCommand(req));
res.Reservations.forEach((r) => {
rval = rval.concat(r.Instances);
});
req.NextToken = res.NextToken;
} while (req.NextToken);
Logger.debug('Finished pulling instances (found %d)', rval.length);
return rval;
}
async sendPublicKeyToEc2Instance(instanceId, publicKeyString, instanceOsUser) {
const userName = instanceOsUser || 'ec2-user';
const req = {
InstanceId: instanceId,
AvailabilityZone: this.availabilityZone,
InstanceOSUser: userName,
SSHPublicKey: publicKeyString,
};
const rval = await this.ec2InstanceConnect.send(new SendSSHPublicKeyCommand(req));
return rval;
}
}
//# sourceMappingURL=ec2-ratchet.js.map