Skip to content

Commit

Permalink
Add a context to Reconciler interface
Browse files Browse the repository at this point in the history
Signed-off-by: Vince Prignano <vincepri@vmware.com>
  • Loading branch information
vincepri committed Jul 20, 2020
1 parent 229c3c3 commit 57c1a6b
Show file tree
Hide file tree
Showing 20 changed files with 226 additions and 76 deletions.
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ linters:
- unparam
- ineffassign
- nakedret
- interfacer
- gocyclo
- lll
- dupl
Expand Down
10 changes: 5 additions & 5 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ limitations under the License.
package controllerruntime_test

import (
"context"
"fmt"
"os"
"time"
Expand All @@ -26,6 +25,7 @@ import (
corev1 "k8s.io/api/core/v1"
controllers "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/context"
)

// This example creates a simple application Controller that is configured for ReplicaSets and Pods.
Expand Down Expand Up @@ -116,24 +116,24 @@ type ReplicaSetReconciler struct {
// * Read the ReplicaSet
// * Read the Pods
// * Set a Label on the ReplicaSet with the Pod count
func (a *ReplicaSetReconciler) Reconcile(req controllers.Request) (controllers.Result, error) {
func (a *ReplicaSetReconciler) Reconcile(ctx context.Context, req controllers.Request) (controllers.Result, error) {
// Read the ReplicaSet
rs := &appsv1.ReplicaSet{}
err := a.Get(context.TODO(), req.NamespacedName, rs)
err := a.Get(ctx, req.NamespacedName, rs)
if err != nil {
return controllers.Result{}, err
}

// List the Pods matching the PodTemplate Labels
pods := &corev1.PodList{}
err = a.List(context.TODO(), pods, client.InNamespace(req.Namespace), client.MatchingLabels(rs.Spec.Template.Labels))
err = a.List(ctx, pods, client.InNamespace(req.Namespace), client.MatchingLabels(rs.Spec.Template.Labels))
if err != nil {
return controllers.Result{}, err
}

// Update the ReplicaSet
rs.Labels["pod-count"] = fmt.Sprintf("%v", len(pods.Items))
err = a.Update(context.TODO(), rs)
err = a.Update(ctx, rs)
if err != nil {
return controllers.Result{}, err
}
Expand Down
18 changes: 6 additions & 12 deletions examples/builtins/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,30 @@ limitations under the License.
package main

import (
"context"
"fmt"

"github.com/go-logr/logr"

appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/context"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

// reconcileReplicaSet reconciles ReplicaSets
type reconcileReplicaSet struct {
// client can be used to retrieve objects from the APIServer.
client client.Client
log logr.Logger
}

// Implement reconcile.Reconciler so the controller can reconcile objects
var _ reconcile.Reconciler = &reconcileReplicaSet{}

func (r *reconcileReplicaSet) Reconcile(request reconcile.Request) (reconcile.Result, error) {
// set up a convenient log object so we don't have to type request over and over again
log := r.log.WithValues("request", request)

func (r *reconcileReplicaSet) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
// Fetch the ReplicaSet from the cache
rs := &appsv1.ReplicaSet{}
err := r.client.Get(context.TODO(), request.NamespacedName, rs)
err := r.client.Get(ctx, request.NamespacedName, rs)
if errors.IsNotFound(err) {
log.Error(nil, "Could not find ReplicaSet")
ctx.Log().Error(nil, "Could not find ReplicaSet")
return reconcile.Result{}, nil
}

Expand All @@ -55,7 +49,7 @@ func (r *reconcileReplicaSet) Reconcile(request reconcile.Request) (reconcile.Re
}

// Print the ReplicaSet
log.Info("Reconciling ReplicaSet", "container name", rs.Spec.Template.Spec.Containers[0].Name)
ctx.Log().Info("Reconciling ReplicaSet", "container name", rs.Spec.Template.Spec.Containers[0].Name)

// Set the label if it is missing
if rs.Labels == nil {
Expand All @@ -67,7 +61,7 @@ func (r *reconcileReplicaSet) Reconcile(request reconcile.Request) (reconcile.Re

// Update the ReplicaSet
rs.Labels["hello"] = "world"
err = r.client.Update(context.TODO(), rs)
err = r.client.Update(ctx, rs)
if err != nil {
return reconcile.Result{}, fmt.Errorf("could not write ReplicaSet: %+v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion examples/builtins/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func main() {
// Setup a new controller to reconcile ReplicaSets
entryLog.Info("Setting up controller")
c, err := controller.New("foo-controller", mgr, controller.Options{
Reconciler: &reconcileReplicaSet{client: mgr.GetClient(), log: log.WithName("reconciler")},
Reconciler: &reconcileReplicaSet{client: mgr.GetClient()},
})
if err != nil {
entryLog.Error(err, "unable to set up individual controller")
Expand Down
20 changes: 9 additions & 11 deletions examples/crd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ limitations under the License.
package main

import (
"context"
"math/rand"
"os"
"time"
Expand All @@ -29,6 +28,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
api "sigs.k8s.io/controller-runtime/examples/crd/pkg"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/context"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)

Expand All @@ -42,22 +42,20 @@ type reconciler struct {
scheme *runtime.Scheme
}

func (r *reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
log := recLog.WithValues("chaospod", req.NamespacedName)
log.V(1).Info("reconciling chaos pod")
ctx := context.Background()
func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
ctx.Log().V(1).Info("reconciling chaos pod")

var chaospod api.ChaosPod
if err := r.Get(ctx, req.NamespacedName, &chaospod); err != nil {
log.Error(err, "unable to get chaosctl")
ctx.Log().Error(err, "unable to get chaosctl")
return ctrl.Result{}, err
}

var pod corev1.Pod
podFound := true
if err := r.Get(ctx, req.NamespacedName, &pod); err != nil {
if !apierrors.IsNotFound(err) {
log.Error(err, "unable to get pod")
ctx.Log().Error(err, "unable to get pod")
return ctrl.Result{}, err
}
podFound = false
Expand All @@ -70,7 +68,7 @@ func (r *reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
}

if err := r.Delete(ctx, &pod); err != nil {
log.Error(err, "unable to delete pod")
ctx.Log().Error(err, "unable to delete pod")
return ctrl.Result{}, err
}

Expand All @@ -84,19 +82,19 @@ func (r *reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
pod.Spec = templ.Spec

if err := ctrl.SetControllerReference(&chaospod, &pod, r.scheme); err != nil {
log.Error(err, "unable to set pod's owner reference")
ctx.Log().Error(err, "unable to set pod's owner reference")
return ctrl.Result{}, err
}

if err := r.Create(ctx, &pod); err != nil {
log.Error(err, "unable to create pod")
ctx.Log().Error(err, "unable to create pod")
return ctrl.Result{}, err
}

chaospod.Spec.NextStop.Time = time.Now().Add(time.Duration(10*(rand.Int63n(2)+1)) * time.Second)
chaospod.Status.LastRun = pod.CreationTimestamp
if err := r.Update(ctx, &chaospod); err != nil {
log.Error(err, "unable to update chaosctl status")
ctx.Log().Error(err, "unable to update chaosctl status")
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
Expand Down
12 changes: 7 additions & 5 deletions pkg/builder/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ limitations under the License.
package builder

import (
"context"
"fmt"
"strings"
"sync/atomic"
Expand All @@ -32,6 +31,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/workqueue"
"sigs.k8s.io/controller-runtime/pkg/context"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
Expand All @@ -54,7 +54,9 @@ var _ = Describe("application", func() {
close(stop)
})

noop := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) { return reconcile.Result{}, nil })
noop := reconcile.Func(func(_ context.Context, req reconcile.Request) (reconcile.Result, error) {
return reconcile.Result{}, nil
})

Describe("New", func() {
It("should return success if given valid objects", func() {
Expand Down Expand Up @@ -275,7 +277,7 @@ func doReconcileTest(nameSuffix string, stop chan struct{}, blder *Builder, mgr

By("Creating the application")
ch := make(chan reconcile.Request)
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
fn := reconcile.Func(func(_ context.Context, req reconcile.Request) (reconcile.Result, error) {
defer GinkgoRecover()
if !strings.HasSuffix(req.Name, nameSuffix) {
// From different test, ignore this request. Etcd is shared across tests.
Expand Down Expand Up @@ -327,7 +329,7 @@ func doReconcileTest(nameSuffix string, stop chan struct{}, blder *Builder, mgr
},
},
}
err := mgr.GetClient().Create(context.TODO(), dep)
err := mgr.GetClient().Create(context.Background(), dep)
Expect(err).NotTo(HaveOccurred())

By("Waiting for the Deployment Reconcile")
Expand Down Expand Up @@ -357,7 +359,7 @@ func doReconcileTest(nameSuffix string, stop chan struct{}, blder *Builder, mgr
Template: dep.Spec.Template,
},
}
err = mgr.GetClient().Create(context.TODO(), rs)
err = mgr.GetClient().Create(context.Background(), rs)
Expect(err).NotTo(HaveOccurred())

By("Waiting for the ReplicaSet Reconcile")
Expand Down
10 changes: 5 additions & 5 deletions pkg/builder/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ limitations under the License.
package builder_test

import (
"context"
"fmt"
"os"

Expand All @@ -28,6 +27,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/context"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
Expand Down Expand Up @@ -79,25 +79,25 @@ type ReplicaSetReconciler struct {
// * Read the ReplicaSet
// * Read the Pods
// * Set a Label on the ReplicaSet with the Pod count
func (a *ReplicaSetReconciler) Reconcile(req reconcile.Request) (reconcile.Result, error) {
func (a *ReplicaSetReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
// Read the ReplicaSet
rs := &appsv1.ReplicaSet{}
err := a.Get(context.TODO(), req.NamespacedName, rs)
err := a.Get(ctx, req.NamespacedName, rs)
if err != nil {
return reconcile.Result{}, err
}

// List the Pods matching the PodTemplate Labels
pods := &corev1.PodList{}
err = a.List(context.TODO(), pods, client.InNamespace(req.Namespace),
err = a.List(ctx, pods, client.InNamespace(req.Namespace),
client.MatchingLabels(rs.Spec.Template.Labels))
if err != nil {
return reconcile.Result{}, err
}

// Update the ReplicaSet
rs.Labels["pod-count"] = fmt.Sprintf("%v", len(pods.Items))
err = a.Update(context.TODO(), rs)
err = a.Update(ctx, rs)
if err != nil {
return reconcile.Result{}, err
}
Expand Down
32 changes: 32 additions & 0 deletions pkg/context/alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright 2020 The Kubernetes 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
http://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 context

import "context"

// A CancelFunc tells an operation to abandon its work.
// A CancelFunc does not wait for the work to stop.
// A CancelFunc may be called by multiple goroutines simultaneously.
// After the first call, subsequent calls to a CancelFunc do nothing.
type CancelFunc context.CancelFunc

// DeadlineExceeded is the error returned by Context.Err when the context's
// deadline passes.
var DeadlineExceeded error = context.DeadlineExceeded

// Canceled is the error returned by Context.Err when the context is canceled.
var Canceled error = context.Canceled
Loading

0 comments on commit 57c1a6b

Please sign in to comment.