Skip to content

Commit 70a0abf

Browse files
committed
Scope resource names to CR instance for multi-CR support
Multiple OpenStackLightspeed CRs in the same namespace failed because all Kubernetes resources used hardcoded names, causing ownership conflicts on the second CR. Convert resource name constants to functions that prefix with the instance name and add app.kubernetes.io/instance to label selectors so each CR manages its own isolated set of resources.
1 parent c60a659 commit 70a0abf

15 files changed

Lines changed: 295 additions & 234 deletions

internal/controller/ca_bundle.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ func reconcileCABundleConfigMap(h *common_helper.Helper, ctx context.Context, in
170170

171171
cm := &corev1.ConfigMap{
172172
ObjectMeta: metav1.ObjectMeta{
173-
Name: CABundleConfigMapName,
173+
Name: CABundleConfigMapName(instance.Name),
174174
Namespace: h.GetBeforeObject().GetNamespace(),
175175
},
176176
}

internal/controller/ca_bundle_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ func TestReconcileCABundle_MergesServiceCA(t *testing.T) {
480480

481481
resultCM := &corev1.ConfigMap{}
482482
err = h.GetClient().Get(ctx, types.NamespacedName{
483-
Name: CABundleConfigMapName,
483+
Name: CABundleConfigMapName("test-instance"),
484484
Namespace: "test-ns",
485485
}, resultCM)
486486
if err != nil {
@@ -620,7 +620,7 @@ func TestReconcileCABundle_DeduplicatesAcrossSources(t *testing.T) {
620620

621621
resultCM := &corev1.ConfigMap{}
622622
err = h.GetClient().Get(ctx, types.NamespacedName{
623-
Name: CABundleConfigMapName,
623+
Name: CABundleConfigMapName("test-instance"),
624624
Namespace: "test-ns",
625625
}, resultCM)
626626
if err != nil {

internal/controller/common.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,10 @@ func getRawClient(helper *common_helper.Helper) (client.Client, error) {
5757
return rawClient, nil
5858
}
5959

60-
// generateAppServerSelectorLabels returns a map of labels used as selectors
61-
// for the application server pods.
62-
func generateAppServerSelectorLabels() map[string]string {
60+
func generateAppServerSelectorLabels(instanceName string) map[string]string {
6361
return map[string]string{
6462
"app.kubernetes.io/component": "app-server",
63+
"app.kubernetes.io/instance": instanceName,
6564
"app.kubernetes.io/managed-by": "openstack-lightspeed-operator",
6665
"app.kubernetes.io/name": "openstack-lightspeed-app-server",
6766
"app.kubernetes.io/part-of": "openstack-lightspeed",
@@ -92,10 +91,10 @@ func providerNameToEnvVarName(providerName string) string {
9291
return name
9392
}
9493

95-
// generatePostgresSelectorLabels returns selector labels for Postgres components.
96-
func generatePostgresSelectorLabels() map[string]string {
94+
func generatePostgresSelectorLabels(instanceName string) map[string]string {
9795
return map[string]string{
9896
"app.kubernetes.io/component": "postgres-server",
97+
"app.kubernetes.io/instance": instanceName,
9998
"app.kubernetes.io/managed-by": "openstack-lightspeed-operator",
10099
"app.kubernetes.io/name": "openstack-lightspeed-service-postgres",
101100
"app.kubernetes.io/part-of": "openstack-lightspeed",
@@ -120,10 +119,10 @@ func isDeploymentReady(deploy *appsv1.Deployment) bool {
120119
deploy.Status.Replicas == replicas
121120
}
122121

123-
// generateOKPSelectorLabels returns selector labels for OKP components.
124-
func generateOKPSelectorLabels() map[string]string {
122+
func generateOKPSelectorLabels(instanceName string) map[string]string {
125123
return map[string]string{
126124
"app.kubernetes.io/component": "okp-server",
125+
"app.kubernetes.io/instance": instanceName,
127126
"app.kubernetes.io/managed-by": "openstack-lightspeed-operator",
128127
"app.kubernetes.io/name": "openstack-lightspeed-okp-server",
129128
"app.kubernetes.io/part-of": "openstack-lightspeed",

internal/controller/console_deployment.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,10 @@ import (
2828
"k8s.io/apimachinery/pkg/util/intstr"
2929
)
3030

31-
// generateConsoleSelectorLabels returns a map of labels used as selectors
32-
// for the console plugin pods.
33-
func generateConsoleSelectorLabels() map[string]string {
31+
func generateConsoleSelectorLabels(instanceName string) map[string]string {
3432
return map[string]string{
3533
"app.kubernetes.io/component": "console-plugin",
34+
"app.kubernetes.io/instance": instanceName,
3635
"app.kubernetes.io/managed-by": "openstack-lightspeed-operator",
3736
"app.kubernetes.io/name": "lightspeed-console-plugin",
3837
"app.kubernetes.io/part-of": "openstack-lightspeed",
@@ -48,10 +47,10 @@ const consoleLocalesPath = "/usr/share/nginx/html/locales/en/" + consoleLocalesF
4847
// buildConsoleDeploymentSpec builds the Deployment spec for the console plugin.
4948
// Includes an init container that rewrites OpenShift references to OpenStack
5049
// in the locales JSON file using an emptyDir volume.
51-
func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec {
50+
func buildConsoleDeploymentSpec(instanceName string, consoleImage string) appsv1.DeploymentSpec {
5251
replicas := int32(1)
5352
volumeDefaultMode := VolumeDefaultMode
54-
labels := generateConsoleSelectorLabels()
53+
labels := generateConsoleSelectorLabels(instanceName)
5554

5655
return appsv1.DeploymentSpec{
5756
Replicas: &replicas,
@@ -69,7 +68,7 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec {
6968
Type: corev1.SeccompProfileTypeRuntimeDefault,
7069
},
7170
},
72-
ServiceAccountName: ConsoleUIServiceAccountName,
71+
ServiceAccountName: ConsoleUIServiceAccountName(instanceName),
7372
InitContainers: []corev1.Container{
7473
{
7574
Name: "rewrite-locales",
@@ -159,7 +158,7 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec {
159158
Name: "lightspeed-console-plugin-cert",
160159
VolumeSource: corev1.VolumeSource{
161160
Secret: &corev1.SecretVolumeSource{
162-
SecretName: ConsoleUIServiceCertSecretName,
161+
SecretName: ConsoleUIServiceCertSecretName(instanceName),
163162
DefaultMode: &volumeDefaultMode,
164163
},
165164
},
@@ -169,7 +168,7 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec {
169168
VolumeSource: corev1.VolumeSource{
170169
ConfigMap: &corev1.ConfigMapVolumeSource{
171170
LocalObjectReference: corev1.LocalObjectReference{
172-
Name: ConsoleUIConfigMapName,
171+
Name: ConsoleUIConfigMapName(instanceName),
173172
},
174173
DefaultMode: &volumeDefaultMode,
175174
},
@@ -194,11 +193,11 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec {
194193
}
195194

196195
// buildConsolePluginSpec builds the ConsolePlugin spec with backend and proxy configuration.
197-
func buildConsolePluginSpec(namespace string) consolev1.ConsolePluginSpec {
196+
func buildConsolePluginSpec(instanceName string, namespace string) consolev1.ConsolePluginSpec {
198197
return consolev1.ConsolePluginSpec{
199198
Backend: consolev1.ConsolePluginBackend{
200199
Service: &consolev1.ConsolePluginService{
201-
Name: ConsoleUIServiceName,
200+
Name: ConsoleUIServiceName(instanceName),
202201
Namespace: namespace,
203202
Port: ConsoleUIHTTPSPort,
204203
BasePath: "/",
@@ -215,7 +214,7 @@ func buildConsolePluginSpec(namespace string) consolev1.ConsolePluginSpec {
215214
Authorization: consolev1.UserToken,
216215
Endpoint: consolev1.ConsolePluginProxyEndpoint{
217216
Service: &consolev1.ConsolePluginProxyServiceConfig{
218-
Name: OpenStackLightspeedAppServerServiceName,
217+
Name: OpenStackLightspeedAppServerServiceName(instanceName),
219218
Namespace: namespace,
220219
Port: OpenStackLightspeedAppServerServicePort,
221220
},
@@ -232,10 +231,10 @@ func buildConsoleNginxConfig() string {
232231
}
233232

234233
// buildConsoleNetworkPolicySpec builds the NetworkPolicy spec for the console plugin.
235-
func buildConsoleNetworkPolicySpec() networkingv1.NetworkPolicySpec {
234+
func buildConsoleNetworkPolicySpec(instanceName string) networkingv1.NetworkPolicySpec {
236235
return networkingv1.NetworkPolicySpec{
237236
PodSelector: metav1.LabelSelector{
238-
MatchLabels: generateConsoleSelectorLabels(),
237+
MatchLabels: generateConsoleSelectorLabels(instanceName),
239238
},
240239
Ingress: []networkingv1.NetworkPolicyIngressRule{
241240
{

internal/controller/console_reconciler.go

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ func ReconcileConsoleDeployment(h *common_helper.Helper, ctx context.Context, in
6969
}
7070

7171
// reconcileConsoleConfigMap ensures the console plugin nginx ConfigMap exists.
72-
func reconcileConsoleConfigMap(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
72+
func reconcileConsoleConfigMap(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
7373
logger := h.GetLogger()
7474

7575
cm := &corev1.ConfigMap{
7676
ObjectMeta: metav1.ObjectMeta{
77-
Name: ConsoleUIConfigMapName,
77+
Name: ConsoleUIConfigMapName(instance.Name),
7878
Namespace: h.GetBeforeObject().GetNamespace(),
7979
},
8080
}
@@ -95,18 +95,18 @@ func reconcileConsoleConfigMap(h *common_helper.Helper, ctx context.Context, _ *
9595
}
9696

9797
// reconcileConsoleNetworkPolicy ensures the console plugin network policy exists.
98-
func reconcileConsoleNetworkPolicy(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
98+
func reconcileConsoleNetworkPolicy(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
9999
logger := h.GetLogger()
100100

101101
np := &networkingv1.NetworkPolicy{
102102
ObjectMeta: metav1.ObjectMeta{
103-
Name: ConsoleUINetworkPolicyName,
103+
Name: ConsoleUINetworkPolicyName(instance.Name),
104104
Namespace: h.GetBeforeObject().GetNamespace(),
105105
},
106106
}
107107

108108
result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), np, func() error {
109-
np.Spec = buildConsoleNetworkPolicySpec()
109+
np.Spec = buildConsoleNetworkPolicySpec(instance.Name)
110110
return controllerutil.SetControllerReference(h.GetBeforeObject(), np, h.GetScheme())
111111
})
112112

@@ -119,12 +119,12 @@ func reconcileConsoleNetworkPolicy(h *common_helper.Helper, ctx context.Context,
119119
}
120120

121121
// reconcileConsoleServiceAccount ensures the console plugin service account exists.
122-
func reconcileConsoleServiceAccount(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
122+
func reconcileConsoleServiceAccount(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
123123
logger := h.GetLogger()
124124

125125
sa := &corev1.ServiceAccount{
126126
ObjectMeta: metav1.ObjectMeta{
127-
Name: ConsoleUIServiceAccountName,
127+
Name: ConsoleUIServiceAccountName(instance.Name),
128128
Namespace: h.GetBeforeObject().GetNamespace(),
129129
},
130130
}
@@ -181,20 +181,20 @@ func resolveConsoleImage(ctx context.Context, h *common_helper.Helper) string {
181181
}
182182

183183
// reconcileConsoleDeploymentResource ensures the console plugin deployment exists.
184-
func reconcileConsoleDeploymentResource(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
184+
func reconcileConsoleDeploymentResource(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
185185
logger := h.GetLogger()
186186

187187
consoleImage := resolveConsoleImage(ctx, h)
188188

189189
deployment := &appsv1.Deployment{
190190
ObjectMeta: metav1.ObjectMeta{
191-
Name: ConsoleUIDeploymentName,
191+
Name: ConsoleUIDeploymentName(instance.Name),
192192
Namespace: h.GetBeforeObject().GetNamespace(),
193193
},
194194
}
195195

196196
result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), deployment, func() error {
197-
spec := buildConsoleDeploymentSpec(consoleImage)
197+
spec := buildConsoleDeploymentSpec(instance.Name, consoleImage)
198198
deployment.Spec.Replicas = spec.Replicas
199199
deployment.Spec.Selector = spec.Selector
200200
deployment.Spec.Template = spec.Template
@@ -210,18 +210,18 @@ func reconcileConsoleDeploymentResource(h *common_helper.Helper, ctx context.Con
210210
}
211211

212212
// reconcileConsoleService ensures the console plugin service exists.
213-
func reconcileConsoleService(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
213+
func reconcileConsoleService(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
214214
logger := h.GetLogger()
215215

216216
svc := &corev1.Service{
217217
ObjectMeta: metav1.ObjectMeta{
218-
Name: ConsoleUIServiceName,
218+
Name: ConsoleUIServiceName(instance.Name),
219219
Namespace: h.GetBeforeObject().GetNamespace(),
220220
},
221221
}
222222

223223
result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), svc, func() error {
224-
svc.Spec.Selector = generateConsoleSelectorLabels()
224+
svc.Spec.Selector = generateConsoleSelectorLabels(instance.Name)
225225
svc.Spec.Ports = []corev1.ServicePort{
226226
{
227227
Port: ConsoleUIHTTPSPort,
@@ -235,7 +235,7 @@ func reconcileConsoleService(h *common_helper.Helper, ctx context.Context, _ *ap
235235
if svc.Annotations == nil {
236236
svc.Annotations = make(map[string]string)
237237
}
238-
svc.Annotations[ServingCertSecretAnnotationKey] = ConsoleUIServiceCertSecretName
238+
svc.Annotations[ServingCertSecretAnnotationKey] = ConsoleUIServiceCertSecretName(instance.Name)
239239

240240
return controllerutil.SetControllerReference(h.GetBeforeObject(), svc, h.GetScheme())
241241
})
@@ -250,12 +250,12 @@ func reconcileConsoleService(h *common_helper.Helper, ctx context.Context, _ *ap
250250

251251
// reconcileConsoleTLSSecret waits for the console TLS secret to be populated by
252252
// the service-ca operator.
253-
func reconcileConsoleTLSSecret(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
253+
func reconcileConsoleTLSSecret(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
254254
logger := h.GetLogger()
255-
logger.Info("waiting for console TLS secret", "name", ConsoleUIServiceCertSecretName)
255+
logger.Info("waiting for console TLS secret", "name", ConsoleUIServiceCertSecretName(instance.Name))
256256

257257
secretKey := client.ObjectKey{
258-
Name: ConsoleUIServiceCertSecretName,
258+
Name: ConsoleUIServiceCertSecretName(instance.Name),
259259
Namespace: h.GetBeforeObject().GetNamespace(),
260260
}
261261

@@ -275,23 +275,23 @@ func reconcileConsoleTLSSecret(h *common_helper.Helper, ctx context.Context, _ *
275275
return fmt.Errorf("%w: %v", ErrReconcileConsoleTLSSecret, err)
276276
}
277277

278-
logger.Info("Console TLS secret is ready", "name", ConsoleUIServiceCertSecretName)
278+
logger.Info("Console TLS secret is ready", "name", ConsoleUIServiceCertSecretName(instance.Name))
279279
return nil
280280
}
281281

282282
// reconcileConsolePlugin ensures the ConsolePlugin CR exists.
283-
func reconcileConsolePlugin(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
283+
func reconcileConsolePlugin(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
284284
logger := h.GetLogger()
285285
namespace := h.GetBeforeObject().GetNamespace()
286286

287287
plugin := &consolev1.ConsolePlugin{
288288
ObjectMeta: metav1.ObjectMeta{
289-
Name: ConsoleUIPluginName,
289+
Name: ConsoleUIPluginName(instance.Name),
290290
},
291291
}
292292

293293
result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), plugin, func() error {
294-
plugin.Spec = buildConsolePluginSpec(namespace)
294+
plugin.Spec = buildConsolePluginSpec(instance.Name, namespace)
295295
// ConsolePlugin is cluster-scoped, no owner reference
296296
return nil
297297
})
@@ -305,8 +305,9 @@ func reconcileConsolePlugin(h *common_helper.Helper, ctx context.Context, _ *api
305305
}
306306

307307
// activateConsole adds the console plugin to the Console CR's plugin list.
308-
func activateConsole(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
308+
func activateConsole(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
309309
logger := h.GetLogger()
310+
pluginName := ConsoleUIPluginName(instance.Name)
310311

311312
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
312313
console := &openshiftv1.Console{}
@@ -320,9 +321,9 @@ func activateConsole(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1
320321
}
321322

322323
if console.Spec.Plugins == nil {
323-
console.Spec.Plugins = []string{ConsoleUIPluginName}
324-
} else if !slices.Contains(console.Spec.Plugins, ConsoleUIPluginName) {
325-
console.Spec.Plugins = append(console.Spec.Plugins, ConsoleUIPluginName)
324+
console.Spec.Plugins = []string{pluginName}
325+
} else if !slices.Contains(console.Spec.Plugins, pluginName) {
326+
console.Spec.Plugins = append(console.Spec.Plugins, pluginName)
326327
} else {
327328
return nil
328329
}
@@ -338,8 +339,9 @@ func activateConsole(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1
338339
}
339340

340341
// reconcileDeleteConsole deactivates the console plugin and deletes the ConsolePlugin CR.
341-
func reconcileDeleteConsole(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
342+
func reconcileDeleteConsole(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
342343
logger := h.GetLogger()
344+
pluginName := ConsoleUIPluginName(instance.Name)
343345

344346
// Deactivate: remove plugin from Console CR
345347
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
@@ -356,12 +358,12 @@ func reconcileDeleteConsole(h *common_helper.Helper, ctx context.Context, _ *api
356358
if console.Spec.Plugins == nil {
357359
return nil
358360
}
359-
if !slices.Contains(console.Spec.Plugins, ConsoleUIPluginName) {
361+
if !slices.Contains(console.Spec.Plugins, pluginName) {
360362
return nil
361363
}
362364

363365
console.Spec.Plugins = slices.DeleteFunc(console.Spec.Plugins, func(name string) bool {
364-
return name == ConsoleUIPluginName
366+
return name == pluginName
365367
})
366368

367369
return h.GetClient().Update(ctx, console)
@@ -373,7 +375,7 @@ func reconcileDeleteConsole(h *common_helper.Helper, ctx context.Context, _ *api
373375

374376
// Delete ConsolePlugin CR
375377
plugin := &consolev1.ConsolePlugin{}
376-
err = h.GetClient().Get(ctx, client.ObjectKey{Name: ConsoleUIPluginName}, plugin)
378+
err = h.GetClient().Get(ctx, client.ObjectKey{Name: pluginName}, plugin)
377379
if err != nil {
378380
if errors.IsNotFound(err) {
379381
logger.Info("ConsolePlugin not found, skip deletion")

0 commit comments

Comments
 (0)