Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(fwprovider): export the provider implementation for embedding - #434

Open
michvllni wants to merge 1 commit into
coder:mainfrom
axiansinfoma:feat/export-provider-for-embedding
Open

feat(fwprovider): export the provider implementation for embedding#434
michvllni wants to merge 1 commit into
coder:mainfrom
axiansinfoma:feat/export-provider-for-embedding

Conversation

@michvllni

@michvllni michvllni commented Sep 9, 2026

Copy link
Copy Markdown

Adds a public fwprovider package that hands out the provider implementation, so Go programs can embed the provider in-process instead of running it as a plugin binary.

Motivation

In #354 I asked for a Crossplane provider for Coder. Crossplane's Upjet generates one directly from a Terraform provider's schema, and it can drive that provider two ways:

  • Terraform CLI mode. Upjet bundles the terraform binary and the provider binary into its controller image, then runs terraform against a workspace per managed resource, which in turn launches the provider plugin. It works against any provider and needs no cooperation from upstream.
  • In-process mode. Upjet calls the provider's provider.Provider implementation directly through its plugin-framework client. No terraform binary, no provider binary, no subprocess per reconcile.

In-process mode needs an importable provider.Provider. internal/provider is unimportable outside this module, so today the only route is to fork this repo and add the export in the fork. That is exactly what Upbound does for the providers that keep theirs internal — terraform-provider-aws/xpprovider and terraform-provider-azurerm/xpprovider, both wired in through a replace directive. Providers that expose theirs upstream need no fork at all: terraform-provider-google has google/fwprovider, terraform-provider-keycloak has provider.

I would rather not maintain a fork of this repo that has to be re-synced on every release, and I doubt you want one circulating either.

What changed

A single public package delegating to the existing constructor:

func New(version string) func() tfprovider.Provider {
	return provider.New(version)
}

Returning the factory rather than an instance keeps the signature identical to provider.New, so it still drops straight into providerserver.Serve; embedders call it to get an instance.

Kept deliberately small:

  • No new dependencies — terraform-plugin-framework is already required.
  • No behaviour change and no second code path. It is a one-line delegation, so it cannot drift, and a signature change to provider.New breaks the build here too.
  • internal/ stays internal. This exports the provider surface only, not resource implementations, codersdk plumbing, or helpers.
  • main.go is untouched.
  • A test asserts the factory yields the provider main.go serves, with TypeName, version, resources and data sources all wired.

I named it fwprovider after the terraform-provider-google precedent rather than Upbound's Crossplane-specific xpprovider, on the grounds that this is an export you own rather than one living in a downstream fork. Happy to rename it, relocate it, or narrow the signature.

Context

I have built an Upjet-based Crossplane provider covering all 15 resources, exposing both cluster-scoped and namespaced Crossplane v2 APIs, with a scheduled job that regenerates and opens a PR when a release lands here. It runs in Terraform CLI mode today, because that is the only mode available without forking this repo.

I took the liberty of starting the implementation rather than just filing the request, so there is something concrete to react to. If you would like the Crossplane provider itself to live under the Coder org, I am happy to donate it; equally happy to keep maintaining it out-of-tree if you would rather not adopt another repo. Either way this export stands on its own for anyone embedding the provider.

Refs #354

The provider lives in internal/provider, so consumers outside this module
cannot obtain a provider.Provider value. That blocks embedding it in-process
and forces downstreams to fork this repo just to add the export.

Add a public fwprovider package that delegates to the existing constructor,
following the terraform-provider-google precedent. No new dependencies, no
behaviour change, and the rest of internal/ stays internal.

Refs coder#354
Comment thread fwprovider/fwprovider_test.go

@ethanndickson ethanndickson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

fwprovider as a name is fine with me, and I don't have any objections with the export.

I'm not able to say if we'll have resources for any maintenance work this introduces, i.e. reviewing fixes for bugs only present downstream, but if this alone is useful I suppose it's fine?

@michvllni

Copy link
Copy Markdown
Author

fwprovider as a name is fine with me, and I don't have any objections with the export.

I'm not able to say if we'll have resources for any maintenance work this introduces, i.e. reviewing fixes for bugs only present downstream, but if this alone is useful I suppose it's fine?

I think that's fair. In the end this is an extension that allows extended usage. If there is something missing or issues, it would be the job of said extensions to handle it or open PRs to mitigate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants