hashicorp / vault-client-go

HashiCorp Vault Go Client Library generated from OpenAPI spec.
Mozilla Public License 2.0
84 stars 17 forks source link

Proposal: Improved system for filtering operations out of the generated library #179

Open maxb opened 1 year ago

maxb commented 1 year ago

I propose that this project is in need of a nicer way to exclude specific operations from the generated library.

Currently, operationIds ending with 2 or 3 are filtered, but accomplishing this has required implementing the filter list in multiple ways, in many places:

https://github.com/hashicorp/vault-client-go/blob/c9387ae5ce128b9e82fdc283a99a917f4c9c6729/generate/templates/api.handlebars#L20-L23

https://github.com/hashicorp/vault-client-go/blob/c9387ae5ce128b9e82fdc283a99a917f4c9c6729/generate/templates/api_doc.handlebars#L7

https://github.com/hashicorp/vault-client-go/blob/c9387ae5ce128b9e82fdc283a99a917f4c9c6729/generate/templates/api_doc.handlebars#L11

https://github.com/hashicorp/vault-client-go/blob/c9387ae5ce128b9e82fdc283a99a917f4c9c6729/.openapi-generator-ignore#L7-L15

It is already very unappealing to extend this list further, and yet, there are more endpoints I think are in the interests of the library's users, to exclude, such as:

Other cases may arise.

Ideally we would just add these to a simple exclude list in a format that could be easily shared with vault-client-dotnet or future languages.

The upstream openapi-generator project does not have an answer for us. It only supports include lists for things to generate, not exclude lists, and then only as a single string, not reading from a file.

I propose, therefore, that we need to create a small filter script, that reads the raw OpenAPI spec fetched from Vault, selectively deletes operations by matching against an operationId exclude list, and feeds the filtered OpenAPI spec to openapi-generator.

Such a filter script could be very easily implemented in Python, using exclusively its built in standard library. Also, Python is a common language interpreter available in many developer environments. Therefore, Python feels like the right tool for the job for this filter script. Go is not an appealing tool for the job, as its builtin JSON library isn't well suited to dynamic processing, and insists on randomizing the order of object keys.

Please advise what you think of this, and whether it's worth progressing to a PR.

averche commented 1 year ago

Hello again, @maxb and thank you for the detailed proposal!

The exclusion of 2 and 3 suffixes was indeed a hacky fix introduced in #154. To add to the list of the endpoints you mentioned above, we also now have ACME endpoints under PKI, which are not supposed to be generated in the libraries.

Internally, we have been discussing adding yet another vendor field in the openapi spec at the operation level, e.g. x-vault-excludeFromCodeGeneration (similar to the existing x-vault-unauthenticated and x-vault-sudo). Alternatively, we could add the field to the existing x-vault-displayAttributes object.

I like your proposal as well! Once the OpenAPI spec is a bit more polished, we are planning to publish it in a separate repo with its own CI pipelines and two separate specs (a raw one and one specific to the generated vault-client-* libraries). The python script and the corresponding exclusion list could be migrated to that new repo once it is ready.

We'll have a further discussion in the team to determine which approach is best. Meanwhile, we'd be happy to hear your thoughts as well!

maxb commented 1 year ago

Internally, we have been discussing adding yet another vendor field in the openapi spec at the operation level, e.g. x-vault-excludeFromCodeGeneration

I have two concerns with this approach:

averche commented 1 year ago

It commits you to making a single include/exclude decision for all code generation purposes.

I think that's a desired outcome. We are moving towards a single source-of-truth OpenAPI document, whether it is generated by a python script or has flags to prevent generation.

Suppose that one day in the future you have released vault-client-go v1.0, and later some endpoints in Vault are deprecated (but still work). You may decide to retain the methods in vault-client-go until the next major version of the library, to preserve compatibility.

What you described applies well to a deprecation workflow. OpenAPI already supports deprecated: true at the operation level. We can use it to mark individual endpoints as deprecated (scheduled to be removed in the future). If / when they are removed at the OpenAPI level, we can release a new major version of all vault-client-* libraries.

The suggested x-vault-excludeFromCodeGeneration is less for the deprecated endpoints and more for duplicates (e.g. TokenLookupSelf2, TokenLookupSelf3) and operations we may want to deliberately exclude from all client libraries (e.g. Monitor, ACME-related endpoints, etc.) even though they are not deprecated.

At the same time you may be preparing to release vault-client-some-new-language v1.0. You may well not want to include deprecated methods in a brand new library, where no compatibility constraints exist.

I think it still could make sense to keep deprecated methods in a new library until they have been fully removed from the OpenAPI spec to keep the libraries consistent between each other.

It commits you to a many-PR process for making changes... first update the plugin repo, second pull a new plugin version into Vault core, third pull a new OpenAPI spec into the library. I think it would be useful for the client library to have control, without needing to work through the release process of other repositories.

Yes, this has been an issue we've been dealing with for populating the response structures and operation ID's. It does add more operational overhead but I think it may be justified in the end. The exclusion flag is not likely to change once set. We could also have logic in openapi.go to add the flag for all "*2", "*3" and "*acme*" endpoints at the time of generating the API (effectively maintain the exclusion list there), though this solution may be too flaky.