Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple api_versions in the same codebase #228

Merged
merged 2 commits into from
Oct 10, 2023

Conversation

drevell
Copy link
Contributor

@drevell drevell commented Oct 10, 2023

Apologies for the large PR, but I think in this case it's important to present all the pieces at the same time.

This PR creates a system for supporting YAML files using different api_versions from a single binary. This is implemented by having a separate set of structs for each (kind,api_version) pair. Each api_version can change the semantics or existence of YAML fields. The structs are stored in templates/model/$KIND/$APIVERSION.

Instructions for adding a new api_version are in templates/model/README.md, that might be a good starting point for review.

Old versions are automatically converted to new versions before being used: old structs define an Upgrade() method that define how to upgrade them.

There's a registry of api_versions in decode.go that defines which versions exist and which structs are associated with each.

To demonstrate that this all actually works, this PR creates a new API version v1beta1. The only change in this new version is adding the optional if field for each step in spec.yaml (#220).

Alternatives considered to try to avoid this huge copy-pasting of structs:

  • Struct embedding to reduce copy-pasta: this would expose a more complicated API to the rest of the code that has to use the structs. It makes creating a new version more painful. It also triggers reflect: StructOf doesn't generate wrapper methods for embedded fields golang/go#15924 since we use reflect.StructOf.
  • Use http://github.com/mitchellh/mapstructure to avoid so much double-parsing: we'd lose YAML position information, and our users really appreciate getting line numbers on their error messages.
  • Use switch(apiVersion) within a single struct instead of copy-pasting structs: high risk of accidentally changing the behavior of old API versions and generally creating fragile code.

I've marked files that are mostly copy-pasted so you can mostly skip reviewing them

@drevell drevell requested review from a team as code owners October 10, 2023 00:59
…o present all the pieces at the same time.

This PR creates a system for supporting YAML files using different `api_version`s from a single binary. This is implemented by having a separate set of structs for each `(kind,api_version)` pair. Each api_version can change the semantics or existence of YAML fields. The structs are stored in `templates/model/$KIND/$APIVERSION`.

Instructions for adding a new `api_version` are in `templates/model/README.md`, that might be a good starting point for review.

Old versions are automatically converted to new versions before being used: old structs define an Upgrade() method that define how to upgrade them.

There's a registry of `api_version`s in decode.go that defines which versions exist and which structs are associated with each.

To demonstrate that this all actually works, this PR creates a new API version `v1beta1`. The only change in this new version is adding the optional `if` field for each step in spec.yaml (#220).

Alternatives considered to try to avoid this huge copy-pasting of structs:
- Struct embedding to reduce copy-pasta: this would expose a more complicated API to the rest of the code that has to use the structs. It makes creating a new version more painful. It also triggers golang/go#15924 since we use `reflect.StructOf`.
- Use github.com/mitchellh/mapstructure` to avoid so much double-parsing: we'd lose YAML position information, and our users really appreciate getting line numbers on their error messages.
- Use `switch(apiVersion)` within a single struct instead of copy-pasting structs: high risk of accidentally changing the behavior of old API versions and generally creating fragile code.

I've marked files that are mostly copy-pasted so you can mostly skip reviewing them
templates/model/spec/v1beta1/upgrade.go Outdated Show resolved Hide resolved
templates/model/unmarshal.go Outdated Show resolved Hide resolved
templates/model/spec/v1alpha1/upgrade.go Outdated Show resolved Hide resolved
templates/model/decode/decode.go Outdated Show resolved Hide resolved
@drevell drevell merged commit dc14cac into main Oct 10, 2023
2 checks passed
@drevell drevell deleted the drevell/api-versions branch October 10, 2023 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants