Skip to content

Commit

Permalink
Add support for the hahicorp mux library
Browse files Browse the repository at this point in the history
Hashicorp has a new "framework" for provider development that replaces
SDK v2.0.  We can combine "framework" provider code which can still be
in separate repos with SDK v2.0 provider code using the Hashicorp "mux"
library.  In this PR we adapt the existing pkg/provider code to allow us
to use "mux" with "legacy" provider code that uses the framework that we
put together for SDK v2.0.

To do this instead of creating one combined provider instance we create
separate provider instances one for each service.  There are a couple of
restrictions on providers that are passed to the mux library:
- the ProviderSchema (i.e. the schema that determines the provider
  stanza) must be same for each sub-provider
- you cannot repeat any data-source or resource definitions in any of
  the sub-providers

We've implemented a NewProviderMux function in pkg/provider which
creates sub-providers that satisfy the above restrictions.  The inputs
to this function are the same as those to NewProviderFunc.  SDK v2.0
provider repos that use the framework don't need any changes.  However
we will need to add registration.ServiceRegistration implementations for
all new "framework" providers that implement just the
ProviderSchemaEntry and pass those down to NewProviderMux.

Signed-off-by: Eamonn O'Toole <[email protected]>
  • Loading branch information
eamonnotoole committed Jul 11, 2024
1 parent 487d1c0 commit dff283b
Showing 1 changed file with 69 additions and 0 deletions.
69 changes: 69 additions & 0 deletions pkg/provider/provider_mux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// (C) Copyright 2021-2024 Hewlett Packard Enterprise Development LP

package provider

import (
"fmt"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/hewlettpackard/hpegl-provider-lib/pkg/registration"
)

// ProviderForMux is a function that returns a list of ProviderServer functions that can be used with the
// Hashicorp mux library. This function will be called from terraform-provider-hpegl which will be adapted
// to support "legacy" provider code that use SDK v2.0 (i.e. metal, vmaas, caas on PCE) as well as newer provider
// code that uses the new Hashicorp provider "framework".
//
// Note that we will need to add the ProviderSchemaEntry() functions for the newer providers. This means that
// registration.ServiceRegistration implementations for the newer providers that only contain ProviderSchemaEntry()
// and no SupportedResource() or SupportedDataSources().
func ProviderForMux(reg []registration.ServiceRegistration, pf ConfigureFunc) []func() tfprotov5.ProviderServer {
providerSchema := generateProviderSchema(reg)
providerServerList := make([]func() tfprotov5.ProviderServer, 0)
for _, service := range reg {
// Only create a provider if it has resources or data sources
if service.SupportedResources() != nil || service.SupportedDataSources() != nil {
providerServerList = append(providerServerList, generateProvider(service, pf, providerSchema))
}
}

return providerServerList
}

// generateProviderSchema generates the provider schema from the service registrations. Note that this schema
// needs to be added to each of the sub-providers.
func generateProviderSchema(reg []registration.ServiceRegistration) map[string]*schema.Schema {
providerSchema := Schema()
for _, service := range reg {
if service.ProviderSchemaEntry() != nil {
// We panic if the service.Name() key is repeated in providerSchema
if _, ok := providerSchema[service.Name()]; ok {
panic(fmt.Sprintf("service name %s is repeated", service.Name()))
}
providerSchema[service.Name()] = convertToTypeSet(service.ProviderSchemaEntry())
}
}

return providerSchema
}

// generateProvider will generate a sub-provider for each service that can be used with the Hashicorp mux library.
func generateProvider(
service registration.ServiceRegistration,
pf ConfigureFunc,
providerSchema map[string]*schema.Schema,
) func() tfprotov5.ProviderServer {
p := schema.Provider{
Schema: providerSchema,
ResourcesMap: service.SupportedResources(),
DataSourcesMap: service.SupportedDataSources(),
// Don't use the following field, experimental
ProviderMetaSchema: nil,
TerraformVersion: "",
}

p.ConfigureContextFunc = pf(&p) // nolint staticcheck

return p.GRPCProvider
}

0 comments on commit dff283b

Please sign in to comment.