Skip to content

Commit

Permalink
Added predicates to the controller manager with option reconcile only…
Browse files Browse the repository at this point in the history
… if annotation present.
  • Loading branch information
I308301 committed Mar 26, 2020
1 parent 5df592a commit 4908026
Show file tree
Hide file tree
Showing 62 changed files with 669 additions and 86 deletions.
3 changes: 3 additions & 0 deletions api/v1alpha1/etcd_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ type LastOperation struct {

// EtcdStatus defines the observed state of Etcd
type EtcdStatus struct {
// ObservedGeneration is the most recent generation observedfor this resource.
// +optional
ObserverdGeneration *int64 `json:"observedGeneration,omitempty"`
// +optional
Etcd CrossVersionObjectReference `json:"etcd,omitempty"`
// +optional
Expand Down
3 changes: 0 additions & 3 deletions charts/etcd/templates/etcd-statefulset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ spec:
matchLabels:
name: etcd
instance: {{ .Values.name }}
{{- if .Values.labels }}
{{ toYaml .Values.labels | indent 6 }}
{{- end }}
template:
metadata:
annotations:
Expand Down
5 changes: 5 additions & 0 deletions config/crd/bases/druid.gardener.cloud_etcds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,11 @@ spec:
type: object
lastError:
type: string
observedGeneration:
description: ObservedGeneration is the most recent generation observedfor
this resource.
format: int64
type: integer
ready:
type: boolean
readyReplicas:
Expand Down
40 changes: 29 additions & 11 deletions controllers/etcd_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/predicate"

druidv1alpha1 "github.com/gardener/etcd-druid/api/v1alpha1"
"github.com/gardener/etcd-druid/pkg/chartrenderer"
"github.com/gardener/etcd-druid/pkg/common"
druidpredicates "github.com/gardener/etcd-druid/pkg/predicate"
"github.com/gardener/etcd-druid/pkg/utils"

kubernetes "github.com/gardener/etcd-druid/pkg/client/kubernetes"
Expand Down Expand Up @@ -179,6 +181,9 @@ func (r *EtcdReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
if !reflect.DeepEqual(etcd.Spec, etcdCopy.Spec) {
etcdCopy.Spec = etcd.Spec
}

etcdCopy.Status.ObserverdGeneration = &etcdCopy.Generation

logger.Infof("Reconciling etcd: %s/%s", etcd.GetNamespace(), etcd.GetName())
if !etcdCopy.DeletionTimestamp.IsZero() {
logger.Infof("Deletion timestamp set for etcd: %s", etcd.GetName())
Expand Down Expand Up @@ -268,8 +273,8 @@ func (r *EtcdReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
logger.Infof("Successfully reconciled etcd: %s", etcd.GetName())

return ctrl.Result{
Requeue: true,
RequeueAfter: time.Minute * 5,
Requeue: false,
//RequeueAfter: time.Minute * 5,
}, nil
}

Expand Down Expand Up @@ -966,6 +971,7 @@ func (r *EtcdReconciler) updateEtcdStatus(etcdCopy, etcd *druidv1alpha1.Etcd, sv
etcdCopy.Status.UpdatedReplicas = ss.Status.UpdatedReplicas
etcdCopy.Status.Ready = (ss.Status.ReadyReplicas == ss.Status.Replicas)
etcdCopy.Status.ServiceName = &svcName
etcdCopy.Status.LastError = nil

if err := r.Status().Update(context.TODO(), etcdCopy); err != nil && !errors.IsNotFound(err) {
return err
Expand All @@ -983,15 +989,6 @@ func convertConditionsToEtcd(condition *appsv1.StatefulSetCondition) druidv1alph
}
}

// SetupWithManager sets up manager with a new controller and r as the reconcile.Reconciler
func (r *EtcdReconciler) SetupWithManager(mgr ctrl.Manager, workers int) error {
return ctrl.NewControllerManagedBy(mgr).WithOptions(controller.Options{
MaxConcurrentReconciles: workers,
}).For(&druidv1alpha1.Etcd{}).
Owns(&appsv1.StatefulSet{}).
Complete(r)
}

func (r *EtcdReconciler) claimStatefulSets(etcd *druidv1alpha1.Etcd, selector labels.Selector, ss *appsv1.StatefulSetList) ([]*appsv1.StatefulSet, error) {
// If any adoptions are attempted, we should first recheck for deletion with
// an uncached quorum read sometime after listing Machines (see #42639).
Expand Down Expand Up @@ -1045,3 +1042,24 @@ func (r *EtcdReconciler) claimConfigMaps(etcd *druidv1alpha1.Etcd, selector labe
cm := NewEtcdDruidRefManager(r, etcd, selector, etcdGVK, canAdoptFunc)
return cm.ClaimConfigMaps(ss)
}

// SetupWithManager sets up manager with a new controller and r as the reconcile.Reconciler
func (r *EtcdReconciler) SetupWithManager(mgr ctrl.Manager, workers int, ignoreOperationAnnotation bool) error {
predicates := []predicate.Predicate{
druidpredicates.GenerationChangedPredicate{},
druidpredicates.LastOperationNotSuccessful(),
}
builder := ctrl.NewControllerManagedBy(mgr).WithOptions(controller.Options{
MaxConcurrentReconciles: workers,
})
if !ignoreOperationAnnotation {
predicates = append(predicates, druidpredicates.HasOperationAnnotation())
}
builder = builder.WithEventFilter(druidpredicates.Or(predicates...))
return builder.
For(&druidv1alpha1.Etcd{}).
Owns(&appsv1.StatefulSet{}).
Owns(&v1.Service{}).
Owns(&v1.ConfigMap{}).
Complete(r)
}
10 changes: 5 additions & 5 deletions controllers/etcd_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,14 @@ func getEtcd(name, namespace string) *druidv1alpha1.Etcd {
"role": "test",
},
Labels: map[string]string{
"app": "etcd-statefulset",
"role": "test",
"name": name,
"app": "etcd-statefulset",
"role": "test",
"instance": name,
},
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "etcd-statefulset",
"name": name,
"app": "etcd-statefulset",
"instance": name,
},
},
Replicas: 1,
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ require (
github.com/imdario/mergo v0.3.8 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/onsi/ginkgo v1.8.0
github.com/onsi/gomega v1.5.0
github.com/onsi/ginkgo v1.10.1
github.com/onsi/gomega v1.7.0
github.com/prometheus/client_golang v1.3.0 // indirect
github.com/sirupsen/logrus v1.4.2
go.uber.org/atomic v1.5.1 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,15 @@ github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pborman/uuid v0.0.0-20170612153648-e790cca94e6c/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
Expand Down Expand Up @@ -634,6 +638,7 @@ k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783 h1:V6ndwCPoao1
k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY=
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 h1:CS1tBQz3HOXiseWZu6ZicKX361CZLT97UFnnPx0aqBw=
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4=
k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad h1:IMoNR9pilTBaCS5WpwWnAdmoVYVeXowOD3bLrwxIAtQ=
k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg=
k8s.io/autoscaler v0.0.0-20190805135949-100e91ba756e h1:5AX59ZgftHpbmNupSWosdtW4q/rCnF4s/0J0dEfJkAQ=
k8s.io/autoscaler v0.0.0-20190805135949-100e91ba756e/go.mod h1:QEXezc9uKPT91dwqhSJq3GNI3B1HxFRQHiku9kmrsSA=
Expand Down
14 changes: 10 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,19 @@ func init() {
}

func main() {
var metricsAddr string
var enableLeaderElection bool
var workers int
var (
metricsAddr string
enableLeaderElection bool
workers int
ignoreOperationAnnotation bool
)

flag.IntVar(&workers, "workers", 3, "Number of worker threads.")
flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
flag.BoolVar(&ignoreOperationAnnotation, "ignore-operation-annotation", true, "Ignore the operation annotation or not.")

flag.Parse()

ctrl.SetLogger(zap.Logger(true))
Expand All @@ -69,7 +75,7 @@ func main() {
setupLog.Error(err, "unable to initialize controller with image vector")
os.Exit(1)
}
err = ec.SetupWithManager(mgr, workers)
err = ec.SetupWithManager(mgr, workers, ignoreOperationAnnotation)
if err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Etcd")
os.Exit(1)
Expand Down
116 changes: 116 additions & 0 deletions pkg/predicate/mapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file
//
// 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 predicate

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"

"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
)

// MapperTrigger is a trigger a Mapper can react upon.
type MapperTrigger uint8

const (
// CreateTrigger is a MapperTrigger for create events.
CreateTrigger MapperTrigger = iota
// UpdateOldTrigger is a MapperTrigger for update events with the old meta and object.
UpdateOldTrigger
// UpdateNewTrigger is a MapperTrigger for update events with the new meta and object.
UpdateNewTrigger
// DeleteTrigger is a MapperTrigger for delete events.
DeleteTrigger
// GenericTrigger is a MapperTrigger for generic events.
GenericTrigger
)

// Mapper maps any event (in form of a GenericEvent) to a boolean whether the event shall be
// propagated or not.
type Mapper interface {
Map(event event.GenericEvent) bool
}

// MapperFunc is a function that implements Mapper.
type MapperFunc func(event.GenericEvent) bool

// Map implements Mapper.
func (f MapperFunc) Map(event event.GenericEvent) bool {
return f(event)
}

type mapperWithTriggers struct {
triggers map[MapperTrigger]struct{}
mapper Mapper
}

// FromMapper creates a new predicate from the given Mapper that reacts on the given MapperTriggers.
func FromMapper(mapper Mapper, triggers ...MapperTrigger) predicate.Predicate {
t := make(map[MapperTrigger]struct{})
for _, trigger := range triggers {
t[trigger] = struct{}{}
}
return &mapperWithTriggers{t, mapper}
}

// InjectFunc implements Injector.
func (m *mapperWithTriggers) InjectFunc(f inject.Func) error {
return f(m.mapper)
}

// NewGeneric creates a new GenericEvent from the given metav1.Object and runtime.Object.
func NewGeneric(meta metav1.Object, obj runtime.Object) event.GenericEvent {
return event.GenericEvent{
Meta: meta,
Object: obj,
}
}

// Create implements Predicate.
func (m *mapperWithTriggers) Create(e event.CreateEvent) bool {
if _, ok := m.triggers[CreateTrigger]; ok {
return m.mapper.Map(NewGeneric(e.Meta, e.Object))
}
return true
}

// Delete implements Predicate.
func (m *mapperWithTriggers) Delete(e event.DeleteEvent) bool {
if _, ok := m.triggers[DeleteTrigger]; ok {
return m.mapper.Map(NewGeneric(e.Meta, e.Object))
}
return true
}

// Update implements Predicate.
func (m *mapperWithTriggers) Update(e event.UpdateEvent) bool {
if _, ok := m.triggers[UpdateOldTrigger]; ok {
return m.mapper.Map(NewGeneric(e.MetaOld, e.ObjectOld))
}
if _, ok := m.triggers[UpdateNewTrigger]; ok {
return m.mapper.Map(NewGeneric(e.MetaNew, e.ObjectNew))
}
return true
}

// Generic implements Predicate.
func (m *mapperWithTriggers) Generic(e event.GenericEvent) bool {
if _, ok := m.triggers[GenericTrigger]; ok {
return m.mapper.Map(NewGeneric(e.Meta, e.Object))
}
return true
}
Loading

0 comments on commit 4908026

Please sign in to comment.