Skip to content

Commit 06d2eb5

Browse files
committed
Add observedGeneration to status and conditions
1 parent ee9bd26 commit 06d2eb5

8 files changed

Lines changed: 82 additions & 7 deletions

File tree

vertical-pod-autoscaler/charts/vertical-pod-autoscaler/crds/vpa-v1-crd-gen.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,14 @@ spec:
625625
message is a human-readable explanation containing details about
626626
the transition
627627
type: string
628+
observedGeneration:
629+
description: |-
630+
observedGeneration represents the .metadata.generation that the condition was set based upon.
631+
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
632+
with respect to the current state of the instance.
633+
format: int64
634+
minimum: 0
635+
type: integer
628636
reason:
629637
description: reason is the reason for the condition's last transition.
630638
type: string
@@ -640,6 +648,11 @@ spec:
640648
- type
641649
type: object
642650
type: array
651+
observedGeneration:
652+
description: observedGeneration is the most recent generation observed
653+
by this autoscaler.
654+
format: int64
655+
type: integer
643656
recommendation:
644657
description: |-
645658
The most recently computed amount of resources recommended by the

vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,14 @@ spec:
625625
message is a human-readable explanation containing details about
626626
the transition
627627
type: string
628+
observedGeneration:
629+
description: |-
630+
observedGeneration represents the .metadata.generation that the condition was set based upon.
631+
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
632+
with respect to the current state of the instance.
633+
format: int64
634+
minimum: 0
635+
type: integer
628636
reason:
629637
description: reason is the reason for the condition's last transition.
630638
type: string
@@ -640,6 +648,11 @@ spec:
640648
- type
641649
type: object
642650
type: array
651+
observedGeneration:
652+
description: observedGeneration is the most recent generation observed
653+
by this autoscaler.
654+
format: int64
655+
type: integer
643656
recommendation:
644657
description: |-
645658
The most recently computed amount of resources recommended by the

vertical-pod-autoscaler/docs/api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ _Appears in:_
366366
| `lastTransitionTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#time-v1-meta)_ | lastTransitionTime is the last time the condition transitioned from<br />one status to another | | Optional: \{\} <br /> |
367367
| `reason` _string_ | reason is the reason for the condition's last transition. | | Optional: \{\} <br /> |
368368
| `message` _string_ | message is a human-readable explanation containing details about<br />the transition | | Optional: \{\} <br /> |
369+
| `observedGeneration` _integer_ | observedGeneration represents the .metadata.generation that the condition was set based upon.<br />For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date<br />with respect to the current state of the instance. | | Minimum: 0 <br />Optional: \{\} <br /> |
369370

370371

371372
#### VerticalPodAutoscalerConditionType
@@ -436,5 +437,6 @@ _Appears in:_
436437
| --- | --- | --- | --- |
437438
| `recommendation` _[RecommendedPodResources](#recommendedpodresources)_ | The most recently computed amount of resources recommended by the<br />autoscaler for the controlled pods. | | Optional: \{\} <br /> |
438439
| `conditions` _[VerticalPodAutoscalerCondition](#verticalpodautoscalercondition) array_ | Conditions is the set of conditions required for this autoscaler to scale its target,<br />and indicates whether or not those conditions are met. | | Optional: \{\} <br /> |
440+
| `observedGeneration` _integer_ | observedGeneration is the most recent generation observed by this autoscaler. | | Optional: \{\} <br /> |
439441

440442

vertical-pod-autoscaler/e2e/v1/recommender.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141
klog "k8s.io/klog/v2"
4242
"k8s.io/kubernetes/test/e2e/framework"
4343
podsecurity "k8s.io/pod-security-admission/api"
44+
"k8s.io/utils/ptr"
4445
)
4546

4647
func init() {
@@ -242,6 +243,28 @@ var _ = utils.RecommenderE2eDescribe("VPA CRD object", func() {
242243
gomega.Expect(err).NotTo(gomega.HaveOccurred())
243244
})
244245

246+
// FIXME: Move this to an integration test once we have integration test available
247+
ginkgo.It("sets observedGeneration and conditions.observedGeneration", func() {
248+
ginkgo.By("Waiting for observedGeneration to be updated")
249+
250+
_, err := utils.WaitForVPAMatch(vpaClientSet, vpaCRD, func(vpa *vpa_types.VerticalPodAutoscaler) bool {
251+
return vpa.Generation > 0 && ptr.Deref(vpa.Status.ObservedGeneration, 0) == vpa.Generation
252+
})
253+
gomega.Expect(err).NotTo(gomega.HaveOccurred())
254+
255+
ginkgo.By("Waiting for conditions.observedGeneration to be updated")
256+
_, err = utils.WaitForVPAMatch(vpaClientSet, vpaCRD, func(vpa *vpa_types.VerticalPodAutoscaler) bool {
257+
for _, cond := range vpa.Status.Conditions {
258+
if cond.ObservedGeneration == 0 || cond.ObservedGeneration != vpa.Generation {
259+
return false
260+
}
261+
}
262+
return true
263+
})
264+
265+
gomega.Expect(err).NotTo(gomega.HaveOccurred())
266+
})
267+
245268
// FIXME todo(adrianmoisey): This test seems to be flaky after running in parallel, unsure why, see if it's possible to fix
246269
f.It("doesn't drop lower/upper after recommender's restart", framework.WithSerial(), framework.WithSlow(), func() {
247270

vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ type VerticalPodAutoscalerStatus struct {
348348
// +patchMergeKey=type
349349
// +patchStrategy=merge
350350
Conditions []VerticalPodAutoscalerCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,2,rep,name=conditions"`
351+
352+
// observedGeneration is the most recent generation observed by this autoscaler.
353+
// +optional
354+
ObservedGeneration *int64 `json:"observedGeneration,omitempty" protobuf:"varint,3,opt,name=observedGeneration"`
351355
}
352356

353357
// RecommendedPodResources is the recommendation of resources computed by
@@ -429,6 +433,13 @@ type VerticalPodAutoscalerCondition struct {
429433
// the transition
430434
// +optional
431435
Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"`
436+
437+
// observedGeneration represents the .metadata.generation that the condition was set based upon.
438+
// For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
439+
// with respect to the current state of the instance.
440+
// +optional
441+
// +kubebuilder:validation:Minimum=0
442+
ObservedGeneration int64 `json:"observedGeneration,omitempty" protobuf:"bytes,6,opt,name=observedGeneration"`
432443
}
433444

434445
// +genclient

vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vertical-pod-autoscaler/pkg/recommender/model/cluster.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ func (cluster *clusterState) AddOrUpdateVpa(apiObject *vpa_types.VerticalPodAuto
312312
vpa.SetUpdateMode(apiObject.Spec.UpdatePolicy)
313313
vpa.SetResourcePolicy(apiObject.Spec.ResourcePolicy)
314314
vpa.SetAPIVersion(apiObject.GetObjectKind().GroupVersionKind().Version)
315+
vpa.Generation = apiObject.Generation
315316
return nil
316317
}
317318

vertical-pod-autoscaler/pkg/recommender/model/vpa.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@ type vpaConditionsMap map[vpa_types.VerticalPodAutoscalerConditionType]vpa_types
4040

4141
func (conditionsMap *vpaConditionsMap) Set(
4242
conditionType vpa_types.VerticalPodAutoscalerConditionType,
43+
observedGeneration int64,
4344
status bool, reason string, message string) *vpaConditionsMap {
4445
oldCondition, alreadyPresent := (*conditionsMap)[conditionType]
4546
condition := vpa_types.VerticalPodAutoscalerCondition{
46-
Type: conditionType,
47-
Reason: reason,
48-
Message: message,
47+
Type: conditionType,
48+
Reason: reason,
49+
Message: message,
50+
ObservedGeneration: observedGeneration,
4951
}
5052
if status {
5153
condition.Status = corev1.ConditionTrue
@@ -93,7 +95,7 @@ func (vpa *Vpa) ConditionActive(conditionType vpa_types.VerticalPodAutoscalerCon
9395
func (vpa *Vpa) SetCondition(conditionType vpa_types.VerticalPodAutoscalerConditionType, status bool, reason string, message string) {
9496
vpa.mutex.Lock()
9597
defer vpa.mutex.Unlock()
96-
vpa.conditions.Set(conditionType, status, reason, message)
98+
vpa.conditions.Set(conditionType, vpa.Generation, status, reason, message)
9799
}
98100

99101
// DeleteCondition deletes a condition in a thread-safe manner.
@@ -142,14 +144,14 @@ func (vpa *Vpa) updateConditionsLocked(podsMatched bool) {
142144
} else {
143145
reason = "NoPodsMatched"
144146
msg = "No pods match this VPA object"
145-
vpa.conditions.Set(vpa_types.NoPodsMatched, true, reason, msg)
147+
vpa.conditions.Set(vpa_types.NoPodsMatched, vpa.Generation, true, reason, msg)
146148
}
147149

148150
// Can safely call hasRecommendationLocked() - no deadlock risk
149151
if vpa.hasRecommendationLocked() {
150-
vpa.conditions.Set(vpa_types.RecommendationProvided, true, "", "")
152+
vpa.conditions.Set(vpa_types.RecommendationProvided, vpa.Generation, true, "", "")
151153
} else {
152-
vpa.conditions.Set(vpa_types.RecommendationProvided, false, reason, msg)
154+
vpa.conditions.Set(vpa_types.RecommendationProvided, vpa.Generation, false, reason, msg)
153155
}
154156
}
155157

@@ -208,6 +210,9 @@ type Vpa struct {
208210

209211
// mutex protects concurrent access to conditions and recommendation fields
210212
mutex sync.RWMutex
213+
214+
// Generation is the generation of the VPA object observed by the recommender.
215+
Generation int64
211216
}
212217

213218
// NewVpa returns a new Vpa with a given ID and pod selector. Doesn't set the
@@ -228,6 +233,7 @@ func NewVpa(id VpaID, selector labels.Selector, created time.Time) *Vpa {
228233
// to the version requested by the client server side.
229234
APIVersion: vpa_types.SchemeGroupVersion.Version,
230235
PodCount: 0,
236+
Generation: 0,
231237
}
232238
return vpa
233239
}
@@ -378,6 +384,7 @@ func (vpa *Vpa) AsStatus() *vpa_types.VerticalPodAutoscalerStatus {
378384
if vpa.recommendation != nil {
379385
status.Recommendation = vpa.recommendation
380386
}
387+
status.ObservedGeneration = &vpa.Generation
381388
return status
382389
}
383390

0 commit comments

Comments
 (0)