@@ -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
5360const (
@@ -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.
291331func (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}
0 commit comments