Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5aa9856
Split KResource into a file. Include an interface.
whaught May 1, 2020
8948106
Update apis/duck/v1/kresource_type.go
whaught May 1, 2020
484ba2f
type
whaught May 1, 2020
ff5f133
Merge branch 'and1' of github.com:whaught/pkg into and1
whaught May 1, 2020
ad28421
Merge remote-tracking branch 'upstream/master' into and1
whaught May 1, 2020
af872c1
rename to KRShaped
whaught May 1, 2020
28f1033
Merge remote-tracking branch 'upstream/master' into and1
whaught May 4, 2020
1533333
Create common logic for bumping obsgen
whaught May 4, 2020
2e9c4ee
Merge remote-tracking branch 'upstream/master' into and1
whaught May 4, 2020
8a9b56d
fix typo
whaught May 4, 2020
1197a30
remove interface cast
whaught May 4, 2020
a379c4b
missed a spot
whaught May 5, 2020
ac9806f
Update to use ObjectMetaAccessor
whaught May 5, 2020
9e36f80
switch alias to duckv1
whaught May 5, 2020
9cf316b
fix var names
whaught May 5, 2020
cf92f7e
include a reason
whaught May 5, 2020
508e61a
Switch to preprocess
whaught May 5, 2020
c214920
Merge remote-tracking branch 'upstream/master' into and1
whaught May 5, 2020
0f7f613
rename variable from new to resource
whaught May 5, 2020
b14ef38
Merge remote-tracking branch 'upstream/master' into and1
whaught May 5, 2020
4d9f0e3
Create a table style test
whaught May 5, 2020
9ddd78f
missed a spot
whaught May 5, 2020
e5741b1
Merge remote-tracking branch 'upstream/master' into and1
whaught May 5, 2020
be00d8b
update deps
whaught May 5, 2020
66f8162
fix nits
whaught May 6, 2020
b029b20
fix gomod deps
whaught May 6, 2020
083bec0
Merge remote-tracking branch 'upstream/master' into and1
whaught May 6, 2020
18cd45a
update with new KRshaped
whaught May 6, 2020
5c62918
Update reconciler/reconcile_common_test.go
whaught May 7, 2020
fb5242f
Update reconciler/reconcile_common_test.go
whaught May 7, 2020
f9b76da
Update reconciler/reconcile_common_test.go
whaught May 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apis/condition_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ type conditionsImpl struct {
accessor ConditionsAccessor
}

// GetTopLevelConditionType is an accessor for the top-level happy condition.
func (r ConditionSet) GetTopLevelConditionType() ConditionType {
return r.happy
}

// Manage creates a ConditionManager from an accessor object using the original
// ConditionSet as a reference. Status must be a pointer to a struct.
func (r ConditionSet) Manage(status ConditionsAccessor) ConditionManager {
Expand Down
55 changes: 55 additions & 0 deletions reconciler/reconcile_common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
Copyright 2020 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package reconciler

import (
"context"

duckv1 "knative.dev/pkg/apis/duck/v1"
"knative.dev/pkg/logging"
)

const failedGenerationBump = "NewObservedGenFailure"

// PreProcessReconcile contains logic to apply before reconciliation of a resource.
func PreProcessReconcile(ctx context.Context, resource duckv1.KRShaped) {
newStatus := resource.GetStatus()

if newStatus.ObservedGeneration != resource.GetObjectMeta().GetGeneration() {
condSet := resource.GetConditionSet()
manager := condSet.Manage(newStatus)

// Reset Ready/Successful to unknown. The reconciler is expected to overwrite this.
manager.MarkUnknown(condSet.GetTopLevelConditionType(), failedGenerationBump, "unsuccessfully observed a new generation")
}
}

// PostProcessReconcile contains logic to apply after reconciliation of a resource.
func PostProcessReconcile(ctx context.Context, resource duckv1.KRShaped) {
logger := logging.FromContext(ctx)
newStatus := resource.GetStatus()
mgr := resource.GetConditionSet().Manage(newStatus)

// Bump observed generation to denote that we have processed this
// generation regardless of success or failure.
newStatus.ObservedGeneration = resource.GetObjectMeta().GetGeneration()

rc := mgr.GetTopLevelCondition()
if rc.Reason == failedGenerationBump {
logger.Warn("A reconciler observed a new generation without updating the resource status")
}
}
96 changes: 96 additions & 0 deletions reconciler/reconcile_common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
Copyright 2020 The Knative Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package reconciler

import (
"context"
"testing"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"knative.dev/pkg/apis"
duckv1 "knative.dev/pkg/apis/duck/v1"
)

func makeResource(topLevelCond string) *duckv1.KResource {
fooCond := apis.Condition{
Type: "Foo",
Status: corev1.ConditionTrue,
Message: "Something something foo",
}
readyCond := apis.Condition{
Type: apis.ConditionType(topLevelCond),
Status: corev1.ConditionTrue,
Message: "Something something bar",
}

return &duckv1.KResource{
ObjectMeta: metav1.ObjectMeta{
Generation: 42,
},

Status: duckv1.Status{
ObservedGeneration: 0,
Conditions: duckv1.Conditions{fooCond, readyCond},
},
}
}

func TestPreProcessResetsReady(t *testing.T) {
testCases := []struct {
name string
initTopLevelCond string
expectedTopLevelCondition apis.ConditionType
}{{
name: "top level Ready",
initTopLevelCond: "Ready",
expectedTopLevelCondition: apis.ConditionReady,
}, {
name: "top level Succeeded",
initTopLevelCond: "Succeeded",
expectedTopLevelCondition: apis.ConditionSucceeded,
}}

for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
resource := makeResource(test.initTopLevelCond)
krShape := duckv1.KRShaped(resource)

PreProcessReconcile(context.Background(), krShape)

if rc := resource.Status.GetCondition(test.expectedTopLevelCondition); rc.Status != "Unknown" {
t.Errorf("Expected unchanged ready status got=%s want=Unknown", rc.Status)
}
})
}
}

func TestPostProcessReconcileBumpsGeneration(t *testing.T) {
resource := makeResource("Ready")

krShape := duckv1.KRShaped(resource)
PostProcessReconcile(context.Background(), krShape)

if resource.Status.ObservedGeneration != resource.Generation {
t.Errorf("Expected observed generation bump got=%d want=%d", resource.Status.ObservedGeneration, resource.Generation)
}

if krShape.GetStatus().ObservedGeneration != krShape.GetObjectMeta().GetGeneration() {
t.Errorf("Expected observed generation bump got=%d want=%d", resource.Status.ObservedGeneration, resource.Generation)
}
}