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

Structured Renderer: use the new renderer when rendering the state in addition to the plan #32629

Merged
merged 2 commits into from Feb 7, 2023

Conversation

liamcervante
Copy link
Member

@liamcervante liamcervante commented Feb 6, 2023

Fixes #32621

This PR adds an additional function to the new structured renderer: RenderHumanState. This function is called from the show command so the state rendering and the plan rendering both use the same code path.

There are a few changes to the diffing and rendering code to make this work.

  • Firstly, a new option has been added to the renderer (HideDiffActionSymbols) that tells the renderer not to place any indents for symbols or actual symbols into the rendered output. This means the state rendering doesn't use the extra offsets placed in for the symbols that are used in the plan rendering. This is because the state renderer is always rendering no-ops so never has to show any symbols.
  • Secondly, the ComputeChangeForType function on the differ.Change objects is made public as the state renderer has more information about the types of outputs than the plan renderer and can use this function instead of interpreting the type.

In addition to the above, I have refactored the renderer code so the plan and state rendering code paths are in their own files as the renderer.go file was getting very full. I think this makes the API of the renderer cleaner and clearer for callers. This change has no functional changes on anything and is just for aesthetics.

There are also numerous changes making the structs in the jsonstate package public so the renderer can use them. This also involves making the Index attributes into json.RawMessage slices instead of keeping them as unparseable objects. This is an okay change, because they are rendered the same in JSON anyway and until now we were not reading them anywhere so the fact they couldn't be read back in was not a problem. Additionally, I update the AttributeValues type so that it explicitly states that the values are json.RawMessage slices. Previously, they were identified as interface{} types but were always being populated as json.RawMessage so I don't see why we don't just say that's what they are. This change also doesn't affect the actual output since they were always json.RawMessage objects anyway.

A future change could optimise the TFC backend so that it retrieves a JSONified version of the state and passes that directly into the renderer, but for now it can carry on retrieving the full state and converting to JSON locally as the local backend does anyway.

@liamcervante liamcervante requested review from alisdair and a team February 6, 2023 14:20
@liamcervante
Copy link
Member Author

I could go through here and make a chain of smaller changes as I did before, if you think this PR is too big/complex to review in one.

Copy link
Member

@alisdair alisdair left a comment

Choose a reason for hiding this comment

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

Nice work!

renderer.Streams.Println()
}

// Render depth-first, so we show children first.
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand the "so we show children first" part of this comment. At first I thought this block should be before the loop over resources in this module, but I think the behaviour we have is reasonable, it just doesn't seem to quite line up with the comment. Maybe I'm missing something.

Copy link
Member Author

Choose a reason for hiding this comment

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

We don't want to show the children first. This is left over from confusion caused by the old approach.

Previously, the order of the modules was not consistent and AFAICT fairly random. And I was doing diff testing, and noticed in one run that my order was different and thought it was because I had root first and children after. I rearranged the order as described by you and then re-ran my checks and got a different result. So I decided that it makes more sense to show the root first as I had previously, and that we would now have a consistent ordering but I never went back and removed this comment 😓

I've removed the comment now, and since we're no longer making claims on the ordering I don't think a test is needed.

Copy link
Member

Choose a reason for hiding this comment

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

I'm lacking some context here so this is just "FYI this exists" rather than any assumption it would be appropriate to use here, but I wanted to note that we have addrs.AbsResourceInstance.Less to define our "default ordering" for sets of resource instances where we don't have any other specific order to use.

That Less function takes into account various details, such as sorting first by module membership and then by resource address, and making sure that we use numeric ordering rather than string-based ordering for the integer instance keys caused by the count feature.

It looks like this code is currently using a locally-implemented order, I guess in part because it needs to take into account the possibility of "deposed objects" which are outside of what AbsResourceInstance can describe. But perhaps we could use the canonical ordering for any pair of addresses that have differences beyond the deposed key.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for this Martin, that's some good context.

I'll leave this as is for now, because I think a better approach if we wanted to do the sorting properly would be to do the sorting in the json packages that generate the JSON structs themselves, and then the renderer can just print the things without sorting. I'll have a look at this in a separate PR.

For this PR, I think it's more important just to make sure the output is consistent and then we don't have to worry about converting back into the Terraform structs. If we do the sorting before we marshal it into JSON then it's already in the Terraform structs.

internal/command/jsonformat/state_test.go Show resolved Hide resolved
Streams: v.view.streams,
Colorize: v.view.colorize,
Streams: v.view.streams,
RunningInAutomation: v.inAutomation,
Copy link
Member

Choose a reason for hiding this comment

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

Huh. I hadn't realized this wasn't hooked up until now. Nice catch!

@@ -53,7 +53,7 @@ func TestShowHuman(t *testing.T) {
},
testSchemas(),
true,
"\n",
"The state file is empty. No resources are represented.\n",
Copy link
Member

Choose a reason for hiding this comment

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

This seems like a good change in behaviour, and our human-readable output is largely exempt from backwards compatibility guarantees, so I think it's fine. We should probably note it in the changelog, though.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll update the changelog 👍

@liamcervante liamcervante merged commit d818d78 into main Feb 7, 2023
@liamcervante liamcervante deleted the liamcervante/renderer/state branch February 7, 2023 08:14
@github-actions
Copy link

github-actions bot commented Feb 7, 2023

Reminder for the merging maintainer: if this is a user-visible change, please update the changelog on the appropriate release branch.

@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 10, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

terraform show output incorrectly omits nested attribute values, marking them as "unchanged elements"
3 participants