Skip to content

Commit 10c5a02

Browse files
Reconcile on libvirt domain events
1 parent c16be82 commit 10c5a02

7 files changed

Lines changed: 309 additions & 394 deletions

File tree

internal/controller/hypervisor_controller.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,16 @@ import (
2525
"time"
2626

2727
kvmv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1"
28+
golibvirt "github.com/digitalocean/go-libvirt"
2829
"k8s.io/apimachinery/pkg/api/meta"
2930
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3031
"k8s.io/apimachinery/pkg/runtime"
3132
ctrl "sigs.k8s.io/controller-runtime"
3233
"sigs.k8s.io/controller-runtime/pkg/client"
34+
"sigs.k8s.io/controller-runtime/pkg/event"
35+
"sigs.k8s.io/controller-runtime/pkg/handler"
3336
logger "sigs.k8s.io/controller-runtime/pkg/log"
37+
"sigs.k8s.io/controller-runtime/pkg/source"
3438

3539
"github.com/cobaltcore-dev/kvm-node-agent/internal/certificates"
3640
"github.com/cobaltcore-dev/kvm-node-agent/internal/evacuation"
@@ -48,6 +52,9 @@ type HypervisorReconciler struct {
4852

4953
osDescriptor *systemd.Descriptor
5054
evacuateOnReboot bool
55+
56+
// Channel that can be used to trigger reconcile events.
57+
reconcileCh chan event.GenericEvent
5158
}
5259

5360
const (
@@ -287,6 +294,39 @@ func (r *HypervisorReconciler) Reconcile(ctx context.Context, req ctrl.Request)
287294
return ctrl.Result{RequeueAfter: 1 * time.Minute}, nil
288295
}
289296

297+
// Start is called when the manager starts. It starts the libvirt
298+
// event subscription to receive events when the hypervisor needs to be
299+
// reconciled.
300+
func (r *HypervisorReconciler) Start(ctx context.Context) error {
301+
log := logger.FromContext(ctx, "controller", "hypervisor")
302+
log.Info("starting libvirt event subscription")
303+
304+
// Ensure we're connected to libvirt.
305+
if err := r.Libvirt.Connect(); err != nil {
306+
log.Error(err, "unable to connect to libvirt")
307+
return err
308+
}
309+
310+
// Reconcile the hypervisor resource when libvirt domain lifecycle events occur.
311+
reconcile := func(ctx context.Context, _ any) {
312+
r.reconcileCh <- event.GenericEvent{
313+
Object: &kvmv1.Hypervisor{
314+
TypeMeta: metav1.TypeMeta{
315+
Kind: "Hypervisor",
316+
APIVersion: "kvm.cloud.sap/v1",
317+
},
318+
ObjectMeta: metav1.ObjectMeta{
319+
Name: sys.Hostname,
320+
Namespace: sys.Namespace,
321+
},
322+
},
323+
}
324+
}
325+
r.Libvirt.Watch(golibvirt.DomainEventIDLifecycle, "rec-domain-lifecycle", reconcile)
326+
327+
return nil
328+
}
329+
290330
// SetupWithManager sets up the controller with the Manager.
291331
func (r *HypervisorReconciler) SetupWithManager(mgr ctrl.Manager) error {
292332
ctx := context.Background()
@@ -296,7 +336,17 @@ func (r *HypervisorReconciler) SetupWithManager(mgr ctrl.Manager) error {
296336
return fmt.Errorf("unable to get Systemd hostname describe(): %w", err)
297337
}
298338

339+
// Prepare an event channel that will trigger a reconcile event when
340+
// the libvirt state changes.
341+
r.reconcileCh = make(chan event.GenericEvent)
342+
src := source.Channel(r.reconcileCh, &handler.EnqueueRequestForObject{})
343+
// Run the Start(ctx context.Context) method when the manager starts.
344+
if err := mgr.Add(r); err != nil {
345+
return err
346+
}
347+
299348
return ctrl.NewControllerManagedBy(mgr).
300349
For(&kvmv1.Hypervisor{}).
350+
WatchesRawSource(src).
301351
Complete(r)
302352
}

internal/libvirt/interface.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ limitations under the License.
2020
package libvirt
2121

2222
import (
23+
"context"
24+
2325
v1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1"
26+
"github.com/digitalocean/go-libvirt"
2427
)
2528

2629
type Interface interface {
@@ -30,6 +33,9 @@ type Interface interface {
3033
// Close closes the connection to the libvirt daemon.
3134
Close() error
3235

36+
// Watch libvirt changes and notify the provided handler.
37+
Watch(eventId libvirt.DomainEventID, handlerId string, handler func(context.Context, any))
38+
3339
// Add information extracted from the libvirt socket to the hypervisor instance.
3440
// If an error occurs, the instance is returned unmodified. The libvirt
3541
// connection needs to be established before calling this function.

internal/libvirt/interface_mock.go

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)