@@ -115,82 +115,150 @@ func (r *ScalityUIReconciler) createOrUpdateDeployment(ctx context.Context, depl
115115 return fmt .Errorf ("failed to set owner reference on Deployment %s/%s: %w" , deploy .Namespace , deploy .Name , err )
116116 }
117117
118- mountPath := "/usr/share/nginx/html/shell"
118+ // Ensure selector and basic strategy
119+ if deploy .Spec .Selector == nil {
120+ deploy .Spec .Selector = & metav1.LabelSelector {
121+ MatchLabels : make (map [string ]string ),
122+ }
123+ }
124+ deploy .Spec .Selector .MatchLabels ["app" ] = scalityui .Name
125+
126+ one := int32 (1 )
127+ if deploy .Spec .Replicas == nil {
128+ deploy .Spec .Replicas = & one
129+ } else {
130+ * deploy .Spec .Replicas = one
131+ }
132+
133+ zeroIntStr := intstr .FromInt (0 )
134+ oneIntStr := intstr .FromInt (1 )
135+ if deploy .Spec .Strategy .Type == "" {
136+ deploy .Spec .Strategy .Type = appsv1 .RollingUpdateDeploymentStrategyType
137+ }
138+ if deploy .Spec .Strategy .RollingUpdate == nil {
139+ deploy .Spec .Strategy .RollingUpdate = & appsv1.RollingUpdateDeployment {
140+ MaxUnavailable : & zeroIntStr ,
141+ MaxSurge : & oneIntStr ,
142+ }
143+ } else {
144+ if deploy .Spec .Strategy .RollingUpdate .MaxUnavailable == nil {
145+ deploy .Spec .Strategy .RollingUpdate .MaxUnavailable = & zeroIntStr
146+ }
147+ if deploy .Spec .Strategy .RollingUpdate .MaxSurge == nil {
148+ deploy .Spec .Strategy .RollingUpdate .MaxSurge = & oneIntStr
149+ }
150+ }
151+
152+ // Manage PodTemplate Labels
153+ if deploy .Spec .Template .Labels == nil {
154+ deploy .Spec .Template .Labels = make (map [string ]string )
155+ }
156+ deploy .Spec .Template .Labels ["app" ] = scalityui .Name
157+
158+ // Manage PodTemplate Annotations
159+ if deploy .Spec .Template .Annotations == nil {
160+ deploy .Spec .Template .Annotations = make (map [string ]string )
161+ }
162+ deploy .Spec .Template .Annotations ["checksum/config" ] = configHash
163+
164+ // Volume definitions
119165 configVolumeName := scalityui .Name + "-config-volume"
120- deployedAppsVolumeName := scalityui .Name + "-deployed-apps-volume"
121- configMapDeployedAppsName := scalityui .Name + "-deployed-apps"
122-
123- zero := intstr .FromInt (0 )
124- one := intstr .FromInt (1 )
125-
126- deploy .Spec = appsv1.DeploymentSpec {
127- Replicas : & []int32 {1 }[0 ],
128- Strategy : appsv1.DeploymentStrategy {
129- Type : appsv1 .RollingUpdateDeploymentStrategyType ,
130- RollingUpdate : & appsv1.RollingUpdateDeployment {
131- MaxUnavailable : & zero ,
132- MaxSurge : & one ,
133- },
134- },
135- Selector : & metav1.LabelSelector {
136- MatchLabels : map [string ]string {"app" : scalityui .Name },
137- },
138- Template : corev1.PodTemplateSpec {
139- ObjectMeta : metav1.ObjectMeta {
140- Labels : map [string ]string {"app" : scalityui .Name },
141- Annotations : map [string ]string {
142- "checksum/config" : configHash ,
166+ deployedAppsVolumeName := scalityui .Name + "-deployed-ui-apps-volume"
167+ configMapDeployedAppsName := scalityui .Name + "-deployed-ui-apps"
168+
169+ configVolume := corev1.Volume {
170+ Name : configVolumeName ,
171+ VolumeSource : corev1.VolumeSource {
172+ ConfigMap : & corev1.ConfigMapVolumeSource {
173+ LocalObjectReference : corev1.LocalObjectReference {
174+ Name : scalityui .Name , // ConfigMap for config.json
143175 },
144176 },
145- Spec : corev1.PodSpec {
146- Containers : []corev1.Container {
147- {
148- Name : scalityui .Name ,
149- Image : scalityui .Spec .Image ,
150- VolumeMounts : []corev1.VolumeMount {
151- {
152- Name : configVolumeName ,
153- MountPath : filepath .Join (mountPath , "config.json" ),
154- SubPath : "config.json" ,
155- },
156- {
157- Name : deployedAppsVolumeName ,
158- MountPath : filepath .Join (mountPath , "deployed-ui-apps.json" ),
159- SubPath : "deployed-ui-apps.json" ,
160- },
161- },
162- },
163- },
164- Volumes : []corev1.Volume {
165- {
166- Name : configVolumeName ,
167- VolumeSource : corev1.VolumeSource {
168- ConfigMap : & corev1.ConfigMapVolumeSource {
169- LocalObjectReference : corev1.LocalObjectReference {
170- Name : scalityui .Name , // Name of the ConfigMap for config.json
171- },
172- },
173- },
174- },
175- {
176- Name : deployedAppsVolumeName ,
177- VolumeSource : corev1.VolumeSource {
178- ConfigMap : & corev1.ConfigMapVolumeSource {
179- LocalObjectReference : corev1.LocalObjectReference {
180- Name : configMapDeployedAppsName , // Name of the ConfigMap for deployed-ui-apps.json
181- },
182- },
183- },
184- },
177+ },
178+ }
179+ deployedAppsVolume := corev1.Volume {
180+ Name : deployedAppsVolumeName ,
181+ VolumeSource : corev1.VolumeSource {
182+ ConfigMap : & corev1.ConfigMapVolumeSource {
183+ LocalObjectReference : corev1.LocalObjectReference {
184+ Name : configMapDeployedAppsName , // ConfigMap for deployed-ui-apps.json
185185 },
186186 },
187187 },
188188 }
189189
190+ // Ensure volumes exist
191+ volumes := & deploy .Spec .Template .Spec .Volumes
192+ * volumes = ensureVolume (* volumes , configVolume )
193+ * volumes = ensureVolume (* volumes , deployedAppsVolume )
194+
195+ // Container and VolumeMount definitions
196+ mountPath := "/usr/share/nginx/html/shell"
197+ containerName := scalityui .Name
198+
199+ configVolumeMount := corev1.VolumeMount {
200+ Name : configVolumeName ,
201+ MountPath : filepath .Join (mountPath , "config.json" ),
202+ SubPath : "config.json" ,
203+ }
204+ deployedAppsVolumeMount := corev1.VolumeMount {
205+ Name : deployedAppsVolumeName ,
206+ MountPath : filepath .Join (mountPath , "deployed-ui-apps.json" ),
207+ SubPath : "deployed-ui-apps.json" ,
208+ }
209+
210+ // Find or create the main container
211+ var mainContainer * corev1.Container
212+ containerFound := false
213+ for i := range deploy .Spec .Template .Spec .Containers {
214+ if deploy .Spec .Template .Spec .Containers [i ].Name == containerName {
215+ mainContainer = & deploy .Spec .Template .Spec .Containers [i ]
216+ containerFound = true
217+ break
218+ }
219+ }
220+
221+ if ! containerFound {
222+ deploy .Spec .Template .Spec .Containers = append (deploy .Spec .Template .Spec .Containers , corev1.Container {Name : containerName })
223+ mainContainer = & deploy .Spec .Template .Spec .Containers [len (deploy .Spec .Template .Spec .Containers )- 1 ]
224+ }
225+
226+ // Set image for the main container
227+ mainContainer .Image = scalityui .Spec .Image
228+
229+ // Ensure volume mounts exist in the main container
230+ mounts := & mainContainer .VolumeMounts
231+ * mounts = ensureVolumeMount (* mounts , configVolumeMount )
232+ * mounts = ensureVolumeMount (* mounts , deployedAppsVolumeMount )
233+
190234 return nil
191235 })
192236}
193237
238+ // ensureVolume checks if a volume exists in the slice and updates/adds it.
239+ // It returns the modified slice of volumes.
240+ func ensureVolume (volumes []corev1.Volume , desiredVolume corev1.Volume ) []corev1.Volume {
241+ for i , vol := range volumes {
242+ if vol .Name == desiredVolume .Name {
243+ volumes [i ] = desiredVolume // Update existing volume
244+ return volumes
245+ }
246+ }
247+ return append (volumes , desiredVolume ) // Add new volume
248+ }
249+
250+ // ensureVolumeMount checks if a volumeMount exists in the slice and updates/adds it.
251+ // It returns the modified slice of volumeMounts.
252+ func ensureVolumeMount (volumeMounts []corev1.VolumeMount , desiredMount corev1.VolumeMount ) []corev1.VolumeMount {
253+ for i , mount := range volumeMounts {
254+ if mount .Name == desiredMount .Name {
255+ volumeMounts [i ] = desiredMount // Update existing mount
256+ return volumeMounts
257+ }
258+ }
259+ return append (volumeMounts , desiredMount ) // Add new mount
260+ }
261+
194262// ScalityUIReconciler reconciles a ScalityUI object
195263type ScalityUIReconciler struct {
196264 client.Client
@@ -256,40 +324,41 @@ func (r *ScalityUIReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
256324
257325 logOperationResult (r .Log , configMapResult , "ConfigMap config.json" , configMap .Name )
258326
259- // Verify ConfigMap for config.json exists
260- err = r .Client .Get (ctx , client.ObjectKey {Name : configMap .Name , Namespace : configMap .Namespace }, & corev1.ConfigMap {})
261- if err != nil {
262- r .Log .Error (err , "ConfigMap for config.json was not created successfully" )
263- return ctrl.Result {}, err
264- }
265- r .Log .Info ("ConfigMap config.json exists" , "name" , configMap .Name )
266-
267- // Define ConfigMap for deployed-ui-apps.json
268- configMapDeployedAppsName := scalityui .Name + "-deployed-apps"
327+ // Define and manage ConfigMap for deployed-ui-apps.json
328+ configMapDeployedAppsName := scalityui .Name + "-deployed-ui-apps"
269329 configMapDeployedApps := & corev1.ConfigMap {
270330 ObjectMeta : metav1.ObjectMeta {
271331 Name : configMapDeployedAppsName ,
272332 Namespace : scalityui .Namespace ,
273333 },
274334 }
275- deployedAppsData := map [string ]string {"deployed-ui-apps.json" : "[]" }
276335
277- // Create or update ConfigMap for deployed-ui-apps.json
278- configMapDeployedAppsResult , err := r . createOrUpdateOwnedConfigMap ( ctx , scalityui , configMapDeployedApps , deployedAppsData )
279- if err != nil {
280- r . Log . Error ( err , "Failed to create or update ConfigMap for deployed-ui-apps.json" )
281- return ctrl. Result {}, err
282- }
336+ // Use CreateOrUpdate to ensure the ConfigMap exists and has the correct owner reference.
337+ // The data for "deployed-ui-apps.json" should only be initialized if it's missing.
338+ opResultDeployedApps , err := controllerutil . CreateOrUpdate ( ctx , r . Client , configMapDeployedApps , func () error {
339+ if err := controllerutil . SetControllerReference ( scalityui , configMapDeployedApps , r . Scheme ); err != nil {
340+ return fmt . Errorf ( "failed to set owner reference on ConfigMap %s/%s: %w" , configMapDeployedApps . Namespace , configMapDeployedApps . Name , err )
341+ }
283342
284- logOperationResult (r .Log , configMapDeployedAppsResult , "ConfigMap deployed-ui-apps.json" , configMapDeployedApps .Name )
343+ // Initialize Data map if nil
344+ if configMapDeployedApps .Data == nil {
345+ configMapDeployedApps .Data = make (map [string ]string )
346+ }
347+
348+ // Only set "deployed-ui-apps.json" if it doesn't already exist.
349+ // This allows other controllers (like ScalityUIComponentExposerReconciler) to manage its content.
350+ if _ , ok := configMapDeployedApps .Data ["deployed-ui-apps.json" ]; ! ok {
351+ configMapDeployedApps .Data ["deployed-ui-apps.json" ] = "[]" // Default to empty JSON array
352+ }
353+ return nil
354+ })
285355
286- // Verify ConfigMap for deployed-ui-apps.json exists
287- err = r .Client .Get (ctx , client.ObjectKey {Name : configMapDeployedApps .Name , Namespace : configMapDeployedApps .Namespace }, & corev1.ConfigMap {})
288356 if err != nil {
289- r .Log .Error (err , "ConfigMap for deployed-ui-apps.json was not created successfully" )
357+ r .Log .Error (err , "Failed to create or update ConfigMap for deployed-ui-apps.json" , "name" , configMapDeployedApps . Name )
290358 return ctrl.Result {}, err
291359 }
292- r .Log .Info ("ConfigMap deployed-ui-apps.json exists" , "name" , configMapDeployedApps .Name )
360+
361+ logOperationResult (r .Log , opResultDeployedApps , "ConfigMap deployed-ui-apps.json" , configMapDeployedApps .Name )
293362
294363 // Define Deployment
295364 deploy := & appsv1.Deployment {
0 commit comments