Skip to content

Commit f02c897

Browse files
committed
migrate ssm use cases
1 parent 239b597 commit f02c897

File tree

7 files changed

+1314
-530
lines changed

7 files changed

+1314
-530
lines changed

package-lock.json

Lines changed: 1278 additions & 378 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
@@ -70,6 +70,7 @@
7070
"webpack-merge": "^5.10.0"
7171
},
7272
"dependencies": {
73+
"@aws-sdk/client-ssm": "^3.699.0",
7374
"@aws-sdk/protocol-http": "^3.370.0",
7475
"@types/node": "^22.7.5",
7576
"vscode-nls": "^5.2.0",

packages/core/src/awsService/ec2/model.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55
import * as vscode from 'vscode'
6-
import { Session } from 'aws-sdk/clients/ssm'
7-
import { EC2, IAM, SSM } from 'aws-sdk'
6+
import { EC2, IAM } from 'aws-sdk'
87
import { Ec2Selection } from './prompter'
98
import { getOrInstallCli } from '../../shared/utilities/cliUtils'
109
import { isCloud9 } from '../../shared/extensionUtilities'
1110
import { ToolkitError } from '../../shared/errors'
12-
import { SsmClient } from '../../shared/clients/ssmClient'
11+
import { SSMWrapper } from '../../shared/clients/ssm'
1312
import { Ec2Client } from '../../shared/clients/ec2Client'
1413
import {
1514
VscodeRemoteConnection,
@@ -29,17 +28,18 @@ import { SshConfig } from '../../shared/sshConfig'
2928
import { SshKeyPair } from './sshKeyPair'
3029
import { Ec2SessionTracker } from './remoteSessionManager'
3130
import { getEc2SsmEnv } from './utils'
31+
import { Session, StartSessionCommandOutput } from '@aws-sdk/client-ssm'
3232

3333
export type Ec2ConnectErrorCode = 'EC2SSMStatus' | 'EC2SSMPermission' | 'EC2SSMConnect' | 'EC2SSMAgentStatus'
3434

3535
export interface Ec2RemoteEnv extends VscodeRemoteConnection {
3636
selection: Ec2Selection
3737
keyPair: SshKeyPair
38-
ssmSession: SSM.StartSessionResponse
38+
ssmSession: StartSessionCommandOutput
3939
}
4040

4141
export class Ec2Connecter implements vscode.Disposable {
42-
protected ssmClient: SsmClient
42+
protected ssm: SSMWrapper
4343
protected ec2Client: Ec2Client
4444
protected iamClient: DefaultIamClient
4545
protected sessionManager: Ec2SessionTracker
@@ -53,14 +53,14 @@ export class Ec2Connecter implements vscode.Disposable {
5353
)
5454

5555
public constructor(readonly regionCode: string) {
56-
this.ssmClient = this.createSsmSdkClient()
56+
this.ssm = this.createSsmSdkClient()
5757
this.ec2Client = this.createEc2SdkClient()
5858
this.iamClient = this.createIamSdkClient()
59-
this.sessionManager = new Ec2SessionTracker(regionCode, this.ssmClient)
59+
this.sessionManager = new Ec2SessionTracker(regionCode, this.ssm)
6060
}
6161

62-
protected createSsmSdkClient(): SsmClient {
63-
return new SsmClient(this.regionCode)
62+
protected createSsmSdkClient(): SSMWrapper {
63+
return new SSMWrapper(this.regionCode)
6464
}
6565

6666
protected createEc2SdkClient(): Ec2Client {
@@ -71,7 +71,7 @@ export class Ec2Connecter implements vscode.Disposable {
7171
return new DefaultIamClient(this.regionCode)
7272
}
7373

74-
public async addActiveSession(sessionId: SSM.SessionId, instanceId: EC2.InstanceId): Promise<void> {
74+
public async addActiveSession(sessionId: string, instanceId: EC2.InstanceId): Promise<void> {
7575
await this.sessionManager.addSession(instanceId, sessionId)
7676
}
7777

@@ -139,7 +139,7 @@ export class Ec2Connecter implements vscode.Disposable {
139139
}
140140

141141
private async checkForInstanceSsmError(selection: Ec2Selection): Promise<void> {
142-
const isSsmAgentRunning = (await this.ssmClient.getInstanceAgentPingStatus(selection.instanceId)) === 'Online'
142+
const isSsmAgentRunning = (await this.ssm.getInstanceAgentPingStatus(selection.instanceId)) === 'Online'
143143

144144
if (!isSsmAgentRunning) {
145145
this.throwConnectionError('Is SSM Agent running on the target instance?', selection, {
@@ -173,15 +173,15 @@ export class Ec2Connecter implements vscode.Disposable {
173173
shellArgs: shellArgs,
174174
}
175175

176-
await openRemoteTerminal(terminalOptions, () => this.ssmClient.terminateSession(session)).catch((err) => {
176+
await openRemoteTerminal(terminalOptions, () => this.ssm.terminateSession(session)).catch((err) => {
177177
throw ToolkitError.chain(err, 'Failed to open ec2 instance.')
178178
})
179179
}
180180

181181
public async attemptToOpenEc2Terminal(selection: Ec2Selection): Promise<void> {
182182
await this.checkForStartSessionError(selection)
183183
try {
184-
const response = await this.ssmClient.startSession(selection.instanceId)
184+
const response = await this.ssm.startSession(selection.instanceId)
185185
await this.openSessionInTerminal(response, selection)
186186
} catch (err: unknown) {
187187
this.throwGeneralConnectionError(selection, err as Error)
@@ -222,7 +222,7 @@ export class Ec2Connecter implements vscode.Disposable {
222222

223223
throw err
224224
}
225-
const ssmSession = await this.ssmClient.startSession(selection.instanceId, 'AWS-StartSSHSession')
225+
const ssmSession = await this.ssm.startSession(selection.instanceId, 'AWS-StartSSHSession')
226226
await this.addActiveSession(selection.instanceId, ssmSession.SessionId!)
227227

228228
const vars = getEc2SsmEnv(selection, ssm, ssmSession)
@@ -270,13 +270,13 @@ export class Ec2Connecter implements vscode.Disposable {
270270
const command = `echo "${sshPubKey}" > ${remoteAuthorizedKeysPaths}`
271271
const documentName = 'AWS-RunShellScript'
272272

273-
await this.ssmClient.sendCommandAndWait(selection.instanceId, documentName, {
273+
await this.ssm.sendCommandAndWait(selection.instanceId, documentName, {
274274
commands: [command],
275275
})
276276
}
277277

278278
public async getRemoteUser(instanceId: string) {
279-
const osName = await this.ssmClient.getTargetPlatformName(instanceId)
279+
const osName = await this.ssm.getTargetPlatformName(instanceId)
280280
if (osName === 'Amazon Linux') {
281281
return 'ec2-user'
282282
}

packages/core/src/awsService/ec2/remoteSessionManager.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,30 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { EC2, SSM } from 'aws-sdk'
7-
import { SsmClient } from '../../shared/clients/ssmClient'
6+
import { EC2 } from 'aws-sdk'
7+
import { SSMWrapper } from '../../shared/clients/ssm'
88
import { Disposable } from 'vscode'
99

10-
export class Ec2SessionTracker extends Map<EC2.InstanceId, SSM.SessionId> implements Disposable {
10+
export class Ec2SessionTracker extends Map<EC2.InstanceId, string> implements Disposable {
1111
public constructor(
1212
readonly regionCode: string,
13-
protected ssmClient: SsmClient
13+
protected ssm: SSMWrapper
1414
) {
1515
super()
1616
}
1717

18-
public async addSession(instanceId: EC2.InstanceId, sessionId: SSM.SessionId): Promise<void> {
18+
public async addSession(instanceId: EC2.InstanceId, sessionId: string): Promise<void> {
1919
if (this.isConnectedTo(instanceId)) {
2020
const existingSessionId = this.get(instanceId)!
21-
await this.ssmClient.terminateSessionFromId(existingSessionId)
21+
await this.ssm.terminateSessionFromId(existingSessionId)
2222
this.set(instanceId, sessionId)
2323
} else {
2424
this.set(instanceId, sessionId)
2525
}
2626
}
2727

2828
private async disconnectEnv(instanceId: EC2.InstanceId): Promise<void> {
29-
await this.ssmClient.terminateSessionFromId(this.get(instanceId)!)
29+
await this.ssm.terminateSessionFromId(this.get(instanceId)!)
3030
this.delete(instanceId)
3131
}
3232

packages/core/src/shared/clients/ssmClient.ts

Lines changed: 0 additions & 117 deletions
This file was deleted.

packages/core/src/test/awsService/ec2/model.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import assert from 'assert'
77
import * as sinon from 'sinon'
88
import { Ec2Connecter } from '../../../awsService/ec2/model'
9-
import { SsmClient } from '../../../shared/clients/ssmClient'
9+
import { SSMWrapper } from '../../../shared/clients/ssm'
1010
import { Ec2Client } from '../../../shared/clients/ec2Client'
1111
import { Ec2Selection } from '../../../awsService/ec2/prompter'
1212
import { ToolkitError } from '../../../shared/errors'
@@ -110,7 +110,7 @@ describe('Ec2ConnectClient', function () {
110110
sinon.stub(Ec2Connecter.prototype, 'isInstanceRunning').resolves(true)
111111
sinon.stub(Ec2Connecter.prototype, 'getAttachedIamRole').resolves({ Arn: 'testRole' } as IAM.Role)
112112
sinon.stub(Ec2Connecter.prototype, 'hasProperPermissions').resolves(true)
113-
sinon.stub(SsmClient.prototype, 'getInstanceAgentPingStatus').resolves('offline')
113+
sinon.stub(SSMWrapper.prototype, 'getInstanceAgentPingStatus').resolves('offline')
114114

115115
try {
116116
await client.checkForStartSessionError(instanceSelection)
@@ -124,15 +124,15 @@ describe('Ec2ConnectClient', function () {
124124
sinon.stub(Ec2Connecter.prototype, 'isInstanceRunning').resolves(true)
125125
sinon.stub(Ec2Connecter.prototype, 'getAttachedIamRole').resolves({ Arn: 'testRole' } as IAM.Role)
126126
sinon.stub(Ec2Connecter.prototype, 'hasProperPermissions').resolves(true)
127-
sinon.stub(SsmClient.prototype, 'getInstanceAgentPingStatus').resolves('Online')
127+
sinon.stub(SSMWrapper.prototype, 'getInstanceAgentPingStatus').resolves('Online')
128128

129129
assert.doesNotThrow(async () => await client.checkForStartSessionError(instanceSelection))
130130
})
131131
})
132132

133133
describe('sendSshKeysToInstance', async function () {
134134
it('calls the sdk with the proper parameters', async function () {
135-
const sendCommandStub = sinon.stub(SsmClient.prototype, 'sendCommandAndWait')
135+
const sendCommandStub = sinon.stub(SSMWrapper.prototype, 'sendCommandAndWait')
136136

137137
const testSelection = {
138138
instanceId: 'test-id',
@@ -146,7 +146,7 @@ describe('Ec2ConnectClient', function () {
146146
})
147147

148148
it('avoids writing the keys to any telemetry metrics', async function () {
149-
sinon.stub(SsmClient.prototype, 'sendCommandAndWait')
149+
sinon.stub(SSMWrapper.prototype, 'sendCommandAndWait')
150150

151151
const testSelection = {
152152
instanceId: 'test-id',
@@ -168,7 +168,7 @@ describe('Ec2ConnectClient', function () {
168168
let getTargetPlatformNameStub: sinon.SinonStub<[target: string], Promise<string>>
169169

170170
before(async function () {
171-
getTargetPlatformNameStub = sinon.stub(SsmClient.prototype, 'getTargetPlatformName')
171+
getTargetPlatformNameStub = sinon.stub(SSMWrapper.prototype, 'getTargetPlatformName')
172172
})
173173

174174
after(async function () {

packages/core/src/test/awsService/ec2/remoteSessionManager.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
import assert from 'assert'
77
import * as sinon from 'sinon'
88
import { Ec2SessionTracker } from '../../../awsService/ec2/remoteSessionManager'
9-
import { SsmClient } from '../../../shared/clients/ssmClient'
9+
import { SSMWrapper } from '../../../shared/clients/ssm'
1010

1111
describe('Ec2RemoteSessionManager', async function () {
1212
it('maintains connections to instances', async function () {
13-
const envManager = new Ec2SessionTracker('test-region', new SsmClient('test-region'))
13+
const envManager = new Ec2SessionTracker('test-region', new SSMWrapper('test-region'))
1414
await envManager.addSession('test-instance', 'test-env')
1515
await envManager.addSession('test-instance2', 'test-env2')
1616
await envManager.addSession('test-instance3', 'test-env3')
@@ -22,8 +22,8 @@ describe('Ec2RemoteSessionManager', async function () {
2222
})
2323

2424
it('only allows for single connection with any given instance', async function () {
25-
const envManager = new Ec2SessionTracker('test-region', new SsmClient('test-region'))
26-
const terminateStub = sinon.stub(SsmClient.prototype, 'terminateSessionFromId')
25+
const envManager = new Ec2SessionTracker('test-region', new SSMWrapper('test-region'))
26+
const terminateStub = sinon.stub(SSMWrapper.prototype, 'terminateSessionFromId')
2727

2828
await envManager.addSession('test-instance', 'test-env')
2929
sinon.assert.notCalled(terminateStub)
@@ -37,8 +37,8 @@ describe('Ec2RemoteSessionManager', async function () {
3737
})
3838

3939
it('closes all active connections', async function () {
40-
const envManager = new Ec2SessionTracker('test-region', new SsmClient('test-region'))
41-
const terminateStub = sinon.stub(SsmClient.prototype, 'terminateSessionFromId')
40+
const envManager = new Ec2SessionTracker('test-region', new SSMWrapper('test-region'))
41+
const terminateStub = sinon.stub(SSMWrapper.prototype, 'terminateSessionFromId')
4242

4343
await envManager.addSession('test-instance', 'test-env')
4444
await envManager.addSession('test-instance2', 'test-env2')

0 commit comments

Comments
 (0)