Skip to content

Commit

Permalink
Improve provider generation performance.
Browse files Browse the repository at this point in the history
Speedup in upbound/provider-aws, obtained via non-rigorous measurement
techniques, is around 1.1x. Performance benefits would be higher, if
there were more Terraform Plugin Framework resources configured.

Signed-off-by: Cem Mergenci <[email protected]>
  • Loading branch information
mergenci committed Jan 30, 2024
1 parent 199c2d5 commit b348aaf
Showing 1 changed file with 34 additions and 20 deletions.
54 changes: 34 additions & 20 deletions pkg/config/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ func WithMainTemplate(template string) ProviderOption {
// NewProvider builds and returns a new Provider from provider
// tfjson schema, that is generated using Terraform CLI with:
// `terraform providers schema --json`
func NewProvider(ctx context.Context, schema []byte, prefix string, modulePath string, metadata []byte, opts ...ProviderOption) *Provider { //nolint:gocyclo
func NewProvider(schema []byte, prefix string, modulePath string, metadata []byte, opts ...ProviderOption) *Provider { //nolint:gocyclo
ps := tfjson.ProviderSchemas{}
if err := ps.UnmarshalJSON(schema); err != nil {
panic(err)
Expand Down Expand Up @@ -304,7 +304,7 @@ func NewProvider(ctx context.Context, schema []byte, prefix string, modulePath s
}

p.skippedResourceNames = make([]string, 0, len(resourceMap))
terraformPluginFrameworkResourceFunctions := p.TerraformPluginFrameworkProvider.Resources(ctx)
terraformPluginFrameworkResourceFunctionsMap := terraformPluginFrameworkResourceFunctionsMap(p.TerraformPluginFrameworkProvider)
for name, terraformResource := range resourceMap {
if len(terraformResource.Schema) == 0 {
// There are resources with no schema, that we will address later.
Expand Down Expand Up @@ -334,27 +334,14 @@ func NewProvider(ctx context.Context, schema []byte, prefix string, modulePath s
}

var terraformPluginFrameworkResource fwresource.Resource

if isPluginFrameworkResource {
// TODO: Consider whether to replace the commented out conditional in the next line with an equivalent conditional for plugin framework.
if p.TerraformPluginFrameworkProvider == nil /*|| p.TerraformProvider.ResourcesMap[name] == nil */ {
panic(errors.Errorf("resource %q is configured to be reconciled without the Terraform CLI"+
"but either config.Provider.TerraformProvider is not configured or the Go schema does not exist for the resource", name))
resourceFunc := terraformPluginFrameworkResourceFunctionsMap[name]
if p.TerraformPluginFrameworkProvider == nil || resourceFunc == nil {
panic(errors.Errorf("resource %q is configured to be reconciled with Terraform Plugin Framework"+
"but either config.Provider.TerraformPluginFrameworkProvider is not configured or the provider doesn't have the resource.", name))
}

for _, resourceFunc := range terraformPluginFrameworkResourceFunctions {
resource := resourceFunc()

resourceTypeNameReq := fwresource.MetadataRequest{
ProviderTypeName: name,
}
resourceTypeNameResp := fwresource.MetadataResponse{}
resource.Metadata(ctx, resourceTypeNameReq, &resourceTypeNameResp)
if resourceTypeNameResp.TypeName == name {
terraformPluginFrameworkResource = resource
break
}
}
terraformPluginFrameworkResource = resourceFunc()
}

p.Resources[name] = DefaultResource(name, terraformResource, terraformPluginFrameworkResource, providerMetadata.Resources[name], p.DefaultResourceOptions...)
Expand Down Expand Up @@ -414,3 +401,30 @@ func matches(name string, regexList []string) bool {
}
return false
}

func terraformPluginFrameworkResourceFunctionsMap(provider fwprovider.Provider) map[string]func() fwresource.Resource {
if provider == nil {
return make(map[string]func() fwresource.Resource, 0)
}

ctx := context.TODO()
resourceFunctions := provider.Resources(ctx)
resourceFunctionsMap := make(map[string]func() fwresource.Resource, len(resourceFunctions))

providerMetadata := fwprovider.MetadataResponse{}
provider.Metadata(ctx, fwprovider.MetadataRequest{}, &providerMetadata)

for _, resourceFunction := range resourceFunctions {
resource := resourceFunction()

resourceTypeNameReq := fwresource.MetadataRequest{
ProviderTypeName: providerMetadata.TypeName,
}
resourceTypeNameResp := fwresource.MetadataResponse{}
resource.Metadata(ctx, resourceTypeNameReq, &resourceTypeNameResp)

resourceFunctionsMap[resourceTypeNameResp.TypeName] = resourceFunction
}

return resourceFunctionsMap
}

0 comments on commit b348aaf

Please sign in to comment.