@@ -17,166 +17,95 @@ limitations under the License.
17
17
package gc
18
18
19
19
import (
20
- "cmp"
21
20
"context"
22
21
"fmt"
23
- "slices"
24
22
"time"
25
23
26
24
"github.com/robfig/cron/v3"
27
- "k8s.io/apimachinery/pkg/api/meta"
28
- "k8s.io/apimachinery/pkg/runtime"
29
25
"k8s.io/apimachinery/pkg/types"
30
26
"k8s.io/client-go/util/workqueue"
31
27
ctrl "sigs.k8s.io/controller-runtime"
32
28
"sigs.k8s.io/controller-runtime/pkg/client"
33
- "sigs.k8s.io/controller-runtime/pkg/event"
34
29
"sigs.k8s.io/controller-runtime/pkg/handler"
35
30
"sigs.k8s.io/controller-runtime/pkg/predicate"
36
31
"sigs.k8s.io/controller-runtime/pkg/source"
37
32
38
33
"github.com/deckhouse/deckhouse/pkg/log"
39
- "github.com/deckhouse/virtualization-controller/pkg/common/object"
34
+ "k8s.io/utils/clock"
35
+
40
36
"github.com/deckhouse/virtualization-controller/pkg/logger"
41
37
)
42
38
43
39
var _ source.Source = & CronSource {}
44
40
45
41
const sourceName = "CronSource"
46
42
47
- func NewCronSource (c client.Client ,
48
- standardSpec string ,
49
- objList client.ObjectList ,
50
- option CronSourceOption ,
51
- log * log.Logger ,
52
- ) * CronSource {
53
- return & CronSource {
54
- Client : c ,
55
- standardSpec : standardSpec ,
56
- objList : objList ,
57
- option : option ,
58
- log : log .With ("WatchSource" , sourceName ),
59
- }
60
- }
61
-
62
- type CronSource struct {
63
- client.Client
64
- standardSpec string
65
- objList client.ObjectList
66
- option CronSourceOption
67
- log * log.Logger
43
+ type SourceGCManager interface {
44
+ ListForDelete (ctx context.Context ) ([]client.Object , error )
68
45
}
69
46
70
- type CronSourceOption struct {
71
- GetOlder func (objList client.ObjectList ) client.ObjectList
72
- }
73
-
74
- func NewDefaultCronSourceOption (objs client.ObjectList , ttl time.Duration , log * log.Logger ) CronSourceOption {
75
- return CronSourceOption {
76
- GetOlder : DefaultGetOlder (objs , ttl , 10 , log ),
47
+ func NewCronSource (scheduleSpec string , client client.Client , mgr SourceGCManager , log * log.Logger ) (* CronSource , error ) {
48
+ schedule , err := cron .ParseStandard (scheduleSpec )
49
+ if err != nil {
50
+ return nil , fmt .Errorf ("parsing standard spec %q: %w" , scheduleSpec , err )
77
51
}
78
- }
79
-
80
- func DefaultGetOlder (objs client.ObjectList , ttl time.Duration , maxCount int , log * log.Logger ) func (objList client.ObjectList ) client.ObjectList {
81
- return func (objList client.ObjectList ) client.ObjectList {
82
- var expiredItems []runtime.Object
83
- var notExpiredItems []runtime.Object
84
52
85
- if err := meta .EachListItem (objList , func (o runtime.Object ) error {
86
- obj , ok := o .(client.Object )
87
- if ! ok {
88
- return nil
89
- }
90
- if object .GetAge (obj ) > ttl {
91
- expiredItems = append (expiredItems , o )
92
- } else {
93
- notExpiredItems = append (notExpiredItems , o )
94
- }
95
-
96
- return nil
97
- }); err != nil {
98
- log .Error ("failed to populate list" , logger .SlogErr (err ))
99
- }
100
-
101
- if maxCount != 0 && len (notExpiredItems ) > maxCount {
102
- slices .SortFunc (notExpiredItems , func (a , b runtime.Object ) int {
103
- aObj , _ := a .(client.Object )
104
- bObj , _ := b .(client.Object )
105
-
106
- return cmp .Compare (object .GetAge (aObj ), object .GetAge (bObj ))
107
- })
108
- expiredItems = append (expiredItems , notExpiredItems [maxCount :]... )
109
- }
53
+ return & CronSource {
54
+ schedule : schedule ,
55
+ client : client ,
56
+ mgr : mgr ,
57
+ log : log .With ("WatchSource" , sourceName ),
58
+ clock : clock.RealClock {},
59
+ }, nil
60
+ }
110
61
111
- if err := meta .SetList (objs , expiredItems ); err != nil {
112
- log .Error ("failed to set list" , logger .SlogErr (err ))
113
- }
114
- return objs
115
- }
62
+ type CronSource struct {
63
+ schedule cron.Schedule
64
+ client client.Client
65
+ mgr SourceGCManager
66
+ log * log.Logger
67
+ clock clock.Clock
116
68
}
117
69
118
- func (c * CronSource ) Start (ctx context.Context , _ handler.EventHandler , queue workqueue.RateLimitingInterface , predicates ... predicate.Predicate ) error {
119
- schedule , err := cron .ParseStandard (c .standardSpec )
120
- if err != nil {
121
- return fmt .Errorf ("parsing standard spec %q: %w" , c .standardSpec , err )
122
- }
123
- work := func () {
124
- if err = meta .SetList (c .objList , nil ); err != nil {
125
- c .log .Error ("failed to reset resource list" , logger .SlogErr (err ))
126
- return
127
- }
128
- if err = c .List (ctx , c .objList ); err != nil {
129
- c .log .Error ("failed to listing resources" , logger .SlogErr (err ))
130
- return
131
- }
132
- if meta .LenList (c .objList ) == 0 {
133
- c .log .Debug ("no resources, skip" )
134
- return
135
- }
136
- if c .option .GetOlder != nil {
137
- c .objList = c .option .GetOlder (c .objList )
138
- }
139
- if err = meta .EachListItem (c .objList , func (object runtime.Object ) error {
140
- obj , ok := object .(client.Object )
141
- if ! ok {
142
- c .log .Error (fmt .Sprintf ("%s's type isn't metav1.Object" , object .GetObjectKind ().GroupVersionKind ().String ()))
143
- return nil
144
- }
145
- genericEvent := event.GenericEvent {Object : obj }
146
- for _ , p := range predicates {
147
- if ! p .Generic (genericEvent ) {
148
- c .log .Debug (fmt .Sprintf ("skip enqueue object %s/%s due to the predicate." , obj .GetNamespace (), obj .GetName ()))
149
- return nil
150
- }
151
- }
152
- queue .Add (ctrl.Request {
153
- NamespacedName : types.NamespacedName {
154
- Namespace : obj .GetNamespace (),
155
- Name : obj .GetName (),
156
- },
157
- })
158
- c .log .Debug (fmt .Sprintf ("resource %s/%s enqueued" , obj .GetNamespace (), obj .GetName ()))
159
- return nil
160
- }); err != nil {
161
- c .log .Error ("failed to enqueueing resources" , logger .SlogErr (err ))
162
- return
163
- }
164
- }
165
- ta := nextScheduleTimeDuration (schedule , time .Now ())
70
+ func (c * CronSource ) Start (ctx context.Context , _ handler.EventHandler , queue workqueue.RateLimitingInterface , _ ... predicate.Predicate ) error {
71
+ ta := nextScheduleTimeDuration (c .schedule , c .clock .Now ())
166
72
go func () {
167
73
for {
168
74
select {
169
75
case <- ctx .Done ():
170
76
return
171
- case <- time .After (ta ):
172
- work ( )
173
- ta = nextScheduleTimeDuration (schedule , time .Now ())
77
+ case <- c . clock .After (ta ):
78
+ c . addObjects ( ctx , queue . Add )
79
+ ta = nextScheduleTimeDuration (c . schedule , c . clock .Now ())
174
80
}
175
81
}
176
82
}()
177
83
return nil
178
84
}
179
85
86
+ func (c * CronSource ) addObjects (ctx context.Context , addToQueue func (interface {})) {
87
+ objs , err := c .mgr .ListForDelete (ctx )
88
+ if err != nil {
89
+ c .log .Error ("Failed to get ObjectList for delete" , logger .SlogErr (err ))
90
+ return
91
+ }
92
+
93
+ if len (objs ) == 0 {
94
+ c .log .Debug ("No resources, skip" )
95
+ return
96
+ }
97
+
98
+ for _ , obj := range objs {
99
+ addToQueue (ctrl.Request {
100
+ NamespacedName : types.NamespacedName {
101
+ Namespace : obj .GetNamespace (),
102
+ Name : obj .GetName (),
103
+ },
104
+ })
105
+ c .log .Debug (fmt .Sprintf ("Resource %s/%s enqueued" , obj .GetNamespace (), obj .GetName ()))
106
+ }
107
+ }
108
+
180
109
func nextScheduleTimeDuration (schedule cron.Schedule , now time.Time ) time.Duration {
181
110
return schedule .Next (now ).Sub (now )
182
111
}
0 commit comments