Skip to content

Commit

Permalink
Add helper function to filter by owning Run
Browse files Browse the repository at this point in the history
Add a filter function that can be used when creating an event handler to notify your custom controller when an object owned by a Run is modified.
  • Loading branch information
GregDritschler authored and tekton-robot committed Oct 5, 2020
1 parent 29e4132 commit 3a8d414
Show file tree
Hide file tree
Showing 2 changed files with 220 additions and 2 deletions.
39 changes: 39 additions & 0 deletions pkg/controller/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ limitations under the License.
package controller

import (
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
listersalpha "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// FilterRunRef returns a filter that can be passed to a Run Informer, which
Expand Down Expand Up @@ -50,3 +53,39 @@ func FilterRunRef(apiVersion, kind string) func(interface{}) bool {
return r.Spec.Ref.APIVersion == apiVersion && r.Spec.Ref.Kind == v1alpha1.TaskKind(kind)
}
}

// FilterOwnerRunRef returns a filter that can be passed to an Informer for any runtime object, which
// filters out objects that aren't controlled by a Run that references a particular apiVersion and kind.
//
// For example, a controller impl that wants to be notified of updates to TaskRuns that are controlled by
// a Run which references a custom task with apiVersion "example.dev/v0" and kind "Example":
//
// taskruninformer.Get(ctx).Informer().AddEventHandler(cache.FilteringResourceEventHandler{
// FilterFunc: FilterOwnerRunRef("example.dev/v0", "Example"),
// Handler: controller.HandleAll(impl.Enqueue),
// })
func FilterOwnerRunRef(runLister listersalpha.RunLister, apiVersion, kind string) func(interface{}) bool {
return func(obj interface{}) bool {
object, ok := obj.(metav1.Object)
if !ok {
return false
}
owner := metav1.GetControllerOf(object)
if owner == nil {
return false
}
if owner.APIVersion != v1alpha1.SchemeGroupVersion.String() || owner.Kind != pipeline.RunControllerName {
// Not owned by a Run
return false
}
run, err := runLister.Runs(object.GetNamespace()).Get(owner.Name)
if err != nil {
return false
}
if run.Spec.Ref == nil {
// These are invalid, but just in case they get created somehow, don't panic.
return false
}
return run.Spec.Ref.APIVersion == apiVersion && run.Spec.Ref.Kind == v1alpha1.TaskKind(kind)
}
}
183 changes: 181 additions & 2 deletions pkg/controller/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,24 @@ package controller_test
import (
"testing"

"github.com/tektoncd/pipeline/pkg/apis/pipeline"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
fakeruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/run/fake"
"github.com/tektoncd/pipeline/pkg/controller"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
rtesting "knative.dev/pkg/reconciler/testing"
)

const (
apiVersion = "example.dev/v0"
kind = "Example"
apiVersion = "example.dev/v0"
apiVersion2 = "example.dev/v1"
kind = "Example"
kind2 = "SomethingCompletelyDifferent"
)

var trueB = true

func TestFilterRunRef(t *testing.T) {
for _, c := range []struct {
desc string
Expand Down Expand Up @@ -103,3 +112,173 @@ func TestFilterRunRef(t *testing.T) {
})
}
}

func TestFilterOwnerRunRef(t *testing.T) {
for _, c := range []struct {
desc string
in interface{}
owner *v1alpha1.Run
want bool
}{{
desc: "Owner is a Run that references a matching apiVersion and kind",
in: &v1beta1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "some-taskrun",
Namespace: "default",
OwnerReferences: []metav1.OwnerReference{{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: pipeline.RunControllerName,
Name: "some-run",
Controller: &trueB,
}},
},
},
owner: &v1alpha1.Run{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: pipeline.RunControllerName,
},
ObjectMeta: metav1.ObjectMeta{
Name: "some-run",
Namespace: "default",
},
Spec: v1alpha1.RunSpec{
Ref: &v1alpha1.TaskRef{
APIVersion: apiVersion,
Kind: kind,
},
},
},
want: true,
}, {
desc: "Owner is a Run that references a non-matching apiversion",
in: &v1beta1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "some-taskrun",
Namespace: "default",
OwnerReferences: []metav1.OwnerReference{{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: pipeline.RunControllerName,
Name: "some-other-run",
Controller: &trueB,
}},
},
},
owner: &v1alpha1.Run{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: pipeline.RunControllerName,
},
ObjectMeta: metav1.ObjectMeta{
Name: "some-other-run",
Namespace: "default",
},
Spec: v1alpha1.RunSpec{
Ref: &v1alpha1.TaskRef{
APIVersion: apiVersion2, // different apiversion
Kind: kind,
},
},
},
want: false,
}, {
desc: "Owner is a Run that references a non-matching kind",
in: &v1beta1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "some-taskrun",
Namespace: "default",
OwnerReferences: []metav1.OwnerReference{{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: pipeline.RunControllerName,
Name: "some-other-run2",
Controller: &trueB,
}},
},
},
owner: &v1alpha1.Run{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: pipeline.RunControllerName,
},
ObjectMeta: metav1.ObjectMeta{
Name: "some-other-run2",
Namespace: "default",
},
Spec: v1alpha1.RunSpec{
Ref: &v1alpha1.TaskRef{
APIVersion: apiVersion,
Kind: kind2, // different kind
},
},
},
want: false,
}, {
desc: "Owner is a Run that with a missing ref",
in: &v1beta1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "some-taskrun",
Namespace: "default",
OwnerReferences: []metav1.OwnerReference{{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: pipeline.RunControllerName,
Name: "some-strange-run",
Controller: &trueB,
}},
},
},
owner: &v1alpha1.Run{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: pipeline.RunControllerName,
},
ObjectMeta: metav1.ObjectMeta{
Name: "some-strange-run",
Namespace: "default",
},
Spec: v1alpha1.RunSpec{}, // missing ref (illegal)
},
want: false,
}, {
desc: "Owner is not a Run",
in: &v1beta1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "some-taskrun",
Namespace: "default",
OwnerReferences: []metav1.OwnerReference{{
APIVersion: v1alpha1.SchemeGroupVersion.String(),
Kind: pipeline.PipelineRunControllerName, // owned by PipelineRun, not Run
Name: "some-pipelinerun",
Controller: &trueB,
}},
},
},
want: false,
}, {
desc: "Object has no owner",
in: &v1beta1.TaskRun{
ObjectMeta: metav1.ObjectMeta{
Name: "some-taskrun-no-owner",
Namespace: "default",
},
},
want: false,
}, {
desc: "input is not a runtime Object",
in: struct{}{},
want: false,
}} {
t.Run(c.desc, func(t *testing.T) {
ctx, _ := rtesting.SetupFakeContext(t)
runInformer := fakeruninformer.Get(ctx)
if c.owner != nil {
if err := runInformer.Informer().GetIndexer().Add(c.owner); err != nil {
t.Fatal(err)
}
}
got := controller.FilterOwnerRunRef(runInformer.Lister(), apiVersion, kind)(c.in)
if got != c.want {
t.Fatalf("FilterOwnerRunRef(%q, %q) got %t, want %t", apiVersion, kind, got, c.want)
}
})
}
}

0 comments on commit 3a8d414

Please sign in to comment.