@@ -4,28 +4,47 @@ import (
4
4
"context"
5
5
"fmt"
6
6
"sort"
7
+ "strings"
7
8
"time"
8
9
9
10
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
10
11
"k8s.io/apimachinery/pkg/util/wait"
11
12
"k8s.io/klog/v2"
12
13
14
+ v1 "github.com/openshift/api/operator/v1"
15
+ operatorv1client "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1"
13
16
"github.com/openshift/insights-operator/pkg/anonymization"
14
17
"github.com/openshift/insights-operator/pkg/config/configobserver"
15
18
"github.com/openshift/insights-operator/pkg/controllerstatus"
16
19
"github.com/openshift/insights-operator/pkg/gather"
17
20
"github.com/openshift/insights-operator/pkg/gatherers"
18
21
"github.com/openshift/insights-operator/pkg/recorder"
22
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23
+ )
24
+
25
+ const (
26
+ DataGatheredCondition = "DataGathered"
27
+ // NoDataGathered is a reason when there is no data gathered - e.g the resource is not in a cluster
28
+ NoDataGatheredReason = "NoData"
29
+ // Error is a reason when there is some error and no data gathered
30
+ GatherErrorReason = "GatherError"
31
+ // Panic is a reason when there is some error and no data gathered
32
+ GatherPanicReason = "GatherPanic"
33
+ // GatheredOK is a reason when data is gathered as expected
34
+ GatheredOKReason = "GatheredOK"
35
+ // GatheredWithError is a reason when data is gathered partially or with another error message
36
+ GatheredWithErrorReason = "GatheredWithError"
19
37
)
20
38
21
39
// Controller periodically runs gatherers, records their results to the recorder
22
40
// and flushes the recorder to create archives
23
41
type Controller struct {
24
- configurator configobserver.Configurator
25
- recorder recorder.FlushInterface
26
- gatherers []gatherers.Interface
27
- statuses map [string ]controllerstatus.StatusController
28
- anonymizer * anonymization.Anonymizer
42
+ configurator configobserver.Configurator
43
+ recorder recorder.FlushInterface
44
+ gatherers []gatherers.Interface
45
+ statuses map [string ]controllerstatus.StatusController
46
+ anonymizer * anonymization.Anonymizer
47
+ insightsOperatorCLI operatorv1client.InsightsOperatorInterface
29
48
}
30
49
31
50
// New creates a new instance of Controller which periodically invokes the gatherers
@@ -35,6 +54,7 @@ func New(
35
54
rec recorder.FlushInterface ,
36
55
listGatherers []gatherers.Interface ,
37
56
anonymizer * anonymization.Anonymizer ,
57
+ insightsOperatorCLI operatorv1client.InsightsOperatorInterface ,
38
58
) * Controller {
39
59
statuses := make (map [string ]controllerstatus.StatusController )
40
60
@@ -44,11 +64,12 @@ func New(
44
64
}
45
65
46
66
return & Controller {
47
- configurator : configurator ,
48
- recorder : rec ,
49
- gatherers : listGatherers ,
50
- statuses : statuses ,
51
- anonymizer : anonymizer ,
67
+ configurator : configurator ,
68
+ recorder : rec ,
69
+ gatherers : listGatherers ,
70
+ statuses : statuses ,
71
+ anonymizer : anonymizer ,
72
+ insightsOperatorCLI : insightsOperatorCLI ,
52
73
}
53
74
}
54
75
@@ -114,7 +135,7 @@ func (c *Controller) Gather() {
114
135
}
115
136
116
137
allFunctionReports := make (map [string ]gather.GathererFunctionReport )
117
-
138
+ gatherTime := metav1 . Now ()
118
139
for _ , gatherer := range gatherersToProcess {
119
140
func () {
120
141
name := gatherer .GetName ()
@@ -142,8 +163,11 @@ func (c *Controller) Gather() {
142
163
})
143
164
}()
144
165
}
145
-
146
- err := gather .RecordArchiveMetadata (mapToArray (allFunctionReports ), c .recorder , c .anonymizer )
166
+ err := c .updateOperatorStatusCR (allFunctionReports , gatherTime )
167
+ if err != nil {
168
+ klog .Errorf ("failed to update the Insights Operator CR status: %v" , err )
169
+ }
170
+ err = gather .RecordArchiveMetadata (mapToArray (allFunctionReports ), c .recorder , c .anonymizer )
147
171
if err != nil {
148
172
klog .Errorf ("unable to record archive metadata because of error: %v" , err )
149
173
}
@@ -176,6 +200,84 @@ func (c *Controller) periodicTrigger(stopCh <-chan struct{}) {
176
200
}
177
201
}
178
202
203
+ // updateOperatorStatusCR gets the 'cluster' insightsoperators.operator.openshift.io resource and updates its status with the last
204
+ // gathering details.
205
+ func (c * Controller ) updateOperatorStatusCR (allFunctionReports map [string ]gather.GathererFunctionReport , gatherTime metav1.Time ) error {
206
+ insightsOperatorCR , err := c .insightsOperatorCLI .Get (context .Background (), "cluster" , metav1.GetOptions {})
207
+ if err != nil {
208
+ return err
209
+ }
210
+
211
+ updatedOperatorCR := insightsOperatorCR .DeepCopy ()
212
+ updatedOperatorCR .Status .GatherStatus = v1.GatherStatus {
213
+ LastGatherTime : gatherTime ,
214
+ LastGatherDuration : metav1.Duration {
215
+ Duration : time .Since (gatherTime .Time ),
216
+ },
217
+ }
218
+
219
+ for k := range allFunctionReports {
220
+ fr := allFunctionReports [k ]
221
+ // duration = 0 means the gatherer didn't run
222
+ if fr .Duration == 0 {
223
+ continue
224
+ }
225
+
226
+ gs := createGathererStatus (& fr )
227
+ updatedOperatorCR .Status .GatherStatus .Gatherers = append (updatedOperatorCR .Status .GatherStatus .Gatherers , gs )
228
+ }
229
+
230
+ _ , err = c .insightsOperatorCLI .UpdateStatus (context .Background (), updatedOperatorCR , metav1.UpdateOptions {})
231
+ if err != nil {
232
+ return err
233
+ }
234
+ return nil
235
+ }
236
+
237
+ func createGathererStatus (gfr * gather.GathererFunctionReport ) v1.GathererStatus {
238
+ gs := v1.GathererStatus {
239
+ Name : gfr .FuncName ,
240
+ LastGatherDuration : metav1.Duration {
241
+ // v.Duration is in milliseconds and we need nanoseconds
242
+ Duration : time .Duration (gfr .Duration * 1000000 ),
243
+ },
244
+ }
245
+ con := metav1.Condition {
246
+ Type : DataGatheredCondition ,
247
+ LastTransitionTime : metav1 .Now (),
248
+ Status : metav1 .ConditionFalse ,
249
+ Reason : NoDataGatheredReason ,
250
+ }
251
+
252
+ if gfr .Panic != nil {
253
+ con .Reason = GatherPanicReason
254
+ con .Message = gfr .Panic .(string )
255
+ }
256
+
257
+ if gfr .RecordsCount > 0 {
258
+ con .Status = metav1 .ConditionTrue
259
+ con .Reason = GatheredOKReason
260
+ con .Message = fmt .Sprintf ("Created %d records in the archive." , gfr .RecordsCount )
261
+
262
+ if len (gfr .Errors ) > 0 {
263
+ con .Reason = GatheredWithErrorReason
264
+ con .Message = fmt .Sprintf ("%s Error: %s" , con .Message , strings .Join (gfr .Errors , "," ))
265
+ }
266
+
267
+ gs .Conditions = append (gs .Conditions , con )
268
+ return gs
269
+ }
270
+
271
+ if len (gfr .Errors ) > 0 {
272
+ con .Reason = GatherErrorReason
273
+ con .Message = strings .Join (gfr .Errors , "," )
274
+ }
275
+
276
+ gs .Conditions = append (gs .Conditions , con )
277
+
278
+ return gs
279
+ }
280
+
179
281
func mapToArray (m map [string ]gather.GathererFunctionReport ) []gather.GathererFunctionReport {
180
282
a := make ([]gather.GathererFunctionReport , 0 , len (m ))
181
283
for _ , v := range m {
0 commit comments