diff --git a/pkg/api/persistentvolume/util.go b/pkg/api/persistentvolume/util.go index 28f1bfc0c54..1e34c995102 100644 --- a/pkg/api/persistentvolume/util.go +++ b/pkg/api/persistentvolume/util.go @@ -41,6 +41,14 @@ func DropDisabledSpecFields(pvSpec *api.PersistentVolumeSpec, oldPVSpec *api.Per } } +// DropDisabledStatusFields removes disabled fields from the pv status. +// This should be called from PrepareForUpdate for all resources containing a pv status. +func DropDisabledStatusFields(oldStatus, newStatus *api.PersistentVolumeStatus) { + if !utilfeature.DefaultFeatureGate.Enabled(features.PersistentVolumeLastPhaseTransitionTime) && oldStatus.LastPhaseTransitionTime.IsZero() { + newStatus.LastPhaseTransitionTime = nil + } +} + func hasNodeExpansionSecrets(oldPVSpec *api.PersistentVolumeSpec) bool { if oldPVSpec == nil || oldPVSpec.CSI == nil { return false diff --git a/pkg/registry/core/persistentvolume/strategy.go b/pkg/registry/core/persistentvolume/strategy.go index 16c1d9528df..d33a3f0a925 100644 --- a/pkg/registry/core/persistentvolume/strategy.go +++ b/pkg/registry/core/persistentvolume/strategy.go @@ -19,6 +19,9 @@ package persistentvolume import ( "context" "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/kubernetes/pkg/features" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" @@ -66,6 +69,12 @@ func (persistentvolumeStrategy) PrepareForCreate(ctx context.Context, obj runtim pv := obj.(*api.PersistentVolume) pv.Status = api.PersistentVolumeStatus{} + if utilfeature.DefaultFeatureGate.Enabled(features.PersistentVolumeLastPhaseTransitionTime) { + pv.Status.Phase = api.VolumePending + now := nowFunc() + pv.Status.LastPhaseTransitionTime = &now + } + pvutil.DropDisabledSpecFields(&pv.Spec, nil) } @@ -134,11 +143,28 @@ func (persistentvolumeStatusStrategy) GetResetFields() map[fieldpath.APIVersion] return fields } +var nowFunc = metav1.Now + // PrepareForUpdate sets the Spec field which is not allowed to be changed when updating a PV's Status func (persistentvolumeStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { newPv := obj.(*api.PersistentVolume) oldPv := old.(*api.PersistentVolume) newPv.Spec = oldPv.Spec + + if utilfeature.DefaultFeatureGate.Enabled(features.PersistentVolumeLastPhaseTransitionTime) { + switch { + case oldPv.Status.Phase == newPv.Status.Phase && newPv.Status.LastPhaseTransitionTime == nil: + // phase didn't change, preserve the existing transition time if set + newPv.Status.LastPhaseTransitionTime = oldPv.Status.LastPhaseTransitionTime + + case oldPv.Status.Phase != newPv.Status.Phase && (newPv.Status.LastPhaseTransitionTime == nil || newPv.Status.LastPhaseTransitionTime.Equal(oldPv.Status.LastPhaseTransitionTime)): + // phase changed and client didn't set or didn't change the transition time + now := nowFunc() + newPv.Status.LastPhaseTransitionTime = &now + } + } + + pvutil.DropDisabledStatusFields(&oldPv.Status, &newPv.Status) } func (persistentvolumeStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {