Terraform-plugin-codegen-framework best practices

Hey Team,

I was working on writing terraform provider for one of our products. I was thinking of using codegen (tfplugingen-framwork). I did explore about it.

I wanted to check with you on best practices/suggestion.

We have two approaches here to think on, which is regarding the file/folder structure and go package.

So, Is it better to maintain a single package for all schema and Model struct generated (for all the resources) using tfplugingen-framework generate resources, and other package for the resources files generated using tfplugingen-framework scaffold resource?
OR
Other option would be to make a single package for the particular resource and than generate both resource file and schema file in the same package, but the issue/concern here is that, we have nearly 300 resources/endpoints, which can expand as well, So, this creates a lot of folders and packages to maintain.

Can you suggest us here on what is the best way?

Hey there @rohit-myali :wave:,

Generally speaking, we (the TF DevEx team) currently don’t have a broad recommendation for how to structure code generation projects for terraform providers, as it’s still in tech preview and we’re actively researching how to build further on it, which may influence that recommendation.


More specifically, to the two approaches you provided, I would lean towards a project structure like option 1, which separates β€œgenerated code” (generate command) from β€œmanually written” (initially created with scaffold command) code. That could be one generated package for all resources, or multiple generated packages for each resource, but the general rule of thumb there would be a package should either be entirely managed by a code generation process, or the package should be manually developed/managed (aided with the scaffold command).

Our current default for code generation package structure creates one package per resource/data source, and the primary reason for that is naming conflicts. There are a lot of exported schema/types that may have similar names across resources, so it’s currently easiest for us to generate the resource schema/types in it’s own package vs. trying to understand the entire context and avoid naming conflicts in a β€œsmarter” way.

If you combine that default with option 1, you could have one package that is β€œmanually” maintained (containing resource files created via scaffold) and then multiple packages (all under /internal/generated) that are maintained by the code generation process:

.
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ generated/
β”‚   β”‚   β”œβ”€β”€ resource_order/
β”‚   β”‚   β”‚   └── order_resource_gen.go
β”‚   β”‚   └── resource_pet/
β”‚   β”‚       └── pet_resource_gen.go
β”‚   β”œβ”€β”€ order_resource.go (CRUD logic, consumes 'resource_order' package)
β”‚   β”œβ”€β”€ pet_resource.go (CRUD logic, consumes 'resource_pet' package)
β”‚   └── provider.go (provider logic)
β”œβ”€β”€ generator_config.yml
β”œβ”€β”€ go.mod
β”œβ”€β”€ go.sum
β”œβ”€β”€ main.go
β”œβ”€β”€ openapi.json
└── provider-code-spec.json

As we expand on the tech preview, there may be more opportunities to move logic from the manually maintained internal package, to the internal/generated packages. (like say, CRUD functionality implemented from a user-defined .gotmpl file)

1 Like