From 70a0abfaf4fee9f8fbeeaa8a329a365048c96f3a Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Sat, 13 Jun 2026 08:20:02 -0400 Subject: [PATCH] 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. --- internal/controller/ca_bundle.go | 2 +- internal/controller/ca_bundle_test.go | 4 +- internal/controller/common.go | 13 +- internal/controller/console_deployment.go | 25 ++- internal/controller/console_reconciler.go | 60 ++++--- .../controller/console_reconciler_test.go | 25 +-- internal/controller/constants.go | 167 ++++++++++++------ internal/controller/lcore_config.go | 14 +- internal/controller/lcore_deployment.go | 65 +++---- internal/controller/lcore_reconciler.go | 54 +++--- internal/controller/llama_stack_config.go | 2 +- internal/controller/okp_reconciler.go | 20 +-- .../openstacklightspeed_controller.go | 6 +- internal/controller/postgres_deployment.go | 30 ++-- internal/controller/postgres_reconciler.go | 42 ++--- 15 files changed, 295 insertions(+), 234 deletions(-) diff --git a/internal/controller/ca_bundle.go b/internal/controller/ca_bundle.go index 7c43a1d8..79607961 100644 --- a/internal/controller/ca_bundle.go +++ b/internal/controller/ca_bundle.go @@ -170,7 +170,7 @@ func reconcileCABundleConfigMap(h *common_helper.Helper, ctx context.Context, in cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: CABundleConfigMapName, + Name: CABundleConfigMapName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } diff --git a/internal/controller/ca_bundle_test.go b/internal/controller/ca_bundle_test.go index 5105ed37..ef1430cd 100644 --- a/internal/controller/ca_bundle_test.go +++ b/internal/controller/ca_bundle_test.go @@ -480,7 +480,7 @@ func TestReconcileCABundle_MergesServiceCA(t *testing.T) { resultCM := &corev1.ConfigMap{} err = h.GetClient().Get(ctx, types.NamespacedName{ - Name: CABundleConfigMapName, + Name: CABundleConfigMapName("test-instance"), Namespace: "test-ns", }, resultCM) if err != nil { @@ -620,7 +620,7 @@ func TestReconcileCABundle_DeduplicatesAcrossSources(t *testing.T) { resultCM := &corev1.ConfigMap{} err = h.GetClient().Get(ctx, types.NamespacedName{ - Name: CABundleConfigMapName, + Name: CABundleConfigMapName("test-instance"), Namespace: "test-ns", }, resultCM) if err != nil { diff --git a/internal/controller/common.go b/internal/controller/common.go index c4b4d949..03e25cb6 100644 --- a/internal/controller/common.go +++ b/internal/controller/common.go @@ -57,11 +57,10 @@ func getRawClient(helper *common_helper.Helper) (client.Client, error) { return rawClient, nil } -// generateAppServerSelectorLabels returns a map of labels used as selectors -// for the application server pods. -func generateAppServerSelectorLabels() map[string]string { +func generateAppServerSelectorLabels(instanceName string) map[string]string { return map[string]string{ "app.kubernetes.io/component": "app-server", + "app.kubernetes.io/instance": instanceName, "app.kubernetes.io/managed-by": "openstack-lightspeed-operator", "app.kubernetes.io/name": "openstack-lightspeed-app-server", "app.kubernetes.io/part-of": "openstack-lightspeed", @@ -92,10 +91,10 @@ func providerNameToEnvVarName(providerName string) string { return name } -// generatePostgresSelectorLabels returns selector labels for Postgres components. -func generatePostgresSelectorLabels() map[string]string { +func generatePostgresSelectorLabels(instanceName string) map[string]string { return map[string]string{ "app.kubernetes.io/component": "postgres-server", + "app.kubernetes.io/instance": instanceName, "app.kubernetes.io/managed-by": "openstack-lightspeed-operator", "app.kubernetes.io/name": "openstack-lightspeed-service-postgres", "app.kubernetes.io/part-of": "openstack-lightspeed", @@ -120,10 +119,10 @@ func isDeploymentReady(deploy *appsv1.Deployment) bool { deploy.Status.Replicas == replicas } -// generateOKPSelectorLabels returns selector labels for OKP components. -func generateOKPSelectorLabels() map[string]string { +func generateOKPSelectorLabels(instanceName string) map[string]string { return map[string]string{ "app.kubernetes.io/component": "okp-server", + "app.kubernetes.io/instance": instanceName, "app.kubernetes.io/managed-by": "openstack-lightspeed-operator", "app.kubernetes.io/name": "openstack-lightspeed-okp-server", "app.kubernetes.io/part-of": "openstack-lightspeed", diff --git a/internal/controller/console_deployment.go b/internal/controller/console_deployment.go index ba39845a..663ef504 100644 --- a/internal/controller/console_deployment.go +++ b/internal/controller/console_deployment.go @@ -28,11 +28,10 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" ) -// generateConsoleSelectorLabels returns a map of labels used as selectors -// for the console plugin pods. -func generateConsoleSelectorLabels() map[string]string { +func generateConsoleSelectorLabels(instanceName string) map[string]string { return map[string]string{ "app.kubernetes.io/component": "console-plugin", + "app.kubernetes.io/instance": instanceName, "app.kubernetes.io/managed-by": "openstack-lightspeed-operator", "app.kubernetes.io/name": "lightspeed-console-plugin", "app.kubernetes.io/part-of": "openstack-lightspeed", @@ -48,10 +47,10 @@ const consoleLocalesPath = "/usr/share/nginx/html/locales/en/" + consoleLocalesF // buildConsoleDeploymentSpec builds the Deployment spec for the console plugin. // Includes an init container that rewrites OpenShift references to OpenStack // in the locales JSON file using an emptyDir volume. -func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec { +func buildConsoleDeploymentSpec(instanceName string, consoleImage string) appsv1.DeploymentSpec { replicas := int32(1) volumeDefaultMode := VolumeDefaultMode - labels := generateConsoleSelectorLabels() + labels := generateConsoleSelectorLabels(instanceName) return appsv1.DeploymentSpec{ Replicas: &replicas, @@ -69,7 +68,7 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec { Type: corev1.SeccompProfileTypeRuntimeDefault, }, }, - ServiceAccountName: ConsoleUIServiceAccountName, + ServiceAccountName: ConsoleUIServiceAccountName(instanceName), InitContainers: []corev1.Container{ { Name: "rewrite-locales", @@ -159,7 +158,7 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec { Name: "lightspeed-console-plugin-cert", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: ConsoleUIServiceCertSecretName, + SecretName: ConsoleUIServiceCertSecretName(instanceName), DefaultMode: &volumeDefaultMode, }, }, @@ -169,7 +168,7 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec { VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: ConsoleUIConfigMapName, + Name: ConsoleUIConfigMapName(instanceName), }, DefaultMode: &volumeDefaultMode, }, @@ -194,11 +193,11 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec { } // buildConsolePluginSpec builds the ConsolePlugin spec with backend and proxy configuration. -func buildConsolePluginSpec(namespace string) consolev1.ConsolePluginSpec { +func buildConsolePluginSpec(instanceName string, namespace string) consolev1.ConsolePluginSpec { return consolev1.ConsolePluginSpec{ Backend: consolev1.ConsolePluginBackend{ Service: &consolev1.ConsolePluginService{ - Name: ConsoleUIServiceName, + Name: ConsoleUIServiceName(instanceName), Namespace: namespace, Port: ConsoleUIHTTPSPort, BasePath: "/", @@ -215,7 +214,7 @@ func buildConsolePluginSpec(namespace string) consolev1.ConsolePluginSpec { Authorization: consolev1.UserToken, Endpoint: consolev1.ConsolePluginProxyEndpoint{ Service: &consolev1.ConsolePluginProxyServiceConfig{ - Name: OpenStackLightspeedAppServerServiceName, + Name: OpenStackLightspeedAppServerServiceName(instanceName), Namespace: namespace, Port: OpenStackLightspeedAppServerServicePort, }, @@ -232,10 +231,10 @@ func buildConsoleNginxConfig() string { } // buildConsoleNetworkPolicySpec builds the NetworkPolicy spec for the console plugin. -func buildConsoleNetworkPolicySpec() networkingv1.NetworkPolicySpec { +func buildConsoleNetworkPolicySpec(instanceName string) networkingv1.NetworkPolicySpec { return networkingv1.NetworkPolicySpec{ PodSelector: metav1.LabelSelector{ - MatchLabels: generateConsoleSelectorLabels(), + MatchLabels: generateConsoleSelectorLabels(instanceName), }, Ingress: []networkingv1.NetworkPolicyIngressRule{ { diff --git a/internal/controller/console_reconciler.go b/internal/controller/console_reconciler.go index 739f9423..42704b1f 100644 --- a/internal/controller/console_reconciler.go +++ b/internal/controller/console_reconciler.go @@ -69,12 +69,12 @@ func ReconcileConsoleDeployment(h *common_helper.Helper, ctx context.Context, in } // reconcileConsoleConfigMap ensures the console plugin nginx ConfigMap exists. -func reconcileConsoleConfigMap(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileConsoleConfigMap(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: ConsoleUIConfigMapName, + Name: ConsoleUIConfigMapName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -95,18 +95,18 @@ func reconcileConsoleConfigMap(h *common_helper.Helper, ctx context.Context, _ * } // reconcileConsoleNetworkPolicy ensures the console plugin network policy exists. -func reconcileConsoleNetworkPolicy(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileConsoleNetworkPolicy(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() np := &networkingv1.NetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: ConsoleUINetworkPolicyName, + Name: ConsoleUINetworkPolicyName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), np, func() error { - np.Spec = buildConsoleNetworkPolicySpec() + np.Spec = buildConsoleNetworkPolicySpec(instance.Name) return controllerutil.SetControllerReference(h.GetBeforeObject(), np, h.GetScheme()) }) @@ -119,12 +119,12 @@ func reconcileConsoleNetworkPolicy(h *common_helper.Helper, ctx context.Context, } // reconcileConsoleServiceAccount ensures the console plugin service account exists. -func reconcileConsoleServiceAccount(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileConsoleServiceAccount(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() sa := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ - Name: ConsoleUIServiceAccountName, + Name: ConsoleUIServiceAccountName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -181,20 +181,20 @@ func resolveConsoleImage(ctx context.Context, h *common_helper.Helper) string { } // reconcileConsoleDeploymentResource ensures the console plugin deployment exists. -func reconcileConsoleDeploymentResource(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileConsoleDeploymentResource(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() consoleImage := resolveConsoleImage(ctx, h) deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: ConsoleUIDeploymentName, + Name: ConsoleUIDeploymentName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), deployment, func() error { - spec := buildConsoleDeploymentSpec(consoleImage) + spec := buildConsoleDeploymentSpec(instance.Name, consoleImage) deployment.Spec.Replicas = spec.Replicas deployment.Spec.Selector = spec.Selector deployment.Spec.Template = spec.Template @@ -210,18 +210,18 @@ func reconcileConsoleDeploymentResource(h *common_helper.Helper, ctx context.Con } // reconcileConsoleService ensures the console plugin service exists. -func reconcileConsoleService(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileConsoleService(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: ConsoleUIServiceName, + Name: ConsoleUIServiceName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), svc, func() error { - svc.Spec.Selector = generateConsoleSelectorLabels() + svc.Spec.Selector = generateConsoleSelectorLabels(instance.Name) svc.Spec.Ports = []corev1.ServicePort{ { Port: ConsoleUIHTTPSPort, @@ -235,7 +235,7 @@ func reconcileConsoleService(h *common_helper.Helper, ctx context.Context, _ *ap if svc.Annotations == nil { svc.Annotations = make(map[string]string) } - svc.Annotations[ServingCertSecretAnnotationKey] = ConsoleUIServiceCertSecretName + svc.Annotations[ServingCertSecretAnnotationKey] = ConsoleUIServiceCertSecretName(instance.Name) return controllerutil.SetControllerReference(h.GetBeforeObject(), svc, h.GetScheme()) }) @@ -250,12 +250,12 @@ func reconcileConsoleService(h *common_helper.Helper, ctx context.Context, _ *ap // reconcileConsoleTLSSecret waits for the console TLS secret to be populated by // the service-ca operator. -func reconcileConsoleTLSSecret(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileConsoleTLSSecret(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() - logger.Info("waiting for console TLS secret", "name", ConsoleUIServiceCertSecretName) + logger.Info("waiting for console TLS secret", "name", ConsoleUIServiceCertSecretName(instance.Name)) secretKey := client.ObjectKey{ - Name: ConsoleUIServiceCertSecretName, + Name: ConsoleUIServiceCertSecretName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), } @@ -275,23 +275,23 @@ func reconcileConsoleTLSSecret(h *common_helper.Helper, ctx context.Context, _ * return fmt.Errorf("%w: %v", ErrReconcileConsoleTLSSecret, err) } - logger.Info("Console TLS secret is ready", "name", ConsoleUIServiceCertSecretName) + logger.Info("Console TLS secret is ready", "name", ConsoleUIServiceCertSecretName(instance.Name)) return nil } // reconcileConsolePlugin ensures the ConsolePlugin CR exists. -func reconcileConsolePlugin(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileConsolePlugin(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() namespace := h.GetBeforeObject().GetNamespace() plugin := &consolev1.ConsolePlugin{ ObjectMeta: metav1.ObjectMeta{ - Name: ConsoleUIPluginName, + Name: ConsoleUIPluginName(instance.Name), }, } result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), plugin, func() error { - plugin.Spec = buildConsolePluginSpec(namespace) + plugin.Spec = buildConsolePluginSpec(instance.Name, namespace) // ConsolePlugin is cluster-scoped, no owner reference return nil }) @@ -305,8 +305,9 @@ func reconcileConsolePlugin(h *common_helper.Helper, ctx context.Context, _ *api } // activateConsole adds the console plugin to the Console CR's plugin list. -func activateConsole(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func activateConsole(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() + pluginName := ConsoleUIPluginName(instance.Name) err := retry.RetryOnConflict(retry.DefaultRetry, func() error { console := &openshiftv1.Console{} @@ -320,9 +321,9 @@ func activateConsole(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1 } if console.Spec.Plugins == nil { - console.Spec.Plugins = []string{ConsoleUIPluginName} - } else if !slices.Contains(console.Spec.Plugins, ConsoleUIPluginName) { - console.Spec.Plugins = append(console.Spec.Plugins, ConsoleUIPluginName) + console.Spec.Plugins = []string{pluginName} + } else if !slices.Contains(console.Spec.Plugins, pluginName) { + console.Spec.Plugins = append(console.Spec.Plugins, pluginName) } else { return nil } @@ -338,8 +339,9 @@ func activateConsole(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1 } // reconcileDeleteConsole deactivates the console plugin and deletes the ConsolePlugin CR. -func reconcileDeleteConsole(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileDeleteConsole(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() + pluginName := ConsoleUIPluginName(instance.Name) // Deactivate: remove plugin from Console CR err := retry.RetryOnConflict(retry.DefaultRetry, func() error { @@ -356,12 +358,12 @@ func reconcileDeleteConsole(h *common_helper.Helper, ctx context.Context, _ *api if console.Spec.Plugins == nil { return nil } - if !slices.Contains(console.Spec.Plugins, ConsoleUIPluginName) { + if !slices.Contains(console.Spec.Plugins, pluginName) { return nil } console.Spec.Plugins = slices.DeleteFunc(console.Spec.Plugins, func(name string) bool { - return name == ConsoleUIPluginName + return name == pluginName }) return h.GetClient().Update(ctx, console) @@ -373,7 +375,7 @@ func reconcileDeleteConsole(h *common_helper.Helper, ctx context.Context, _ *api // Delete ConsolePlugin CR plugin := &consolev1.ConsolePlugin{} - err = h.GetClient().Get(ctx, client.ObjectKey{Name: ConsoleUIPluginName}, plugin) + err = h.GetClient().Get(ctx, client.ObjectKey{Name: pluginName}, plugin) if err != nil { if errors.IsNotFound(err) { logger.Info("ConsolePlugin not found, skip deletion") diff --git a/internal/controller/console_reconciler_test.go b/internal/controller/console_reconciler_test.go index 9e75c100..29f3ecff 100644 --- a/internal/controller/console_reconciler_test.go +++ b/internal/controller/console_reconciler_test.go @@ -34,10 +34,13 @@ var _ = Describe("Console Plugin", func() { apiv1beta1.SetupDefaults() }) + const testInstanceName = "test" + Describe("generateConsoleSelectorLabels", func() { It("should return the expected labels", func() { - labels := generateConsoleSelectorLabels() + labels := generateConsoleSelectorLabels(testInstanceName) Expect(labels).To(HaveKeyWithValue("app.kubernetes.io/component", "console-plugin")) + Expect(labels).To(HaveKeyWithValue("app.kubernetes.io/instance", testInstanceName)) Expect(labels).To(HaveKeyWithValue("app.kubernetes.io/managed-by", "openstack-lightspeed-operator")) Expect(labels).To(HaveKeyWithValue("app.kubernetes.io/name", "lightspeed-console-plugin")) Expect(labels).To(HaveKeyWithValue("app.kubernetes.io/part-of", "openstack-lightspeed")) @@ -48,7 +51,7 @@ var _ = Describe("Console Plugin", func() { var spec appsv1.DeploymentSpec BeforeEach(func() { - spec = buildConsoleDeploymentSpec(apiv1beta1.OpenStackLightspeedDefaultValues.ConsoleImagePF5URL) + spec = buildConsoleDeploymentSpec(testInstanceName, apiv1beta1.OpenStackLightspeedDefaultValues.ConsoleImagePF5URL) }) It("should have one replica", func() { @@ -57,7 +60,7 @@ var _ = Describe("Console Plugin", func() { }) It("should have correct selector labels", func() { - Expect(spec.Selector.MatchLabels).To(Equal(generateConsoleSelectorLabels())) + Expect(spec.Selector.MatchLabels).To(Equal(generateConsoleSelectorLabels(testInstanceName))) }) It("should have one container with the console image", func() { @@ -107,7 +110,7 @@ var _ = Describe("Console Plugin", func() { if v.Name == "lightspeed-console-plugin-cert" { found = true Expect(v.VolumeSource.Secret).NotTo(BeNil()) - Expect(v.VolumeSource.Secret.SecretName).To(Equal(ConsoleUIServiceCertSecretName)) + Expect(v.VolumeSource.Secret.SecretName).To(Equal(ConsoleUIServiceCertSecretName(testInstanceName))) } } Expect(found).To(BeTrue()) @@ -120,7 +123,7 @@ var _ = Describe("Console Plugin", func() { if v.Name == "nginx-config" { found = true Expect(v.VolumeSource.ConfigMap).NotTo(BeNil()) - Expect(v.VolumeSource.ConfigMap.Name).To(Equal(ConsoleUIConfigMapName)) + Expect(v.VolumeSource.ConfigMap.Name).To(Equal(ConsoleUIConfigMapName(testInstanceName))) } } Expect(found).To(BeTrue()) @@ -139,7 +142,7 @@ var _ = Describe("Console Plugin", func() { }) It("should use the console service account", func() { - Expect(spec.Template.Spec.ServiceAccountName).To(Equal(ConsoleUIServiceAccountName)) + Expect(spec.Template.Spec.ServiceAccountName).To(Equal(ConsoleUIServiceAccountName(testInstanceName))) }) It("should have a locales-rewrite emptyDir volume", func() { @@ -189,12 +192,12 @@ var _ = Describe("Console Plugin", func() { Describe("buildConsolePluginSpec", func() { const testNamespace = "test-ns" - var spec = buildConsolePluginSpec(testNamespace) + var spec = buildConsolePluginSpec(testInstanceName, testNamespace) It("should have service backend", func() { Expect(spec.Backend.Type).To(Equal(consolev1.Service)) Expect(spec.Backend.Service).NotTo(BeNil()) - Expect(spec.Backend.Service.Name).To(Equal(ConsoleUIServiceName)) + Expect(spec.Backend.Service.Name).To(Equal(ConsoleUIServiceName(testInstanceName))) Expect(spec.Backend.Service.Namespace).To(Equal(testNamespace)) Expect(spec.Backend.Service.Port).To(Equal(ConsoleUIHTTPSPort)) }) @@ -206,7 +209,7 @@ var _ = Describe("Console Plugin", func() { Expect(proxy.Authorization).To(Equal(consolev1.UserToken)) Expect(proxy.Endpoint.Type).To(Equal(consolev1.ProxyTypeService)) Expect(proxy.Endpoint.Service).NotTo(BeNil()) - Expect(proxy.Endpoint.Service.Name).To(Equal(OpenStackLightspeedAppServerServiceName)) + Expect(proxy.Endpoint.Service.Name).To(Equal(OpenStackLightspeedAppServerServiceName(testInstanceName))) Expect(proxy.Endpoint.Service.Namespace).To(Equal(testNamespace)) Expect(proxy.Endpoint.Service.Port).To(Equal(int32(OpenStackLightspeedAppServerServicePort))) }) @@ -227,10 +230,10 @@ var _ = Describe("Console Plugin", func() { }) Describe("buildConsoleNetworkPolicySpec", func() { - var spec = buildConsoleNetworkPolicySpec() + var spec = buildConsoleNetworkPolicySpec(testInstanceName) It("should select console plugin pods", func() { - Expect(spec.PodSelector.MatchLabels).To(Equal(generateConsoleSelectorLabels())) + Expect(spec.PodSelector.MatchLabels).To(Equal(generateConsoleSelectorLabels(testInstanceName))) }) It("should allow ingress from openshift-console namespace", func() { diff --git a/internal/controller/constants.go b/internal/controller/constants.go index 20b74038..b5ca9243 100644 --- a/internal/controller/constants.go +++ b/internal/controller/constants.go @@ -26,15 +26,10 @@ const ( ResourceCreationTimeout = 60 * time.Second // Application Server - OpenStackLightspeedAppServerServiceAccountName = "lightspeed-app-server" - OpenStackLightspeedAppServerSARRoleName = OpenStackLightspeedAppServerServiceAccountName + "-sar-role" - OpenStackLightspeedAppServerSARRoleBindingName = OpenStackLightspeedAppServerSARRoleName + "-binding" - OpenStackLightspeedAppServerContainerPort = 8443 - OpenStackLightspeedAppServerServicePort = 8443 - OpenStackLightspeedAppServerServiceName = "lightspeed-app-server" - OpenStackLightspeedAppServerNetworkPolicyName = "lightspeed-app-server" - OpenStackLightspeedDefaultProvider = "openstack-lightspeed-provider" - OpenStackLightspeedVectorDBPath = "/rag/vector_db/os_product_docs" + OpenStackLightspeedAppServerContainerPort = 8443 + OpenStackLightspeedAppServerServicePort = 8443 + OpenStackLightspeedDefaultProvider = "openstack-lightspeed-provider" + OpenStackLightspeedVectorDBPath = "/rag/vector_db/os_product_docs" ServingCertSecretAnnotationKey = "service.beta.openshift.io/serving-cert-secret-name" @@ -43,12 +38,6 @@ const ( MetricsReaderServiceAccountName = "lightspeed-operator-metrics-reader" // Postgres - PostgresDeploymentName = "lightspeed-postgres-server" - PostgresServiceName = "lightspeed-postgres-server" - PostgresSecretName = "lightspeed-postgres-secret" - PostgresBootstrapSecretName = "lightspeed-postgres-bootstrap" - PostgresConfigMapName = "lightspeed-postgres-conf" - PostgresNetworkPolicyName = "lightspeed-postgres-server" PostgresServicePort = int32(5432) PostgresDefaultUser = "postgres" PostgresDefaultDbName = "postgres" @@ -61,7 +50,6 @@ const ( PostgresConfigVolumeMountPath = "/usr/share/pgsql/postgresql.conf.sample" PostgresDataVolume = "postgres-data" PostgresDataVolumeMountPath = "/var/lib/pgsql" - PostgresDataPVCName = "openstack-lightspeed-database" PostgresDataPVCDefaultSize = "1Gi" PostgresVarRunVolumeName = "lightspeed-postgres-var-run" PostgresVarRunVolumeMountPath = "/var/run/postgresql" @@ -69,10 +57,7 @@ const ( TmpVolumeMountPath = "/tmp" // LCore specific - LlamaStackContainerPort = int32(8321) - LlamaStackConfigCmName = "llama-stack-config" - LCoreConfigCmName = "lightspeed-stack-config" - LCoreDeploymentName = "lightspeed-stack-deployment" + LlamaStackContainerPort = int32(8321) LCoreConfigMountPath = "/app-root/lightspeed-stack.yaml" LCoreUserDataMountPath = "/tmp/data" ForceReloadAnnotationKey = "ols.openshift.io/force-reload" @@ -81,33 +66,23 @@ const ( ExporterConfigVolumeName = "exporter-config" ExporterConfigMountPath = "/etc/config" ExporterConfigFilename = "config.yaml" - ExporterConfigCmName = "lightspeed-exporter-config" DataverseExporterContainerName = "lightspeed-to-dataverse-exporter" UserDataVolumeName = "ols-user-data" RHOSOLightspeedOwnerIDLabel = "openstack.org/lightspeed-owner-id" ServiceIDRHOSO = "rhos-lightspeed" // OKP (Offline Knowledge Portal) - OKPContainerName = "okp" - OKPContainerPort = int32(8080) - OKPDeploymentName = "lightspeed-okp-server" - OKPServiceName = "lightspeed-okp-server" + OKPContainerName = "okp" + OKPContainerPort = int32(8080) OKPServicePort = int32(8080) OKPAccessKeySecretKey = "access_key" OKPDefaultChunkFilterQuery = "product:(*openstack* OR *openshift*)" ExternalProvidersDir = "/app-root/providers.d" // Console Plugin - ConsoleUIConfigMapName = "lightspeed-console-plugin" - ConsoleUIServiceCertSecretName = "lightspeed-console-plugin-cert" - ConsoleUIServiceName = "lightspeed-console-plugin" - ConsoleUIDeploymentName = "lightspeed-console-plugin" - ConsoleUIHTTPSPort = int32(9443) - ConsoleUIPluginName = "lightspeed-console-plugin" - ConsoleUIServiceAccountName = "lightspeed-console-plugin" - ConsoleCRName = "cluster" - ConsoleProxyAlias = "ols" - ConsoleUINetworkPolicyName = "lightspeed-console-plugin" + ConsoleUIHTTPSPort = int32(9443) + ConsoleCRName = "cluster" + ConsoleProxyAlias = "ols" // Azure AzureOpenAIType = "azure_openai" @@ -161,9 +136,6 @@ const ( // configuration is stored. LightspeedStackConfigCMKey = "lightspeed-stack.yaml" - // VectorDBScriptsConfigMapName is the name of the ConfigMap that contains the - // initialization scripts used by init containers to collect and build vector database data - VectorDBScriptsConfigMapName = "vector-db-scripts" // VectorDBScriptsVolumeName is the name of the volume that mounts the ConfigMap containing // vector database initialization scripts for use by init containers @@ -197,12 +169,6 @@ const ( VolumeRestrictedMode = int32(0600) VolumeExecutableMode = int32(0755) - // CABundleConfigMapName is the name of the ConfigMap that stores the - // CA certificate bundle. It aggregates certificates from three sources — - // operator system CAs, the OpenShift service serving CA (for in-cluster - // service-to-service TLS), and the OpenShift API server CA — along with - // any user-provided additional CAs. - CABundleConfigMapName = "openstack-lightspeed-ca-bundle" // CABundleKey is the key within the CA bundle ConfigMap under which // the PEM-encoded certificate data is stored. @@ -235,17 +201,6 @@ const ( // inside the lightspeed-service-api container, used to serve HTTPS. OpenStackLightspeedTLSKeyPath = OpenStackLightspeedAppCertsMountRoot + "/lightspeed-tls/tls.key" - // OpenStackLightspeedCertsSecretName is the name of the Secret auto-provisioned - // by the OpenShift service-ca operator when the lightspeed-app-server Service is - // annotated with service.beta.openshift.io/serving-cert-secret-name. Contains - // tls.crt and tls.key used by the lightspeed-service-api container to serve HTTPS. - OpenStackLightspeedCertsSecretName = "lightspeed-tls" - - // PostgresCertsSecretName is the name of the Secret auto-provisioned by the - // OpenShift service-ca operator when the lightspeed-postgres-server Service is - // annotated with service.beta.openshift.io/serving-cert-secret-name. Contains - // tls.crt and tls.key used by the postgres container to serve TLS connections. - PostgresCertsSecretName = "lightspeed-postgres-certs" // PostgresDefaultSSLMode is the sslmode used when connecting to PostgreSQL. // "verify-full" requires a valid server certificate and checks @@ -264,6 +219,108 @@ const ( OpenShiftServiceCAConfigMap = "openshift-service-ca.crt" ) +// Resource name functions — each returns a name scoped to the CR instance so +// multiple OpenStackLightspeed CRs can coexist in the same namespace. + +// Application Server +func OpenStackLightspeedAppServerServiceAccountName(instanceName string) string { + return instanceName + "-app-server" +} +func OpenStackLightspeedAppServerSARRoleName(instanceName string) string { + return OpenStackLightspeedAppServerServiceAccountName(instanceName) + "-sar-role" +} +func OpenStackLightspeedAppServerSARRoleBindingName(instanceName string) string { + return OpenStackLightspeedAppServerSARRoleName(instanceName) + "-binding" +} +func OpenStackLightspeedAppServerServiceName(instanceName string) string { + return instanceName + "-app-server" +} +func OpenStackLightspeedAppServerNetworkPolicyName(instanceName string) string { + return instanceName + "-app-server" +} +func OpenStackLightspeedCertsSecretName(instanceName string) string { + return instanceName + "-tls" +} + +// Postgres +func PostgresDeploymentName(instanceName string) string { + return instanceName + "-postgres-server" +} +func PostgresServiceName(instanceName string) string { + return instanceName + "-postgres-server" +} +func PostgresSecretName(instanceName string) string { + return instanceName + "-postgres-secret" +} +func PostgresBootstrapSecretName(instanceName string) string { + return instanceName + "-postgres-bootstrap" +} +func PostgresConfigMapName(instanceName string) string { + return instanceName + "-postgres-conf" +} +func PostgresNetworkPolicyName(instanceName string) string { + return instanceName + "-postgres-server" +} +func PostgresDataPVCName(instanceName string) string { + return instanceName + "-database" +} +func PostgresCertsSecretName(instanceName string) string { + return instanceName + "-postgres-certs" +} + +// LCore +func LlamaStackConfigCmName(instanceName string) string { + return instanceName + "-llama-stack-config" +} +func LCoreConfigCmName(instanceName string) string { + return instanceName + "-stack-config" +} +func LCoreDeploymentName(instanceName string) string { + return instanceName + "-stack-deployment" +} +func ExporterConfigCmName(instanceName string) string { + return instanceName + "-exporter-config" +} + +// OKP +func OKPDeploymentName(instanceName string) string { + return instanceName + "-okp-server" +} +func OKPServiceName(instanceName string) string { + return instanceName + "-okp-server" +} + +// Console Plugin +func ConsoleUIConfigMapName(instanceName string) string { + return instanceName + "-console-plugin" +} +func ConsoleUIServiceCertSecretName(instanceName string) string { + return instanceName + "-console-plugin-cert" +} +func ConsoleUIServiceName(instanceName string) string { + return instanceName + "-console-plugin" +} +func ConsoleUIDeploymentName(instanceName string) string { + return instanceName + "-console-plugin" +} +func ConsoleUIPluginName(instanceName string) string { + return instanceName + "-console-plugin" +} +func ConsoleUIServiceAccountName(instanceName string) string { + return instanceName + "-console-plugin" +} +func ConsoleUINetworkPolicyName(instanceName string) string { + return instanceName + "-console-plugin" +} + +// Other +func CABundleConfigMapName(instanceName string) string { + return instanceName + "-ca-bundle" +} +func VectorDBScriptsConfigMapName(instanceName string) string { + return instanceName + "-vector-db-scripts" +} + // PostgreSQL Bootstrap Script - creates database, extensions, and schemas // //go:embed assets/postgres_bootstrap.sh diff --git a/internal/controller/lcore_config.go b/internal/controller/lcore_config.go index ba464332..8e0f971f 100644 --- a/internal/controller/lcore_config.go +++ b/internal/controller/lcore_config.go @@ -124,10 +124,10 @@ func buildLCoreInferenceConfig(_ *common_helper.Helper, instance *apiv1beta1.Ope } // buildLCoreDatabaseConfig configures persistent database storage (PostgreSQL) -func buildLCoreDatabaseConfig(h *common_helper.Helper, _ *apiv1beta1.OpenStackLightspeed) map[string]interface{} { +func buildLCoreDatabaseConfig(h *common_helper.Helper, instance *apiv1beta1.OpenStackLightspeed) map[string]interface{} { return map[string]interface{}{ "postgres": map[string]interface{}{ - "host": PostgresServiceName + "." + h.GetBeforeObject().GetNamespace() + ".svc", + "host": PostgresServiceName(instance.Name) + "." + h.GetBeforeObject().GetNamespace() + ".svc", "port": PostgresServicePort, "db": PostgresDefaultDbName, "user": PostgresDefaultUser, @@ -155,11 +155,11 @@ func buildLCoreCustomizationConfig() map[string]interface{} { } // buildLCoreConversationCacheConfig configures chat history caching (PostgreSQL) -func buildLCoreConversationCacheConfig(h *common_helper.Helper, _ *apiv1beta1.OpenStackLightspeed) map[string]interface{} { +func buildLCoreConversationCacheConfig(h *common_helper.Helper, instance *apiv1beta1.OpenStackLightspeed) map[string]interface{} { return map[string]interface{}{ "type": "postgres", "postgres": map[string]interface{}{ - "host": PostgresServiceName + "." + h.GetBeforeObject().GetNamespace() + ".svc", + "host": PostgresServiceName(instance.Name) + "." + h.GetBeforeObject().GetNamespace() + ".svc", "port": PostgresServicePort, "db": PostgresDefaultDbName, "user": PostgresDefaultUser, @@ -178,7 +178,7 @@ func isDataCollectionEnabled(instance *apiv1beta1.OpenStackLightspeed) bool { } // buildExporterConfigMap creates the ConfigMap for the dataverse exporter sidecar. -func buildExporterConfigMap(h *common_helper.Helper, _ *apiv1beta1.OpenStackLightspeed) *corev1.ConfigMap { +func buildExporterConfigMap(h *common_helper.Helper, instance *apiv1beta1.OpenStackLightspeed) *corev1.ConfigMap { exporterConfig := fmt.Sprintf(`service_id: "%s" ingress_server_url: "https://console.redhat.com/api/ingress/v1/upload" allowed_subdirs: @@ -192,9 +192,9 @@ ingress_connection_timeout: 30 return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: ExporterConfigCmName, + Name: ExporterConfigCmName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), - Labels: generateAppServerSelectorLabels(), + Labels: generateAppServerSelectorLabels(instance.Name), }, Data: map[string]string{ ExporterConfigFilename: exporterConfig, diff --git a/internal/controller/lcore_deployment.go b/internal/controller/lcore_deployment.go index e5ac3bbf..6646d3ec 100644 --- a/internal/controller/lcore_deployment.go +++ b/internal/controller/lcore_deployment.go @@ -38,15 +38,16 @@ import ( // This function is used by CreateOrPatch to generate the desired pod spec. func buildLCorePodTemplateSpec(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) (corev1.PodTemplateSpec, error) { // Build shared volumes + instanceName := instance.Name volumes := []corev1.Volume{ - buildOGXConfigVolume(VolumeDefaultMode), - buildLightspeedStackConfigVolume(VolumeDefaultMode), - buildVectorDBScriptsVolume(), + buildOGXConfigVolume(instanceName, VolumeDefaultMode), + buildLightspeedStackConfigVolume(instanceName, VolumeDefaultMode), + buildVectorDBScriptsVolume(instanceName), } // Shared volumes - CA bundle covers all cluster CAs sharedMounts := []corev1.VolumeMount{} - addCABundleVolumesAndMounts(&volumes, &sharedMounts) + addCABundleVolumesAndMounts(instanceName, &volumes, &sharedMounts) addVectorDBDataVolumesAndMounts(&volumes, &sharedMounts) // Llama cache emptydir @@ -97,7 +98,7 @@ func buildLCorePodTemplateSpec(h *common_helper.Helper, ctx context.Context, ins // Data collection volumes (shared folder + exporter config) dataCollectionEnabled := isDataCollectionEnabled(instance) if dataCollectionEnabled { - addDataCollectorVolumes(&volumes, VolumeDefaultMode) + addDataCollectorVolumes(instanceName, &volumes, VolumeDefaultMode) } // Lightspeed Stack container mounts: its config + shared + TLS (only API container needs TLS) @@ -105,7 +106,7 @@ func buildLCorePodTemplateSpec(h *common_helper.Helper, ctx context.Context, ins lightspeedStackMounts = append(lightspeedStackMounts, sharedMounts...) tlsMounts := []corev1.VolumeMount{} - addTLSVolumesAndMounts(&volumes, &tlsMounts, VolumeDefaultMode) + addTLSVolumesAndMounts(instanceName, &volumes, &tlsMounts, VolumeDefaultMode) lightspeedStackMounts = append(lightspeedStackMounts, tlsMounts...) // Mount shared data folder on lightspeed-service-api for feedback/transcripts @@ -182,7 +183,7 @@ func buildLCorePodTemplateSpec(h *common_helper.Helper, ctx context.Context, ins } // Build configmap resource version annotations for change detection - annotations, err := buildConfigMapAnnotations(h, ctx) + annotations, err := buildConfigMapAnnotations(instanceName, h, ctx) if err != nil { return corev1.PodTemplateSpec{}, err } @@ -194,11 +195,11 @@ func buildLCorePodTemplateSpec(h *common_helper.Helper, ctx context.Context, ins return corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: generateAppServerSelectorLabels(), + Labels: generateAppServerSelectorLabels(instanceName), Annotations: annotations, }, Spec: corev1.PodSpec{ - ServiceAccountName: OpenStackLightspeedAppServerServiceAccountName, + ServiceAccountName: OpenStackLightspeedAppServerServiceAccountName(instanceName), InitContainers: initContainers, Containers: containers, Volumes: volumes, @@ -310,13 +311,13 @@ func buildInitContainers( } // buildLightspeedStackConfigVolume returns the volume for the lightspeed-stack config. -func buildLightspeedStackConfigVolume(volumeDefaultMode int32) corev1.Volume { +func buildLightspeedStackConfigVolume(instanceName string, volumeDefaultMode int32) corev1.Volume { return corev1.Volume{ Name: LightspeedStackConfig, VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: LCoreConfigCmName, + Name: LCoreConfigCmName(instanceName), }, DefaultMode: toPtr(volumeDefaultMode), }, @@ -325,13 +326,13 @@ func buildLightspeedStackConfigVolume(volumeDefaultMode int32) corev1.Volume { } // buildOGXConfigVolume returns the volume for the OGX config. -func buildOGXConfigVolume(volumeDefaultMode int32) corev1.Volume { +func buildOGXConfigVolume(instanceName string, volumeDefaultMode int32) corev1.Volume { return corev1.Volume{ Name: OGXConfigVolumeName, VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: LlamaStackConfigCmName, + Name: LlamaStackConfigCmName(instanceName), }, DefaultMode: toPtr(volumeDefaultMode), }, @@ -340,13 +341,13 @@ func buildOGXConfigVolume(volumeDefaultMode int32) corev1.Volume { } // buildVectorDBScriptsVolume returns the volume for the Vector DB scripts. -func buildVectorDBScriptsVolume() corev1.Volume { +func buildVectorDBScriptsVolume(instanceName string) corev1.Volume { return corev1.Volume{ Name: VectorDBScriptsVolumeName, VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: VectorDBScriptsConfigMapName, + Name: VectorDBScriptsConfigMapName(instanceName), }, DefaultMode: toPtr(VolumeExecutableMode), }, @@ -369,12 +370,12 @@ func addVectorDBDataVolumesAndMounts(volumes *[]corev1.Volume, mounts *[]corev1. } // addTLSVolumesAndMounts adds the service-ca TLS certificate volume and mount. -func addTLSVolumesAndMounts(volumes *[]corev1.Volume, mounts *[]corev1.VolumeMount, volumeDefaultMode int32) { +func addTLSVolumesAndMounts(instanceName string, volumes *[]corev1.Volume, mounts *[]corev1.VolumeMount, volumeDefaultMode int32) { *volumes = append(*volumes, corev1.Volume{ Name: "tls-certs", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: OpenStackLightspeedCertsSecretName, + SecretName: OpenStackLightspeedCertsSecretName(instanceName), DefaultMode: toPtr(volumeDefaultMode), }, }, @@ -401,7 +402,7 @@ func addLlamaCacheVolumesAndMounts(volumes *[]corev1.Volume, mounts *[]corev1.Vo } // addDataCollectorVolumes adds the shared data EmptyDir and exporter config volumes. -func addDataCollectorVolumes(volumes *[]corev1.Volume, volumeDefaultMode int32) { +func addDataCollectorVolumes(instanceName string, volumes *[]corev1.Volume, volumeDefaultMode int32) { *volumes = append(*volumes, corev1.Volume{ Name: UserDataVolumeName, VolumeSource: corev1.VolumeSource{ @@ -414,7 +415,7 @@ func addDataCollectorVolumes(volumes *[]corev1.Volume, volumeDefaultMode int32) VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: ExporterConfigCmName, + Name: ExporterConfigCmName(instanceName), }, DefaultMode: toPtr(volumeDefaultMode), }, @@ -425,13 +426,13 @@ func addDataCollectorVolumes(volumes *[]corev1.Volume, volumeDefaultMode int32) // addCABundleVolumesAndMounts adds the CA bundle volume and mount. // The CA bundle is always present (created by reconcileCABundleConfigMap) // and mounted at the RHEL system CA path so applications find it automatically. -func addCABundleVolumesAndMounts(volumes *[]corev1.Volume, mounts *[]corev1.VolumeMount) { +func addCABundleVolumesAndMounts(instanceName string, volumes *[]corev1.Volume, mounts *[]corev1.VolumeMount) { *volumes = append(*volumes, corev1.Volume{ Name: CABundleVolumeName, VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: CABundleConfigMapName, + Name: CABundleConfigMapName(instanceName), }, DefaultMode: toPtr(VolumeDefaultMode), }, @@ -547,7 +548,7 @@ func buildLlamaStackEnvVars(h *common_helper.Helper, ctx context.Context, instan } // Postgres password for ${env.POSTGRES_PASSWORD} substitution in llama-stack config - envVars = append(envVars, buildPostgresPasswordEnvVar()) + envVars = append(envVars, buildPostgresPasswordEnvVar(instance.Name)) // Logging configuration - set both for compatibility with llama-stack and OGX ogxLogLevel := getOGXLogLevel(instance) @@ -568,7 +569,7 @@ func buildLlamaStackEnvVars(h *common_helper.Helper, ctx context.Context, instan if isOKPEnabled(instance) { envVars = append(envVars, corev1.EnvVar{ Name: "RH_SERVER_OKP", - Value: fmt.Sprintf("http://%s.%s.svc:%d", OKPServiceName, instance.GetNamespace(), OKPServicePort), + Value: fmt.Sprintf("http://%s.%s.svc:%d", OKPServiceName(instance.Name), instance.GetNamespace(), OKPServicePort), }) // FIXME(lucasagomes): Llama-Stack expects HF_HOME to be set when OKP is enabled because it uses the // Hugging Face Hub client to fetch the embedding model for OKP. Ideally we would include the model it @@ -583,13 +584,13 @@ func buildLlamaStackEnvVars(h *common_helper.Helper, ctx context.Context, instan } // buildPostgresPasswordEnvVar returns the POSTGRES_PASSWORD env var sourced from the postgres secret. -func buildPostgresPasswordEnvVar() corev1.EnvVar { +func buildPostgresPasswordEnvVar(instanceName string) corev1.EnvVar { return corev1.EnvVar{ Name: "POSTGRES_PASSWORD", ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: PostgresSecretName, + Name: PostgresSecretName(instanceName), }, Key: OpenStackLightspeedComponentPasswordFileName, }, @@ -604,12 +605,12 @@ func buildLightspeedStackEnvVars(instance *apiv1beta1.OpenStackLightspeed) []cor Name: "LIGHTSPEED_STACK_LOG_LEVEL", Value: instance.Spec.Logging.LightspeedStackLogLevel, }, - buildPostgresPasswordEnvVar(), + buildPostgresPasswordEnvVar(instance.Name), } if isOKPEnabled(instance) { envVars = append(envVars, corev1.EnvVar{ Name: "RH_SERVER_OKP", - Value: fmt.Sprintf("http://%s.%s.svc:%d", OKPServiceName, instance.GetNamespace(), OKPServicePort), + Value: fmt.Sprintf("http://%s.%s.svc:%d", OKPServiceName(instance.Name), instance.GetNamespace(), OKPServicePort), }) } return envVars @@ -665,10 +666,10 @@ func getOGXLogLevel(instance *apiv1beta1.OpenStackLightspeed) string { // buildConfigMapAnnotations builds annotations with configmap resource versions // so that changes to the configmaps trigger a deployment rollout. -func buildConfigMapAnnotations(h *common_helper.Helper, ctx context.Context) (map[string]string, error) { +func buildConfigMapAnnotations(instanceName string, h *common_helper.Helper, ctx context.Context) (map[string]string, error) { annotations := make(map[string]string) - lcoreVersion, err := getConfigMapResourceVersion(ctx, h, LCoreConfigCmName, h.GetBeforeObject().GetNamespace()) + lcoreVersion, err := getConfigMapResourceVersion(ctx, h, LCoreConfigCmName(instanceName), h.GetBeforeObject().GetNamespace()) if err != nil { // ConfigMap may not exist yet during initial creation if !errors.IsNotFound(err) { @@ -678,7 +679,7 @@ func buildConfigMapAnnotations(h *common_helper.Helper, ctx context.Context) (ma annotations[LCoreConfigMapResourceVersionAnnotation] = lcoreVersion } - llamaVersion, err := getConfigMapResourceVersion(ctx, h, LlamaStackConfigCmName, h.GetBeforeObject().GetNamespace()) + llamaVersion, err := getConfigMapResourceVersion(ctx, h, LlamaStackConfigCmName(instanceName), h.GetBeforeObject().GetNamespace()) if err != nil { if !errors.IsNotFound(err) { return nil, fmt.Errorf("failed to get Llama Stack configmap resource version: %w", err) @@ -687,7 +688,7 @@ func buildConfigMapAnnotations(h *common_helper.Helper, ctx context.Context) (ma annotations[LlamaStackConfigMapResourceVersionAnnotation] = llamaVersion } - vectorDBScriptsVersion, err := getConfigMapResourceVersion(ctx, h, VectorDBScriptsConfigMapName, h.GetBeforeObject().GetNamespace()) + vectorDBScriptsVersion, err := getConfigMapResourceVersion(ctx, h, VectorDBScriptsConfigMapName(instanceName), h.GetBeforeObject().GetNamespace()) if err != nil { if !errors.IsNotFound(err) { return nil, fmt.Errorf("failed to get Vector DB scripts configmap resource version: %w", err) @@ -696,7 +697,7 @@ func buildConfigMapAnnotations(h *common_helper.Helper, ctx context.Context) (ma annotations[VectorDBScriptsConfigMapVersionAnnotation] = vectorDBScriptsVersion } - caBundleVersion, err := getConfigMapResourceVersion(ctx, h, CABundleConfigMapName, h.GetBeforeObject().GetNamespace()) + caBundleVersion, err := getConfigMapResourceVersion(ctx, h, CABundleConfigMapName(instanceName), h.GetBeforeObject().GetNamespace()) if err != nil { if !errors.IsNotFound(err) { return nil, fmt.Errorf("failed to get CA bundle configmap resource version: %w", err) diff --git a/internal/controller/lcore_reconciler.go b/internal/controller/lcore_reconciler.go index 71cc8197..7dbe0e9f 100644 --- a/internal/controller/lcore_reconciler.go +++ b/internal/controller/lcore_reconciler.go @@ -75,7 +75,7 @@ func reconcileServiceAccount(h *common_helper.Helper, ctx context.Context, insta sa := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ - Name: OpenStackLightspeedAppServerServiceAccountName, + Name: OpenStackLightspeedAppServerServiceAccountName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -99,8 +99,8 @@ func reconcileSARRole(h *common_helper.Helper, ctx context.Context, instance *ap role := &rbacv1.ClusterRole{ ObjectMeta: metav1.ObjectMeta{ - Name: OpenStackLightspeedAppServerSARRoleName, - Labels: generateAppServerSelectorLabels(), + Name: OpenStackLightspeedAppServerSARRoleName(instance.Name), + Labels: generateAppServerSelectorLabels(instance.Name), }, } @@ -147,8 +147,8 @@ func reconcileSARRoleBinding(h *common_helper.Helper, ctx context.Context, insta rb := &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: OpenStackLightspeedAppServerSARRoleBindingName, - Labels: generateAppServerSelectorLabels(), + Name: OpenStackLightspeedAppServerSARRoleBindingName(instance.Name), + Labels: generateAppServerSelectorLabels(instance.Name), }, } @@ -157,14 +157,14 @@ func reconcileSARRoleBinding(h *common_helper.Helper, ctx context.Context, insta rb.Subjects = []rbacv1.Subject{ { Kind: "ServiceAccount", - Name: OpenStackLightspeedAppServerServiceAccountName, + Name: OpenStackLightspeedAppServerServiceAccountName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } rb.RoleRef = rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", - Name: OpenStackLightspeedAppServerSARRoleName, + Name: OpenStackLightspeedAppServerSARRoleName(instance.Name), } // Note: ClusterRoleBinding is cluster-scoped, no owner reference needed return nil @@ -190,7 +190,7 @@ func reconcileLlamaStackConfigMap(h *common_helper.Helper, ctx context.Context, cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: LlamaStackConfigCmName, + Name: LlamaStackConfigCmName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -224,7 +224,7 @@ func reconcileLcoreConfigMap(h *common_helper.Helper, ctx context.Context, insta cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: LCoreConfigCmName, + Name: LCoreConfigCmName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -253,7 +253,7 @@ func reconcileExporterConfigMap(h *common_helper.Helper, ctx context.Context, in if !isDataCollectionEnabled(instance) { cm := &corev1.ConfigMap{} - cm.Name = ExporterConfigCmName + cm.Name = ExporterConfigCmName(instance.Name) cm.Namespace = h.GetBeforeObject().GetNamespace() if err := h.GetClient().Delete(ctx, cm); err != nil && !errors.IsNotFound(err) { return fmt.Errorf("failed to delete exporter configmap: %w", err) @@ -263,7 +263,7 @@ func reconcileExporterConfigMap(h *common_helper.Helper, ctx context.Context, in cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: ExporterConfigCmName, + Name: ExporterConfigCmName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -288,7 +288,7 @@ func reconcileVectorDBScriptsConfigMap(h *common_helper.Helper, ctx context.Cont logger := h.GetLogger() cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: VectorDBScriptsConfigMapName, + Name: VectorDBScriptsConfigMapName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -323,7 +323,7 @@ func reconcileNetworkPolicy(h *common_helper.Helper, ctx context.Context, instan np := &networkingv1.NetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: OpenStackLightspeedAppServerNetworkPolicyName, + Name: OpenStackLightspeedAppServerNetworkPolicyName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -332,7 +332,7 @@ func reconcileNetworkPolicy(h *common_helper.Helper, ctx context.Context, instan // Set Spec (wholesale replacement, same as before) np.Spec = networkingv1.NetworkPolicySpec{ PodSelector: metav1.LabelSelector{ - MatchLabels: generateAppServerSelectorLabels(), + MatchLabels: generateAppServerSelectorLabels(instance.Name), }, Ingress: []networkingv1.NetworkPolicyIngressRule{ { @@ -366,7 +366,7 @@ func reconcileDeployment(h *common_helper.Helper, ctx context.Context, instance deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: LCoreDeploymentName, + Name: LCoreDeploymentName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -382,7 +382,7 @@ func reconcileDeployment(h *common_helper.Helper, ctx context.Context, instance replicas := int32(1) deployment.Spec.Replicas = &replicas deployment.Spec.Selector = &metav1.LabelSelector{ - MatchLabels: generateAppServerSelectorLabels(), + MatchLabels: generateAppServerSelectorLabels(instance.Name), } deployment.Spec.Template = podTemplateSpec @@ -405,14 +405,14 @@ func reconcileService(h *common_helper.Helper, ctx context.Context, instance *ap svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: OpenStackLightspeedAppServerServiceName, + Name: OpenStackLightspeedAppServerServiceName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), svc, func() error { // Selective field updates (preserves ClusterIP, ClusterIPs, etc.) - svc.Spec.Selector = generateAppServerSelectorLabels() + svc.Spec.Selector = generateAppServerSelectorLabels(instance.Name) svc.Spec.Ports = []corev1.ServicePort{ { Name: "https", @@ -427,7 +427,7 @@ func reconcileService(h *common_helper.Helper, ctx context.Context, instance *ap if svc.Annotations == nil { svc.Annotations = make(map[string]string) } - svc.Annotations[ServingCertSecretAnnotationKey] = OpenStackLightspeedCertsSecretName + svc.Annotations[ServingCertSecretAnnotationKey] = OpenStackLightspeedCertsSecretName(instance.Name) // Set owner reference return controllerutil.SetControllerReference(h.GetBeforeObject(), svc, h.GetScheme()) @@ -443,12 +443,12 @@ func reconcileService(h *common_helper.Helper, ctx context.Context, instance *ap // reconcileTLSSecret waits for the TLS secret to be populated by the service-ca // operator with tls.key and tls.crt data. -func reconcileTLSSecret(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileTLSSecret(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() - logger.Info("waiting for TLS secret to be populated", "name", OpenStackLightspeedCertsSecretName) + logger.Info("waiting for TLS secret to be populated", "name", OpenStackLightspeedCertsSecretName(instance.Name)) secretKey := client.ObjectKey{ - Name: OpenStackLightspeedCertsSecretName, + Name: OpenStackLightspeedCertsSecretName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), } @@ -468,15 +468,15 @@ func reconcileTLSSecret(h *common_helper.Helper, ctx context.Context, _ *apiv1be return fmt.Errorf("%w: %v", ErrGetTLSSecret, err) } - logger.Info("TLS secret is ready", "name", OpenStackLightspeedCertsSecretName) + logger.Info("TLS secret is ready", "name", OpenStackLightspeedCertsSecretName(instance.Name)) return nil } // reconcileDeleteClusterRoleBindingByLabels deletes ClusterRoleBinding resources by labels. -func reconcileDeleteClusterRoleBindingByLabels(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileDeleteClusterRoleBindingByLabels(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() - labelSelector := labels.Set(generateAppServerSelectorLabels()).AsSelector() + labelSelector := labels.Set(generateAppServerSelectorLabels(instance.Name)).AsSelector() matchingLabels := client.MatchingLabelsSelector{Selector: labelSelector} deleteOptions := &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ @@ -493,10 +493,10 @@ func reconcileDeleteClusterRoleBindingByLabels(h *common_helper.Helper, ctx cont } // reconcileDeleteClusterRoleByLabels deletes ClusterRole resources by labels. -func reconcileDeleteClusterRoleByLabels(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileDeleteClusterRoleByLabels(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() - labelSelector := labels.Set(generateAppServerSelectorLabels()).AsSelector() + labelSelector := labels.Set(generateAppServerSelectorLabels(instance.Name)).AsSelector() matchingLabels := client.MatchingLabelsSelector{Selector: labelSelector} deleteOptions := &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ diff --git a/internal/controller/llama_stack_config.go b/internal/controller/llama_stack_config.go index ed8153f4..7f822ca6 100644 --- a/internal/controller/llama_stack_config.go +++ b/internal/controller/llama_stack_config.go @@ -300,7 +300,7 @@ func buildLlamaStackStorage(_ *common_helper.Helper, instance *apiv1beta1.OpenSt }, "postgres_backend": map[string]interface{}{ "type": "sql_postgres", - "host": fmt.Sprintf("lightspeed-postgres-server.%s.svc", instance.GetNamespace()), + "host": fmt.Sprintf("%s.%s.svc", PostgresServiceName(instance.Name), instance.GetNamespace()), "port": PostgresServicePort, "user": "postgres", "password": "${env.POSTGRES_PASSWORD}", diff --git a/internal/controller/okp_reconciler.go b/internal/controller/okp_reconciler.go index 9e9e9533..1790eeb8 100644 --- a/internal/controller/okp_reconciler.go +++ b/internal/controller/okp_reconciler.go @@ -35,7 +35,7 @@ import ( // When OKP is disabled, it cleans up existing resources. func ReconcileOKPDeployment(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { if !isOKPEnabled(instance) { - return cleanupOKPResources(h, ctx) + return cleanupOKPResources(h, ctx, instance) } tasks := []ReconcileTask{ @@ -45,19 +45,19 @@ func ReconcileOKPDeployment(h *common_helper.Helper, ctx context.Context, instan return ReconcileTasksFailFast(h, ctx, instance, tasks) } -func cleanupOKPResources(h *common_helper.Helper, ctx context.Context) error { +func cleanupOKPResources(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() ns := h.GetBeforeObject().GetNamespace() deploy := &appsv1.Deployment{} - deploy.Name = OKPDeploymentName + deploy.Name = OKPDeploymentName(instance.Name) deploy.Namespace = ns if err := h.GetClient().Delete(ctx, deploy); err != nil && !errors.IsNotFound(err) { return fmt.Errorf("%w: %v", ErrDeleteOKPDeployment, err) } svc := &corev1.Service{} - svc.Name = OKPServiceName + svc.Name = OKPServiceName(instance.Name) svc.Namespace = ns if err := h.GetClient().Delete(ctx, svc); err != nil && !errors.IsNotFound(err) { return fmt.Errorf("%w: %v", ErrDeleteOKPService, err) @@ -72,7 +72,7 @@ func reconcileOKPDeployment(h *common_helper.Helper, ctx context.Context, instan deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: OKPDeploymentName, + Name: OKPDeploymentName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -83,7 +83,7 @@ func reconcileOKPDeployment(h *common_helper.Helper, ctx context.Context, instan replicas := int32(1) deployment.Spec.Replicas = &replicas deployment.Spec.Selector = &metav1.LabelSelector{ - MatchLabels: generateOKPSelectorLabels(), + MatchLabels: generateOKPSelectorLabels(instance.Name), } deployment.Spec.Template = podTemplateSpec @@ -98,18 +98,18 @@ func reconcileOKPDeployment(h *common_helper.Helper, ctx context.Context, instan return nil } -func reconcileOKPService(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcileOKPService(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { logger := h.GetLogger() svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: OKPServiceName, + Name: OKPServiceName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), svc, func() error { - svc.Spec.Selector = generateOKPSelectorLabels() + svc.Spec.Selector = generateOKPSelectorLabels(instance.Name) svc.Spec.Ports = []corev1.ServicePort{ { Name: "http", @@ -149,7 +149,7 @@ func buildOKPPodTemplateSpec(instance *apiv1beta1.OpenStackLightspeed) corev1.Po return corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: generateOKPSelectorLabels(), + Labels: generateOKPSelectorLabels(instance.Name), }, Spec: corev1.PodSpec{ Containers: []corev1.Container{ diff --git a/internal/controller/openstacklightspeed_controller.go b/internal/controller/openstacklightspeed_controller.go index 17f9be6c..22eda6c5 100644 --- a/internal/controller/openstacklightspeed_controller.go +++ b/internal/controller/openstacklightspeed_controller.go @@ -230,9 +230,9 @@ func (r *OpenStackLightspeedReconciler) reconcileStatus( instance *apiv1beta1.OpenStackLightspeed, ) (ctrl.Result, error) { deployments := []string{ - PostgresDeploymentName, - LCoreDeploymentName, - ConsoleUIDeploymentName, + PostgresDeploymentName(instance.Name), + LCoreDeploymentName(instance.Name), + ConsoleUIDeploymentName(instance.Name), } for _, deploymentName := range deployments { deployment, err := getDeployment(ctx, helper, deploymentName, instance.Namespace) diff --git a/internal/controller/postgres_deployment.go b/internal/controller/postgres_deployment.go index 94cfd462..daf9d000 100644 --- a/internal/controller/postgres_deployment.go +++ b/internal/controller/postgres_deployment.go @@ -26,7 +26,7 @@ import ( ) // buildPostgresPodTemplateSpec builds the pod template spec for the Postgres deployment. -func buildPostgresPodTemplateSpec() corev1.PodTemplateSpec { +func buildPostgresPodTemplateSpec(instanceName string) corev1.PodTemplateSpec { // Build volumes and volume mounts volumes := []corev1.Volume{} volumeMounts := []corev1.VolumeMount{} @@ -36,32 +36,32 @@ func buildPostgresPodTemplateSpec() corev1.PodTemplateSpec { // TLS certs volume (auto-provisioned by service-ca via the Service annotation) volumes = append(volumes, corev1.Volume{ - Name: "secret-" + PostgresCertsSecretName, + Name: "secret-" + PostgresCertsSecretName(instanceName), VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: PostgresCertsSecretName, + SecretName: PostgresCertsSecretName(instanceName), DefaultMode: &restrictedMode, }, }, }) volumeMounts = append(volumeMounts, corev1.VolumeMount{ - Name: "secret-" + PostgresCertsSecretName, + Name: "secret-" + PostgresCertsSecretName(instanceName), MountPath: OpenStackLightspeedAppCertsMountRoot, ReadOnly: true, }) // Bootstrap script volume volumes = append(volumes, corev1.Volume{ - Name: "secret-" + PostgresBootstrapSecretName, + Name: "secret-" + PostgresBootstrapSecretName(instanceName), VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: PostgresBootstrapSecretName, + SecretName: PostgresBootstrapSecretName(instanceName), DefaultMode: &restrictedMode, }, }, }) volumeMounts = append(volumeMounts, corev1.VolumeMount{ - Name: "secret-" + PostgresBootstrapSecretName, + Name: "secret-" + PostgresBootstrapSecretName(instanceName), MountPath: PostgresBootstrapVolumeMountPath, SubPath: PostgresExtensionScript, ReadOnly: true, @@ -69,16 +69,16 @@ func buildPostgresPodTemplateSpec() corev1.PodTemplateSpec { // Postgres config volume volumes = append(volumes, corev1.Volume{ - Name: PostgresConfigMapName, + Name: PostgresConfigMapName(instanceName), VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{Name: PostgresConfigMapName}, + LocalObjectReference: corev1.LocalObjectReference{Name: PostgresConfigMapName(instanceName)}, DefaultMode: &defaultMode, }, }, }) volumeMounts = append(volumeMounts, corev1.VolumeMount{ - Name: PostgresConfigMapName, + Name: PostgresConfigMapName(instanceName), MountPath: PostgresConfigVolumeMountPath, SubPath: PostgresConfigKey, }) @@ -87,7 +87,7 @@ func buildPostgresPodTemplateSpec() corev1.PodTemplateSpec { Name: PostgresDataVolume, VolumeSource: corev1.VolumeSource{ PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ - ClaimName: PostgresDataPVCName, + ClaimName: PostgresDataPVCName(instanceName), }, }, }) @@ -122,13 +122,13 @@ func buildPostgresPodTemplateSpec() corev1.PodTemplateSpec { return corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: generatePostgresSelectorLabels(), + Labels: generatePostgresSelectorLabels(instanceName), Annotations: make(map[string]string), }, Spec: corev1.PodSpec{ Containers: []corev1.Container{ { - Name: PostgresDeploymentName, + Name: PostgresDeploymentName(instanceName), Image: apiv1beta1.OpenStackLightspeedDefaultValues.PostgresImageURL, ImagePullPolicy: corev1.PullAlways, Ports: []corev1.ContainerPort{ @@ -174,7 +174,7 @@ func buildPostgresPodTemplateSpec() corev1.PodTemplateSpec { Name: "POSTGRESQL_ADMIN_PASSWORD", ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{Name: PostgresSecretName}, + LocalObjectReference: corev1.LocalObjectReference{Name: PostgresSecretName(instanceName)}, Key: OpenStackLightspeedComponentPasswordFileName, }, }, @@ -183,7 +183,7 @@ func buildPostgresPodTemplateSpec() corev1.PodTemplateSpec { Name: "POSTGRESQL_PASSWORD", ValueFrom: &corev1.EnvVarSource{ SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{Name: PostgresSecretName}, + LocalObjectReference: corev1.LocalObjectReference{Name: PostgresSecretName(instanceName)}, Key: OpenStackLightspeedComponentPasswordFileName, }, }, diff --git a/internal/controller/postgres_reconciler.go b/internal/controller/postgres_reconciler.go index cfdadb3c..a9ebde0f 100644 --- a/internal/controller/postgres_reconciler.go +++ b/internal/controller/postgres_reconciler.go @@ -62,10 +62,10 @@ func ReconcilePostgresDeployment(h *common_helper.Helper, ctx context.Context, i return ReconcileTasksFailFast(h, ctx, instance, tasks) } -func reconcilePostgresConfigMap(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcilePostgresConfigMap(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: PostgresConfigMapName, + Name: PostgresConfigMapName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -87,10 +87,10 @@ func reconcilePostgresConfigMap(h *common_helper.Helper, ctx context.Context, _ return nil } -func reconcilePostgresBootstrapSecret(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcilePostgresBootstrapSecret(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: PostgresBootstrapSecretName, + Name: PostgresBootstrapSecretName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -112,11 +112,11 @@ func reconcilePostgresBootstrapSecret(h *common_helper.Helper, ctx context.Conte return nil } -func reconcilePostgresSecret(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcilePostgresSecret(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { // Check if secret exists - if not, cleanup old secrets first checkSecret := &corev1.Secret{} secretKey := client.ObjectKey{ - Name: PostgresSecretName, + Name: PostgresSecretName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), } err := h.GetClient().Get(ctx, secretKey, checkSecret) @@ -131,7 +131,7 @@ func reconcilePostgresSecret(h *common_helper.Helper, ctx context.Context, _ *ap secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: PostgresSecretName, + Name: PostgresSecretName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -176,10 +176,10 @@ func deleteOldPostgresSecrets(h *common_helper.Helper, ctx context.Context) erro return nil } -func reconcilePostgresNetworkPolicy(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcilePostgresNetworkPolicy(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { np := &networkingv1.NetworkPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: PostgresNetworkPolicyName, + Name: PostgresNetworkPolicyName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -189,14 +189,14 @@ func reconcilePostgresNetworkPolicy(h *common_helper.Helper, ctx context.Context // Restricts ingress to Postgres to only allow traffic from app server pods np.Spec = networkingv1.NetworkPolicySpec{ PodSelector: metav1.LabelSelector{ - MatchLabels: generatePostgresSelectorLabels(), + MatchLabels: generatePostgresSelectorLabels(instance.Name), }, Ingress: []networkingv1.NetworkPolicyIngressRule{ { From: []networkingv1.NetworkPolicyPeer{ { PodSelector: &metav1.LabelSelector{ - MatchLabels: generateAppServerSelectorLabels(), + MatchLabels: generateAppServerSelectorLabels(instance.Name), }, }, }, @@ -236,7 +236,7 @@ func reconcilePostgresPVC(h *common_helper.Helper, ctx context.Context, instance pvc := &corev1.PersistentVolumeClaim{} pvcKey := client.ObjectKey{ - Name: PostgresDataPVCName, + Name: PostgresDataPVCName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), } @@ -259,7 +259,7 @@ func reconcilePostgresPVC(h *common_helper.Helper, ctx context.Context, instance // PVC does not exist, create it pvc = &corev1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ - Name: PostgresDataPVCName, + Name: PostgresDataPVCName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } @@ -288,19 +288,19 @@ func reconcilePostgresPVC(h *common_helper.Helper, ctx context.Context, instance func reconcilePostgresDeploymentTask(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: PostgresDeploymentName, + Name: PostgresDeploymentName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), deployment, func() error { - currentConfigMapVersion, err := getConfigMapResourceVersion(ctx, h, PostgresConfigMapName, h.GetBeforeObject().GetNamespace()) + currentConfigMapVersion, err := getConfigMapResourceVersion(ctx, h, PostgresConfigMapName(instance.Name), h.GetBeforeObject().GetNamespace()) if err != nil && !errors.IsNotFound(err) { return fmt.Errorf("%w: %v", ErrGetPostgresConfigMap, err) } // Build the desired deployment pod spec - podTemplateSpec := buildPostgresPodTemplateSpec() + podTemplateSpec := buildPostgresPodTemplateSpec(instance.Name) // Initialize annotations map if needed if podTemplateSpec.Annotations == nil { @@ -315,7 +315,7 @@ func reconcilePostgresDeploymentTask(h *common_helper.Helper, ctx context.Contex replicas := int32(1) deployment.Spec.Replicas = &replicas deployment.Spec.Selector = &metav1.LabelSelector{ - MatchLabels: generatePostgresSelectorLabels(), + MatchLabels: generatePostgresSelectorLabels(instance.Name), } deployment.Spec.Template = podTemplateSpec @@ -335,17 +335,17 @@ func reconcilePostgresDeploymentTask(h *common_helper.Helper, ctx context.Contex return nil } -func reconcilePostgresServiceTask(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcilePostgresServiceTask(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: PostgresServiceName, + Name: PostgresServiceName(instance.Name), Namespace: h.GetBeforeObject().GetNamespace(), }, } result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), svc, func() error { // Selective field updates (preserves ClusterIP, ClusterIPs, etc.) - svc.Spec.Selector = generatePostgresSelectorLabels() + svc.Spec.Selector = generatePostgresSelectorLabels(instance.Name) svc.Spec.Ports = []corev1.ServicePort{ { Port: PostgresServicePort, @@ -360,7 +360,7 @@ func reconcilePostgresServiceTask(h *common_helper.Helper, ctx context.Context, if svc.Annotations == nil { svc.Annotations = make(map[string]string) } - svc.Annotations[ServingCertSecretAnnotationKey] = PostgresCertsSecretName + svc.Annotations[ServingCertSecretAnnotationKey] = PostgresCertsSecretName(instance.Name) // Set owner reference return controllerutil.SetControllerReference(h.GetBeforeObject(), svc, h.GetScheme())