package xserver import ( "context" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/predicate" "edge-infra.dev/pkg/sds/display/constants" xserverconfig "edge-infra.dev/pkg/sds/display/k8s/controllers/xserver/config" ) type configChannel chan *xserverconfig.Config // ConfigController watches for the node's xserver-config ConfigMap and writes it to a file // on updates, also sending it to the xserver-manager's config channel. type ConfigController struct { Name string Hostname string // configChan is used by the X server config controller to send configuration to the X server. configChan configChannel // The X server config which is currently applied. currentConfig *xserverconfig.Config client client.Client } func NewConfigController(hostname string, configChan configChannel, c client.Client) *ConfigController { return &ConfigController{ Name: constants.XServerConfigControllerName, Hostname: hostname, configChan: configChan, client: c, } } func (c *ConfigController) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&corev1.ConfigMap{}, c.createPredicates()). WithEventFilter(createEventFilter()). Complete(c) } func (c *ConfigController) createPredicates() builder.Predicates { return builder.WithPredicates( predicate.NewPredicateFuncs(configMapFilter(c.Hostname)), ) } // Reconcile display/xserver-config-HOSTNAME and display/global-openbox-config ConfigMaps. func configMapFilter(hostname string) func(client.Object) bool { return func(obj client.Object) bool { if obj.GetNamespace() != constants.Namespace { return false } return obj.GetName() == xserverconfig.ConfigMapNameFromHostname(hostname) || obj.GetName() == xserverconfig.GlobalOpenboxConfig } } func createEventFilter() predicate.Predicate { return predicate.Funcs{ CreateFunc: func(event.CreateEvent) bool { return true }, UpdateFunc: func(event.UpdateEvent) bool { return true }, DeleteFunc: func(event.DeleteEvent) bool { return true }, } } // +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch func (c *ConfigController) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) { log := ctrl.LoggerFrom(ctx).WithName(c.Name) ctx = ctrl.LoggerInto(ctx, log) // fetch X server config from client config, err := xserverconfig.FromClient(ctx, c.Hostname, c.client) if client.IgnoreNotFound(err) != nil { return ctrl.Result{}, err } // if X server config does not exist, use new empty config if kerrors.IsNotFound(err) { log.Info("X server config not found, using default config") config = xserverconfig.New(c.Hostname) } // if Openbox config has not been set in X server config, use the global config if config.OpenboxConf() == "" { if err := useGlobalOpenboxConf(ctx, config, c.client); err != nil { return ctrl.Result{}, err } } // if config has changed, send it to xserver if !xserverconfig.Equal(c.currentConfig, config) { c.configChan <- config c.currentConfig = config } return ctrl.Result{}, nil } func useGlobalOpenboxConf(ctx context.Context, config *xserverconfig.Config, c client.Client) error { globalOpenboxConf, err := xserverconfig.GlobalOpenboxConfFromClient(ctx, c) if err != nil { return err } config.SetOpenboxConf(globalOpenboxConf) return nil }