Skip to content

Commit a5317ca

Browse files
authored
feat(cli): --hotswap will not use CFN anymore, --hotswap-fallback to fall back if necessary (#23653)
Changes the behavior of `--hotswap` to ignore all non-hotswappable changes and hotswap what it can. This works at two levels: changes to non-hotswappable resources are ignored, as well as non-hotswappable changes to hotswappable resources (eg `Tags` on a Lambda Function). In addition, non-hotswappable changes are now logged; the logical ID, rejected changes, resource type, and reason why the changes were rejected are all provided for each non-hotswappable change. At some point, support for tags of lambda functions was added. This either broke or simply never worked, and so this PR removes all logic to handle Tags. The existing behavior of `--hotswap` can be used in `--hotswap-fallback`. It is preserved and unmodified by this change. Closes #22784, #21773, #21556, #23640. ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Construct Runtime Dependencies: * [ ] This PR adds new construct runtime dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-construct-runtime-dependencies) ### New Features * [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [ ] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 08a2f36 commit a5317ca

28 files changed

+5935
-4844
lines changed

Diff for: packages/aws-cdk/README.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -375,15 +375,20 @@ $ cdk deploy --hotswap [StackNames]
375375
```
376376

377377
This will attempt to perform a faster, short-circuit deployment if possible
378-
(for example, if you only changed the code of a Lambda function in your CDK app,
379-
but nothing else in your CDK code),
378+
(for example, if you changed the code of a Lambda function in your CDK app),
380379
skipping CloudFormation, and updating the affected resources directly;
381380
this includes changes to resources in nested stacks.
382381
If the tool detects that the change does not support hotswapping,
383-
it will fall back and perform a full CloudFormation deployment,
384-
exactly like `cdk deploy` does without the `--hotswap` flag.
382+
it will ignore it and display that ignored change.
383+
To have hotswap fall back and perform a full CloudFormation deployment,
384+
exactly like `cdk deploy` does without the `--hotswap` flag,
385+
specify `--hotswap-fallback`, like so:
385386

386-
Passing this option to `cdk deploy` will make it use your current AWS credentials to perform the API calls -
387+
```console
388+
$ cdk deploy --hotswap-fallback [StackNames]
389+
```
390+
391+
Passing either option to `cdk deploy` will make it use your current AWS credentials to perform the API calls -
387392
it will not assume the Roles from your bootstrap stack,
388393
even if the `@aws-cdk/core:newStyleStackSynthesis` feature flag is set to `true`
389394
(as those Roles do not have the necessary permissions to update AWS resources directly, without using CloudFormation).

Diff for: packages/aws-cdk/lib/api/cloudformation-deployments.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Mode } from './aws-auth/credentials';
77
import { ISDK } from './aws-auth/sdk';
88
import { SdkProvider } from './aws-auth/sdk-provider';
99
import { deployStack, DeployStackResult, destroyStack, makeBodyParameterAndUpload, DeploymentMethod } from './deploy-stack';
10+
import { HotswapMode } from './hotswap/common';
1011
import { loadCurrentTemplateWithNestedStacks, loadCurrentTemplate } from './nested-stack-helpers';
1112
import { ToolkitInfo } from './toolkit-info';
1213
import { CloudFormationStack, Template, ResourcesToImport, ResourceIdentifierSummaries } from './util/cloudformation';
@@ -224,9 +225,9 @@ export interface DeployStackOptions {
224225
* A 'hotswap' deployment will attempt to short-circuit CloudFormation
225226
* and update the affected resources like Lambda functions directly.
226227
*
227-
* @default - false for regular deployments, true for 'watch' deployments
228+
* @default - `HotswapMode.FULL_DEPLOYMENT` for regular deployments, `HotswapMode.HOTSWAP_ONLY` for 'watch' deployments
228229
*/
229-
readonly hotswap?: boolean;
230+
readonly hotswap?: HotswapMode;
230231

231232
/**
232233
* The extra string to append to the User-Agent header when performing AWS SDK calls.

Diff for: packages/aws-cdk/lib/api/deploy-stack.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { contentHash } from '../util/content-hash';
1313
import { ISDK, SdkProvider } from './aws-auth';
1414
import { CfnEvaluationException } from './evaluate-cloudformation-template';
1515
import { tryHotswapDeployment } from './hotswap-deployments';
16-
import { ICON } from './hotswap/common';
16+
import { HotswapMode, ICON } from './hotswap/common';
1717
import { ToolkitInfo } from './toolkit-info';
1818
import {
1919
changeSetHasNoChanges, CloudFormationStack, TemplateParameters, waitForChangeSet,
@@ -175,9 +175,9 @@ export interface DeployStackOptions {
175175
* A 'hotswap' deployment will attempt to short-circuit CloudFormation
176176
* and update the affected resources like Lambda functions directly.
177177
*
178-
* @default - false for regular deployments, true for 'watch' deployments
178+
* @default - `HotswapMode.FULL_DEPLOYMENT` for regular deployments, `HotswapMode.HOTSWAP_ONLY` for 'watch' deployments
179179
*/
180-
readonly hotswap?: boolean;
180+
readonly hotswap?: HotswapMode;
181181

182182
/**
183183
* The extra string to append to the User-Agent header when performing AWS SDK calls.
@@ -298,10 +298,13 @@ export async function deployStack(options: DeployStackOptions): Promise<DeploySt
298298
parallel: options.assetParallelism,
299299
});
300300

301-
if (options.hotswap) {
301+
const hotswapMode = options.hotswap;
302+
if (hotswapMode && hotswapMode !== HotswapMode.FULL_DEPLOYMENT) {
302303
// attempt to short-circuit the deployment if possible
303304
try {
304-
const hotswapDeploymentResult = await tryHotswapDeployment(options.sdkProvider, assetParams, cloudFormationStack, stackArtifact);
305+
const hotswapDeploymentResult = await tryHotswapDeployment(
306+
options.sdkProvider, stackParams.values, cloudFormationStack, stackArtifact, hotswapMode,
307+
);
305308
if (hotswapDeploymentResult) {
306309
return hotswapDeploymentResult;
307310
}
@@ -312,16 +315,20 @@ export async function deployStack(options: DeployStackOptions): Promise<DeploySt
312315
}
313316
print('Could not perform a hotswap deployment, because the CloudFormation template could not be resolved: %s', e.message);
314317
}
315-
print('Falling back to doing a full deployment');
316-
options.sdk.appendCustomUserAgent('cdk-hotswap/fallback');
318+
319+
if (hotswapMode === HotswapMode.FALL_BACK) {
320+
print('Falling back to doing a full deployment');
321+
options.sdk.appendCustomUserAgent('cdk-hotswap/fallback');
322+
} else {
323+
return { noOp: true, stackArn: cloudFormationStack.stackId, outputs: cloudFormationStack.outputs };
324+
}
317325
}
318326

319327
// could not short-circuit the deployment, perform a full CFN deploy instead
320328
const fullDeployment = new FullCloudFormationDeployment(options, cloudFormationStack, stackArtifact, stackParams, bodyParameter);
321329
return fullDeployment.performDeployment();
322330
}
323331

324-
325332
type CommonPrepareOptions =
326333
& keyof CloudFormation.CreateStackInput
327334
& keyof CloudFormation.UpdateStackInput

0 commit comments

Comments
 (0)