diff --git a/packages/core/src/awsService/ec2/model.ts b/packages/core/src/awsService/ec2/model.ts index 9a5e13feaef..4817d012b8a 100644 --- a/packages/core/src/awsService/ec2/model.ts +++ b/packages/core/src/awsService/ec2/model.ts @@ -29,7 +29,7 @@ import { testSshConnection, } from '../../shared/extensions/ssh' import { getLogger } from '../../shared/logger/logger' -import { CancellationError, Timeout } from '../../shared/utilities/timeoutUtils' +import { CancellationError, Timeout, waitUntil } from '../../shared/utilities/timeoutUtils' import { showMessageWithCancel } from '../../shared/utilities/messages' import { SshConfig } from '../../shared/sshConfig' import { SshKeyPair } from './sshKeyPair' @@ -150,8 +150,14 @@ export class Ec2Connecter implements vscode.Disposable { } } - private async checkForInstanceSsmError(selection: Ec2Selection): Promise { - const isSsmAgentRunning = (await this.ssmClient.getInstanceAgentPingStatus(selection.instanceId)) === 'Online' + public async checkForInstanceSsmError( + selection: Ec2Selection, + options?: Partial<{ interval: number; timeout: number }> + ): Promise { + const isSsmAgentRunning = await waitUntil( + async () => (await this.ssmClient.getInstanceAgentPingStatus(selection.instanceId)) === 'Online', + { interval: options?.interval ?? 500, timeout: options?.timeout ?? 5000 } + ) if (!isSsmAgentRunning) { this.throwConnectionError('Is SSM Agent running on the target instance?', selection, { diff --git a/packages/core/src/test/awsService/ec2/model.test.ts b/packages/core/src/test/awsService/ec2/model.test.ts index e113332a60d..998726680d6 100644 --- a/packages/core/src/test/awsService/ec2/model.test.ts +++ b/packages/core/src/test/awsService/ec2/model.test.ts @@ -125,6 +125,17 @@ describe('Ec2ConnectClient', function () { } }) + it('retries if agent status is not online', async function () { + const instanceAgentStatus = sinon.stub(SsmClient.prototype, 'getInstanceAgentPingStatus') + instanceAgentStatus.onFirstCall().resolves('Offline') + instanceAgentStatus.onSecondCall().resolves('Online') + try { + await client.checkForInstanceSsmError(instanceSelection, { interval: 10, timeout: 100 }) + } catch (err) { + assert.ok(false, `checkForInstanceSsmError failed with error '${err}'`) + } + }) + it('does not throw an error if all checks pass', async function () { sinon.stub(Ec2Connecter.prototype, 'isInstanceRunning').resolves(true) sinon.stub(Ec2Connecter.prototype, 'getAttachedIamRole').resolves({ Arn: 'testRole' } as IAM.Role)