feat(tfhost): host real providers — protocol 5+6, msgpack, nested blocks#121
Merged
Conversation
Closes the four gaps that blocked openctl's Terraform host from driving a real terraform-provider-* binary. It could previously only round-trip opaque state and send JSON config against an in-repo JSON fake. - msgpack state decoding + nested-block/typed config encoding: encodeConfig builds a tftypes.Value from an openctl spec conforming to the schema's implied type (nested blocks included) and encodes it via the PUBLIC tfprotov6 codec (NewDynamicValue -> msgpack); decodeState reads a provider's DynamicValue (msgpack or JSON) back into a map via DynamicValue.Unmarshal. No deprecated tftypes helpers. New values.go; splitState now classifies decoded fields into spec vs computed-only status; isNullDynamicValue also recognizes msgpack null (0xc0). - protocol 5 + 6 negotiation: Launch offers both via go-plugin VersionedPlugins; SDKv2 providers (proto 5) and framework providers (proto 6) both connect. The adapter stays on tfplugin6 types — a proto-5 provider is driven through v5adapter (client_v5.go), converting the field-identical v5<->v6 messages at the boundary. tfplugin5 gRPC stubs vendored in pkg/tfplugin5 (mirrors pkg/tfplugin6). - real-binary e2e: plugins/tf-fake upgraded to a nested-block, msgpack-emitting framework provider (proto 6) — so existing tests now exercise the real wire encoding, plus a new nested-block round-trip test through the adapter. A gated TestRealProviderTimeStatic drives the PUBLISHED hashicorp/time provider (proto 5) end-to-end (create/read/delete time_static, decoding its computed msgpack outputs), run with TFHOST_E2E_PROVIDER_TIME=<binary>. Tests assert the negotiated protocol (fake=6, time=5). Docs: plugin-architecture.md updated (the earlier "avoid msgpack" decision is superseded by using the public codec); ROADMAP entry added.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes the four gaps that blocked openctl's Terraform host (
tfhost) from driving a realterraform-provider-*binary. It could previously only round-trip opaque state and send JSON config against an in-repo JSON fake.decodeStatereads a provider'sDynamicValue(msgpack or JSON) via the publictfprotov6.DynamicValue.Unmarshal(type)encodeConfigbuilds atftypes.Valueconforming to the schema's implied type (nested blocks included) →NewDynamicValue(msgpack)VersionedPlugins; SDKv2 (proto 5) providers driven throughv5adapterconverting field-identical v5⇄v6 messageshashicorp/timeprovider (proto 5) end-to-end, plus an upgraded msgpack/nested-blocktf-fake(proto 6)How it stays correct
terraform-plugin-go's deprecated low-level helpers. The fix uses the library's intended value codec —tfprotov6.NewDynamicValue/DynamicValue.Unmarshal— the same functions provider authors use. Full msgpack fidelity, zero SA1019.provider.gois unchanged in shape; a protocol-5 provider is bridged at the client boundary (client_v5.go). tfplugin5 gRPC stubs vendored inpkg/tfplugin5(mirrorspkg/tfplugin6, generated from the upstream proto).provider_statestays opaque — stored DynamicValue bytes round-trip untouched into Plan/Apply.Verification
plugins/tf-fakeupgraded to a nested-block, msgpack-emitting framework provider — existing tests now exercise the real wire encoding; a newTestProviderAdapterNestedBlockproves a nestednetworkblock round-trips through the adapter.TestRealProviderTimeStatic(gated onTFHOST_E2E_PROVIDER_TIME) drives the realhashicorp/timev0.12.1 binary: create/read/deletetime_static, decoding computed msgpack outputs (year=2020,unix,id). Verified locally:Local CI
gofmt / go vet / staticcheck / golangci-lint / modernize (generated-filtered) /
go test ./.../go test -race(tfhost) all green. No new external deps (uses already-presentterraform-plugin-go).Follow-ups
UpgradeResourceStatewiring; making the real-provider e2e run in CI (currently gated/local); then wire a real provider (e.g. the Terraform Cloudflare provider) through config.