aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
578 lines • 86.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CurrentActivityPrinter = exports.HistoryActivityPrinter = exports.StackActivityMonitor = exports.StackActivityProgress = void 0;
const util = require("util");
const cxschema = require("@aws-cdk/cloud-assembly-schema");
const chalk = require("chalk");
const logging_1 = require("../../../logging");
const display_1 = require("../display");
/**
* Supported display modes for stack deployment activity
*/
var StackActivityProgress;
(function (StackActivityProgress) {
/**
* Displays a progress bar with only the events for the resource currently being deployed
*/
StackActivityProgress["BAR"] = "bar";
/**
* Displays complete history with all CloudFormation stack events
*/
StackActivityProgress["EVENTS"] = "events";
})(StackActivityProgress || (exports.StackActivityProgress = StackActivityProgress = {}));
class StackActivityMonitor {
/**
* Create a Stack Activity Monitor using a default printer, based on context clues
*/
static withDefaultPrinter(cfn, stackName, stackArtifact, options = {}) {
const stream = options.ci ? process.stdout : process.stderr;
const props = {
resourceTypeColumnWidth: calcMaxResourceTypeLength(stackArtifact.template),
resourcesTotal: options.resourcesTotal,
stream,
};
const isWindows = process.platform === 'win32';
const verbose = options.logLevel ?? logging_1.logLevel;
// On some CI systems (such as CircleCI) output still reports as a TTY so we also
// need an individual check for whether we're running on CI.
// see: https://discuss.circleci.com/t/circleci-terminal-is-a-tty-but-term-is-not-set/9965
const fancyOutputAvailable = !isWindows && stream.isTTY && !options.ci;
const progress = options.progress ?? StackActivityProgress.BAR;
const printer = fancyOutputAvailable && !verbose && (progress === StackActivityProgress.BAR)
? new CurrentActivityPrinter(props)
: new HistoryActivityPrinter(props);
return new StackActivityMonitor(cfn, stackName, printer, stackArtifact, options.changeSetCreationTime);
}
constructor(cfn, stackName, printer, stack, changeSetCreationTime) {
this.cfn = cfn;
this.stackName = stackName;
this.printer = printer;
this.stack = stack;
/**
* Resource errors found while monitoring the deployment
*/
this.errors = new Array();
this.active = false;
this.activity = {};
this.startTime = changeSetCreationTime?.getTime() ?? Date.now();
}
start() {
this.active = true;
this.printer.start();
this.scheduleNextTick();
return this;
}
async stop() {
this.active = false;
if (this.tickTimer) {
clearTimeout(this.tickTimer);
}
// Do a final poll for all events. This is to handle the situation where DescribeStackStatus
// already returned an error, but the monitor hasn't seen all the events yet and we'd end
// up not printing the failure reason to users.
await this.finalPollToEnd();
this.printer.stop();
}
scheduleNextTick() {
if (!this.active) {
return;
}
this.tickTimer = setTimeout(() => void (this.tick()), this.printer.updateSleep);
}
async tick() {
if (!this.active) {
return;
}
try {
this.readPromise = this.readNewEvents();
await this.readPromise;
this.readPromise = undefined;
// We might have been stop()ped while the network call was in progress.
if (!this.active) {
return;
}
this.printer.print();
}
catch (e) {
(0, logging_1.error)('Error occurred while monitoring stack: %s', e);
}
this.scheduleNextTick();
}
findMetadataFor(logicalId) {
const metadata = this.stack?.manifest?.metadata;
if (!logicalId || !metadata) {
return undefined;
}
for (const path of Object.keys(metadata)) {
const entry = metadata[path]
.filter(e => e.type === cxschema.ArtifactMetadataEntryType.LOGICAL_ID)
.find(e => e.data === logicalId);
if (entry) {
return {
entry,
constructPath: this.simplifyConstructPath(path),
};
}
}
return undefined;
}
/**
* Reads all new events from the stack history
*
* The events are returned in reverse chronological order; we continue to the next page if we
* see a next page and the last event in the page is new to us (and within the time window).
* haven't seen the final event
*/
async readNewEvents(stackName) {
const stackToPollForEvents = stackName ?? this.stackName;
const events = [];
const CFN_SUCCESS_STATUS = ['UPDATE_COMPLETE', 'CREATE_COMPLETE', 'DELETE_COMPLETE', 'DELETE_SKIPPED'];
try {
let nextToken;
let finished = false;
while (!finished) {
const response = await this.cfn.describeStackEvents({ StackName: stackToPollForEvents, NextToken: nextToken }).promise();
const eventPage = response?.StackEvents ?? [];
for (const event of eventPage) {
// Event from before we were interested in 'em
if (event.Timestamp.valueOf() < this.startTime) {
finished = true;
break;
}
// Already seen this one
if (event.EventId in this.activity) {
finished = true;
break;
}
// Fresh event
events.push(this.activity[event.EventId] = {
event: event,
metadata: this.findMetadataFor(event.LogicalResourceId),
});
if (event.ResourceType === 'AWS::CloudFormation::Stack' && !CFN_SUCCESS_STATUS.includes(event.ResourceStatus ?? '')) {
// If the event is not for `this` stack and has a physical resource Id, recursively call for events in the nested stack
if (event.PhysicalResourceId && event.PhysicalResourceId !== stackToPollForEvents) {
await this.readNewEvents(event.PhysicalResourceId);
}
}
}
// We're also done if there's nothing left to read
nextToken = response?.NextToken;
if (nextToken === undefined) {
finished = true;
}
}
}
catch (e) {
if (e.code === 'ValidationError' && e.message === `Stack [${stackToPollForEvents}] does not exist`) {
return;
}
throw e;
}
events.reverse();
for (const event of events) {
this.checkForErrors(event);
this.printer.addActivity(event);
}
}
/**
* Perform a final poll to the end and flush out all events to the printer
*
* Finish any poll currently in progress, then do a final one until we've
* reached the last page.
*/
async finalPollToEnd() {
// If we were doing a poll, finish that first. It was started before
// the moment we were sure we weren't going to get any new events anymore
// so we need to do a new one anyway. Need to wait for this one though
// because our state is single-threaded.
if (this.readPromise) {
await this.readPromise;
}
await this.readNewEvents();
}
checkForErrors(activity) {
if (hasErrorMessage(activity.event.ResourceStatus ?? '')) {
const isCancelled = (activity.event.ResourceStatusReason ?? '').indexOf('cancelled') > -1;
// Cancelled is not an interesting failure reason, nor is the stack message (stack
// message will just say something like "stack failed to update")
if (!isCancelled && activity.event.StackName !== activity.event.LogicalResourceId) {
this.errors.push(activity.event.ResourceStatusReason ?? '');
}
}
}
simplifyConstructPath(path) {
path = path.replace(/\/Resource$/, '');
path = path.replace(/^\//, ''); // remove "/" prefix
// remove "<stack-name>/" prefix
if (path.startsWith(this.stackName + '/')) {
path = path.slice(this.stackName.length + 1);
}
return path;
}
}
exports.StackActivityMonitor = StackActivityMonitor;
function padRight(n, x) {
return x + ' '.repeat(Math.max(0, n - x.length));
}
/**
* Infamous padLeft()
*/
function padLeft(n, x) {
return ' '.repeat(Math.max(0, n - x.length)) + x;
}
function calcMaxResourceTypeLength(template) {
const resources = (template && template.Resources) || {};
let maxWidth = 0;
for (const id of Object.keys(resources)) {
const type = resources[id].Type || '';
if (type.length > maxWidth) {
maxWidth = type.length;
}
}
return maxWidth;
}
class ActivityPrinterBase {
constructor(props) {
this.props = props;
/**
* Fetch new activity every 5 seconds
*/
this.updateSleep = 5000;
/**
* A list of resource IDs which are currently being processed
*/
this.resourcesInProgress = {};
/**
* Previous completion state observed by logical ID
*
* We use this to detect that if we see a DELETE_COMPLETE after a
* CREATE_COMPLETE, it's actually a rollback and we should DECREASE
* resourcesDone instead of increase it
*/
this.resourcesPrevCompleteState = {};
/**
* Count of resources that have reported a _COMPLETE status
*/
this.resourcesDone = 0;
/**
* How many digits we need to represent the total count (for lining up the status reporting)
*/
this.resourceDigits = 0;
this.rollingBack = false;
this.failures = new Array();
this.hookFailureMap = new Map();
// +1 because the stack also emits a "COMPLETE" event at the end, and that wasn't
// counted yet. This makes it line up with the amount of events we expect.
this.resourcesTotal = props.resourcesTotal ? props.resourcesTotal + 1 : undefined;
// How many digits does this number take to represent?
this.resourceDigits = this.resourcesTotal ? Math.ceil(Math.log10(this.resourcesTotal)) : 0;
this.stream = props.stream;
}
failureReason(activity) {
const resourceStatusReason = activity.event.ResourceStatusReason ?? '';
const logicalResourceId = activity.event.LogicalResourceId ?? '';
const hookFailureReasonMap = this.hookFailureMap.get(logicalResourceId);
if (hookFailureReasonMap !== undefined) {
for (const hookType of hookFailureReasonMap.keys()) {
if (resourceStatusReason.includes(hookType)) {
return resourceStatusReason + ' : ' + hookFailureReasonMap.get(hookType);
}
}
}
return resourceStatusReason;
}
addActivity(activity) {
const status = activity.event.ResourceStatus;
const hookStatus = activity.event.HookStatus;
const hookType = activity.event.HookType;
if (!status || !activity.event.LogicalResourceId) {
return;
}
if (status === 'ROLLBACK_IN_PROGRESS' || status === 'UPDATE_ROLLBACK_IN_PROGRESS') {
// Only triggered on the stack once we've started doing a rollback
this.rollingBack = true;
}
if (status.endsWith('_IN_PROGRESS')) {
this.resourcesInProgress[activity.event.LogicalResourceId] = activity;
}
if (hasErrorMessage(status)) {
const isCancelled = (activity.event.ResourceStatusReason ?? '').indexOf('cancelled') > -1;
// Cancelled is not an interesting failure reason
if (!isCancelled) {
this.failures.push(activity);
}
}
if (status.endsWith('_COMPLETE') || status.endsWith('_FAILED')) {
delete this.resourcesInProgress[activity.event.LogicalResourceId];
}
if (status.endsWith('_COMPLETE_CLEANUP_IN_PROGRESS')) {
this.resourcesDone++;
}
if (status.endsWith('_COMPLETE')) {
const prevState = this.resourcesPrevCompleteState[activity.event.LogicalResourceId];
if (!prevState) {
this.resourcesDone++;
}
else {
// If we completed this before and we're completing it AGAIN, means we're rolling back.
// Protect against silly underflow.
this.resourcesDone--;
if (this.resourcesDone < 0) {
this.resourcesDone = 0;
}
}
this.resourcesPrevCompleteState[activity.event.LogicalResourceId] = status;
}
if (hookStatus !== undefined && hookStatus.endsWith('_COMPLETE_FAILED') && activity.event.LogicalResourceId !== undefined && hookType !== undefined) {
if (this.hookFailureMap.has(activity.event.LogicalResourceId)) {
this.hookFailureMap.get(activity.event.LogicalResourceId)?.set(hookType, activity.event.HookStatusReason ?? '');
}
else {
this.hookFailureMap.set(activity.event.LogicalResourceId, new Map());
this.hookFailureMap.get(activity.event.LogicalResourceId)?.set(hookType, activity.event.HookStatusReason ?? '');
}
}
}
start() {
// Empty on purpose
}
stop() {
// Empty on purpose
}
}
/**
* Activity Printer which shows a full log of all CloudFormation events
*
* When there hasn't been activity for a while, it will print the resources
* that are currently in progress, to show what's holding up the deployment.
*/
class HistoryActivityPrinter extends ActivityPrinterBase {
constructor(props) {
super(props);
/**
* Last time we printed something to the console.
*
* Used to measure timeout for progress reporting.
*/
this.lastPrintTime = Date.now();
/**
* Number of ms of change absence before we tell the user about the resources that are currently in progress.
*/
this.inProgressDelay = 30000;
this.printable = new Array();
}
addActivity(activity) {
super.addActivity(activity);
this.printable.push(activity);
this.print();
}
print() {
for (const activity of this.printable) {
this.printOne(activity);
}
this.printable.splice(0, this.printable.length);
this.printInProgress();
}
stop() {
// Print failures at the end
if (this.failures.length > 0) {
this.stream.write('\nFailed resources:\n');
for (const failure of this.failures) {
// Root stack failures are not interesting
if (failure.event.StackName === failure.event.LogicalResourceId) {
continue;
}
this.printOne(failure, false);
}
}
}
printOne(activity, progress) {
const e = activity.event;
const color = colorFromStatusResult(e.ResourceStatus);
let reasonColor = chalk.cyan;
let stackTrace = '';
const md = activity.metadata;
if (e.ResourceStatus && e.ResourceStatus.indexOf('FAILED') !== -1) {
if (progress == undefined || progress) {
e.ResourceStatusReason = e.ResourceStatusReason ? this.failureReason(activity) : '';
}
if (md) {
stackTrace = md.entry.trace ? `\n\t${md.entry.trace.join('\n\t\\_ ')}` : '';
}
reasonColor = chalk.red;
}
const resourceName = md ? md.constructPath : (e.LogicalResourceId || '');
const logicalId = resourceName !== e.LogicalResourceId ? `(${e.LogicalResourceId}) ` : '';
this.stream.write(util.format('%s | %s%s | %s | %s | %s %s%s%s\n', e.StackName, (progress !== false ? `${this.progress()} | ` : ''), new Date(e.Timestamp).toLocaleTimeString(), color(padRight(STATUS_WIDTH, (e.ResourceStatus || '').slice(0, STATUS_WIDTH))), // pad left and trim
padRight(this.props.resourceTypeColumnWidth, e.ResourceType || ''), color(chalk.bold(resourceName)), logicalId, reasonColor(chalk.bold(e.ResourceStatusReason ? e.ResourceStatusReason : '')), reasonColor(stackTrace)));
this.lastPrintTime = Date.now();
}
/**
* Report the current progress as a [34/42] string, or just [34] if the total is unknown
*/
progress() {
if (this.resourcesTotal == null) {
// Don't have total, show simple count and hope the human knows
return padLeft(3, util.format('%s', this.resourcesDone)); // max 500 resources
}
return util.format('%s/%s', padLeft(this.resourceDigits, this.resourcesDone.toString()), padLeft(this.resourceDigits, this.resourcesTotal != null ? this.resourcesTotal.toString() : '?'));
}
/**
* If some resources are taking a while to create, notify the user about what's currently in progress
*/
printInProgress() {
if (Date.now() < this.lastPrintTime + this.inProgressDelay) {
return;
}
if (Object.keys(this.resourcesInProgress).length > 0) {
this.stream.write(util.format('%s Currently in progress: %s\n', this.progress(), chalk.bold(Object.keys(this.resourcesInProgress).join(', '))));
}
// We cheat a bit here. To prevent printInProgress() from repeatedly triggering,
// we set the timestamp into the future. It will be reset whenever a regular print
// occurs, after which we can be triggered again.
this.lastPrintTime = +Infinity;
}
}
exports.HistoryActivityPrinter = HistoryActivityPrinter;
/**
* Activity Printer which shows the resources currently being updated
*
* It will continuously reupdate the terminal and show only the resources
* that are currently being updated, in addition to a progress bar which
* shows how far along the deployment is.
*
* Resources that have failed will always be shown, and will be recapitulated
* along with their stack trace when the monitoring ends.
*
* Resources that failed deployment because they have been cancelled are
* not included.
*/
class CurrentActivityPrinter extends ActivityPrinterBase {
constructor(props) {
super(props);
/**
* This looks very disorienting sleeping for 5 seconds. Update quicker.
*/
this.updateSleep = 2000;
this.oldLogLevel = logging_1.LogLevel.DEFAULT;
this.block = new display_1.RewritableBlock(this.stream);
}
print() {
const lines = [];
// Add a progress bar at the top
const progressWidth = Math.max(Math.min((this.block.width ?? 80) - PROGRESSBAR_EXTRA_SPACE - 1, MAX_PROGRESSBAR_WIDTH), MIN_PROGRESSBAR_WIDTH);
const prog = this.progressBar(progressWidth);
if (prog) {
lines.push(' ' + prog, '');
}
// Normally we'd only print "resources in progress", but it's also useful
// to keep an eye on the failures and know about the specific errors asquickly
// as possible (while the stack is still rolling back), so add those in.
const toPrint = [...this.failures, ...Object.values(this.resourcesInProgress)];
toPrint.sort((a, b) => a.event.Timestamp.getTime() - b.event.Timestamp.getTime());
lines.push(...toPrint.map(res => {
const color = colorFromStatusActivity(res.event.ResourceStatus);
const resourceName = res.metadata?.constructPath ?? res.event.LogicalResourceId ?? '';
return util.format('%s | %s | %s | %s%s', padLeft(TIMESTAMP_WIDTH, new Date(res.event.Timestamp).toLocaleTimeString()), color(padRight(STATUS_WIDTH, (res.event.ResourceStatus || '').slice(0, STATUS_WIDTH))), padRight(this.props.resourceTypeColumnWidth, res.event.ResourceType || ''), color(chalk.bold(shorten(40, resourceName))), this.failureReasonOnNextLine(res));
}));
this.block.displayLines(lines);
}
start() {
// Need to prevent the waiter from printing 'stack not stable' every 5 seconds, it messes
// with the output calculations.
this.oldLogLevel = logging_1.logLevel;
(0, logging_1.setLogLevel)(logging_1.LogLevel.DEFAULT);
}
stop() {
(0, logging_1.setLogLevel)(this.oldLogLevel);
// Print failures at the end
const lines = new Array();
for (const failure of this.failures) {
// Root stack failures are not interesting
if (failure.event.StackName === failure.event.LogicalResourceId) {
continue;
}
lines.push(util.format(chalk.red('%s | %s | %s | %s%s') + '\n', padLeft(TIMESTAMP_WIDTH, new Date(failure.event.Timestamp).toLocaleTimeString()), padRight(STATUS_WIDTH, (failure.event.ResourceStatus || '').slice(0, STATUS_WIDTH)), padRight(this.props.resourceTypeColumnWidth, failure.event.ResourceType || ''), shorten(40, failure.event.LogicalResourceId ?? ''), this.failureReasonOnNextLine(failure)));
const trace = failure.metadata?.entry?.trace;
if (trace) {
lines.push(chalk.red(`\t${trace.join('\n\t\\_ ')}\n`));
}
}
// Display in the same block space, otherwise we're going to have silly empty lines.
this.block.displayLines(lines);
this.block.removeEmptyLines();
}
progressBar(width) {
if (!this.resourcesTotal) {
return '';
}
const fraction = Math.min(this.resourcesDone / this.resourcesTotal, 1);
const innerWidth = Math.max(1, width - 2);
const chars = innerWidth * fraction;
const remainder = chars - Math.floor(chars);
const fullChars = FULL_BLOCK.repeat(Math.floor(chars));
const partialChar = PARTIAL_BLOCK[Math.floor(remainder * PARTIAL_BLOCK.length)];
const filler = '·'.repeat(innerWidth - Math.floor(chars) - (partialChar ? 1 : 0));
const color = this.rollingBack ? chalk.yellow : chalk.green;
return '[' + color(fullChars + partialChar) + filler + `] (${this.resourcesDone}/${this.resourcesTotal})`;
}
failureReasonOnNextLine(activity) {
return hasErrorMessage(activity.event.ResourceStatus ?? '')
? `\n${' '.repeat(TIMESTAMP_WIDTH + STATUS_WIDTH + 6)}${chalk.red(this.failureReason(activity) ?? '')}`
: '';
}
}
exports.CurrentActivityPrinter = CurrentActivityPrinter;
const FULL_BLOCK = '█';
const PARTIAL_BLOCK = ['', '▏', '▎', '▍', '▌', '▋', '▊', '▉'];
const MAX_PROGRESSBAR_WIDTH = 60;
const MIN_PROGRESSBAR_WIDTH = 10;
const PROGRESSBAR_EXTRA_SPACE = 2 /* leading spaces */ + 2 /* brackets */ + 4 /* progress number decoration */ + 6 /* 2 progress numbers up to 999 */;
function hasErrorMessage(status) {
return status.endsWith('_FAILED') || status === 'ROLLBACK_IN_PROGRESS' || status === 'UPDATE_ROLLBACK_IN_PROGRESS';
}
function colorFromStatusResult(status) {
if (!status) {
return chalk.reset;
}
if (status.indexOf('FAILED') !== -1) {
return chalk.red;
}
if (status.indexOf('ROLLBACK') !== -1) {
return chalk.yellow;
}
if (status.indexOf('COMPLETE') !== -1) {
return chalk.green;
}
return chalk.reset;
}
function colorFromStatusActivity(status) {
if (!status) {
return chalk.reset;
}
if (status.endsWith('_FAILED')) {
return chalk.red;
}
if (status.startsWith('CREATE_') || status.startsWith('UPDATE_') || status.startsWith('IMPORT_')) {
return chalk.green;
}
// For stacks, it may also be 'UPDDATE_ROLLBACK_IN_PROGRESS'
if (status.indexOf('ROLLBACK_') !== -1) {
return chalk.yellow;
}
if (status.startsWith('DELETE_')) {
return chalk.yellow;
}
return chalk.reset;
}
function shorten(maxWidth, p) {
if (p.length <= maxWidth) {
return p;
}
const half = Math.floor((maxWidth - 3) / 2);
return p.slice(0, half) + '...' + p.slice(-half);
}
const TIMESTAMP_WIDTH = 12;
const STATUS_WIDTH = 20;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhY2stYWN0aXZpdHktbW9uaXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInN0YWNrLWFjdGl2aXR5LW1vbml0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkJBQTZCO0FBQzdCLDJEQUEyRDtBQUczRCwrQkFBK0I7QUFDL0IsOENBQTBFO0FBQzFFLHdDQUE2QztBQVk3Qzs7R0FFRztBQUNILElBQVkscUJBVVg7QUFWRCxXQUFZLHFCQUFxQjtJQUMvQjs7T0FFRztJQUNILG9DQUFXLENBQUE7SUFFWDs7T0FFRztJQUNILDBDQUFpQixDQUFBO0FBQ25CLENBQUMsRUFWVyxxQkFBcUIscUNBQXJCLHFCQUFxQixRQVVoQztBQXNERCxNQUFhLG9CQUFvQjtJQUUvQjs7T0FFRztJQUNJLE1BQU0sQ0FBQyxrQkFBa0IsQ0FDOUIsR0FBdUIsRUFDdkIsU0FBaUIsRUFDakIsYUFBZ0QsRUFBRSxVQUFtQyxFQUFFO1FBQ3ZGLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7UUFFNUQsTUFBTSxLQUFLLEdBQWlCO1lBQzFCLHVCQUF1QixFQUFFLHlCQUF5QixDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUM7WUFDMUUsY0FBYyxFQUFFLE9BQU8sQ0FBQyxjQUFjO1lBQ3RDLE1BQU07U0FDUCxDQUFDO1FBRUYsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLFFBQVEsS0FBSyxPQUFPLENBQUM7UUFDL0MsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLFFBQVEsSUFBSSxrQkFBUSxDQUFDO1FBQzdDLGlGQUFpRjtRQUNqRiw0REFBNEQ7UUFDNUQsMEZBQTBGO1FBQzFGLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxTQUFTLElBQUksTUFBTSxDQUFDLEtBQUssSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDdkUsTUFB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