UNPKG

@bitblit/ratchet-aws

Version:

Common tools for use with AWS browser and node

114 lines 5.01 kB
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