Skip to content

Commit 2a49401

Browse files
Crash on libvirt disconnects and add unit tests for event loop
1 parent f731a12 commit 2a49401

2 files changed

Lines changed: 350 additions & 38 deletions

File tree

internal/libvirt/libvirt.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func (l *LibVirt) Connect() error {
129129
)
130130

131131
// Start the event loop
132-
go l.runEventLoop(context.Background())
132+
go l.runEventLoop(context.Background(), l.virt)
133133

134134
return nil
135135
}
@@ -141,9 +141,13 @@ func (l *LibVirt) Close() error {
141141
return l.virt.Disconnect()
142142
}
143143

144+
// We use this interface in our event loop to detect when the libvirt
145+
// connection has been closed. As an interface, it is easy to mock for testing.
146+
type eventloopRunnable interface{ Disconnected() <-chan struct{} }
147+
144148
// Run a loop which listens for new events on the subscribed libvirt event
145149
// channels and distributes them to the subscribed listeners.
146-
func (l *LibVirt) runEventLoop(ctx context.Context) {
150+
func (l *LibVirt) runEventLoop(ctx context.Context, i eventloopRunnable) {
147151
log := logger.FromContext(ctx, "libvirt", "event-loop")
148152
for {
149153
// The reflect.Select function works the same way as a
@@ -161,14 +165,23 @@ func (l *LibVirt) runEventLoop(ctx context.Context) {
161165
}
162166
l.domEventChsLock.Unlock()
163167

168+
// Add a case to handle context cancellation.
164169
cases = append(cases, reflect.SelectCase{
165170
Dir: reflect.SelectRecv,
166171
Chan: reflect.ValueOf(ctx.Done()),
167172
})
168173
caseCtxDone := len(cases) - 1
169174

175+
// The libvirt connection should never disconnect. If it does,
176+
// we can use the Disconnected channel to detect this.
177+
cases = append(cases, reflect.SelectCase{
178+
Dir: reflect.SelectRecv,
179+
Chan: reflect.ValueOf(i.Disconnected()),
180+
})
181+
caseLibvirtDisconnected := len(cases) - 1
182+
170183
chosen, value, ok := reflect.Select(cases)
171-
if !ok {
184+
if !ok || chosen == caseLibvirtDisconnected {
172185
// This should never happen. If it does, give the
173186
// service a chance to restart and reconnect.
174187
panic("libvirt connection closed")

0 commit comments

Comments
 (0)