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

plugin: Serve via tf5server/tf6server rather than go-plugin directly #857

Merged
merged 1 commit into from Feb 7, 2022

Conversation

bflad
Copy link
Member

@bflad bflad commented Jan 21, 2022

Closes #650

Providers will automatically receive upstream enhancements to provider servers, including protocol logging and the increased gRPC message limit. Lower level dependencies in this SDK, such as gRPC and go-plugin versions, can instead be managed upstream, which will ensure consistency across the SDKs.

@bflad
Copy link
Member Author

bflad commented Jan 31, 2022

Will rebase now due to terraform-exec@v0.16.0 merging in.

Copy link
Contributor

@detro detro left a comment

Choose a reason for hiding this comment

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

I can't pretend to understand fully this, but I'm giving it a go.

So, here you are making the call to Serve use tf5server and tf6server, instead of creating a new grcp.Server. I have to assume this was a "transitional state", where a GRPC Server was added to TF5 and TF6 but not used yet?

Anyway, I left some comments on the logging, thinking that it might useful if the "unrecoverable errors" that you are logging can be .Fatal or .Panic.

Given this is not just a style thing like the PR from yesterday, I think I need to hold the Approval for now: I'm not confident enough in my understanding :)

@@ -69,6 +84,11 @@ type ServeOpts struct {
// Serve serves a plugin. This function never returns and should be the final
// function called in the main function of the plugin.
func Serve(opts *ServeOpts) {
if opts.Debug && opts.TestConfig != nil {
log.Printf("[ERROR] Error starting provider: cannot set both Debug and TestConfig")
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: I assume that changing the interface of the plugin to return an error via Serve would be madness (right?). But I do see that you are checking for a mutually exclusive "either Debug or TestConfig".

Would it make sense for the log. call to be log.Fatal or log.Panic? I'd vote for Fatal as it also calls exit(1), and that is what I'd presume we want (the provider process exiting with a POSIX error).

Am I making any sense?

Copy link
Member Author

@bflad bflad Feb 2, 2022

Choose a reason for hiding this comment

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

Given Serve is exported and effectively in use by every provider developed on top of this SDK (or any wrapping logic developed externally), we need to be very careful about breaking changes, both in Go terms and potential usage.

Since there are no returns now, any calling code wouldn't necessarily be checking for the error return upon upgrading. Calling codebases would need to be using something like the errcheck linter to catch the issue, which we cannot assume, and introducing the new errcheck issue (for those using it) is probably "breaking" enough. Any external Go types that alias the function would also receive the breaking change.

We also cannot assume how callers were interacting with this function. For example, there's no requirement it is only called by main function in provider binaries where it would generally be appropriate to exit(1). There are potential use cases where providers are served as part of other logic and the unilateral decision to exit the Go runtime would be very inappropriate for us to introduce.

Whether we should separately introduce a "Serve" function that has an error return to be more correct in this situation is likely debatable -- no one has asked for it yet and errors (if they didn't already panic or exit themselves as part of the called logic) were previously swallowed. I agree in principle that its probably something that should exist, but I'd love to hear the demand and use cases before extending the package surface area, especially since going forward we are encouraging folks to use the new framework, rather than this one.

Copy link
Contributor

Choose a reason for hiding this comment

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

There are potential use cases where providers are served as part of other logic and the unilateral decision to exit the Go runtime would be very inappropriate for us to introduce.
Absolutely!

Logger: opts.Logger,
Test: opts.TestConfig,
if err != nil {
log.Printf("[ERROR] Error starting provider: %s", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment about the .Fatal here. If this fails, definitely the provider isn't working (and will exit(0)).

@bflad
Copy link
Member Author

bflad commented Feb 2, 2022

I have to assume this was a "transitional state", where a GRPC Server was added to TF5 and TF6 but not used yet?

It indeed is a transitional state, but maybe not in the way you're alluding. 😄 The brief historical context here:

  • Plugin/Provider netRPC servers have existed in the merged Terraform CLI+SDK codebase since the very early Terraform days (0.1 or 0.2?)
  • netRPC was eventually superseded by gRPC
  • The terraform-plugin-sdk Go module was split from the Terraform CLI codebase
  • There was a decision to reimagine the provider development experience because this SDK was built around Terraform 0.11 and earlier type system amongst other things, which wound up with terraform-plugin-go (low level gRPC handling and Go bindings), terraform-plugin-mux (to combine providers), and eventually terraform-plugin-framework (a new higher level SDK) -- you can see tf6server in use in terraform-plugin-framework
  • As part of updating the helper/resource package (the "acceptance testing framework" of this SDK) to support provider testing outside of the types defined by this SDK, the plugin package was migrated over to using the terraform-plugin-go tfprotov5 and tfprotov6 types

However, the server handling hasn't been migrated yet and here we are! This will standardize tf5server and tf6server being the lowest level handlers in both the higher level SDKs, so terraform-plugin-go can consistently manage gRPC/go-plugin dependencies, manage gRPC settings, and have a consistent logger setup (such as generated RPC request IDs, protocol level logging, etc).

Copy link
Contributor

@detro detro left a comment

Choose a reason for hiding this comment

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

Thanks for the clarification.
It makes perfect sense: the amount of ways that a change like that can go wrong is just too much.

LGTM

@bflad bflad added this to the v2.11.0 milestone Feb 4, 2022
@bflad
Copy link
Member Author

bflad commented Feb 4, 2022

Since there's #650, I'm going to add an enhancement changelog entry for this to match the upstream one: https://github.com/hashicorp/terraform-plugin-go/pull/139/files

@bflad
Copy link
Member Author

bflad commented Feb 5, 2022

We should hold off merging or releasing this until hashicorp/terraform-plugin-go#153 is reviewed, merged, released, and the dependency updated. Refer to hashicorp/terraform-plugin-go#152 for additional context.

Providers will automatically receive upstream enhancements to provider servers, including protocol logging. Lower level dependencies in this SDK, such as gRPC and go-plugin versions, can instead be managed upstream, which will ensure consistency across the SDKs.
@bflad
Copy link
Member Author

bflad commented Feb 7, 2022

#884 was merged with the necessary tf5server ServeOpt fixes, rebased this branch and re-verified expected acceptance testing output via terraform-provider-corner, merging!

@bflad bflad merged commit 36ee3aa into main Feb 7, 2022
@bflad bflad deleted the bflad-tpg-servers branch February 7, 2022 20:05
@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, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants