Skip to content

Commit c4dfd7d

Browse files
authored
refactor(cloudformation): migrate client to use sdkv3. (aws#6792)
## Problem client uses sdkv2 ## Solution - Straight forward migration. ## Verification - Create a template from the explorer. - Visualize with app builder, then synchronize it, following wizard steps "sync" to the deployment. - Create a stack in console, verify it shows up in explorer. - Delete the stack from the explorer. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 3b1d258 commit c4dfd7d

File tree

16 files changed

+166
-180
lines changed

16 files changed

+166
-180
lines changed

packages/core/src/dynamicResources/awsResourceManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { writeFileSync } from 'fs' // eslint-disable-line no-restricted-imports
77
import * as path from 'path'
88
import * as vscode from 'vscode'
9-
import { CloudFormationClient } from '../shared/clients/cloudFormationClient'
9+
import { CloudFormationClient } from '../shared/clients/cloudFormation'
1010
import {
1111
getNonexistentFilename,
1212
makeTemporaryToolkitFolder,

packages/core/src/dynamicResources/explorer/nodes/resourcesNode.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55

66
import * as vscode from 'vscode'
77
import * as nls from 'vscode-nls'
8-
import { CloudFormationClient, DefaultCloudFormationClient } from '../../../shared/clients/cloudFormationClient'
8+
import { CloudFormationClient } from '../../../shared/clients/cloudFormation'
99
import { AWSTreeNodeBase } from '../../../shared/treeview/nodes/awsTreeNodeBase'
1010
import { PlaceholderNode } from '../../../shared/treeview/nodes/placeholderNode'
1111
import { makeChildrenNodes } from '../../../shared/treeview/utils'
1212
import { toArrayAsync, updateInPlace } from '../../../shared/utilities/collectionUtils'
1313
import { ResourceTypeNode } from './resourceTypeNode'
14-
import { CloudFormation } from 'aws-sdk'
1514
import { CloudControlClient } from '../../../shared/clients/cloudControl'
1615
import { memoizedGetResourceTypes, ResourceTypeMetadata } from '../../model/resources'
1716
import { ResourcesSettings } from '../../commands/configure'
17+
import { TypeSummary } from '@aws-sdk/client-cloudformation'
1818

1919
const localize = nls.loadMessageBundle()
2020

@@ -23,7 +23,7 @@ export class ResourcesNode extends AWSTreeNodeBase {
2323

2424
public constructor(
2525
public readonly region: string,
26-
public readonly cloudFormation: CloudFormationClient = new DefaultCloudFormationClient(region),
26+
public readonly cloudFormation: CloudFormationClient = new CloudFormationClient(region),
2727
private readonly cloudControl: CloudControlClient = new CloudControlClient(region),
2828
private readonly settings = new ResourcesSettings()
2929
) {
@@ -62,7 +62,7 @@ export class ResourcesNode extends AWSTreeNodeBase {
6262
const types = await toArrayAsync(this.cloudFormation.listTypes())
6363
types.sort((a, b) => (a.LastUpdated?.getTime() ?? 0) - (b.LastUpdated?.getTime() ?? 0))
6464

65-
const availableTypes: Map<string, CloudFormation.TypeSummary> = new Map()
65+
const availableTypes: Map<string, TypeSummary> = new Map()
6666
for (const type of types) {
6767
if (type.TypeName) {
6868
availableTypes.set(type.TypeName!, type)

packages/core/src/lambda/commands/deleteCloudFormation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as nls from 'vscode-nls'
77
const localize = nls.loadMessageBundle()
88

99
import * as vscode from 'vscode'
10-
import { DefaultCloudFormationClient } from '../../shared/clients/cloudFormationClient'
10+
import { CloudFormationClient } from '../../shared/clients/cloudFormation'
1111

1212
import * as localizedText from '../../shared/localizedText'
1313
import { getLogger, Logger } from '../../shared/logger/logger'
@@ -45,7 +45,7 @@ export async function deleteCloudFormation(refresh: () => void, node?: CloudForm
4545
})
4646

4747
if (userResponse) {
48-
const client = new DefaultCloudFormationClient(node.regionCode)
48+
const client = new CloudFormationClient(node.regionCode)
4949

5050
await client.deleteStack(stackName)
5151

packages/core/src/lambda/explorer/cloudFormationNodes.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const localize = nls.loadMessageBundle()
99
import { CloudFormation, Lambda } from 'aws-sdk'
1010
import * as os from 'os'
1111
import * as vscode from 'vscode'
12-
import { DefaultCloudFormationClient } from '../../shared/clients/cloudFormationClient'
12+
import { CloudFormationClient, StackSummary } from '../../shared/clients/cloudFormation'
1313
import { DefaultLambdaClient } from '../../shared/clients/lambdaClient'
1414

1515
import { AWSResourceNode } from '../../shared/treeview/nodes/awsResourceNode'
@@ -28,7 +28,7 @@ export class CloudFormationNode extends AWSTreeNodeBase {
2828

2929
public constructor(
3030
public override readonly regionCode: string,
31-
private readonly client = new DefaultCloudFormationClient(regionCode)
31+
private readonly client = new CloudFormationClient(regionCode)
3232
) {
3333
super('CloudFormation', vscode.TreeItemCollapsibleState.Collapsed)
3434
this.stackNodes = new Map<string, CloudFormationStackNode>()
@@ -66,9 +66,9 @@ export class CloudFormationStackNode extends AWSTreeNodeBase implements AWSResou
6666
public constructor(
6767
public readonly parent: AWSTreeNodeBase,
6868
public override readonly regionCode: string,
69-
private stackSummary: CloudFormation.StackSummary,
69+
private stackSummary: StackSummary,
7070
private readonly lambdaClient = new DefaultLambdaClient(regionCode),
71-
private readonly cloudformationClient = new DefaultCloudFormationClient(regionCode)
71+
private readonly cloudformationClient = new CloudFormationClient(regionCode)
7272
) {
7373
super('', vscode.TreeItemCollapsibleState.Collapsed)
7474

@@ -114,7 +114,7 @@ export class CloudFormationStackNode extends AWSTreeNodeBase implements AWSResou
114114
})
115115
}
116116

117-
public update(stackSummary: CloudFormation.StackSummary): void {
117+
public update(stackSummary: StackSummary): void {
118118
this.stackSummary = stackSummary
119119
this.label = `${this.stackName} [${stackSummary.StackStatus}]`
120120
this.tooltip = `${this.stackName}${os.EOL}${this.stackId}`

packages/core/src/lambda/utils.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import * as nls from 'vscode-nls'
77
const localize = nls.loadMessageBundle()
88

99
import xml2js = require('xml2js')
10-
import { CloudFormation, Lambda } from 'aws-sdk'
10+
import { Lambda } from 'aws-sdk'
1111
import * as vscode from 'vscode'
12-
import { CloudFormationClient } from '../shared/clients/cloudFormationClient'
12+
import { CloudFormationClient, StackSummary } from '../shared/clients/cloudFormation'
1313
import { LambdaClient } from '../shared/clients/lambdaClient'
1414
import { getFamily, getNodeMajorVersion, RuntimeFamily } from './models/samLambdaRuntime'
1515
import { getLogger } from '../shared/logger/logger'
@@ -18,9 +18,7 @@ import { FileResourceFetcher } from '../shared/resourcefetcher/fileResourceFetch
1818
import { sampleRequestManifestPath } from './constants'
1919
import globals from '../shared/extensionGlobals'
2020

21-
export async function* listCloudFormationStacks(
22-
client: CloudFormationClient
23-
): AsyncIterableIterator<CloudFormation.StackSummary> {
21+
export async function* listCloudFormationStacks(client: CloudFormationClient): AsyncIterableIterator<StackSummary> {
2422
// TODO: this 'loading' message needs to go under each regional entry
2523
// in the explorer, and be removed when that region's query completes
2624
const status = vscode.window.setStatusBarMessage(
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import * as CloudFormation from '@aws-sdk/client-cloudformation'
7+
import { AsyncCollection } from '../utilities/asyncCollection'
8+
import { hasProps, isNonNullable, RequiredProps } from '../utilities/tsUtils'
9+
import { ClientWrapper } from './clientWrapper'
10+
11+
export interface StackSummary
12+
extends RequiredProps<CloudFormation.StackSummary, 'StackName' | 'CreationTime' | 'StackStatus'> {
13+
DriftInformation: RequiredProps<CloudFormation.StackDriftInformation, 'StackDriftStatus'>
14+
}
15+
16+
export type StackResource = RequiredProps<CloudFormation.StackResource, 'ResourceType'>
17+
18+
export interface DescribeStackResourcesOutput extends CloudFormation.DescribeStackResourcesOutput {
19+
StackResources: StackResource[]
20+
}
21+
export class CloudFormationClient extends ClientWrapper<CloudFormation.CloudFormationClient> {
22+
public constructor(regionCode: string) {
23+
super(regionCode, CloudFormation.CloudFormationClient)
24+
}
25+
26+
public async deleteStack(name: string): Promise<CloudFormation.DeleteStackCommandOutput> {
27+
return await this.makeRequest(CloudFormation.DeleteStackCommand, { StackName: name })
28+
}
29+
30+
public async describeType(typeName: string): Promise<CloudFormation.DescribeTypeOutput> {
31+
return await this.makeRequest(CloudFormation.DescribeTypeCommand, { TypeName: typeName })
32+
}
33+
34+
public async *listStacks(
35+
statusFilter: CloudFormation.StackStatus[] = ['CREATE_COMPLETE', 'UPDATE_COMPLETE']
36+
): AsyncIterableIterator<StackSummary> {
37+
const request: CloudFormation.ListStacksInput = {
38+
StackStatusFilter: statusFilter,
39+
}
40+
41+
do {
42+
const response: CloudFormation.ListStacksOutput = await this.makeRequest(
43+
CloudFormation.ListStacksCommand,
44+
request
45+
)
46+
47+
const filteredResponse = response.StackSummaries?.filter(isStackSummary)
48+
if (filteredResponse && filteredResponse.length > 0) {
49+
yield* filteredResponse
50+
}
51+
52+
request.NextToken = response.NextToken
53+
} while (request.NextToken)
54+
}
55+
56+
public listAllStacks(request: CloudFormation.ListStacksInput = {}): AsyncCollection<StackSummary[]> {
57+
return this.makePaginatedRequest(CloudFormation.paginateListStacks, request, (page) => page.StackSummaries).map(
58+
(s) => s.filter(isStackSummary)
59+
)
60+
}
61+
62+
public async *listTypes(): AsyncIterableIterator<CloudFormation.TypeSummary> {
63+
const request: CloudFormation.ListTypesInput = {
64+
DeprecatedStatus: 'LIVE',
65+
Type: 'RESOURCE',
66+
Visibility: 'PUBLIC',
67+
}
68+
69+
do {
70+
const response: CloudFormation.ListTypesOutput = await this.makeRequest(
71+
CloudFormation.ListTypesCommand,
72+
request
73+
)
74+
75+
if (response.TypeSummaries) {
76+
yield* response.TypeSummaries
77+
}
78+
79+
request.NextToken = response.NextToken
80+
} while (request.NextToken)
81+
}
82+
83+
public async describeStackResources(name: string): Promise<DescribeStackResourcesOutput> {
84+
return await this.makeRequest(CloudFormation.DescribeStackResourcesCommand, { StackName: name })
85+
}
86+
}
87+
88+
function isStackSummary(s: CloudFormation.StackSummary | undefined): s is StackSummary {
89+
return (
90+
isNonNullable(s) &&
91+
hasProps(s, 'StackName', 'CreationTime', 'StackStatus', 'DriftInformation') &&
92+
hasProps(s.DriftInformation, 'StackDriftStatus')
93+
)
94+
}

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

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

packages/core/src/shared/sam/deploy.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { AWSTreeNodeBase } from '../treeview/nodes/awsTreeNodeBase'
88
import { TreeNode, isTreeNode } from '../treeview/resourceTreeDataProvider'
99
import globals from '../../shared/extensionGlobals'
1010
import { ToolkitError } from '../../shared/errors'
11-
import { DefaultCloudFormationClient } from '../clients/cloudFormationClient'
11+
import { CloudFormationClient } from '../clients/cloudFormation'
1212
import { S3Client } from '../clients/s3'
1313
import { samDeployUrl } from '../constants'
1414
import { getSpawnEnv } from '../env/resolveEnv'
@@ -115,8 +115,7 @@ export class DeployWizard extends CompositeWizard<DeployParams> {
115115
paramsSource === ParamsSource.Specify || paramsSource === ParamsSource.SpecifyAndSave,
116116
})
117117
this.form.stackName.bindPrompter(
118-
({ region }) =>
119-
createStackPrompter(new DefaultCloudFormationClient(region!), deployMementoRootKey, samDeployUrl),
118+
({ region }) => createStackPrompter(new CloudFormationClient(region!), deployMementoRootKey, samDeployUrl),
120119
{
121120
showWhen: ({ paramsSource }) =>
122121
paramsSource === ParamsSource.Specify || paramsSource === ParamsSource.SpecifyAndSave,

packages/core/src/shared/sam/sync.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import * as path from 'path'
1010
import * as localizedText from '../localizedText'
1111
import { S3Client } from '../clients/s3'
1212
import { DataQuickPickItem, createMultiPick, createQuickPick } from '../ui/pickerPrompter'
13-
import { DefaultCloudFormationClient } from '../clients/cloudFormationClient'
13+
import { CloudFormationClient } from '../clients/cloudFormation'
1414
import * as CloudFormation from '../cloudformation/cloudformation'
1515
import { DefaultEcrClient } from '../clients/ecrClient'
1616
import { createRegionPrompter } from '../ui/common/region'
@@ -217,8 +217,7 @@ export class SyncWizard extends CompositeWizard<SyncParams> {
217217
})
218218

219219
this.form.stackName.bindPrompter(
220-
({ region }) =>
221-
createStackPrompter(new DefaultCloudFormationClient(region!), syncMementoRootKey, samSyncUrl),
220+
({ region }) => createStackPrompter(new CloudFormationClient(region!), syncMementoRootKey, samSyncUrl),
222221
{
223222
showWhen: ({ paramsSource }) =>
224223
paramsSource === ParamsSource.Specify || paramsSource === ParamsSource.SpecifyAndSave,

packages/core/src/shared/ui/sam/stackPrompter.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55
import { StackSummary } from 'aws-sdk/clients/cloudformation'
66
import { getAwsConsoleUrl } from '../../awsConsole'
7-
import { DefaultCloudFormationClient } from '../../clients/cloudFormationClient'
7+
import { CloudFormationClient } from '../../clients/cloudFormation'
88
import * as vscode from 'vscode'
99
import { createCommonButtons } from '../buttons'
1010
import { createQuickPick } from '../pickerPrompter'
@@ -27,11 +27,7 @@ const canShowStack = (s: StackSummary) =>
2727
* @returns A quick pick prompter configured for stack selection
2828
*
2929
*/
30-
export function createStackPrompter(
31-
client: DefaultCloudFormationClient,
32-
mementoRootKey: string,
33-
samCommandUrl: vscode.Uri
34-
) {
30+
export function createStackPrompter(client: CloudFormationClient, mementoRootKey: string, samCommandUrl: vscode.Uri) {
3531
const recentStack = getRecentResponse(mementoRootKey, client.regionCode, 'stackName')
3632
const consoleUrl = getAwsConsoleUrl('cloudformation', client.regionCode)
3733
const items = client.listAllStacks().map((stacks) =>

0 commit comments

Comments
 (0)