Skip to content

Commit 41e360b

Browse files
ShadowCat567aws-amplify-bot
authored andcommitted
Feat: Update Gen1 Data to be compatible with SDK v2->V3 migrations happening in Gen1 CLI (#3310)
* fix: remove global config * chore: update api * v1.0.0 * Revert "v1.0.0" This reverts commit 1aca077. * fix: ssmclient can use v1 or v2 * chore: add ssm-client * chore: update dep license * fix: update expected error message * chore: update node types * chore: update node type for client-test-app * chore: update jest to handle node: imports * chore: upgrade jest * chore: licenses * Revert "chore: licenses" This reverts commit 8e43f0e. * Revert "chore: upgrade jest" This reverts commit fa3dc3d. * chore: change client-ssm version * chore: license * chore: update yarn lock * chore: remove workaround * fix: unit tests and better way of identifing v3 client * chore: license * chore: update v3 Client detection * fix: search for other acc for FunctionTransformerV2 test like main does --------- Co-authored-by: aws-amplify-bot <aws@amazon.com>
1 parent 7fdfe6f commit 41e360b

22 files changed

Lines changed: 892 additions & 337 deletions

File tree

client-test-apps/js/api-model-relationship-app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"@types/ini": "^1.3.31",
1212
"@types/jest": "^27.5.2",
1313
"@types/jest-dev-server": "^5.0.0",
14-
"@types/node": "^16.11.56",
14+
"@types/node": "^18.18.0",
1515
"@types/react": "18.2.42",
1616
"@types/react-dom": "^18.0.6",
1717
"aws-amplify": "^4.3.30",

dependency_licenses.txt

Lines changed: 76 additions & 2 deletions
Large diffs are not rendered by default.

packages/amplify-category-api/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@aws-sdk/client-ec2": "3.624.0",
4040
"@aws-sdk/client-iam": "3.624.0",
4141
"@aws-sdk/client-lambda": "3.624.0",
42+
"@aws-sdk/client-ssm": "3.624.0",
4243
"@graphql-tools/merge": "^6.0.18",
4344
"@octokit/rest": "^20.1.2",
4445
"aws-sdk": "^2.1113.0",
@@ -81,8 +82,10 @@
8182
"devDependencies": {
8283
"@aws-amplify/graphql-transformer-test-utils": "0.6.7",
8384
"@types/js-yaml": "^4.0.0",
84-
"@types/node": "^12.12.6",
85+
"@types/node": "^18.18.0",
8586
"amplify-util-headless-input": "^1.9.18",
87+
"aws-sdk-client-mock": "3.0.1",
88+
"aws-sdk-client-mock-jest": "3.0.1",
8689
"ts-jest": "26.4.4"
8790
},
8891
"jest": {

packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rds-secrets/ssmClient.test.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import { $TSContext } from '@aws-amplify/amplify-cli-core';
22
import { SSMClient } from '../../../../../provider-utils/awscloudformation/utils/rds-resources/ssmClient';
33
import aws from 'aws-sdk';
4+
import {
5+
DeleteParameterCommand,
6+
DeleteParametersCommand,
7+
GetParametersCommand,
8+
PutParameterCommand,
9+
SSMClient as SSM_Client,
10+
} from '@aws-sdk/client-ssm';
11+
import { mockClient } from 'aws-sdk-client-mock';
12+
import 'aws-sdk-client-mock-jest';
413

514
const secretName = 'mock-test-secret-name';
615
const secretValue = 'mock-test-secret-value';
@@ -36,6 +45,8 @@ jest.mock('aws-sdk', () => {
3645
};
3746
});
3847

48+
const mockSSMClient = mockClient(SSM_Client);
49+
3950
describe('SSM client configuration', () => {
4051
const mockContext = {
4152
amplify: {
@@ -91,3 +102,70 @@ describe('SSM client configuration', () => {
91102
});
92103
});
93104
});
105+
106+
describe('SSM V3 Client Configuration', () => {
107+
const mockContext = {
108+
amplify: {
109+
invokePluginMethod: jest.fn().mockResolvedValue({ client: new SSM_Client() }),
110+
},
111+
} as any as $TSContext;
112+
113+
beforeEach(() => {
114+
mockSSMClient.reset();
115+
mockSSMClient.on(PutParameterCommand).resolves({});
116+
mockSSMClient.on(GetParametersCommand).resolves({
117+
Parameters: [{ Name: secretName, Value: secretValue }],
118+
});
119+
mockSSMClient.on(DeleteParameterCommand).resolves({});
120+
mockSSMClient.on(DeleteParameterCommand).resolves({});
121+
});
122+
123+
test('able to get the configured SSM instance via provider plugin', async () => {
124+
(SSMClient as any).instance = undefined;
125+
const ssmClient = await SSMClient.getInstance(mockContext);
126+
expect(ssmClient).toBeDefined();
127+
expect(mockContext.amplify.invokePluginMethod).toBeCalledTimes(1);
128+
expect(mockContext.amplify.invokePluginMethod).toBeCalledWith(mockContext, 'awscloudformation', undefined, 'getConfiguredSSMClient', [
129+
mockContext,
130+
]);
131+
});
132+
133+
test('able to set the secret value', async () => {
134+
const ssmClient = await SSMClient.getInstance(mockContext);
135+
136+
ssmClient.setSecret(secretName, secretValue);
137+
expect(mockSSMClient).toHaveReceivedCommandWith(PutParameterCommand, {
138+
Name: secretName,
139+
Overwrite: true,
140+
Type: 'SecureString',
141+
Value: secretValue,
142+
});
143+
});
144+
145+
test('able to get the secret value', async () => {
146+
const ssmClient = await SSMClient.getInstance(mockContext);
147+
const result = await ssmClient.getSecrets([secretName]);
148+
149+
expect(mockSSMClient).toHaveReceivedCommandWith(GetParametersCommand, {
150+
Names: [secretName],
151+
WithDecryption: true,
152+
});
153+
expect(result).toEqual([{ secretName: secretName, secretValue: secretValue }]);
154+
});
155+
156+
test('able to delete the secret', async () => {
157+
const ssmClient = await SSMClient.getInstance(mockContext);
158+
ssmClient.deleteSecret(secretName);
159+
expect(mockSSMClient).toHaveReceivedCommandWith(DeleteParameterCommand, {
160+
Name: secretName,
161+
});
162+
});
163+
164+
test('able to delete multiple secrets', async () => {
165+
const ssmClient = await SSMClient.getInstance(mockContext);
166+
ssmClient.deleteSecrets([secretName]);
167+
expect(mockSSMClient).toHaveReceivedCommandWith(DeleteParametersCommand, {
168+
Names: [secretName],
169+
});
170+
});
171+
});

packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const name = subcommand;
3333
*/
3434
export const run = async (context: $TSContext): Promise<void> => {
3535
try {
36-
const AWS = await getAwsClient(context, 'list');
36+
const AWSConfig = await getAwsClientConfig(context, 'list');
3737

3838
const result: any = await datasourceSelectionPrompt(context, supportedDataSources);
3939

@@ -76,7 +76,7 @@ export const run = async (context: $TSContext): Promise<void> => {
7676
answers.secretStoreArn,
7777
answers.dbClusterArn,
7878
answers.databaseName,
79-
AWS,
79+
AWSConfig,
8080
);
8181

8282
/**
@@ -219,12 +219,12 @@ const datasourceSelectionPrompt = async (context: $TSContext, supportedDataSourc
219219
return inquirer.prompt(question).then((answer) => answer.datasource);
220220
};
221221

222-
const getAwsClient = async (context: $TSContext, action: string): Promise<any> => {
222+
const getAwsClientConfig = async (context: $TSContext, action: string): Promise<any> => {
223223
const providerPlugins = context.amplify.getProviderPlugins(context);
224224
// eslint-disable-next-line
225225
const provider = require(providerPlugins[providerName]);
226226

227-
return provider.getConfiguredAWSClient(context, 'aurora-serverless', action);
227+
return provider.getConfiguredAWSClientConfig(context, 'aurora-serverless', action);
228228
};
229229

230230
/**

packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import chalk from 'chalk';
1212
import { DataApiParams } from 'graphql-relational-schema-transformer';
1313
import ora from 'ora';
1414
import { rootStackFileName } from '@aws-amplify/amplify-provider-awscloudformation';
15+
import * as aws from 'aws-sdk';
1516

1617
const spinner = ora('');
1718
const category = 'api';
@@ -62,30 +63,28 @@ export async function serviceWalkthrough(context: $TSContext, datasourceMetadata
6263
selectedRegion = await promptWalkthroughQuestion(inputs, 0, availableRegions);
6364
}
6465

65-
const AWS = await getAwsClient(context, 'list');
66+
const AWSConfig = await getAwsClientConfig(context, 'list');
6667

6768
// Prepare the SDK with the region
68-
AWS.config.update({
69-
region: selectedRegion,
70-
});
69+
const config = { ...AWSConfig, region: selectedRegion };
7170

7271
// RDS Cluster Question
7372
let selectedClusterArn = cfnJsonParameters?.rdsClusterIdentifier;
74-
let clusterResourceId = getRdsClusterResourceIdFromArn(selectedClusterArn, AWS);
73+
let clusterResourceId = getRdsClusterResourceIdFromArn(selectedClusterArn, config);
7574
if (!selectedClusterArn || !clusterResourceId) {
76-
({ selectedClusterArn, clusterResourceId } = await selectCluster(context, inputs, AWS));
75+
({ selectedClusterArn, clusterResourceId } = await selectCluster(context, inputs, config));
7776
}
7877

7978
// Secret Store Question
8079
let selectedSecretArn = cfnJsonParameters?.rdsSecretStoreArn;
8180
if (!selectedSecretArn) {
82-
selectedSecretArn = await getSecretStoreArn(context, inputs, clusterResourceId, AWS);
81+
selectedSecretArn = await getSecretStoreArn(context, inputs, clusterResourceId, config);
8382
}
8483

8584
// Database Name Question
8685
let selectedDatabase = cfnJsonParameters?.rdsDatabaseName;
8786
if (!selectedDatabase) {
88-
selectedDatabase = await selectDatabase(context, inputs, selectedClusterArn, selectedSecretArn, AWS);
87+
selectedDatabase = await selectDatabase(context, inputs, selectedClusterArn, selectedSecretArn, config);
8988
}
9089

9190
return {
@@ -97,13 +96,13 @@ export async function serviceWalkthrough(context: $TSContext, datasourceMetadata
9796
};
9897
}
9998

100-
async function getRdsClusterResourceIdFromArn(arn: string | undefined, AWS) {
99+
async function getRdsClusterResourceIdFromArn(arn: string | undefined, AWSConfig) {
101100
// If the arn was not already existing in cloudformation template, return undefined to prompt for input.
102101
if (!arn) {
103102
return;
104103
}
105104

106-
const RDS = new AWS.RDS();
105+
const RDS = new aws.RDS(AWSConfig);
107106
const describeDBClustersResult = await RDS.describeDBClusters().promise();
108107
const rawClusters = describeDBClustersResult.DBClusters;
109108
const identifiedCluster = rawClusters.find((cluster) => cluster.DBClusterArn === arn);
@@ -114,8 +113,8 @@ async function getRdsClusterResourceIdFromArn(arn: string | undefined, AWS) {
114113
*
115114
* @param {*} inputs
116115
*/
117-
async function selectCluster(context: $TSContext, inputs, AWS) {
118-
const RDS = new AWS.RDS();
116+
async function selectCluster(context: $TSContext, inputs, AWSConfig) {
117+
const RDS = new aws.RDS(AWSConfig);
119118

120119
const describeDBClustersResult = await RDS.describeDBClusters().promise();
121120
const rawClusters = describeDBClustersResult.DBClusters;
@@ -163,8 +162,8 @@ async function selectCluster(context: $TSContext, inputs, AWS) {
163162
* @param {*} inputs
164163
* @param {*} clusterResourceId
165164
*/
166-
async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, AWS) {
167-
const SecretsManager = new AWS.SecretsManager();
165+
async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, AWSConfig) {
166+
const SecretsManager = new aws.SecretsManager(AWSConfig);
168167
const NextToken = 'NextToken';
169168
let rawSecrets = [];
170169
const params = {
@@ -221,9 +220,9 @@ async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId,
221220
* @param {*} clusterArn
222221
* @param {*} secretArn
223222
*/
224-
async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn, AWS) {
223+
async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn, AWSConfig) {
225224
// Database Name Question
226-
const DataApi = new AWS.RDSDataService();
225+
const DataApi = new aws.RDSDataService(AWSConfig);
227226
const params = new DataApiParams();
228227
const databaseList = [];
229228
params.secretArn = secretArn;
@@ -285,8 +284,8 @@ async function promptWalkthroughQuestion(inputs, questionNumber, choicesList) {
285284
return await prompter.pick(question.message, choicesList);
286285
}
287286

288-
async function getAwsClient(context: $TSContext, action: string) {
287+
async function getAwsClientConfig(context: $TSContext, action: string) {
289288
const providerPlugins = context.amplify.getProviderPlugins(context);
290289
const provider = require(providerPlugins[providerName]);
291-
return await provider.getConfiguredAWSClient(context, 'aurora-serverless', action);
290+
return await provider.getConfiguredAWSClientConfig(context, 'aurora-serverless', action);
292291
}

0 commit comments

Comments
 (0)