From e2229d6e708f583ed15847fbacbbae5dd041ae2e Mon Sep 17 00:00:00 2001 From: bjeevan-ib Date: Wed, 25 Oct 2023 11:11:38 -0700 Subject: [PATCH] support system function during upgrade --- Makefile | 2 +- controllers/databaseclaim_controller.go | 6 ++- helm/db-controller/minikube.yaml | 1 + helm/db-controller/templates/configmap.yaml | 2 +- helm/db-controller/values.yaml | 9 +++-- pkg/dbclient/client.go | 45 +++++++++++++++++++-- pkg/pgctl/pgctl.go | 1 + 7 files changed, 57 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index e3e99853..acc28cd9 100644 --- a/Makefile +++ b/Makefile @@ -343,7 +343,7 @@ push-chart-crd: clean: rm -f *build.properties || true rm -f *.tgz || true - rm .push* .image* + rm .push* .image* || true deploy-crds: .id build-chart-crd ${HELM} upgrade --install --namespace $(cat .id) ${CRDS_CHART} --version $(CHART_VERSION) diff --git a/controllers/databaseclaim_controller.go b/controllers/databaseclaim_controller.go index 4f9d0098..67004f8d 100644 --- a/controllers/databaseclaim_controller.go +++ b/controllers/databaseclaim_controller.go @@ -609,6 +609,10 @@ func (r *DatabaseClaimReconciler) reconcileNewDB(ctx context.Context, if err != nil { return ctrl.Result{}, err } + err = dbClient.ManageSystemFunctions(GetDBName(dbClaim), r.getSystemFunctions()) + if err != nil { + return ctrl.Result{}, err + } return ctrl.Result{}, nil } @@ -1079,7 +1083,7 @@ func (r *DatabaseClaimReconciler) getDbSubnetGroupNameRef() string { } func (r *DatabaseClaimReconciler) getSystemFunctions() map[string]string { - return r.Config.GetStringMapString("system-functions") + return r.Config.GetStringMapString("systemFunctions") } func (r *DatabaseClaimReconciler) getDynamicHostWaitTime() time.Duration { diff --git a/helm/db-controller/minikube.yaml b/helm/db-controller/minikube.yaml index b8b64797..17043567 100644 --- a/helm/db-controller/minikube.yaml +++ b/helm/db-controller/minikube.yaml @@ -8,3 +8,4 @@ zapLogger: level: debug dbproxy: enabled: false +env: box-3 \ No newline at end of file diff --git a/helm/db-controller/templates/configmap.yaml b/helm/db-controller/templates/configmap.yaml index bc0b67a4..4c585adb 100644 --- a/helm/db-controller/templates/configmap.yaml +++ b/helm/db-controller/templates/configmap.yaml @@ -10,5 +10,5 @@ metadata: data: {{- with .Values.controllerConfig }} "config.yaml": |- - {{- toYaml . | trim | nindent 4 }} + {{- tpl (toYaml .) $ | trim | nindent 4 }} {{ end }} diff --git a/helm/db-controller/values.yaml b/helm/db-controller/values.yaml index 1f78f4a6..2bc50d91 100644 --- a/helm/db-controller/values.yaml +++ b/helm/db-controller/values.yaml @@ -8,7 +8,8 @@ secrets: enabled: false env: local -realm: "us" +ib: + realm: "us" lifecycle: "dev" db: identifier: @@ -160,8 +161,10 @@ controllerConfig: enablePerfInsight: true # Possible values for enableCloudwatchLogsExport are all, none, postgresql and upgrade. enableCloudwatchLogsExport: "none" - system-functions: - ib_realm: "{{ tpl .Values.realm . }}" + # system funtions are created as functions in the database. The prefix is used as the schema name. + # only "ib_" prefixed functions are supported at this time. + systemFunctions: + ib_realm: "{{ .Values.ib.realm }}" ib_env: "{{ .Values.env }}" ib_lifecycle: "{{ .Values.lifecycle }}" diff --git a/pkg/dbclient/client.go b/pkg/dbclient/client.go index 3ae5fc98..e165f2c2 100644 --- a/pkg/dbclient/client.go +++ b/pkg/dbclient/client.go @@ -171,11 +171,44 @@ func (pc *client) ManageSystemFunctions(dbName string, functions map[string]stri } pc.log.Info("ManageSystemFunctions - connected to " + dbName) defer db.Close() + //check if schema ib exists + var exists bool + err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM information_schema.schemata WHERE schema_name = 'ib')").Scan(&exists) + if err != nil { + pc.log.Error(err, "could not query for schema ib") + return err + } + if !exists { + createSchema := ` + CREATE SCHEMA IF NOT EXISTS ib; + REVOKE ALL ON SCHEMA ib FROM PUBLIC; + GRANT USAGE ON SCHEMA ib TO PUBLIC; + REVOKE ALL ON ALL TABLES IN SCHEMA ib FROM PUBLIC ; + GRANT SELECT ON ALL TABLES IN SCHEMA ib TO PUBLIC; + ` + //create schema ib + _, err = db.Exec(createSchema) + if err != nil { + pc.log.Error(err, "could not create schema ib") + return err + } + } var currVal string var create bool + var schema string + sep := "_" // separator between schema and function name for f, v := range functions { create = false - err := db.QueryRow(fmt.Sprintf("SELECT %s()", f)).Scan(&currVal) + // split ib_lifecycle into schema and function name. eg. ib_life_cycle -> ib.life_cycle + f_parts := strings.Split(f, sep) + if len(f_parts) == 1 { + schema = "public" + } else { + schema = f_parts[0] + f = pq.QuoteIdentifier(strings.Join(f_parts[1:], sep)) + } + + err := db.QueryRow(fmt.Sprintf("SELECT %s.%s()", schema, f)).Scan(&currVal) //check if error contains "does not exist" if err != nil { if strings.Contains(err.Error(), "does not exist") { @@ -191,9 +224,15 @@ func (pc *client) ManageSystemFunctions(dbName string, functions map[string]stri } } if create { - _, err = db.Exec(fmt.Sprintf("CREATE OR REPLACE FUNCTION %s() RETURNS text AS $$SELECT text '%s'$$ LANGUAGE sql IMMUTABLE PARALLEL SAFE;", f, v)) + createFunction := ` + CREATE OR REPLACE FUNCTION %s.%s() + RETURNS text AS $$SELECT text '%s'$$ + LANGUAGE sql IMMUTABLE PARALLEL SAFE; + ` + _, err = db.Exec(fmt.Sprintf(createFunction, schema, f, v)) if err != nil { - pc.log.Error(err, "could not create function", "database_name", dbName, "function", f, "value", v) + pc.log.Error(err, "could not create function", "database_name", + dbName, "function", f, "value", v) return err } } diff --git a/pkg/pgctl/pgctl.go b/pkg/pgctl/pgctl.go index 7b12468a..2b59a713 100644 --- a/pkg/pgctl/pgctl.go +++ b/pkg/pgctl/pgctl.go @@ -315,6 +315,7 @@ func (s *copy_schema_state) Execute() (State, error) { "--no-subscriptions", "--no-privileges", "--no-owner", + "--exclude-schema=ib", }) dumpExec := dump.Exec(ExecOptions{StreamPrint: true})