Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(aws-cdk): Improvements to IAM diff rendering #1542

Merged
merged 10 commits into from
Jan 16, 2019

Conversation

rix0rrr
Copy link
Contributor

@rix0rrr rix0rrr commented Jan 14, 2019

Contains the following changes:

  • Print table to STDOUT instead of STDERR. This ensures the diff output and the "confirm (y/n)" prompt that follows it don't interleave on the terminal, degrading readability.
  • Control table width to not exceed the terminal width, so that it doesn't wrap and lead to a mess of lines.
  • Switch back to the new version of the table library (instead of cli-table) which now has in-cell newline support, to get rid of the rendering bugs in cli-table that would occasionally eat newlines.
  • Render resource replace impact as red instead of yellow, to indicate that data loss will be happening here (fixes diff ui: replace is as dangerous as destroy - so should be in red #1458).
  • Change replacement diffing in order to not trigger IAM changes dialog (fixes IAM Diff Thrash with Lambda Permissions #1495).

Explanation:

We used to modify the new target template in place, causing changes to
the logical ids of replaced resources, which would trigger downstream
changes, which would further trigger potential downstream replacements, etc.

This would properly calculate the set of impacted resources, but would also lead to the modified logical ID popping up in the IAM diff, which was not desirable.

In this change, we do the same processing but we throw away the
template after all changes have been propagated, and only copy
the resultant property statuses onto the diff object that gets
returned to the user. This leads to the same displayed result
without the changes to the template actually propagating.

In the course of this modification, the diff classes have been changed
to also have objects in places of resources and properties that
didn't actually change (so that they could be modified in-place),
and diff objects have a boolean telling whether they are actual
changes or not.


Pull Request Checklist

  • Testing
    • Unit test added
    • CLI change?: manually run integration tests and paste output as a PR comment
    • cdk-init template change?: coordinated update of integration tests with team
  • Docs
    • jsdocs: All public APIs documented
    • README: README and/or documentation topic updated
  • Title and Description
    • Change type: title prefixed with fix, feat will appear in changelog
    • Title: use lower-case and doesn't end with a period
    • Breaking?: last paragraph: "BREAKING CHANGE: <describe what changed + link for details>"
    • Issues: Indicate issues fixed via: "Fixes #xxx" or "Closes #xxx"
  • Sensitive Modules (requires 2 PR approvers)
    • IAM Policy Document (in @aws-cdk/aws-iam)
    • EC2 Security Groups and ACLs (in @aws-cdk/aws-ec2)
    • Grant APIs (only if not based on official documentation with a reference)

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.

This ensure so that the diff output and the prompt don't interleave.
Calculcate column widths so that the table will not overflow the
terminal anymore.

Switch back to 'table' library which now has newline support and not the
rendering bug that 'cli-table' had.
We used to modify the new template in place, causing changes to
"logicalIDs" of replaced resources, which would trigger downstream
changes and potential downstream replacements, etc.

This would lead to the changed logical ID popping up in the IAM
diff which was not desirable.

In this change, we do the same processing but we throw away the
template after all changes have been propagated, and only copy
the resultant property STATUSES onto the diff object that gets
returned to the user. This leads to the same displayed result
without the changes to the template actually propagating.

In the course of this modification, the diff classes have been changed
to also have objects in places of resources and properties that
didn't actually change (so that they could be modified in-place),
and diff objects have a boolean telling whether they are actual
changes or not.

Fixes #1495.
@rix0rrr rix0rrr requested a review from a team as a code owner January 14, 2019 13:42
@eladb
Copy link
Contributor

eladb commented Jan 14, 2019

Could you please upload a nice little screenshot?

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Jan 14, 2019

This PR is blocked on gajus/table#89

@rix0rrr
Copy link
Contributor Author

rix0rrr commented Jan 14, 2019

selection_033

Copy link
Contributor

@sam-goodwin sam-goodwin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Table looks beautiful! I had some comments but nothing worth blocking on.

count += this.outputs.differenceCount;
count += this.parameters.differenceCount;
count += this.resources.differenceCount;
count += this.unknown.differenceCount;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: scope these under a single object so you can enumerate and reduce?

[ResourceImpact.WILL_ORPHAN]: 3,
[ResourceImpact.MAY_REPLACE]: 4,
[ResourceImpact.WILL_REPLACE]: 5,
[ResourceImpact.WILL_DESTROY]: 6,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why declare this in the function scope?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not? It's only used here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it optimized away? :)

widths.forEach((width, i) => {
ret[i] = { width, useWordWrap: true } as any; // 'useWordWrap' is not in @types/table
if (width === undefined) {
delete ret[i].width;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This undefined terminal width has penetrated the logic everywhere. Can we not switch it on/off in a simpler way to avoid delete ret[i].width and Array<number | undefined>? It seems to have a single source: formatTable(_, columns: number | undefined).

const columns = rows[0].map((_, i) => Math.max(...rows.map(row => stringWidth(row[i]))));

// If we have no terminal width, do nothing
if (terminalWidth === undefined) { return columns.map(_ => undefined); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

array of undefined? Is this the optimal signal?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it this way because I wanted the useWordWrap: true for every column.

But I suppose that's silly, because if there's no width, what does it even matter how you wrap?

return ret;
}

function sum(xs: number[]): number {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xs.reduce((a,b) => a + b, 0)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did it this way on purpose because I believe V8 JITs this better. But I will agree it's a micro-optimization :)

return table.toString();
if (options.colWidths) {
options.colWidths.forEach((width, i) => {
columns[i] = { width, useWordWrap: true } as any; // @types doesn't have this type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to cast to any here? You have the type, table.ColumnConfig, is this not the correct shape?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the comment says, The @types package for this library is for 4.x.x and we're using 5.x.x. There is no newer one and I don't really feel like writing it... :(

joinLeft: tableColor('├'),
joinRight: tableColor('┤'),
joinJoin: tableColor('┼')
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've seen this table twice .. redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One is in @aws-cdk/cloudformation-diff and the other one is in aws-cdk. I'd prefer to keep the table rendering private to the package, because it doesn't seem like an exportable feature of @aws-cdk/cloudformationd-diff`, and extracting to another package just to share seemed a bit too much.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But, otoh, terminal width wrapping now only works for the IAM changes table, not for the others. Maybe I should share...

Rewrite 'undefined' logic to make it less onerous.

Print a message instead of an empty table if 'cdk context' has no
information in it (fixes #1549).
@rix0rrr rix0rrr merged commit 3270b47 into master Jan 16, 2019
@rix0rrr rix0rrr deleted the huijbers/iam-diff-improvements branch January 16, 2019 10:30
@NGL321 NGL321 added the contribution/core This is a PR that came from AWS. label Sep 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

IAM Diff Thrash with Lambda Permissions diff ui: replace is as dangerous as destroy - so should be in red
4 participants