-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
icinga2: Reset Event#ID
before resending ack set event
#243
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to retrace the steps how this can happened. Thanks for giving me some pointers, @yhabteab, as otherwise I have totally missed it.
- The journey of our new
fakeEv
starts incheckMissedChanges
, from where it will be send tocatchupEventCh
by reference
case catchupEventCh <- &catchupEventMsg{eventMsg: &eventMsg{fakeEv, attrs.LastStateChange.Time()}}: - It ends up in the
worker
's catchup case..
case catchupMsg, ok := <-catchupEventCh: - ..and will be eventually passed to the
CallbackFn
client.CallbackFn(ev) - In there, our adventurous event will be passed on to
incident.ProcessEvent
err := incident.ProcessEvent(subCtx, launcher.Db, launcher.Logs, launcher.RuntimeConfig, ev) - As it is a new incident, it gets
.Sync
ed
err = utils.RunInTx(ctx, db, func(tx *sqlx.Tx) error { return ev.Sync(ctx, tx, db, obj.ID) }) - And ends up in the database and gets its
.ID
set
icinga-notifications/internal/event/event.go
Lines 164 to 168 in 7b6ea92
eventRow := NewEventRow(e, objectId) eventID, err := utils.InsertAndFetchId(ctx, tx, utils.BuildInsertStmtWithout(db, eventRow, "id"), eventRow) if err == nil { e.ID = eventID } - Back in
checkMissedChanges
, after sending the host service event, thefakeEv
might be sent again
icinga-notifications/internal/icinga2/client_api.go
Lines 322 to 329 in 15392c9
case catchupEventCh <- &catchupEventMsg{eventMsg: &eventMsg{ev, attrs.LastStateChange.Time()}}: stateChangeEvents++ if fakeEv.Type == event.TypeAcknowledgementSet { fakeEv.ID = 0 // We don't want to reference a previously sent event, so reset its ID! select { // Retry the AckSet event so that the author of the ack is set as the incident // manager if there was no existing incident before the above state change event. case catchupEventCh <- &catchupEventMsg{eventMsg: &eventMsg{fakeEv, attrs.LastStateChange.Time()}}: - Now, I am going to skip some steps as shown above until the event ends up in
Sync
icinga-notifications/internal/event/event.go
Lines 160 to 162 in 7b6ea92
if e.ID != 0 { return nil } - And here it goes silently unnoticed as it got an
ID
in the meantime. Yikes.
I am going to take another look tomorrow.
If it is synced here, there should be no problems. The real problem, however, is that if there is an existing incident, that fake event will make its way to the fellowing scopes multiple times.
icinga-notifications/internal/incident/incident.go Lines 163 to 164 in 5986128
When the incident finally notices that this ack set event is superfluous here ... icinga-notifications/internal/incident/incident.go Lines 199 to 200 in 5986128
It will simply return without committing the transaction, leaving the now dangling ev.ID set above.
|
15392c9
to
babb370
Compare
internal/icinga2/client_api.go
Outdated
case catchupEventCh <- &catchupEventMsg{eventMsg: &eventMsg{ev, attrs.LastStateChange.Time()}}: | ||
stateChangeEvents++ | ||
if fakeEv.Type == event.TypeAcknowledgementSet { | ||
ackEvent := *fakeEv | ||
ackEvent.ID = 0 // We don't want to reference a previously sent event, so reset its ID! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplicate the whole event before sending it to any channel
By that, I meant before fakeEv
is sent to any channel for the first time, i.e. before line 305. That way, the pointer wasn't yet passed anywhere else and duplicating it is safe for sure. So that would mean creating a second variable next to fakeEv
and duplicating the event right after client.buildAcknowledgementEvent()
.
babb370
to
931f059
Compare
Event#Sync()
synchronises an event row with the database only if its ID is set to no other value than0
. Therefore, we must reset the event ID for the acknowledgement set event generated in the catch-up phase before resending it.