UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

578 lines 86.4 kB
"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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