@@ -17,6 +17,7 @@ package agent
17
17
import (
18
18
"bytes"
19
19
"context"
20
+ "errors"
20
21
"fmt"
21
22
"strings"
22
23
"time"
@@ -95,10 +96,18 @@ func (agent *Agent) getHealth() *protobufs.ComponentHealth {
95
96
LastError : err .Error (),
96
97
}
97
98
}
99
+ statusTime , err := agent .getCurrentTimeUnixNano ()
100
+ if err != nil {
101
+ return & protobufs.ComponentHealth {
102
+ Healthy : false ,
103
+ StartTimeUnixNano : agent .startTime ,
104
+ LastError : err .Error (),
105
+ }
106
+ }
98
107
return & protobufs.ComponentHealth {
99
108
Healthy : true ,
100
109
StartTimeUnixNano : agent .startTime ,
101
- StatusTimeUnixNano : uint64 ( agent . clock . Now (). UnixNano ()) ,
110
+ StatusTimeUnixNano : statusTime ,
102
111
LastError : "" ,
103
112
ComponentHealthMap : healthMap ,
104
113
}
@@ -124,9 +133,17 @@ func (agent *Agent) generateCollectorPoolHealth() (map[string]*protobufs.Compone
124
133
for _ , pod := range podMap {
125
134
isPoolHealthy = isPoolHealthy && pod .Healthy
126
135
}
136
+ podStartTime , err := timeToUnixNanoUnsigned (col .ObjectMeta .GetCreationTimestamp ().Time )
137
+ if err != nil {
138
+ return nil , err
139
+ }
140
+ statusTime , err := agent .getCurrentTimeUnixNano ()
141
+ if err != nil {
142
+ return nil , err
143
+ }
127
144
healthMap [key .String ()] = & protobufs.ComponentHealth {
128
- StartTimeUnixNano : uint64 ( col . ObjectMeta . GetCreationTimestamp (). UnixNano ()) ,
129
- StatusTimeUnixNano : uint64 ( agent . clock . Now (). UnixNano ()) ,
145
+ StartTimeUnixNano : podStartTime ,
146
+ StatusTimeUnixNano : statusTime ,
130
147
Status : col .Status .Scale .StatusReplicas ,
131
148
ComponentHealthMap : podMap ,
132
149
Healthy : isPoolHealthy ,
@@ -158,6 +175,10 @@ func (agent *Agent) getCollectorSelector(col v1beta1.OpenTelemetryCollector) map
158
175
}
159
176
160
177
func (agent * Agent ) generateCollectorHealth (selectorLabels map [string ]string , namespace string ) (map [string ]* protobufs.ComponentHealth , error ) {
178
+ statusTime , err := agent .getCurrentTimeUnixNano ()
179
+ if err != nil {
180
+ return nil , err
181
+ }
161
182
pods , err := agent .applier .GetCollectorPods (selectorLabels , namespace )
162
183
if err != nil {
163
184
return nil , err
@@ -169,15 +190,18 @@ func (agent *Agent) generateCollectorHealth(selectorLabels map[string]string, na
169
190
if item .Status .Phase != "Running" {
170
191
healthy = false
171
192
}
172
- var startTime int64
193
+ var startTime uint64
173
194
if item .Status .StartTime != nil {
174
- startTime = item .Status .StartTime .UnixNano ()
195
+ startTime , err = timeToUnixNanoUnsigned (item .Status .StartTime .Time )
196
+ if err != nil {
197
+ return nil , err
198
+ }
175
199
} else {
176
200
healthy = false
177
201
}
178
202
healthMap [key .String ()] = & protobufs.ComponentHealth {
179
- StartTimeUnixNano : uint64 ( startTime ) ,
180
- StatusTimeUnixNano : uint64 ( agent . clock . Now (). UnixNano ()) ,
203
+ StartTimeUnixNano : startTime ,
204
+ StatusTimeUnixNano : statusTime ,
181
205
Status : string (item .Status .Phase ),
182
206
Healthy : healthy ,
183
207
}
@@ -197,7 +221,7 @@ func (agent *Agent) onConnectFailed(ctx context.Context, err error) {
197
221
198
222
// onError is called when an agent receives an error response from the server.
199
223
func (agent * Agent ) onError (ctx context.Context , err * protobufs.ServerErrorResponse ) {
200
- agent .logger .Error (fmt . Errorf (err .GetErrorMessage ()), "server returned an error response" )
224
+ agent .logger .Error (errors . New (err .GetErrorMessage ()), "server returned an error response" )
201
225
}
202
226
203
227
// saveRemoteConfigStatus receives a status from the server when the server sets a remote configuration.
@@ -207,7 +231,11 @@ func (agent *Agent) saveRemoteConfigStatus(_ context.Context, status *protobufs.
207
231
208
232
// Start sets up the callbacks for the OpAMP client and begins the client's connection to the server.
209
233
func (agent * Agent ) Start () error {
210
- agent .startTime = uint64 (agent .clock .Now ().UnixNano ())
234
+ startTime , err := agent .getCurrentTimeUnixNano ()
235
+ if err != nil {
236
+ return err
237
+ }
238
+ agent .startTime = startTime
211
239
settings := types.StartSettings {
212
240
OpAMPServerURL : agent .config .Endpoint ,
213
241
Header : agent .config .Headers .ToHTTPHeader (),
@@ -224,7 +252,7 @@ func (agent *Agent) Start() error {
224
252
PackagesStateProvider : nil ,
225
253
Capabilities : agent .config .GetCapabilities (),
226
254
}
227
- err : = agent .opampClient .SetAgentDescription (agent .agentDescription )
255
+ err = agent .opampClient .SetAgentDescription (agent .agentDescription )
228
256
if err != nil {
229
257
return err
230
258
}
@@ -429,3 +457,20 @@ func (agent *Agent) onMessage(ctx context.Context, msg *types.MessageData) {
429
457
agent .initMeter (msg .OwnMetricsConnSettings )
430
458
}
431
459
}
460
+
461
+ // getCurrentTimeUnixNano returns the current time as a uint64, which the protocol expects.
462
+ func (agent * Agent ) getCurrentTimeUnixNano () (uint64 , error ) {
463
+ // technically this could be negative if the system time is set to before 1970-01-1
464
+ // the proto demands this to be a nonnegative number, so in that case, just return 0
465
+ return timeToUnixNanoUnsigned (agent .clock .Now ())
466
+ }
467
+
468
+ // timeToUnixNanoUnsigned returns the number of nanoseconds elapsed from 1970-01-01 to the given time, but returns an
469
+ // error if the value is negative. OpAMP expects these values to be non-negative.
470
+ func timeToUnixNanoUnsigned (t time.Time ) (uint64 , error ) {
471
+ signedUnixNano := t .UnixNano ()
472
+ if signedUnixNano < 0 {
473
+ return 0 , fmt .Errorf ("invalid system time, must be after 01-01-1970 due to OpAMP requirements: %v" , t )
474
+ }
475
+ return uint64 (signedUnixNano ), nil
476
+ }
0 commit comments