그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그 그
2 minute read
Defaulting Strategy and Developer Guidelines
This document walks you through:
- Conventions to be followed when writing defaulting functions
- How to write a test for a defaulting function
The document is aimed towards developers who want to contribute code and need to write defaulting code and unit tests covering the defaulting functions, as well as maintainers and reviewers who review code. It serves as a common guide that we commit to follow in our project to ensure consistency in our defaulting code, good coverage for high confidence, and good maintainability.
Writing defaulting code
- Every kubernetes type should have a dedicated
defaults_*.go
file. For instance, if you have aShoot
type, there should be a correspondingdefaults_shoot.go
file containing all defaulting logic for that type. - If there is only one type under an api group then we can just have
types.go
and a correspondingdefaults.go
. For instance,resourcemanager
api has only onetypes.go
, hence in this case onlydefaults.go
file would suffice. - Aim to segregate each struct type into its own
SetDefaults_*
function. These functions encapsulate the defaulting logic specific to the corresponding struct type, enhancing modularity and maintainability. For example,ServerConfiguration
struct inresourcemanager
api has correspondingSetDefaults_ServerConfiguration()
function.
⚠️ Ensure to run the make generate WHAT=codegen
command when new SetDefaults_*
function is added, which generates the zz_generated.defaults.go
file containing the overall defaulting function.
Writing unit tests for defaulting code
Each test case should validate the overall defaulting function
SetObjectDefaults_*
generated bydefaulter-gen
and not a specificSetDefaults_*
. This way we also test if thezz_generated.defaults.go
was generated correctly. For example, thespec.machineImages[].updateStrategy
field in the CloudProfile is defaulted as follows: https://github.com/gardener/gardener/blob/ff5a5be6049777b0695659a50189e461e1b17796/pkg/apis/core/v1beta1/defaults_cloudprofile.go#L23-L29 The defaulting should be tested with the overall defaulting functionSetObjectDefaults_CloudProfile
(and not withSetDefaults_MachineImage
): https://github.com/gardener/gardener/blob/ff5a5be6049777b0695659a50189e461e1b17796/pkg/apis/core/v1beta1/defaults_cloudprofile_test.go#L40-L47Test each defaulting function carefully to ensure:
Proper defaulting behaviour when fields are empty or nil. Note that some fields may be optional and should not be defaulted.
Preservation of existing values, ensuring that defaulting does not accidentally overwrite them.
For example, when
spec.secretRef.namespace
field ofSecretBinding
is nil, it should be defaulted to the namespace of SecretBinding object. Butspec.secretRef.namespace
field should not be overwritten by defaulting logic if it is already set. https://github.com/gardener/gardener/blob/ff5a5be6049777b0695659a50189e461e1b17796/pkg/apis/core/v1beta1/defaults_secretbinding_test.go#L26-L54