package displayctl import ( "context" "fmt" "os" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kruntime "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "edge-infra.dev/pkg/k8s/runtime/controller" "edge-infra.dev/pkg/sds/display/constants" "edge-infra.dev/pkg/sds/display/displaymanager/manager" xorgmanager "edge-infra.dev/pkg/sds/display/displaymanager/manager/xorg" v2 "edge-infra.dev/pkg/sds/display/k8s/apis/v2" ) var scheme = kruntime.NewScheme() func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(v2.AddToScheme(scheme)) } const hostnameEnvvar = "HOSTNAME" var errHostnameEnvvarNotSet = fmt.Errorf("%s envvar is not set", hostnameEnvvar) func Run(ctx context.Context, opts ...controller.Option) error { log := ctrl.LoggerFrom(ctx).WithName(constants.DisplayctlName) mgr, err := CreateManager(opts...) if err != nil { log.Error(err, "unable to create controller manager") return err } hostname := os.Getenv(hostnameEnvvar) if hostname == "" { log.Error(errHostnameEnvvarNotSet, "unable to find hostname") return errHostnameEnvvarNotSet } // before controllers start, create NodeDisplayConfig for host if it does not exist if err := createHostNodeDisplayConfig(ctx, mgr.GetConfig(), hostname); err != nil { log.Error(err, "unable to create host NodeDisplayConfig") return err } displayManager := xorgmanager.NewXorgDisplayManager(hostname, mgr.GetClient(), log) if err := registerComponentsWithManager(mgr, displayManager); err != nil { log.Error(err, "unable to register components with manager") return err } if err := mgr.Start(ctx); err != nil { log.Error(err, "displayctl received an error") return err } return nil } func CreateManager(opts ...controller.Option) (ctrl.Manager, error) { mgrCfg, mgrOpts := controller.ProcessOptions(opts...) mgrOpts.Scheme = scheme return ctrl.NewManager(mgrCfg, mgrOpts) } // Create an empty NodeDisplayConfig for the host if one does not exist func createHostNodeDisplayConfig(ctx context.Context, restConfig *rest.Config, hostname string) error { nodeDisplayConfig := &v2.NodeDisplayConfig{ ObjectMeta: metav1.ObjectMeta{ Name: hostname, }, } // create a non-caching client as we have not started the manager (yet) c, err := client.New(restConfig, client.Options{Scheme: scheme}) if err != nil { return err } err = c.Get(ctx, client.ObjectKeyFromObject(nodeDisplayConfig), &v2.NodeDisplayConfig{}) if errors.IsNotFound(err) { return c.Create(ctx, nodeDisplayConfig) } return err } func registerComponentsWithManager(mgr ctrl.Manager, displayManager manager.DisplayManager) error { displayManagerWatcher := NewDisplayManagerWatcherRunnable(displayManager, mgr.GetClient()) if err := displayManagerWatcher.SetupWithManager(mgr); err != nil { return err } deviceWatcher := NewDeviceWatcherRunnable(displayManager.Hostname(), mgr.GetClient()) if err := deviceWatcher.SetupWithManager(mgr); err != nil { return err } nodeDisplayConfigController := NewNodeDisplayConfigController(displayManager, mgr) return nodeDisplayConfigController.SetupWithManager(mgr) }