diff --git a/api/clusters/v1alpha1/accessrequest_types.go b/api/clusters/v1alpha1/accessrequest_types.go index 9e8545d..f961963 100644 --- a/api/clusters/v1alpha1/accessrequest_types.go +++ b/api/clusters/v1alpha1/accessrequest_types.go @@ -39,7 +39,23 @@ type PermissionsRequest struct { // AccessRequestStatus defines the observed state of AccessRequest type AccessRequestStatus struct { - CommonStatus `json:",inline"` + // ObservedGeneration is the generation of this resource that was last reconciled by the controller. + ObservedGeneration int64 `json:"observedGeneration"` + + // LastReconcileTime is the time when the resource was last reconciled by the controller. + LastReconcileTime metav1.Time `json:"lastReconcileTime"` + + // Reason is expected to contain a CamelCased string that provides further information in a machine-readable format. + // +optional + Reason string `json:"reason,omitempty"` + + // Message contains further details in a human-readable format. + // +optional + Message string `json:"message,omitempty"` + + // Conditions contains the conditions of this resource using the standard Kubernetes condition format. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` // Phase is the current phase of the request. // +kubebuilder:default=Pending diff --git a/api/clusters/v1alpha1/cluster_types.go b/api/clusters/v1alpha1/cluster_types.go index d932fca..3cd666c 100644 --- a/api/clusters/v1alpha1/cluster_types.go +++ b/api/clusters/v1alpha1/cluster_types.go @@ -52,7 +52,23 @@ type K8sConfiguration struct { // ClusterStatus defines the observed state of Cluster type ClusterStatus struct { - CommonStatus `json:",inline"` + // ObservedGeneration is the generation of this resource that was last reconciled by the controller. + ObservedGeneration int64 `json:"observedGeneration"` + + // LastReconcileTime is the time when the resource was last reconciled by the controller. + LastReconcileTime metav1.Time `json:"lastReconcileTime"` + + // Reason is expected to contain a CamelCased string that provides further information in a machine-readable format. + // +optional + Reason string `json:"reason,omitempty"` + + // Message contains further details in a human-readable format. + // +optional + Message string `json:"message,omitempty"` + + // Conditions contains the conditions of this resource using the standard Kubernetes condition format. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` // Phase is the current phase of the cluster. Phase ClusterPhase `json:"phase"` diff --git a/api/clusters/v1alpha1/clusterrequest_types.go b/api/clusters/v1alpha1/clusterrequest_types.go index a7b2943..caa5a90 100644 --- a/api/clusters/v1alpha1/clusterrequest_types.go +++ b/api/clusters/v1alpha1/clusterrequest_types.go @@ -13,7 +13,23 @@ type ClusterRequestSpec struct { // +kubebuilder:validation:XValidation:rule="!has(oldSelf.cluster) || has(self.cluster)", message="cluster may not be removed once set" type ClusterRequestStatus struct { - CommonStatus `json:",inline"` + // ObservedGeneration is the generation of this resource that was last reconciled by the controller. + ObservedGeneration int64 `json:"observedGeneration"` + + // LastReconcileTime is the time when the resource was last reconciled by the controller. + LastReconcileTime metav1.Time `json:"lastReconcileTime"` + + // Reason is expected to contain a CamelCased string that provides further information in a machine-readable format. + // +optional + Reason string `json:"reason,omitempty"` + + // Message contains further details in a human-readable format. + // +optional + Message string `json:"message,omitempty"` + + // Conditions contains the conditions of this resource using the standard Kubernetes condition format. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` // Phase is the current phase of the request. // +kubebuilder:default=Pending diff --git a/api/clusters/v1alpha1/constants.go b/api/clusters/v1alpha1/constants.go index 0f8372e..8822ba3 100644 --- a/api/clusters/v1alpha1/constants.go +++ b/api/clusters/v1alpha1/constants.go @@ -13,15 +13,6 @@ const ( PURPOSE_MCP = "mcp" ) -const ( - // CONDITION_UNKNOWN represents an unknown status for the condition. - CONDITION_UNKNOWN ConditionStatus = "Unknown" - // CONDITION_TRUE marks the condition as true. - CONDITION_TRUE ConditionStatus = "True" - // CONDITION_FALSE marks the condition as false. - CONDITION_FALSE ConditionStatus = "False" -) - const ( // PHASE_UNKNOWN represents an unknown phase for the cluster. PHASE_UNKNOWN ClusterPhase = "Unknown" diff --git a/api/clusters/v1alpha1/shared_types.go b/api/clusters/v1alpha1/shared_types.go index 30b4e1d..dd9ec4c 100644 --- a/api/clusters/v1alpha1/shared_types.go +++ b/api/clusters/v1alpha1/shared_types.go @@ -1,105 +1,26 @@ package v1alpha1 -import ( - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +// These are standard condition types that can be used across resources +const ( + // ReadyConditionType indicates whether the resource is ready + ReadyConditionType = "Ready" + // AvailableConditionType indicates whether the resource is available + AvailableConditionType = "Available" + // ReconcileSuccessConditionType indicates whether the last reconciliation was successful + ReconcileSuccessConditionType = "ReconcileSuccess" ) -type ConditionStatus string - -type Condition struct { - // Type is the type of the condition. - // Must be unique within the resource. - Type string `json:"type"` - - // Status is the status of the condition. - Status ConditionStatus `json:"status"` - - // Reason is expected to contain a CamelCased string that provides further information regarding the condition. - // It should have a fixed value set (like an enum) to be machine-readable. The value set depends on the condition type. - // It is optional, but should be filled at least when Status is not "True". - // +optional - Reason string `json:"reason,omitempty"` - - // Message contains further details regarding the condition. - // It is meant for human users, Reason should be used for programmatic evaluation instead. - // It is optional, but should be filled at least when Status is not "True". - // +optional - Message string `json:"message,omitempty"` - - // LastTransitionTime specifies the time when this condition's status last changed. - LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` -} - -// Implement the Condition interface from our controller-utils library -func (c *Condition) GetType() string { - return c.Type -} -func (c *Condition) SetType(t string) { - c.Type = t -} -func (c *Condition) GetStatus() ConditionStatus { - return c.Status -} -func (c *Condition) SetStatus(s ConditionStatus) { - c.Status = s -} -func (c *Condition) GetReason() string { - return c.Reason -} -func (c *Condition) SetReason(r string) { - c.Reason = r -} -func (c *Condition) GetMessage() string { - return c.Message -} -func (c *Condition) SetMessage(m string) { - c.Message = m -} -func (c *Condition) GetLastTransitionTime() time.Time { - return c.LastTransitionTime.Time -} -func (c *Condition) SetLastTransitionTime(t time.Time) { - c.LastTransitionTime = metav1.NewTime(t) -} - -// ConditionList is a list of Conditions. -type ConditionList []Condition - -// ConditionStatusFromBoolPtr converts a bool pointer into the corresponding ConditionStatus. -// If nil, "Unknown" is returned. -func ConditionStatusFromBoolPtr(src *bool) ConditionStatus { - if src == nil { - return CONDITION_UNKNOWN - } - return ConditionStatusFromBool(*src) -} - -// ConditionStatusFromBool converts a bool into the corresponding ConditionStatus. -func ConditionStatusFromBool(src bool) ConditionStatus { - if src { - return CONDITION_TRUE - } - return CONDITION_FALSE -} - -// IsTrue returns true if the Condition's status is "True". -// Note that the status can be "Unknown", so !IsTrue() is not the same as IsFalse(). -func (cc Condition) IsTrue() bool { - return cc.Status == CONDITION_TRUE -} - -// IsFalse returns true if the Condition's status is "False". -// Note that the status can be "Unknown", so !IsFalse() is not the same as IsTrue(). -func (cc Condition) IsFalse() bool { - return cc.Status == CONDITION_FALSE -} - -// IsUnknown returns true if the Condition's status is "Unknown". -func (cc Condition) IsUnknown() bool { - return cc.Status == CONDITION_UNKNOWN -} +// These are standard condition reasons that can be used across resources +const ( + // ReconcileSuccessReason indicates that the reconciliation was successful + ReconcileSuccessReason = "ReconcileSuccess" + // ReconcileErrorReason indicates that there was an error during reconciliation + ReconcileErrorReason = "ReconcileError" + // ResourceAvailableReason indicates that the resource is available + ResourceAvailableReason = "ResourceAvailable" + // ResourceUnavailableReason indicates that the resource is not available + ResourceUnavailableReason = "ResourceUnavailable" +) type ObjectReference struct { // Name is the name of the referenced resource. @@ -113,26 +34,3 @@ type NamespacedObjectReference struct { // Namespace is the namespace of the referenced resource. Namespace string `json:"namespace"` } - -// CommonStatus is a status shared by multiple resource. -// Note that a 'phase' is also part of the status, but it cannot be included in this struct. -// The reason is that we want to use string-like types for the phase, but the goddamn code generation does not support generics, no matter which annotations are added. -type CommonStatus struct { - // ObservedGeneration is the generation of this resource that was last reconciled by the controller. - ObservedGeneration int64 `json:"observedGeneration"` - - // LastReconcileTime is the time when the resource was last reconciled by the controller. - LastReconcileTime metav1.Time `json:"lastReconcileTime"` - - // Reason is expected to contain a CamelCased string that provides further information in a machine-readable format. - // +optional - Reason string `json:"reason,omitempty"` - - // Message contains further details in a human-readable format. - // +optional - Message string `json:"message,omitempty"` - - // Conditions contains the conditions. - // +optional - Conditions ConditionList `json:"conditions,omitempty"` -} diff --git a/api/clusters/v1alpha1/zz_generated.deepcopy.go b/api/clusters/v1alpha1/zz_generated.deepcopy.go index c53fff4..06c1b85 100644 --- a/api/clusters/v1alpha1/zz_generated.deepcopy.go +++ b/api/clusters/v1alpha1/zz_generated.deepcopy.go @@ -6,6 +6,7 @@ package v1alpha1 import ( v1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ) @@ -103,7 +104,14 @@ func (in *AccessRequestSpec) DeepCopy() *AccessRequestSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AccessRequestStatus) DeepCopyInto(out *AccessRequestStatus) { *out = *in - in.CommonStatus.DeepCopyInto(&out.CommonStatus) + in.LastReconcileTime.DeepCopyInto(&out.LastReconcileTime) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.SecretRef != nil { in, out := &in.SecretRef, &out.SecretRef *out = new(NamespacedObjectReference) @@ -352,7 +360,14 @@ func (in *ClusterRequestSpec) DeepCopy() *ClusterRequestSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterRequestStatus) DeepCopyInto(out *ClusterRequestStatus) { *out = *in - in.CommonStatus.DeepCopyInto(&out.CommonStatus) + in.LastReconcileTime.DeepCopyInto(&out.LastReconcileTime) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.Cluster != nil { in, out := &in.Cluster, &out.Cluster *out = new(NamespacedObjectReference) @@ -398,85 +413,32 @@ func (in *ClusterSpec) DeepCopy() *ClusterSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { - *out = *in - in.CommonStatus.DeepCopyInto(&out.CommonStatus) - if in.ProviderStatus != nil { - in, out := &in.ProviderStatus, &out.ProviderStatus - *out = new(runtime.RawExtension) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus. -func (in *ClusterStatus) DeepCopy() *ClusterStatus { - if in == nil { - return nil - } - out := new(ClusterStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CommonStatus) DeepCopyInto(out *CommonStatus) { *out = *in in.LastReconcileTime.DeepCopyInto(&out.LastReconcileTime) if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make(ConditionList, len(*in)) + *out = make([]metav1.Condition, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonStatus. -func (in *CommonStatus) DeepCopy() *CommonStatus { - if in == nil { - return nil + if in.ProviderStatus != nil { + in, out := &in.ProviderStatus, &out.ProviderStatus + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) } - out := new(CommonStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Condition) DeepCopyInto(out *Condition) { - *out = *in - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. -func (in *Condition) DeepCopy() *Condition { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus. +func (in *ClusterStatus) DeepCopy() *ClusterStatus { if in == nil { return nil } - out := new(Condition) + out := new(ClusterStatus) in.DeepCopyInto(out) return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in ConditionList) DeepCopyInto(out *ConditionList) { - { - in := &in - *out = make(ConditionList, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionList. -func (in ConditionList) DeepCopy() ConditionList { - if in == nil { - return nil - } - out := new(ConditionList) - in.DeepCopyInto(out) - return *out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *K8sConfiguration) DeepCopyInto(out *K8sConfiguration) { *out = *in diff --git a/api/crds/manifests/clusters.openmcp.cloud_accessrequests.yaml b/api/crds/manifests/clusters.openmcp.cloud_accessrequests.yaml index bd04ae0..7ffa424 100644 --- a/api/crds/manifests/clusters.openmcp.cloud_accessrequests.yaml +++ b/api/crds/manifests/clusters.openmcp.cloud_accessrequests.yaml @@ -164,35 +164,59 @@ spec: description: AccessRequestStatus defines the observed state of AccessRequest properties: conditions: - description: Conditions contains the conditions. + description: Conditions contains the conditions of this resource using + the standard Kubernetes condition format. items: + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: - description: LastTransitionTime specifies the time when this - condition's status last changed. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - Message contains further details regarding the condition. - It is meant for human users, Reason should be used for programmatic evaluation instead. - It is optional, but should be filled at least when Status is not "True". + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer reason: description: |- - Reason is expected to contain a CamelCased string that provides further information regarding the condition. - It should have a fixed value set (like an enum) to be machine-readable. The value set depends on the condition type. - It is optional, but should be filled at least when Status is not "True". + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ type: string status: - description: Status is the status of the condition. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: - description: |- - Type is the type of the condition. - Must be unique within the resource. + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - message + - reason - status - type type: object diff --git a/api/crds/manifests/clusters.openmcp.cloud_clusterrequests.yaml b/api/crds/manifests/clusters.openmcp.cloud_clusterrequests.yaml index 38dc4f7..47d190d 100644 --- a/api/crds/manifests/clusters.openmcp.cloud_clusterrequests.yaml +++ b/api/crds/manifests/clusters.openmcp.cloud_clusterrequests.yaml @@ -88,35 +88,59 @@ spec: - message: cluster is immutable rule: self == oldSelf conditions: - description: Conditions contains the conditions. + description: Conditions contains the conditions of this resource using + the standard Kubernetes condition format. items: + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: - description: LastTransitionTime specifies the time when this - condition's status last changed. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - Message contains further details regarding the condition. - It is meant for human users, Reason should be used for programmatic evaluation instead. - It is optional, but should be filled at least when Status is not "True". + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer reason: description: |- - Reason is expected to contain a CamelCased string that provides further information regarding the condition. - It should have a fixed value set (like an enum) to be machine-readable. The value set depends on the condition type. - It is optional, but should be filled at least when Status is not "True". + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ type: string status: - description: Status is the status of the condition. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: - description: |- - Type is the type of the condition. - Must be unique within the resource. + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - message + - reason - status - type type: object diff --git a/api/crds/manifests/clusters.openmcp.cloud_clusters.yaml b/api/crds/manifests/clusters.openmcp.cloud_clusters.yaml index fa3d824..dffaa24 100644 --- a/api/crds/manifests/clusters.openmcp.cloud_clusters.yaml +++ b/api/crds/manifests/clusters.openmcp.cloud_clusters.yaml @@ -126,35 +126,59 @@ spec: description: APIServer is the API server endpoint of the cluster. type: string conditions: - description: Conditions contains the conditions. + description: Conditions contains the conditions of this resource using + the standard Kubernetes condition format. items: + description: Condition contains details for one aspect of the current + state of this API Resource. properties: lastTransitionTime: - description: LastTransitionTime specifies the time when this - condition's status last changed. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: description: |- - Message contains further details regarding the condition. - It is meant for human users, Reason should be used for programmatic evaluation instead. - It is optional, but should be filled at least when Status is not "True". + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer reason: description: |- - Reason is expected to contain a CamelCased string that provides further information regarding the condition. - It should have a fixed value set (like an enum) to be machine-readable. The value set depends on the condition type. - It is optional, but should be filled at least when Status is not "True". + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ type: string status: - description: Status is the status of the condition. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: - description: |- - Type is the type of the condition. - Must be unique within the resource. + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string required: + - lastTransitionTime + - message + - reason - status - type type: object diff --git a/internal/controllers/accessrequest/controller.go b/internal/controllers/accessrequest/controller.go index 0439d29..4a4bc24 100644 --- a/internal/controllers/accessrequest/controller.go +++ b/internal/controllers/accessrequest/controller.go @@ -40,7 +40,7 @@ type AccessRequestReconciler struct { var _ reconcile.Reconciler = &AccessRequestReconciler{} -type ReconcileResult = ctrlutils.ReconcileResult[*clustersv1alpha1.AccessRequest, clustersv1alpha1.ConditionStatus] +type ReconcileResult = ctrlutils.ReconcileResult[*clustersv1alpha1.AccessRequest, *clustersv1alpha1.AccessRequestStatus] func (r *AccessRequestReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { log := logging.FromContextOrPanic(ctx).WithName(ControllerName) @@ -48,7 +48,7 @@ func (r *AccessRequestReconciler) Reconcile(ctx context.Context, req reconcile.R log.Info("Starting reconcile") rr := r.reconcile(ctx, req) // status update - return ctrlutils.NewStatusUpdaterBuilder[*clustersv1alpha1.AccessRequest, clustersv1alpha1.RequestPhase, clustersv1alpha1.ConditionStatus](). + return ctrlutils.NewStatusUpdaterBuilder[*clustersv1alpha1.AccessRequest, clustersv1alpha1.RequestPhase, clustersv1alpha1.AccessRequestStatus](). WithNestedStruct("CommonStatus"). WithFieldOverride(ctrlutils.STATUS_FIELD_PHASE, "Phase"). WithoutFields(ctrlutils.STATUS_FIELD_CONDITIONS).