github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/dataprotection/utils/periodical_enqueue_source.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package utils 21 22 import ( 23 "context" 24 "fmt" 25 "reflect" 26 "time" 27 28 "github.com/go-logr/logr" 29 "k8s.io/apimachinery/pkg/api/meta" 30 "k8s.io/apimachinery/pkg/runtime" 31 "k8s.io/apimachinery/pkg/types" 32 "k8s.io/apimachinery/pkg/util/wait" 33 "k8s.io/client-go/util/workqueue" 34 ctrl "sigs.k8s.io/controller-runtime" 35 "sigs.k8s.io/controller-runtime/pkg/client" 36 "sigs.k8s.io/controller-runtime/pkg/event" 37 "sigs.k8s.io/controller-runtime/pkg/handler" 38 "sigs.k8s.io/controller-runtime/pkg/log" 39 "sigs.k8s.io/controller-runtime/pkg/predicate" 40 ) 41 42 // PeriodicalEnqueueSource is an implementation of interface sigs.k8s.io/controller-runtime/pkg/source/Source 43 // It reads the specific resources from cache and enqueue them into the queue to trigger 44 // the reconcile procedure periodically. 45 type PeriodicalEnqueueSource struct { 46 client.Client 47 log logr.Logger 48 objList client.ObjectList 49 period time.Duration 50 option PeriodicalEnqueueSourceOption 51 } 52 53 type PeriodicalEnqueueSourceOption struct { 54 OrderFunc func(objList client.ObjectList) client.ObjectList 55 } 56 57 func NewPeriodicalEnqueueSource( 58 client client.Client, 59 objList client.ObjectList, 60 period time.Duration, 61 option PeriodicalEnqueueSourceOption) *PeriodicalEnqueueSource { 62 return &PeriodicalEnqueueSource{ 63 log: log.Log.WithValues("resource", reflect.TypeOf(objList).String()), 64 Client: client, 65 objList: objList, 66 period: period, 67 option: option, 68 } 69 } 70 71 func (p *PeriodicalEnqueueSource) Start( 72 ctx context.Context, 73 _ handler.EventHandler, 74 q workqueue.RateLimitingInterface, 75 predicates ...predicate.Predicate) error { 76 go wait.Until(func() { 77 p.log.V(1).Info("enqueueing resources ...") 78 if err := p.List(ctx, p.objList); err != nil { 79 p.log.Error(err, "error listing resources") 80 return 81 } 82 83 if meta.LenList(p.objList) == 0 { 84 p.log.V(1).Info("no resources found, skip") 85 return 86 } 87 88 if p.option.OrderFunc != nil { 89 p.objList = p.option.OrderFunc(p.objList) 90 } 91 92 if err := meta.EachListItem(p.objList, func(object runtime.Object) error { 93 obj, ok := object.(client.Object) 94 if !ok { 95 p.log.Error(nil, "object is not a client.Object", "object", object) 96 return nil 97 } 98 e := event.GenericEvent{Object: obj} 99 for _, pred := range predicates { 100 if !pred.Generic(e) { 101 p.log.V(1).Info("skip enqueue object due to the predicate", "object", obj) 102 return nil 103 } 104 } 105 106 q.Add(ctrl.Request{ 107 NamespacedName: types.NamespacedName{ 108 Namespace: obj.GetNamespace(), 109 Name: obj.GetName(), 110 }, 111 }) 112 p.log.V(1).Info("resource enqueued", "object", obj) 113 return nil 114 }); err != nil { 115 p.log.Error(err, "error enqueueing resources") 116 return 117 } 118 }, p.period, ctx.Done()) 119 120 return nil 121 } 122 123 func (p *PeriodicalEnqueueSource) String() string { 124 if p.objList != nil { 125 return fmt.Sprintf("periodical enqueue source: %T", p.objList) 126 } 127 return "periodical enqueue source: unknown type" 128 }