diff --git a/operator/pkg/controllers/storage/manifests.sts/postgres-config-configmap.yaml b/operator/pkg/controllers/storage/manifests.sts/postgres-config-configmap.yaml index e73593bd8..cf90927f2 100644 --- a/operator/pkg/controllers/storage/manifests.sts/postgres-config-configmap.yaml +++ b/operator/pkg/controllers/storage/manifests.sts/postgres-config-configmap.yaml @@ -14,3 +14,4 @@ data: pg_stat_statements.max = 10000 pg_stat_statements.track = all {{- end }} + {{- .PostgresCustomizedConfig | indent 4 }} \ No newline at end of file diff --git a/operator/pkg/controllers/storage/postgres_statefulset.go b/operator/pkg/controllers/storage/postgres_statefulset.go index 198731cf7..405319786 100644 --- a/operator/pkg/controllers/storage/postgres_statefulset.go +++ b/operator/pkg/controllers/storage/postgres_statefulset.go @@ -31,6 +31,7 @@ var ( builtinPostgresInitName = fmt.Sprintf("%s-init", BuiltinPostgresName) builtinPartialPostgresURI = fmt.Sprintf("%s.%s.svc:5432/hoh?sslmode=verify-ca", BuiltinPostgresName, utils.GetDefaultNamespace()) + BuiltinPostgresCustomizedConfigName = "multicluster-global-hub-custom-postgresql-config" ) type postgresCredential struct { @@ -53,6 +54,13 @@ func InitPostgresByStatefulset(ctx context.Context, mgh *globalhubv1alpha4.Multi imagePullPolicy = mgh.Spec.ImagePullPolicy } + // postgres configurable + customizedConfig, err := getPostgresCustomizedConfig(ctx, mgh, mgr.GetClient()) + if err != nil { + return nil, err + } + log.Infof("the postgres customized config: %s", customizedConfig) + // get the postgres objects postgresRenderer, postgresDeployer := renderer.NewHoHRenderer(stsPostgresFS), deployer.NewHoHDeployer(mgr.GetClient()) postgresObjects, err := postgresRenderer.Render("manifests.sts", "", @@ -81,6 +89,7 @@ func InitPostgresByStatefulset(ctx context.Context, mgh *globalhubv1alpha4.Multi EnableMetrics bool EnablePostgresMetrics bool EnableInventoryAPI bool + PostgresCustomizedConfig []byte }{ Name: BuiltinPostgresName, Namespace: mgh.GetNamespace(), @@ -105,13 +114,15 @@ func InitPostgresByStatefulset(ctx context.Context, mgh *globalhubv1alpha4.Multi PostgresURI: strings.ReplaceAll(builtinPartialPostgresURI, "sslmode=verify-ca", "sslmode=disable"), Resources: operatorutils.GetResources(operatorconstants.Postgres, mgh.Spec.AdvancedSpec), - EnableMetrics: mgh.Spec.EnableMetrics, - EnablePostgresMetrics: (!config.IsBYOPostgres()) && mgh.Spec.EnableMetrics, - EnableInventoryAPI: config.WithInventory(mgh), + EnableMetrics: mgh.Spec.EnableMetrics, + EnablePostgresMetrics: (!config.IsBYOPostgres()) && mgh.Spec.EnableMetrics, + EnableInventoryAPI: config.WithInventory(mgh), + PostgresCustomizedConfig: []byte(customizedConfig), }, nil }) if err != nil { - return nil, fmt.Errorf("failed to render postgres manifests: %w", err) + log.Errorf("failed to render postgres manifests: %w", err) + return nil, err } // create restmapper for deployer to find GVR @@ -164,6 +175,24 @@ func getPostgresCredential(ctx context.Context, mgh *globalhubv1alpha4.Multiclus }, nil } +func getPostgresCustomizedConfig(ctx context.Context, mgh *globalhubv1alpha4.MulticlusterGlobalHub, + c client.Client, +) (string, error) { + cm := &corev1.ConfigMap{} + err := c.Get(ctx, types.NamespacedName{ + Name: BuiltinPostgresCustomizedConfigName, + Namespace: mgh.Namespace, + }, cm) + if err != nil && !errors.IsNotFound(err) { + return "", fmt.Errorf("failed to get the postgres customized config: %v", err) + } + customizedConfig := "" + if !errors.IsNotFound(err) { + customizedConfig = fmt.Sprintf("\n%s", cm.Data["postgresql.conf"]) + } + return customizedConfig, nil +} + func getPostgresCA(ctx context.Context, mgh *globalhubv1alpha4.MulticlusterGlobalHub, c client.Client) (string, error) { ca := &corev1.ConfigMap{} if err := c.Get(ctx, types.NamespacedName{ diff --git a/operator/pkg/controllers/storage/storage_reconciler.go b/operator/pkg/controllers/storage/storage_reconciler.go index 3199b451d..633e7b4a1 100644 --- a/operator/pkg/controllers/storage/storage_reconciler.go +++ b/operator/pkg/controllers/storage/storage_reconciler.go @@ -75,6 +75,7 @@ var WatchedSecret = sets.NewString( var WatchedConfigMap = sets.NewString( BuiltinPostgresCAName, + BuiltinPostgresCustomizedConfigName, ) var ( @@ -120,7 +121,7 @@ func (r *StorageReconciler) SetupWithManager(mgr ctrl.Manager) error { Watches(&corev1.Secret{}, &handler.EnqueueRequestForObject{}, builder.WithPredicates(secretPred)). Watches(&corev1.ConfigMap{}, - &handler.EnqueueRequestForObject{}, builder.WithPredicates(config.GeneralPredicate)). + &handler.EnqueueRequestForObject{}, builder.WithPredicates(configMapPredicate)). Watches(&appsv1.StatefulSet{}, &handler.EnqueueRequestForObject{}, builder.WithPredicates(statefulSetPred)). Watches(&corev1.ServiceAccount{}, @@ -132,6 +133,20 @@ func (r *StorageReconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } +var configMapPredicate = predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + return WatchedConfigMap.Has(e.Object.GetName()) + }, + UpdateFunc: func(e event.UpdateEvent) bool { + return WatchedConfigMap.Has(e.ObjectNew.GetName()) || + e.ObjectNew.GetLabels()[constants.GlobalHubOwnerLabelKey] == constants.GHOperatorOwnerLabelVal + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return WatchedConfigMap.Has(e.Object.GetName()) || + e.Object.GetLabels()[constants.GlobalHubOwnerLabelKey] == constants.GHOperatorOwnerLabelVal + }, +} + var statefulSetPred = predicate.Funcs{ CreateFunc: func(e event.CreateEvent) bool { return e.Object.GetNamespace() == commonutils.GetDefaultNamespace() && diff --git a/test/integration/operator/controllers/storage_test.go b/test/integration/operator/controllers/storage_test.go index f7b6b78bb..bc3af16be 100644 --- a/test/integration/operator/controllers/storage_test.go +++ b/test/integration/operator/controllers/storage_test.go @@ -23,10 +23,11 @@ import ( "github.com/stolostron/multicluster-global-hub/operator/pkg/controllers/storage" operatorutils "github.com/stolostron/multicluster-global-hub/operator/pkg/utils" "github.com/stolostron/multicluster-global-hub/pkg/constants" + "github.com/stolostron/multicluster-global-hub/pkg/utils" testutils "github.com/stolostron/multicluster-global-hub/test/integration/utils" ) -// go test ./test/integration/operator -ginkgo.focus "storage" -v +// go test ./test/integration/operator/controllers -ginkgo.focus "storage" -v var _ = Describe("storage", Ordered, func() { It("should init database with BYO", func() { namespace := fmt.Sprintf("namespace-%s", rand.String(6)) @@ -194,6 +195,18 @@ var _ = Describe("storage", Ordered, func() { Expect(runtimeClient.Create(ctx, mgh)).To(Succeed()) Expect(runtimeClient.Get(ctx, client.ObjectKeyFromObject(mgh), mgh)).To(Succeed()) + // add customized postgres configuration + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multicluster-global-hub-custom-postgresql-config", + Namespace: namespace, + }, + Data: map[string]string{ + "postgresql.conf": "wal_level = logical\nmax_wal_size = 2GB\n", + }, + } + Expect(runtimeClient.Create(ctx, cm)).To(Succeed()) + storageReconciler := storage.NewStorageReconciler(runtimeManager, true, false) // blocking until get the connection @@ -216,6 +229,13 @@ var _ = Describe("storage", Ordered, func() { return nil }, 10*time.Second, 100*time.Millisecond).ShouldNot(HaveOccurred()) + // verify the customized configuration + cm = &corev1.ConfigMap{} + err = runtimeClient.Get(ctx, types.NamespacedName{Namespace: mgh.Namespace, Name: "multicluster-global-hub-postgresql-config"}, cm) + Expect(err).To(Succeed()) + Expect(cm.Data["postgresql.conf"]).To(ContainSubstring("max_wal_size = 2GB")) + utils.PrettyPrint(cm.Data["postgresql.conf"]) + // cleanup Eventually(func() error { if err := testutils.DeleteMgh(ctx, runtimeClient, mgh); err != nil {