You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+141Lines changed: 141 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -103,10 +103,151 @@ The `pkg/controller` package contains useful functions for setting up and runnin
103
103
#### Noteworthy Functions
104
104
105
105
-`LoadKubeconfig` creates a REST config for accessing a k8s cluster. It can be used with a path to a kubeconfig file, or a directory containing files for a trust relationship. When called with an empty path, it returns the in-cluster configuration.
106
+
- See also the [`clusters`](#clusters) package, which uses this function internally, but provides some further tooling around it.
106
107
- There are some functions useful for working with annotations and labels, e.g. `HasAnnotationWithValue` or `EnsureLabel`.
107
108
- There are multiple predefined predicates to help with filtering reconciliation triggers in controllers, e.g. `HasAnnotationPredicate` or `DeletionTimestampChangedPredicate`.
108
109
- The `K8sNameHash` function can be used to create a hash that can be used as a name for k8s resources.
109
110
111
+
#### Status Updater
112
+
113
+
The status updater gets its own section, because it requires a slightly longer explanation. The idea of it is that many of our resources use a status similar to this:
114
+
```go
115
+
typeMyStatusstruct {
116
+
// ObservedGeneration is the generation of this resource that was last reconciled by the controller.
The logic for most of these fields is very similar across all of our controllers: `ObservedGeneration` and `LastReconcileTime` should always be updated, `Phase` is usually computed based on the conditions or on whether an error occurred, `Reason`, `Message` and `Conditions` are generated during reconciliation.
140
+
141
+
To reduce redundant coding and ensure a similar behavior in all controllers, the _status updater_ can be used to update the status. A full example could look something like this:
-`v1alpha1.MyResource` is the resource type being reconciled in this example.
183
+
-`v1alpha1.MyResourcePhase` is the type of the `Phase` field used in the status of `MyResource`.
184
+
- It must be a string-like type, e.g. `type MyResourcePhase string`.
185
+
- If the resource status doesn't have a `Phase` or updating it is not desired, simply set this type argument to `string`.
186
+
-`v1alpha1.ConditionStatus` is the type of the `Status` field within the conditions. It must be `comparable`.
187
+
- Usually, this will either be a boolean or a string-like type.
188
+
- If the resource status doesn't have conditions or updating them is not desired, simply set this type argument to `bool`.
189
+
- The conditions must be a list of a type `T`, where either `T` or `*T` implements the `conditions.Condition[ConType]` interface.
190
+
- `ConType` is `v1alpha1.ConditionStatus` in this example.
191
+
192
+
193
+
**How to use the status updater**
194
+
195
+
It is recommended to move the actual reconciliation logic into a helper function (`reconcile` in the example). This makes it easier to ensure that the status updater is always called, no matter where the reconciliation exits, e.g. due to an error. This helper function should then return the `ReconcileResult` required by the status updater.
It takes the type of the reconciled resource, the type of its `Phase` attribute and the type of the `Status` attribute of its conditions as type arguments.
202
+
203
+
If you want to update the phase, you have to pass in a function that computes the new phase based on the the current state of the object and the returned reconcile result. Note that the function just has to return the phase, not to set it in the object. Failing to provide this function causes the updater to use a dummy implementation that sets the phase to the empty string.
If the conditions should be updated, the `WithConditionUpdater` method must be called. Similarly to the condition updater from the `conditions` package - which is used internally - it requires a constructor function that returns a new, empty instance of the controller-specific `conditions.Condition` implementation. The second argument specifies whether existing conditions that are not part of the updated conditions in the `ReconcileResult` should be removed or kept.
221
+
222
+
You can then `Build()` the status updater and run `UpdateStatus()` to do the actual status update. The return values of this method are meant to be returned by the `Reconcile` function.
223
+
224
+
**Some more details**
225
+
226
+
- The status updater uses reflection to modifiy the status' fields. This requires it to know the field names (the ones in go, not the ones in the YAML representation). By default, it expects them to be `Status` for the status itself and `Phase`, `ObservedGeneration`, `LastReconcileTime`, `Reason`, `Message`, and `Conditions` for the respective fields within the status.
227
+
- To use a different field name, overwrite it by using either `WithFieldOverride` or `WithFieldOverrides`.
228
+
- If any of the fields is not contained top-level in the status but within a nested struct, the names of these fields must be prefixed with the names of the corresponding structs, separated by a `.`. The `WithNestedStruct` method can be used to set such a prefix quickly for one or more fields.
229
+
- To disable the update of a specific field altogether, set its name to the empty string. This can be done via the aforementioned `WithFieldOverride`/`WithFieldOverrides` methods, or simpler via `WithoutFields`.
230
+
- Doing this for the status field itself turns the status update into a no-op.
231
+
- The package contains constants with the field keys that are required by most of these methods. `STATUS_FIELD` refers to the `Status` field itself, the other field keys are prefixed with `STATUS_FIELD_`.
232
+
- The `AllStatusFields()` function returns a list containing all status field keys, _except the one for the status field itself_, for convenience.
233
+
- The `WithCustomUpdateFunc` method can be used to inject a function that performs custom logic on the resource's status. Note that while the function gets the complete object as an argument, only changes to its status will be updated by the status updater.
234
+
235
+
**The ReconcileResult**
236
+
237
+
The `ReconcileResult` that is passed into the status updater is expected to contain a representation of what happened during the reconciliation. Its fields influence what the updated status will look like.
238
+
239
+
-`Result` contains the `reconcile.Result` that is expected as a return value from the `reconcile.Reconciler` interface's `Reconcile` method. It is not modified in any way and simply passed through. It does not affect any of the status' fields.
240
+
-`ReconcileError` contains any error(s) that occurred during the actual reconciliation. It must be of type `errors.ReasonableError`. This will also be the second return argument from the `UpdateStatus()` method.
241
+
-`Reason` and `Message` can be set to set the status' corresponding fields.
242
+
- If either one is nil, but `ReconcileError` is not, it will be filled with a value derived from the error.
243
+
-`Conditions` contains the updated conditions. Depending on with which arguments `WithConditionUpdater` was called, the existing conditions will be either updated with these ones (keeping the other ones), or be replaced by them.
244
+
-`Object` contains the object to be updated.
245
+
- If `Object` is nil, no status update will be performed.
246
+
-`OldObject` holds the version of the object that will be used as a base for constructing the patch during the status update.
247
+
- If this is nil, `Object` will be used instead.
248
+
- If this is non-nil, it must not point to the same instance as `Object` - use the `DeepCopy()` function to create a different instance.
249
+
- All changes to `Object`'s status that are not part to `OldObject`'s status will be included in the patch during the status update. This can be used to inject custom changes to the status into the status update (in addition to the `WithCustomUpdateFunc` mentioned above).
250
+
110
251
### logging
111
252
112
253
This package contains the logging library from the [Landscaper controller-utils module](https://github.com/gardener/landscaper/tree/master/controller-utils/pkg/logging).
0 commit comments