|
| 1 | +# VEP #NNNN: Your short, descriptive title |
| 2 | + |
| 3 | +## Release Signoff Checklist |
| 4 | + |
| 5 | +Items marked with (R) are required *prior to targeting to a milestone / release*. |
| 6 | + |
| 7 | +- [X] (R) Enhancement issue created, which links to VEP dir in [kubevirt/enhancements] (not the initial VEP PR) |
| 8 | +- [ ] (R) Target version is explicitly mentioned and approved |
| 9 | +- [ ] (R) Graduation criteria filled |
| 10 | + |
| 11 | +## Overview |
| 12 | + |
| 13 | +Today, Kubevirt's API for feature gate management is a `kv.spec.configuration.developerConfiguration.featureGates` |
| 14 | +which is a [list of strings](https://github.com/kubevirt/kubevirt/blob/18c78c0f4d5f4c155ff2b425d0a213b563ac720e/staging/src/kubevirt.io/api/core/v1/types.go#L2813-L2815), |
| 15 | +each string is an enabled feature gate. |
| 16 | + |
| 17 | +The API is defined as follows: |
| 18 | +```go |
| 19 | + type DeveloperConfiguration struct { |
| 20 | + // FeatureGates is the list of experimental features to enable. Defaults to none |
| 21 | + FeatureGates []string `json:"featureGates,omitempty" |
| 22 | +``` |
| 23 | + |
| 24 | +With this approach it is impossible to explicitly disable a feature gate. |
| 25 | +This VEP aims to make it possible. |
| 26 | + |
| 27 | +## Motivation |
| 28 | + |
| 29 | +Disabling a feature gate is very important for different reasons, the main one arguably being that it opens the door to |
| 30 | +enable beta feature gates by default. |
| 31 | +This capability is very important, because it allows widely testing a feature upstream |
| 32 | +(which will at least be tested by CI and developers, alongside small users) while possibly disabling it downstream. |
| 33 | + |
| 34 | +This approach enables to gain wider feedback and confidence before the feature becomes GA, |
| 35 | +which has the potential to ensure features are much more stable and get a much wider feedback before graduating. |
| 36 | + |
| 37 | +## Goals |
| 38 | + |
| 39 | +* Allow to explicitly disable feature gates. |
| 40 | + |
| 41 | +## Non Goals |
| 42 | + |
| 43 | +## Definition of Users |
| 44 | + |
| 45 | +* Feature developers. |
| 46 | +* Cluster admins. |
| 47 | + |
| 48 | +## User Stories |
| 49 | + |
| 50 | +* As a feature developer, I want my feature to be widely tested and used before graduating, |
| 51 | +so I can gain wide feedback and confidence in it. |
| 52 | +* As a cluster administrator, I want to be able to decide on whether to use Alpha/Beta features or not. |
| 53 | + |
| 54 | +## Repos |
| 55 | + |
| 56 | +kubevirt/kubevirt. |
| 57 | + |
| 58 | +## Design |
| 59 | + |
| 60 | +Kubevirt CR's API needs to change in order to allow disablement of feature gates. |
| 61 | +
|
| 62 | +See the different alternatives below. |
| 63 | +
|
| 64 | +## API Examples |
| 65 | +
|
| 66 | +See below. |
| 67 | +
|
| 68 | +## Alternatives |
| 69 | +
|
| 70 | +Before deciding to create a VEP, this change was re-implemented three times as part of PR [#14427](https://github.com/kubevirt/kubevirt/pull/14427). |
| 71 | +
|
| 72 | +In this section, I'll outline the three approaches so we can discuss which of them is the best moving forward. |
| 73 | +I'd be happy for more pros and cons from reviewers if you can think of any. |
| 74 | +
|
| 75 | +### Approach #1 - Use a `FeatureGateConfiguration` struct slice with an `Enabled` field |
| 76 | +
|
| 77 | +As part of this approach, a feature enablement is determined by its configuration in the new `kv.spec.configuration.featureGates` field. |
| 78 | +This field is a slice of `FeatureGateConfiguration` objects which currently contain two fields, `name` and `enabled`: |
| 79 | +```go |
| 80 | +type FeatureGateConfiguration struct { |
| 81 | + Name string `json:"name"` |
| 82 | + // Enabled indicates whether the feature gate is enabled or not. Defaults to true. |
| 83 | + // +optional |
| 84 | + Enabled *bool `json:"enabled,omitempty"` |
| 85 | +} |
| 86 | +``` |
| 87 | +
|
| 88 | +`kv.spec.configuration.featureGates` has precedence over `kv.spec.configuration.developerConfiguration.featureGates`. |
| 89 | +However, if a feature gate exists only in the legacy feature gate slice, it would be considered enabled. |
| 90 | +This way we keep backward compatibility. |
| 91 | +
|
| 92 | +Usage Example: |
| 93 | +```go |
| 94 | +kind: KubeVirt |
| 95 | +spec: |
| 96 | + configuration: |
| 97 | + featureGates: |
| 98 | + - name: VMExport |
| 99 | + enabled: true |
| 100 | + - name: ImageVolume |
| 101 | + enabled: false |
| 102 | + - name: DownwardMetrics |
| 103 | + # defaults to true |
| 104 | + developerConfiguration: |
| 105 | + featureGates: |
| 106 | + - IncrementalBackup # This enables the FG |
| 107 | + - ImageVolume # Being ignored since the same FG is listed in the above config which takes precedence |
| 108 | +``` |
| 109 | +
|
| 110 | +Pros: |
| 111 | +* Extensible: a struct opens the door for further configuration moving forward. |
| 112 | +* Aligns with Kubernetes best practices: "the convention is to use a list of subobjects containing name fields ... |
| 113 | +This rule maintains the invariant that all JSON/YAML keys are fields in API objects". |
| 114 | +See [Kubernetes api conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#lists-of-named-subobjects-preferred-over-maps) |
| 115 | +for more info. |
| 116 | +
|
| 117 | +Cons: |
| 118 | +* Verbose: when there is no desire to disable feature gates, the admin would now have to supply the `name: ` boilerplate |
| 119 | +which makes the manifest more verbose. |
| 120 | +
|
| 121 | +### Approach #2 - Use a new map structure from a string to bool |
| 122 | +
|
| 123 | +As part of this approach, a new `kv.spec.configuration.featureGateMap` will be added of type `map[string]bool`. |
| 124 | +That is a map from string to bool types, i.e. feature name to whether it's enabled or not. |
| 125 | + |
| 126 | +`kv.spec.configuration.featureGates` has precedence over `kv.spec.configuration.developerConfiguration.featureGates`. |
| 127 | +However, if a feature gate exists only in the legacy feature gate slice, it would be considered enabled. |
| 128 | +This way we keep backward compatibility. |
| 129 | + |
| 130 | +Usage Example: |
| 131 | +```go |
| 132 | +kind: KubeVirt |
| 133 | +spec: |
| 134 | + configuration: |
| 135 | + featureGateMap: |
| 136 | + VMExport: true |
| 137 | + ImageVolume: false |
| 138 | + DownwardMetrics: false |
| 139 | + developerConfiguration: |
| 140 | + featureGates: |
| 141 | + - IncrementalBackup # This enables the FG |
| 142 | + - ImageVolume # Being ignored since the same FG is listed in the above config which takes precedence |
| 143 | +``` |
| 144 | + |
| 145 | +Pros: |
| 146 | +* Simplicity (?): Easy to implement and understand. |
| 147 | + |
| 148 | +Cons: |
| 149 | +* Goes against Kubernetes best practices: "the convention is to use a list of subobjects containing name fields". |
| 150 | +The api conventions specifically mention using maps as an anti-pattern: |
| 151 | +"Lists of named subobjects preferred over maps ... There are no maps of subobjects in any API objects". |
| 152 | +See [Kubernetes api conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#lists-of-named-subobjects-preferred-over-maps) |
| 153 | +for more info. |
| 154 | +* Maps are, by definition, unordered. This means that users/clients always have to sort it in a consistent manner |
| 155 | +to avoid entities mistakenly assuming that the state had changed because a change of ordering. |
| 156 | +* Non-extensible: If we'll need to add more configurations to feature gates in the future, we'll be in the same problem |
| 157 | +of having to extend the API. |
| 158 | + |
| 159 | +### Approach #3 - Use a complementary slice for disabled feature gates |
| 160 | + |
| 161 | +As part of this approach, a complementary `kv.spec.configuration.developerConfiguration.disabledFeatureGates` string slice will be added. |
| 162 | +The same feature gate cannot be provided to both slices, this should result with an error. |
| 163 | + |
| 164 | +Usage Example: |
| 165 | +```go |
| 166 | +kind: KubeVirt |
| 167 | +spec: |
| 168 | + configuration: |
| 169 | + developerConfiguration: |
| 170 | + featureGates: |
| 171 | + - IncrementalBackup |
| 172 | + - ImageVolume |
| 173 | + disabledFeatureGates: |
| 174 | + - VMExport |
| 175 | + - DownwardMetrics |
| 176 | + # - ImageVolume -> invalid, would result in an error since already provided above |
| 177 | +``` |
| 178 | + |
| 179 | +Pros: |
| 180 | +* No need to deprecate the old `kv.spec.configuration.developerConfiguration.featureGates` field. |
| 181 | +* Easy adoption: the API is very familiar to what we have to day. |
| 182 | + |
| 183 | +Cons: |
| 184 | +* Non-extensible: If we'll need to add more configurations to feature gates in the future, we'll be in the same problem |
| 185 | +of having to extend the API. |
| 186 | +* We keep both API fields under `kv.spec.configuration.developerConfiguration` instead of finding a new home under `kv.spec.configuration`. |
| 187 | + |
| 188 | +### Approach #4 - Reuse the current string slice, allow special syntax for disablement |
| 189 | + |
| 190 | +As part of this approach no new API fields will be added, but the current `kv.spec.configuration.developerConfiguration.featureGates` |
| 191 | +will be reused to allow disabling feature gates. |
| 192 | + |
| 193 | +This will be achieved by allowing the following special syntax: `<gate>=<true|false>`, |
| 194 | +or just `<gate>` that will be interpreted as `<gate>=true`. |
| 195 | + |
| 196 | +Usage Example: |
| 197 | +```go |
| 198 | +kind: KubeVirt |
| 199 | +spec: |
| 200 | + configuration: |
| 201 | + developerConfiguration: |
| 202 | + featureGates: |
| 203 | + - "IncrementalBackup: true" |
| 204 | + - "ImageVolume: false" |
| 205 | + - VMExport # defaults to true |
| 206 | +``` |
| 207 | + |
| 208 | +Pros: |
| 209 | +* Avoid adding / changing API fields. |
| 210 | +* Syntax is fairly simple and elegant. |
| 211 | + |
| 212 | +Cons: |
| 213 | +* Special parsing would be needed by any user/client. This means: |
| 214 | + * Kubevirt's code would need to include many parsing logic. |
| 215 | + * Standard tooling would have trouble working with that. |
| 216 | +* We keep the API field under `kv.spec.configuration.developerConfiguration` instead of finding a new home under `kv.spec.configuration`. |
| 217 | +
|
| 218 | +## Scalability |
| 219 | +
|
| 220 | +No scalability issues are expected. |
| 221 | +
|
| 222 | +## Update/Rollback Compatibility |
| 223 | +
|
| 224 | +In all of the approached above backward compatibility will be kept. |
| 225 | +
|
| 226 | +In some of the approaches above `kv.spec.configuration.developerConfiguration` will be deprecated, but will not be |
| 227 | +removed in the foreseen future. |
| 228 | +
|
| 229 | +## Functional Testing Approach |
| 230 | +
|
| 231 | +## Implementation History |
| 232 | +
|
| 233 | +<!-- |
| 234 | +For example: |
| 235 | +01-02-1921: Implemented mechanism for doing great stuff. PR: <LINK>. |
| 236 | +03-04-1922: Added support for doing even greater stuff. PR: <LINK>. |
| 237 | +--> |
| 238 | +
|
| 239 | +## Graduation Requirements |
| 240 | +
|
| 241 | +<!-- |
| 242 | +The requirements for graduating to each stage. |
| 243 | +Example: |
| 244 | +### Alpha |
| 245 | +- [ ] Feature gate guards all code changes |
| 246 | +- [ ] Initial implementation supporting only X and Y use-cases |
| 247 | +
|
| 248 | +### Beta |
| 249 | +- [ ] Implementation supports all X use-cases |
| 250 | +
|
| 251 | +It is not necessary to have all the requirements for all stages in the initial VEP. |
| 252 | +They can be added later as the feature progresses, and there is more clarity towards its future. |
| 253 | +
|
| 254 | +Refer to https://github.com/kubevirt/community/blob/main/design-proposals/feature-lifecycle.md#releases for more details |
| 255 | +--> |
| 256 | +
|
| 257 | +### Alpha |
| 258 | +
|
| 259 | +- [ ] Feature gate guards all code changes. |
| 260 | +- [ ] It is possible to explicitly disable feature gates in Kubevirt CR. |
| 261 | +
|
| 262 | +### Beta |
| 263 | +
|
| 264 | +### GA |
0 commit comments