@@ -59,10 +59,50 @@ type ConfigSpec struct {
5959 Version string `json:"version"`
6060}
6161
62+ // ConfigFetcher defines an interface for fetching UI component configurations
63+ type ConfigFetcher interface {
64+ FetchConfig (ctx context.Context , namespace , serviceName string , port int ) (string , error )
65+ }
66+
67+ // K8sServiceProxyFetcher implements ConfigFetcher using Kubernetes service proxy
68+ type K8sServiceProxyFetcher struct {
69+ Config * rest.Config
70+ }
71+
72+ // FetchConfig retrieves the micro-app configuration from the specified service
73+ func (f * K8sServiceProxyFetcher ) FetchConfig (ctx context.Context , namespace , serviceName string , port int ) (string , error ) {
74+ logger := log .FromContext (ctx )
75+
76+ clientset , err := kubernetes .NewForConfig (f .Config )
77+ if err != nil {
78+ logger .Error (err , "Failed to create clientset" )
79+ return "" , err
80+ }
81+
82+ restClient := clientset .CoreV1 ().RESTClient ()
83+ req := restClient .Get ().
84+ Namespace (namespace ).
85+ Resource ("services" ).
86+ Name (fmt .Sprintf ("%s:%d" , serviceName , port )).
87+ SubResource ("proxy" ).
88+ Suffix ("/.well-known/micro-app-configuration" )
89+
90+ // Execute the request
91+ result := req .Do (ctx )
92+ raw , err := result .Raw ()
93+ if err != nil {
94+ logger .Error (err , "Failed to get configuration" )
95+ return "" , err
96+ }
97+
98+ return string (raw ), nil
99+ }
100+
62101type ScalityUIComponentReconciler struct {
63102 client.Client
64- Scheme * runtime.Scheme
65- Config * rest.Config
103+ Scheme * runtime.Scheme
104+ Config * rest.Config
105+ ConfigFetcher ConfigFetcher
66106}
67107
68108// +kubebuilder:rbac:groups=ui.scality.com,resources=scalityuicomponents,verbs=get;list;watch;create;update;patch;delete
@@ -158,114 +198,124 @@ func (r *ScalityUIComponentReconciler) Reconcile(ctx context.Context, req ctrl.R
158198 }
159199
160200 if deployment .Status .ReadyReplicas > 0 {
161- // Fetch configuration
162- configContent , err := r .fetchMicroAppConfig (ctx , scalityUIComponent .Namespace , scalityUIComponent .Name )
163-
164- if err != nil {
165- logger .Error (err , "Failed to fetch micro-app-configuration" )
166-
167- // Add a failure condition
168- meta .SetStatusCondition (& scalityUIComponent .Status .Conditions , metav1.Condition {
169- Type : "ConfigurationRetrieved" ,
170- Status : metav1 .ConditionFalse ,
171- Reason : "FetchFailed" ,
172- Message : fmt .Sprintf ("Failed to fetch configuration: %v" , err ),
173- LastTransitionTime : metav1 .Now (),
174- })
175-
176- if updateErr := r .Status ().Update (ctx , scalityUIComponent ); updateErr != nil {
177- logger .Error (updateErr , "Failed to update status with failure condition" )
178- }
179-
180- return ctrl.Result {RequeueAfter : time .Second * 10 }, nil
181- }
201+ // Fetch and process configuration
202+ return r .processUIComponentConfig (ctx , scalityUIComponent )
203+ } else {
204+ logger .Info ("Deployment not ready yet, waiting for pods to start" )
205+ return ctrl.Result {RequeueAfter : time .Second * 10 }, nil
206+ }
207+ }
182208
183- // Parse JSON to extract information
184- var config MicroAppConfig
185- if err := json .Unmarshal ([]byte (configContent ), & config ); err != nil {
186- logger .Error (err , "Failed to parse micro-app-configuration" )
187-
188- // Add a failure condition
189- meta .SetStatusCondition (& scalityUIComponent .Status .Conditions , metav1.Condition {
190- Type : "ConfigurationRetrieved" ,
191- Status : metav1 .ConditionFalse ,
192- Reason : "ParseFailed" ,
193- Message : fmt .Sprintf ("Failed to parse configuration: %v" , err ),
194- LastTransitionTime : metav1 .Now (),
195- })
196-
197- if updateErr := r .Status ().Update (ctx , scalityUIComponent ); updateErr != nil {
198- logger .Error (updateErr , "Failed to update status with failure condition" )
199- }
200-
201- return ctrl.Result {RequeueAfter : time .Second * 10 }, nil
202- }
209+ // processUIComponentConfig fetches and processes UI component configuration,
210+ // updates the status and returns the reconcile result
211+ func (r * ScalityUIComponentReconciler ) processUIComponentConfig (ctx context.Context , scalityUIComponent * uiv1alpha1.ScalityUIComponent ) (ctrl.Result , error ) {
212+ logger := log .FromContext (ctx )
203213
204- // Update status with retrieved information
205- scalityUIComponent .Status .Kind = config .Metadata .Kind
206- scalityUIComponent .Status .PublicPath = config .Spec .PublicPath
207- scalityUIComponent .Status .Version = config .Spec .Version
214+ // Fetch configuration
215+ configContent , err := r .fetchMicroAppConfig (ctx , scalityUIComponent .Namespace , scalityUIComponent .Name )
216+
217+ if err != nil {
218+ logger .Error (err , "Failed to fetch micro-app-configuration" )
208219
209- // Add a success condition
220+ // Add a failure condition
210221 meta .SetStatusCondition (& scalityUIComponent .Status .Conditions , metav1.Condition {
211222 Type : "ConfigurationRetrieved" ,
212- Status : metav1 .ConditionTrue ,
213- Reason : "FetchSucceeded " ,
214- Message : "Successfully fetched and applied UI component configuration" ,
223+ Status : metav1 .ConditionFalse ,
224+ Reason : "FetchFailed " ,
225+ Message : fmt . Sprintf ( "Failed to fetch configuration: %v" , err ) ,
215226 LastTransitionTime : metav1 .Now (),
216227 })
217228
218- // Update the status
219- if err := r .Status ().Update (ctx , scalityUIComponent ); err != nil {
220- logger .Error (err , "Failed to update status with configuration" )
221- return ctrl.Result {}, err
229+ if updateErr := r .Status ().Update (ctx , scalityUIComponent ); updateErr != nil {
230+ logger .Error (updateErr , "Failed to update status with failure condition" )
222231 }
223232
224- logger .Info ("ScalityUIComponent status updated with configuration" ,
225- "kind" , scalityUIComponent .Status .Kind ,
226- "publicPath" , scalityUIComponent .Status .PublicPath ,
227- "version" , scalityUIComponent .Status .Version )
228- } else {
229- logger .Info ("Deployment not ready yet, waiting for pods to start" )
230233 return ctrl.Result {RequeueAfter : time .Second * 10 }, nil
231234 }
232235
236+ // Parse and apply configuration
237+ result , err := r .parseAndApplyConfig (ctx , scalityUIComponent , configContent )
238+ if err != nil {
239+ return result , nil // Error handling is done in parseAndApplyConfig
240+ }
241+
242+ logger .Info ("ScalityUIComponent status updated with configuration" ,
243+ "kind" , scalityUIComponent .Status .Kind ,
244+ "publicPath" , scalityUIComponent .Status .PublicPath ,
245+ "version" , scalityUIComponent .Status .Version )
246+
233247 return ctrl.Result {}, nil
234248}
235249
236- func (r * ScalityUIComponentReconciler ) fetchMicroAppConfig (ctx context.Context , namespace , serviceName string ) (string , error ) {
250+ // parseAndApplyConfig parses the configuration content and updates the ScalityUIComponent status
251+ func (r * ScalityUIComponentReconciler ) parseAndApplyConfig (ctx context.Context ,
252+ scalityUIComponent * uiv1alpha1.ScalityUIComponent , configContent string ) (ctrl.Result , error ) {
237253 logger := log .FromContext (ctx )
238254
239- clientset , err := kubernetes .NewForConfig (r .Config )
240- if err != nil {
241- logger .Error (err , "Failed to create clientset" )
242- return "" , err
255+ var config MicroAppConfig
256+ if err := json .Unmarshal ([]byte (configContent ), & config ); err != nil {
257+ logger .Error (err , "Failed to parse micro-app-configuration" )
258+
259+ // Add a failure condition
260+ meta .SetStatusCondition (& scalityUIComponent .Status .Conditions , metav1.Condition {
261+ Type : "ConfigurationRetrieved" ,
262+ Status : metav1 .ConditionFalse ,
263+ Reason : "ParseFailed" ,
264+ Message : fmt .Sprintf ("Failed to parse configuration: %v" , err ),
265+ LastTransitionTime : metav1 .Now (),
266+ })
267+
268+ if updateErr := r .Status ().Update (ctx , scalityUIComponent ); updateErr != nil {
269+ logger .Error (updateErr , "Failed to update status with failure condition" )
270+ }
271+
272+ return ctrl.Result {RequeueAfter : time .Second * 10 }, err
243273 }
244274
245- restClient := clientset .CoreV1 ().RESTClient ()
246- req := restClient .Get ().
247- Namespace (namespace ).
248- Resource ("services" ).
249- Name (fmt .Sprintf ("%s:%d" , serviceName , DefaultServicePort )).
250- SubResource ("proxy" ).
251- Suffix ("/.well-known/micro-app-configuration" )
275+ // Update status with retrieved information
276+ scalityUIComponent .Status .Kind = config .Metadata .Kind
277+ scalityUIComponent .Status .PublicPath = config .Spec .PublicPath
278+ scalityUIComponent .Status .Version = config .Spec .Version
279+
280+ // Add a success condition
281+ meta .SetStatusCondition (& scalityUIComponent .Status .Conditions , metav1.Condition {
282+ Type : "ConfigurationRetrieved" ,
283+ Status : metav1 .ConditionTrue ,
284+ Reason : "FetchSucceeded" ,
285+ Message : "Successfully fetched and applied UI component configuration" ,
286+ LastTransitionTime : metav1 .Now (),
287+ })
252288
253- // Execute the request
254- result := req .Do (ctx )
255- raw , err := result .Raw ()
256- if err != nil {
257- logger .Error (err , "Failed to get configuration" )
258- return "" , err
289+ // Update the status
290+ if err := r .Status ().Update (ctx , scalityUIComponent ); err != nil {
291+ logger .Error (err , "Failed to update status with configuration" )
292+ return ctrl.Result {}, err
259293 }
260294
261- return string (raw ), nil
295+ return ctrl.Result {}, nil
296+ }
297+
298+ func (r * ScalityUIComponentReconciler ) fetchMicroAppConfig (ctx context.Context , namespace , serviceName string ) (string , error ) {
299+ // Use the ConfigFetcher if available, otherwise use the default K8sServiceProxyFetcher
300+ if r .ConfigFetcher != nil {
301+ return r .ConfigFetcher .FetchConfig (ctx , namespace , serviceName , DefaultServicePort )
302+ }
303+
304+ // Default implementation using K8s service proxy
305+ fetcher := & K8sServiceProxyFetcher {Config : r .Config }
306+ return fetcher .FetchConfig (ctx , namespace , serviceName , DefaultServicePort )
262307}
263308
264309// SetupWithManager sets up the controller with the Manager.
265310func (r * ScalityUIComponentReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
266311 // Store the Kubernetes REST configuration for later use in API requests
267312 r .Config = mgr .GetConfig ()
268313
314+ // Initialize the default config fetcher if not explicitly provided
315+ if r .ConfigFetcher == nil {
316+ r .ConfigFetcher = & K8sServiceProxyFetcher {Config : r .Config }
317+ }
318+
269319 return ctrl .NewControllerManagedBy (mgr ).
270320 For (& uiv1alpha1.ScalityUIComponent {}).
271321 Owns (& appsv1.Deployment {}).
0 commit comments