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

tfsdk: Added Debug field to ServeOpts for running providers via debugger and testing processes #243

Merged
merged 1 commit into from
Jan 18, 2022

Conversation

bflad
Copy link
Contributor

@bflad bflad commented Jan 4, 2022

Closes #239
Reference: https://www.terraform.io/plugin/sdkv2/debugging

Similar to Terraform Plugin SDK, providers need to be executable via debugger and testing processes for instrumenting the provider code. In this workflow, the caller manages the provider lifecycle, rather than Terraform CLI. The Terraform CLI reattach configuration is output to stdout.

Verified in a framework-based provider by:

  • go mod edit -replace=github.com/hashicorp/terraform-plugin-framework=/Users/bflad/src/github.com/hashicorp/terraform-plugin-framework (use this worktree)
  • Updated provider main function code to
func main() {
	var debug bool

	flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
	flag.Parse()

	var err error
	ctx := context.Background()
	serveOpts := tfsdk.ServeOpts{
		Name: "registry.terraform.io/bflad/framework",
	}

	if debug {
		err = tfsdk.Debug(ctx, provider.New, serveOpts)
	} else {
		err = tfsdk.Serve(ctx, provider.New, serveOpts)
	}

	if err != nil {
		fmt.Printf("Error serving provider: %s", err)
		os.Exit(1)
	}
}
  • Added provider VSCode configuration to .vscode/launch.json (refer also to terraform-provider-scaffolding)
        {
            "name": "Debug - Attach External CLI",
            "type": "go",
            "request": "launch",
            "mode": "debug",
            // this assumes your workspace is the root of the repo
            "program": "${workspaceFolder}",
            "env": {},
            "args": [
                // pass the debug flag for reattaching
                "-debug",
            ],
        }
  • In provider code, set a breakpoint
  • Launched debug process
  • Copied TF_REATTACH_PROVIDERS string from Outputs > Go Debug
  • Exported environment variable and executed Terraform CLI
  • Breakpoint hit and halted further execution

@bflad bflad added enhancement New feature or request sdkv2-parity Issues tracking feature parity with terraform-plugin-sdk v2 and PRs working towards it. labels Jan 4, 2022
@bflad bflad added this to the v0.6.0 milestone Jan 4, 2022
@bflad bflad requested a review from a team January 4, 2022 17:28
bflad added a commit that referenced this pull request Jan 4, 2022
@bflad bflad mentioned this pull request Jan 4, 2022
go.mod Outdated
@@ -4,6 +4,7 @@ go 1.17

require (
github.com/google/go-cmp v0.5.6
github.com/hashicorp/go-plugin v1.4.3
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: This is temporary until terraform-plugin-go is updated: hashicorp/terraform-plugin-go#123

tfsdk/debug.go Outdated
Comment on lines 104 to 108
// Debug runs the provider in a mode acceptable for debugging and testing
// processes, such as delve, by managing the process lifecycle. Information
// needed for Terraform CLI to connect to the provider is output to stdout.
// os.Interrupt (Ctrl-c) can be used to stop the provider.
func Debug(ctx context.Context, providerFunc func() Provider, opts ServeOpts) error {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Aside: Instead of introducing an exported function, we could also implement this by adding a Debug bool field to ServeOpts, then triggering this logic via an unexported function. Thinking about that again, maybe that would be a cleaner implementation for providers rather than forcing them to implement the conditional between serving functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Opted to go with the ServeOpts approach!

@bflad
Copy link
Contributor Author

bflad commented Jan 4, 2022

Switched this to using a Debug bool field in ServeOpts and its cleaner for provider implementations (and not bloating the tfsdk function surface area further). 👍

Verified with this main function:

func main() {
	var debug bool

	flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
	flag.Parse()

	ctx := context.Background()
	serveOpts := tfsdk.ServeOpts{
		Debug: debug,
		Name:  "registry.terraform.io/bflad/framework",
	}

	err := tfsdk.Serve(ctx, provider.New, serveOpts)

	if err != nil {
		fmt.Printf("Error serving provider: %s", err)
		os.Exit(1)
	}
}

@bflad bflad changed the title tfsdk: Added Debug function for running providers via debugger and testing processes tfsdk: Added Debug field to ServeOpts for running providers via debugger and testing processes Jan 5, 2022
bflad added a commit that referenced this pull request Jan 5, 2022
@ewbankkit
Copy link
Contributor

Will this work with a muxed provider?

@bflad
Copy link
Contributor Author

bflad commented Jan 6, 2022

terraform-plugin-mux would likely require its own debug functionality, since providers are served using the terraform-plugin-go server implementations, rather than the SDK or framework implementations. I'll open an issue to investigate that further there, thanks for the call out!

@bflad
Copy link
Contributor Author

bflad commented Jan 10, 2022

Almost all of this code could be removed via an upstream implementation such as: hashicorp/terraform-plugin-go#137

func Serve(ctx context.Context, providerFunc func() Provider, opts ServeOpts) error {
	var tf6serverOpts []tf6server.ServeOpt

	if opts.Debug {
		tf6serverOpts = append(tf6serverOpts, tf6server.WithManagedDebug())
	}

	return tf6server.Serve(opts.Name, func() tfprotov6.ProviderServer {
		return &server{
			p: providerFunc(),
		}
	}, tf6serverOpts...)
}

It may be worth getting that in before recreating the implementation here.

…sting processes

Reference: #239
Reference: https://www.terraform.io/plugin/sdkv2/debugging

Similar to Terraform Plugin SDK, providers need to be executable via debugger and testing processes for instrumenting the provider code. In this workflow, the caller manages the provider lifecycle, rather than Terraform CLI. The Terraform CLI reattach configuration is output to stdout.
@bflad
Copy link
Contributor Author

bflad commented Jan 18, 2022

Rebased on [email protected] and ready for review. 👍

@ewbankkit
Copy link
Contributor

LGTM 🚀.

@bflad bflad merged commit 25319fc into main Jan 18, 2022
@bflad bflad deleted the bflad-tfsdk-debug branch January 18, 2022 19:44
@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 Feb 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request sdkv2-parity Issues tracking feature parity with terraform-plugin-sdk v2 and PRs working towards it.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Debugger-Debugging mode
2 participants