Skip to content

Commit 0d9912f

Browse files
authored
refactor(cli): stack monitor uses io-host (#150)
Provides stack events to the IoHost in a structured way. The main change here is that `StackActivityMonitor` does not directly talk to the `ActivityPrinter` anymore. Instead messages are emitted to the `IoHost`. This caused two related changes: - Progress tracking has been split into a more generic `StackProgressMonitor` and progress information is now provided directly by the `StackActivityMonitor` - Originally we only had a single timer that covered polling events and printing them. With the split, we now have two separate timers: one for polling events and a separate one for updating the view Removed low-level options: - `progress` -> now a `CliIoHost` property - `ci` -> use value from `CliIoHost` directly instead of passing through all the layers - `quiet` -> surprisingly this was unused by CLI. We should have something like this again, but can be implemented in a follow up PR. Manually tested the changes in addition to integ tests. --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license
1 parent f0677df commit 0d9912f

34 files changed

+1659
-1310
lines changed

packages/@aws-cdk/toolkit-lib/CODE_REGISTRY.md

+4
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@
1313
| CDK_TOOLKIT_I5031 | Informs about any log groups that are traced as part of the deployment | info | n/a |
1414
| CDK_TOOLKIT_I5050 | Confirm rollback during deployment | info | n/a |
1515
| CDK_TOOLKIT_I5060 | Confirm deploy security sensitive changes | info | n/a |
16+
| CDK_TOOLKIT_I5501 | Stack Monitoring: Start monitoring of a single stack | info | [StackMonitoringControlEvent](https://docs.aws.amazon.com/cdk/api/toolkit-lib/interfaces/StackMonitoringControlEvent.html) |
17+
| CDK_TOOLKIT_I5502 | Stack Monitoring: Activity event for a single stack | info | [StackActivity](https://docs.aws.amazon.com/cdk/api/toolkit-lib/interfaces/StackActivity.html) |
18+
| CDK_TOOLKIT_I5503 | Stack Monitoring: Finished monitoring of a single stack | info | [StackMonitoringControlEvent](https://docs.aws.amazon.com/cdk/api/toolkit-lib/interfaces/StackMonitoringControlEvent.html) |
1619
| CDK_TOOLKIT_I5900 | Deployment results on success | result | [SuccessfulDeployStackResult](https://docs.aws.amazon.com/cdk/api/toolkit-lib/interfaces/SuccessfulDeployStackResult.html) |
1720
| CDK_TOOLKIT_E5001 | No stacks found | error | n/a |
21+
| CDK_TOOLKIT_E5500 | Stack Monitoring error | error | [ErrorPayload](https://docs.aws.amazon.com/cdk/api/toolkit-lib/interfaces/ErrorPayload.html) |
1822
| CDK_TOOLKIT_I6000 | Provides rollback times | info | n/a |
1923
| CDK_TOOLKIT_E6001 | No stacks found | error | n/a |
2024
| CDK_TOOLKIT_E6900 | Rollback failed | error | n/a |

packages/@aws-cdk/toolkit-lib/lib/actions/deploy/index.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { BaseDeployOptions } from './private/deploy-options';
2-
import type { StackActivityProgress, Tag } from '../../api/aws-cdk';
2+
import type { Tag } from '../../api/aws-cdk';
33

44
export type DeploymentMethod = DirectDeploymentMethod | ChangeSetDeploymentMethod;
55

@@ -164,16 +164,16 @@ export interface DeployOptions extends BaseDeployOptions {
164164
/**
165165
* Change stack watcher output to CI mode.
166166
*
167-
* @deprecated Implement in IoHost instead
167+
* @deprecated has no functionality, please implement in your IoHost
168168
*/
169169
readonly ci?: boolean;
170170

171171
/**
172172
* Display mode for stack deployment progress.
173173
*
174-
* @deprecated Implement in IoHost instead
174+
* @deprecated has no functionality, please implement in your IoHost
175175
*/
176-
readonly progress?: StackActivityProgress;
176+
readonly progress?: any;
177177

178178
/**
179179
* Represents configuration property overrides for hotswap deployments.

packages/@aws-cdk/toolkit-lib/lib/api/aws-cdk.ts

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ export { Settings } from '../../../../aws-cdk/lib/api/settings';
88
export { tagsForStack, Tag } from '../../../../aws-cdk/lib/api/tags';
99
export { DEFAULT_TOOLKIT_STACK_NAME } from '../../../../aws-cdk/lib/api/toolkit-info';
1010
export { ResourceMigrator } from '../../../../aws-cdk/lib/api/resource-import';
11-
export { StackActivityProgress } from '../../../../aws-cdk/lib/api/stack-events';
1211
export { CloudWatchLogEventMonitor, findCloudWatchLogGroups } from '../../../../aws-cdk/lib/api/logs';
1312
export { type WorkGraph, WorkGraphBuilder, AssetBuildNode, AssetPublishNode, StackNode, Concurrency } from '../../../../aws-cdk/lib/api/work-graph';
1413

packages/@aws-cdk/toolkit-lib/lib/api/io/private/codes.ts

+26
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,26 @@ export const CODES = {
109109
description: 'Confirm deploy security sensitive changes',
110110
level: 'info',
111111
}),
112+
113+
CDK_TOOLKIT_I5501: codeInfo({
114+
code: 'CDK_TOOLKIT_I5501',
115+
description: 'Stack Monitoring: Start monitoring of a single stack',
116+
level: 'info',
117+
interface: 'StackMonitoringControlEvent',
118+
}),
119+
CDK_TOOLKIT_I5502: codeInfo({
120+
code: 'CDK_TOOLKIT_I5502',
121+
description: 'Stack Monitoring: Activity event for a single stack',
122+
level: 'info',
123+
interface: 'StackActivity',
124+
}),
125+
CDK_TOOLKIT_I5503: codeInfo({
126+
code: 'CDK_TOOLKIT_I5503',
127+
description: 'Stack Monitoring: Finished monitoring of a single stack',
128+
level: 'info',
129+
interface: 'StackMonitoringControlEvent',
130+
}),
131+
112132
CDK_TOOLKIT_I5900: codeInfo({
113133
code: 'CDK_TOOLKIT_I5900',
114134
description: 'Deployment results on success',
@@ -121,6 +141,12 @@ export const CODES = {
121141
description: 'No stacks found',
122142
level: 'error',
123143
}),
144+
CDK_TOOLKIT_E5500: codeInfo({
145+
code: 'CDK_TOOLKIT_E5500',
146+
description: 'Stack Monitoring error',
147+
level: 'error',
148+
interface: 'ErrorPayload',
149+
}),
124150

125151
// 6: Rollback
126152
CDK_TOOLKIT_I6000: codeInfo({

packages/@aws-cdk/toolkit-lib/lib/toolkit/toolkit.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { type SynthOptions } from '../actions/synth';
1515
import { WatchOptions } from '../actions/watch';
1616
import { patternsArrayForWatch } from '../actions/watch/private';
1717
import { type SdkConfig } from '../api/aws-auth';
18-
import { DEFAULT_TOOLKIT_STACK_NAME, SdkProvider, SuccessfulDeployStackResult, StackCollection, Deployments, HotswapMode, StackActivityProgress, ResourceMigrator, obscureTemplate, serializeStructure, tagsForStack, CliIoHost, validateSnsTopicArn, Concurrency, WorkGraphBuilder, AssetBuildNode, AssetPublishNode, StackNode, formatErrorMessage, CloudWatchLogEventMonitor, findCloudWatchLogGroups, formatTime, StackDetails } from '../api/aws-cdk';
18+
import { DEFAULT_TOOLKIT_STACK_NAME, SdkProvider, SuccessfulDeployStackResult, StackCollection, Deployments, HotswapMode, ResourceMigrator, obscureTemplate, serializeStructure, tagsForStack, CliIoHost, validateSnsTopicArn, Concurrency, WorkGraphBuilder, AssetBuildNode, AssetPublishNode, StackNode, formatErrorMessage, CloudWatchLogEventMonitor, findCloudWatchLogGroups, formatTime, StackDetails } from '../api/aws-cdk';
1919
import { ICloudAssemblySource, StackSelectionStrategy } from '../api/cloud-assembly';
2020
import { ALL_STACKS, CachedCloudAssemblySource, CloudAssemblySourceBuilder, IdentityCloudAssemblySource, StackAssembly } from '../api/cloud-assembly/private';
2121
import { ToolkitError } from '../api/errors';
@@ -375,8 +375,6 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
375375
force: options.force,
376376
parameters: Object.assign({}, parameterMap['*'], parameterMap[stack.stackName]),
377377
usePreviousParameters: options.parameters?.keepExistingParameters,
378-
progress,
379-
ci: options.ci,
380378
rollback,
381379
hotswap: hotswapMode,
382380
extraUserAgent: options.extraUserAgent,
@@ -494,10 +492,6 @@ export class Toolkit extends CloudAssemblySourceBuilder implements AsyncDisposab
494492
const assetBuildTime = options.assetBuildTime ?? AssetBuildTime.ALL_BEFORE_DEPLOY;
495493
const prebuildAssets = assetBuildTime === AssetBuildTime.ALL_BEFORE_DEPLOY;
496494
const concurrency = options.concurrency || 1;
497-
const progress = concurrency > 1 ? StackActivityProgress.EVENTS : options.progress;
498-
if (concurrency > 1 && options.progress && options.progress != StackActivityProgress.EVENTS) {
499-
await ioHost.notify(warn('⚠️ The --concurrency flag only supports --progress "events". Switching to "events".'));
500-
}
501495

502496
const stacksAndTheirAssetManifests = stacks.flatMap((stack) => [
503497
stack,

packages/@aws-cdk/toolkit-lib/lib/toolkit/types.ts

+10
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,13 @@ export interface Duration {
7676
*/
7777
readonly duration: number;
7878
}
79+
80+
/**
81+
* Generic payload of error IoMessages that pass on an instance of `Error`
82+
*/
83+
export interface ErrorPayload {
84+
/**
85+
* The error that occurred
86+
*/
87+
readonly error: Error;
88+
}

packages/aws-cdk/lib/api/deployments/deploy-stack.ts

+22-39
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import type { SDK, SdkProvider, ICloudFormationClient } from '../aws-auth';
3636
import type { EnvironmentResources } from '../environment';
3737
import { CfnEvaluationException } from '../evaluate-cloudformation-template';
3838
import { HotswapMode, HotswapPropertyOverrides, ICON } from '../hotswap/common';
39-
import { StackActivityMonitor, type StackActivityProgress } from '../stack-events';
39+
import { StackActivityMonitor } from '../stack-events';
4040
import { StringWithoutPlaceholders } from '../util/placeholders';
4141
import { type TemplateBodyParameter, makeBodyParameter } from '../util/template-body-parameter';
4242

@@ -105,13 +105,6 @@ export interface DeployStackOptions {
105105
*/
106106
readonly deployName?: string;
107107

108-
/**
109-
* Quiet or verbose deployment
110-
*
111-
* @default false
112-
*/
113-
readonly quiet?: boolean;
114-
115108
/**
116109
* List of asset IDs which shouldn't be built
117110
*
@@ -153,27 +146,12 @@ export interface DeployStackOptions {
153146
*/
154147
readonly usePreviousParameters?: boolean;
155148

156-
/**
157-
* Display mode for stack deployment progress.
158-
*
159-
* @default StackActivityProgress.Bar stack events will be displayed for
160-
* the resource currently being deployed.
161-
*/
162-
readonly progress?: StackActivityProgress;
163-
164149
/**
165150
* Deploy even if the deployed template is identical to the one we are about to deploy.
166151
* @default false
167152
*/
168153
readonly force?: boolean;
169154

170-
/**
171-
* Whether we are on a CI system
172-
*
173-
* @default false
174-
*/
175-
readonly ci?: boolean;
176-
177155
/**
178156
* Rollback failed deployments
179157
*
@@ -612,14 +590,16 @@ class FullCloudFormationDeployment {
612590
}
613591

614592
private async monitorDeployment(startTime: Date, expectedChanges: number | undefined): Promise<SuccessfulDeployStackResult> {
615-
const monitor = this.options.quiet
616-
? undefined
617-
: StackActivityMonitor.withDefaultPrinter(this.cfn, this.stackName, this.stackArtifact, {
618-
resourcesTotal: expectedChanges,
619-
progress: this.options.progress,
620-
changeSetCreationTime: startTime,
621-
ci: this.options.ci,
622-
}).start();
593+
const monitor = new StackActivityMonitor({
594+
cfn: this.cfn,
595+
stack: this.stackArtifact,
596+
stackName: this.stackName,
597+
resourcesTotal: expectedChanges,
598+
ioHost: this.ioHost,
599+
action: this.action,
600+
changeSetCreationTime: startTime,
601+
});
602+
await monitor.start();
623603

624604
let finalState = this.cloudFormationStack;
625605
try {
@@ -631,9 +611,9 @@ class FullCloudFormationDeployment {
631611
}
632612
finalState = successStack;
633613
} catch (e: any) {
634-
throw new ToolkitError(suffixWithErrors(formatErrorMessage(e), monitor?.errors));
614+
throw new ToolkitError(suffixWithErrors(formatErrorMessage(e), monitor.errors));
635615
} finally {
636-
await monitor?.stop();
616+
await monitor.stop();
637617
}
638618
debug(this.action, format('Stack %s has completed updating', this.stackName));
639619
return {
@@ -696,11 +676,14 @@ export async function destroyStack(options: DestroyStackOptions, { ioHost, actio
696676
if (!currentStack.exists) {
697677
return;
698678
}
699-
const monitor = options.quiet
700-
? undefined
701-
: StackActivityMonitor.withDefaultPrinter(cfn, deployName, options.stack, {
702-
ci: options.ci,
703-
}).start();
679+
const monitor = new StackActivityMonitor({
680+
cfn,
681+
stack: options.stack,
682+
stackName: deployName,
683+
ioHost,
684+
action,
685+
});
686+
await monitor.start();
704687

705688
try {
706689
await cfn.deleteStack({ StackName: deployName, RoleARN: options.roleArn });
@@ -709,7 +692,7 @@ export async function destroyStack(options: DestroyStackOptions, { ioHost, actio
709692
throw new ToolkitError(`Failed to destroy ${deployName}: ${destroyedStack.stackStatus}`);
710693
}
711694
} catch (e: any) {
712-
throw new ToolkitError(suffixWithErrors(formatErrorMessage(e), monitor?.errors));
695+
throw new ToolkitError(suffixWithErrors(formatErrorMessage(e), monitor.errors));
713696
} finally {
714697
if (monitor) {
715698
await monitor.stop();

packages/aws-cdk/lib/api/deployments/deployments.ts

+12-42
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { formatErrorMessage } from '../../util/format-error';
3131
import type { SdkProvider } from '../aws-auth/sdk-provider';
3232
import { type EnvironmentResources, EnvironmentAccess } from '../environment';
3333
import { HotswapMode, HotswapPropertyOverrides } from '../hotswap/common';
34-
import { StackActivityMonitor, StackActivityProgress, StackEventPoller, RollbackChoice } from '../stack-events';
34+
import { StackActivityMonitor, StackEventPoller, RollbackChoice } from '../stack-events';
3535
import type { Tag } from '../tags';
3636
import { DEFAULT_TOOLKIT_STACK_NAME } from '../toolkit-info';
3737
import { makeBodyParameter } from '../util/template-body-parameter';
@@ -65,13 +65,6 @@ export interface DeployStackOptions {
6565
*/
6666
readonly deployName?: string;
6767

68-
/**
69-
* Don't show stack deployment events, just wait
70-
*
71-
* @default false
72-
*/
73-
readonly quiet?: boolean;
74-
7568
/**
7669
* Name of the toolkit stack, if not the default name
7770
*
@@ -135,21 +128,6 @@ export interface DeployStackOptions {
135128
*/
136129
readonly usePreviousParameters?: boolean;
137130

138-
/**
139-
* Display mode for stack deployment progress.
140-
*
141-
* @default - StackActivityProgress.Bar - stack events will be displayed for
142-
* the resource currently being deployed.
143-
*/
144-
readonly progress?: StackActivityProgress;
145-
146-
/**
147-
* Whether we are on a CI system
148-
*
149-
* @default false
150-
*/
151-
readonly ci?: boolean;
152-
153131
/**
154132
* Rollback failed deployments
155133
*
@@ -255,14 +233,6 @@ export interface RollbackStackOptions {
255233
*/
256234
readonly orphanLogicalIds?: string[];
257235

258-
/**
259-
* Display mode for stack deployment progress.
260-
*
261-
* @default - StackActivityProgress.Bar - stack events will be displayed for
262-
* the resource currently being deployed.
263-
*/
264-
readonly progress?: StackActivityProgress;
265-
266236
/**
267237
* Whether to validate the version of the bootstrap stack permissions
268238
*
@@ -463,7 +433,6 @@ export class Deployments {
463433
resolvedEnvironment: env.resolvedEnvironment,
464434
deployName: options.deployName,
465435
notificationArns: options.notificationArns,
466-
quiet: options.quiet,
467436
sdk: env.sdk,
468437
sdkProvider: this.deployStackSdkProvider,
469438
roleArn: executionRoleArn,
@@ -474,8 +443,6 @@ export class Deployments {
474443
force: options.force,
475444
parameters: options.parameters,
476445
usePreviousParameters: options.usePreviousParameters,
477-
progress: options.progress,
478-
ci: options.ci,
479446
rollback: options.rollback,
480447
hotswap: options.hotswap,
481448
hotswapPropertyOverrides: options.hotswapPropertyOverrides,
@@ -565,11 +532,14 @@ export class Deployments {
565532
throw new ToolkitError(`Unexpected rollback choice: ${cloudFormationStack.stackStatus.rollbackChoice}`);
566533
}
567534

568-
const monitor = options.quiet
569-
? undefined
570-
: StackActivityMonitor.withDefaultPrinter(cfn, deployName, options.stack, {
571-
ci: options.ci,
572-
}).start();
535+
const monitor = new StackActivityMonitor({
536+
cfn,
537+
stack: options.stack,
538+
stackName: deployName,
539+
ioHost: this.ioHost,
540+
action: this.action,
541+
});
542+
await monitor.start();
573543

574544
let stackErrorMessage: string | undefined = undefined;
575545
let finalStackState = cloudFormationStack;
@@ -582,14 +552,14 @@ export class Deployments {
582552
}
583553
finalStackState = successStack;
584554

585-
const errors = monitor?.errors?.join(', ');
555+
const errors = monitor.errors.join(', ');
586556
if (errors) {
587557
stackErrorMessage = errors;
588558
}
589559
} catch (e: any) {
590-
stackErrorMessage = suffixWithErrors(formatErrorMessage(e), monitor?.errors);
560+
stackErrorMessage = suffixWithErrors(formatErrorMessage(e), monitor.errors);
591561
} finally {
592-
await monitor?.stop();
562+
await monitor.stop();
593563
}
594564

595565
if (finalStackState.stackStatus.isRollbackSuccess || !stackErrorMessage) {

packages/aws-cdk/lib/api/resource-import/importer.ts

-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { error, info, warn } from '../../cli/messages';
99
import { IIoHost, ToolkitAction } from '../../toolkit/cli-io-host';
1010
import { ToolkitError } from '../../toolkit/error';
1111
import { assertIsSuccessfulDeployStackResult, type Deployments, DeploymentMethod, ResourceIdentifierProperties, ResourcesToImport } from '../deployments';
12-
import type { StackActivityProgress } from '../stack-events';
1312
import type { Tag } from '../tags';
1413

1514
export interface ResourceImporterProps {
@@ -49,14 +48,6 @@ export interface ImportDeploymentOptions {
4948
*/
5049
readonly usePreviousParameters?: boolean;
5150

52-
/**
53-
* Display mode for stack deployment progress.
54-
*
55-
* @default - StackActivityProgress.Bar - stack events will be displayed for
56-
* the resource currently being deployed.
57-
*/
58-
readonly progress?: StackActivityProgress;
59-
6051
/**
6152
* Rollback failed deployments
6253
*

packages/aws-cdk/lib/api/resource-import/migrator.ts

-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ export class ResourceMigrator {
6767
roleArn: options.roleArn,
6868
deploymentMethod: options.deploymentMethod,
6969
usePreviousParameters: true,
70-
progress: options.progress,
7170
rollback: options.rollback,
7271
});
7372

0 commit comments

Comments
 (0)