@@ -11,14 +11,17 @@ import (
1111 urlpkg "net/url"
1212
1313 "helm.sh/helm/v3/pkg/cli"
14+ corev1 "k8s.io/api/core/v1"
1415 "k8s.io/apimachinery/pkg/api/meta"
1516 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1617 "k8s.io/apimachinery/pkg/runtime"
1718 ctrl "sigs.k8s.io/controller-runtime"
1819 "sigs.k8s.io/controller-runtime/pkg/client"
20+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1921 "sigs.k8s.io/controller-runtime/pkg/log"
2022
2123 v1alpha1 "github.com/SUSE/aif-operator/api/v1alpha1"
24+ "github.com/SUSE/aif-operator/internal/config"
2225 helmClient "github.com/SUSE/aif-operator/internal/infra/helm"
2326 "github.com/SUSE/aif-operator/internal/infra/kubernetes"
2427 "github.com/SUSE/aif-operator/internal/infra/rancher"
@@ -28,6 +31,7 @@ import (
2831const (
2932 defaultReadinessTimeout = 5 * time .Minute
3033 readinessRequeue = 10 * time .Second
34+ uiConfigMapName = "aif-ui-config"
3135 healthCheckInterval = 60 * time .Second
3236
3337 conditionTypeReady = "Ready"
@@ -143,10 +147,42 @@ func (r *InstallAIExtensionReconciler) reconcile(ctx context.Context, ext *v1alp
143147 ext .Status .ActiveExtensionName = ext .Spec .Extension .Name
144148 ext .Status .ActiveSourceKind = ext .Spec .Source .Kind
145149
150+ if err := r .syncUIConfigMap (ctx ); err != nil {
151+ logger .Error (err , "failed to sync operator coordinates to UI ConfigMap" )
152+ return ctrl.Result {Requeue : true }, nil
153+ }
154+
146155 logger .Info ("reconciled successfully" )
147156 return ctrl.Result {RequeueAfter : healthCheckInterval }, nil
148157}
149158
159+ // syncUIConfigMap writes the operator namespace and service name into the
160+ // aif-ui-config ConfigMap so the UI extension can reach the operator without
161+ // manual configuration. It runs on every successful reconcile loop, giving
162+ // self-healing behaviour if the ConfigMap is deleted or corrupted.
163+ // The ConfigMap is intentionally not deleted when the CR is removed — the UI
164+ // retains the last-known operator coordinates so it remains functional.
165+ func (r * InstallAIExtensionReconciler ) syncUIConfigMap (ctx context.Context ) error {
166+ logger := log .FromContext (ctx )
167+ ns , svc := config .GetOperatorNamespace (), config .GetOperatorService ()
168+ logger .V (1 ).Info ("syncing UI ConfigMap" , "operatorNamespace" , ns , "operatorService" , svc )
169+ cm := & corev1.ConfigMap {
170+ ObjectMeta : metav1.ObjectMeta {
171+ Name : uiConfigMapName ,
172+ Namespace : r .ExtensionNamespace ,
173+ },
174+ }
175+ _ , err := controllerutil .CreateOrUpdate (ctx , r .Client , cm , func () error {
176+ if cm .Data == nil {
177+ cm .Data = make (map [string ]string )
178+ }
179+ cm .Data ["operatorNamespace" ] = ns
180+ cm .Data ["operatorService" ] = svc
181+ return nil
182+ })
183+ return err
184+ }
185+
150186func (r * InstallAIExtensionReconciler ) reconcileHelmSource (
151187 ctx context.Context ,
152188 ext * v1alpha1.InstallAIExtension ,
0 commit comments