Skip to content

Commit 4da0809

Browse files
committed
Refactor ScalityUI deployment
1 parent 718124d commit 4da0809

File tree

2 files changed

+158
-89
lines changed

2 files changed

+158
-89
lines changed

internal/controller/scalityui_controller.go

Lines changed: 155 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -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
195263
type 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{

internal/controller/scalityui_controller_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ var _ = Describe("ScalityUI Controller", func() {
4343
productName = "Test Product"
4444
imageName = "nginx:latest"
4545
baseMountPath = "/usr/share/nginx/html/shell" // Updated to match controller
46-
configMapDeployedAppsExt = "-deployed-apps"
46+
configMapDeployedAppsExt = "-deployed-ui-apps"
4747
)
4848

4949
ctx := context.Background()
@@ -175,7 +175,7 @@ var _ = Describe("ScalityUI Controller", func() {
175175
SubPath: "config.json",
176176
},
177177
corev1.VolumeMount{
178-
Name: resourceName + "-deployed-apps-volume",
178+
Name: resourceName + "-deployed-ui-apps-volume",
179179
MountPath: filepath.Join(baseMountPath, "deployed-ui-apps.json"),
180180
SubPath: "deployed-ui-apps.json",
181181
},
@@ -196,7 +196,7 @@ var _ = Describe("ScalityUI Controller", func() {
196196
},
197197
},
198198
corev1.Volume{
199-
Name: resourceName + "-deployed-apps-volume",
199+
Name: resourceName + "-deployed-ui-apps-volume",
200200
VolumeSource: corev1.VolumeSource{
201201
ConfigMap: &corev1.ConfigMapVolumeSource{
202202
LocalObjectReference: corev1.LocalObjectReference{Name: resourceName + configMapDeployedAppsExt},

0 commit comments

Comments
 (0)