@@ -227,9 +227,9 @@ func AddPgbouncer(clientset *kubernetes.Clientset, cl *crv1.Pgcluster, namespace
227227 replicaName := cl .Spec .Name + "-replica"
228228
229229 pgbouncerUser := cl .Spec .UserLabels [util .LABEL_PGBOUNCER_USER ]
230- // log.Debugf("userSpecifiedPass: %s", pgbouncerUser)
230+ // log.Debugf("userSpecifiedPass: %s", pgbouncerUser)
231231 pgbouncerPass := cl .Spec .UserLabels [util .LABEL_PGBOUNCER_PASS ]
232- // log.Debugf("userSpecifiedPass: %s", pgbouncerPass)
232+ // log.Debugf("userSpecifiedPass: %s", pgbouncerPass)
233233
234234 if updateCreds {
235235
@@ -255,7 +255,7 @@ func AddPgbouncer(clientset *kubernetes.Clientset, cl *crv1.Pgcluster, namespace
255255 clusterName := cl .Spec .Name
256256 pgbouncerName := clusterName + PGBOUNCER_SUFFIX
257257 log .Debugf ("adding a pgbouncer %s" , pgbouncerName )
258- // log.Debugf("secretUser: %s, secretPass: %s", secretUser, secretPass)
258+ // log.Debugf("secretUser: %s, secretPass: %s", secretUser, secretPass)
259259
260260 //create the pgbouncer deployment
261261 fields := PgbouncerTemplateFields {
@@ -343,8 +343,30 @@ func updatePgBouncerCredentials(clientset *kubernetes.Clientset, namespace, user
343343 log .Debug ("Error deleting pgbouncer secret, probaby not found, ignoring" )
344344 }
345345
346- connectionInfo := getDBUserInfo (namespace , clusterName , clientset )
346+ err , databaseNames := getDatabaseListForCredentials (namespace , clusterName , clientset )
347347
348+ if err != nil {
349+ log .Debug (err )
350+ return err
351+ }
352+
353+ for _ , dbName := range databaseNames {
354+
355+ connectionInfo := getDBUserInfo (namespace , clusterName , dbName , clientset )
356+
357+ log .Debugf ("Creating pgbouncer authorization in %s database" , dbName )
358+
359+ err = createPgBouncerAuthInDB (clusterName , connectionInfo , username , namespace )
360+
361+ if err != nil {
362+ log .Debugf ("Unable to create pgbouncer user in %s database" , dbName )
363+ log .Debug (err .Error ())
364+ return err
365+ }
366+ }
367+
368+ // update the password for the pgbouncer user in postgres database
369+ connectionInfo := getDBUserInfo (namespace , clusterName , "postgres" , clientset )
348370 err = updatePgBouncerDBPassword (clusterName , connectionInfo , username , password , namespace )
349371
350372 if err != nil {
@@ -360,7 +382,7 @@ func updatePgBouncerDBPassword(clusterName string, p connectionInfo, username, n
360382 var err error
361383 var conn * sql.DB
362384
363- log .Debugf ("Updating password for %s in %s " , username , p .Database )
385+ // log.Debugf("Updating password for %s in %s with %s ", username, p.Database, newPassword )
364386
365387 conn , err = sql .Open ("postgres" , "sslmode=disable user=" + p .Username + " host=" + p .Hostip + " port=" + p .Port + " dbname=" + p .Database + " password=" + p .Password )
366388 if err != nil {
@@ -389,7 +411,73 @@ func updatePgBouncerDBPassword(clusterName string, p connectionInfo, username, n
389411
390412}
391413
392- func getDBUserInfo (namespace , clusterName string , clientset * kubernetes.Clientset ) connectionInfo {
414+ func createPgBouncerAuthInDB (clusterName string , p connectionInfo , username string , namespace string ) error {
415+
416+ var err error
417+ var conn * sql.DB
418+
419+ log .Debugf ("Creating %s user for pgbouncer in %s " , username , p .Database )
420+
421+ conn , err = sql .Open ("postgres" , "sslmode=disable user=" + p .Username + " host=" + p .Hostip + " port=" + p .Port + " dbname=" + p .Database + " password=" + p .Password )
422+ if err != nil {
423+ log .Debug (err .Error ())
424+ return err
425+ }
426+
427+ var rows * sql.Rows
428+
429+ // create pgbouncer role and setup authorization.
430+ querystr := `
431+ DO $$
432+ BEGIN
433+ IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'pgbouncer') THEN
434+ CREATE ROLE pgbouncer;
435+ END IF;
436+ END
437+ $$;
438+
439+ ALTER ROLE pgbouncer LOGIN;
440+
441+ CREATE SCHEMA IF NOT EXISTS pgbouncer AUTHORIZATION pgbouncer;
442+
443+ CREATE OR REPLACE FUNCTION pgbouncer.get_auth(p_username TEXT)
444+ RETURNS TABLE(username TEXT, password TEXT) AS
445+ $$
446+ BEGIN
447+ RAISE WARNING 'PgBouncer auth request: %', p_username;
448+
449+ RETURN QUERY
450+ SELECT rolname::TEXT, rolpassword::TEXT
451+ FROM pg_authid
452+ WHERE NOT rolsuper
453+ AND rolname = p_username;
454+ END;
455+ $$ LANGUAGE plpgsql SECURITY DEFINER;
456+
457+ REVOKE ALL ON FUNCTION pgbouncer.get_auth(p_username TEXT) FROM PUBLIC;
458+ GRANT EXECUTE ON FUNCTION pgbouncer.get_auth(p_username TEXT) TO pgbouncer; `
459+
460+ rows , err = conn .Query (querystr )
461+
462+ if err != nil {
463+ log .Debug (err .Error ())
464+ return err
465+ }
466+
467+ defer func () {
468+ if conn != nil {
469+ conn .Close ()
470+ }
471+ if rows != nil {
472+ rows .Close ()
473+ }
474+ }()
475+
476+ return err
477+
478+ }
479+
480+ func getDBUserInfo (namespace , clusterName string , targetDB string , clientset * kubernetes.Clientset ) connectionInfo {
393481 info := connectionInfo {}
394482
395483 //get the service for the cluster
@@ -410,7 +498,7 @@ func getDBUserInfo(namespace, clusterName string, clientset *kubernetes.Clientse
410498 for _ , s := range secrets .Items {
411499 username = string (s .Data [util .LABEL_USERNAME ][:])
412500 password = string (s .Data [util .LABEL_PASSWORD ][:])
413- database = "postgres"
501+ database = targetDB
414502 hostip = service .Spec .ClusterIP
415503 if username == "postgres" {
416504 log .Debug ("got postgres user secrets" )
@@ -428,6 +516,53 @@ func getDBUserInfo(namespace, clusterName string, clientset *kubernetes.Clientse
428516 return info
429517}
430518
519+ func getDatabaseListForCredentials (namespace , clusterName string , clientSet * kubernetes.Clientset ) (error , []string ) {
520+
521+ info := getDBUserInfo (namespace , clusterName , "postgres" , clientSet )
522+
523+ log .Debug ("Getting list of database names to update for pgbouncer" )
524+
525+ var databases []string
526+
527+ var err error
528+ var conn * sql.DB
529+
530+ conn , err = sql .Open ("postgres" , "sslmode=disable user=" + info .Username + " host=" + info .Hostip + " port=" + info .Port + " dbname=" + info .Database + " password=" + info .Password )
531+ if err != nil {
532+ log .Debug (err .Error ())
533+ return err , databases
534+ }
535+
536+ // get a list of database names from postgres
537+ var rows * sql.Rows
538+ querystr := "SELECT datname FROM pg_database WHERE datname NOT IN ('template0', 'template1')"
539+ rows , err = conn .Query (querystr )
540+ if err != nil {
541+ log .Debug (err .Error ())
542+ return err , databases
543+ }
544+
545+ defer func () {
546+ if conn != nil {
547+ conn .Close ()
548+ }
549+ if rows != nil {
550+ rows .Close ()
551+ }
552+ }()
553+
554+ for rows .Next () {
555+ var dbName string
556+ if err := rows .Scan (& dbName ); err != nil {
557+ log .Debug (err )
558+ }
559+ databases = append (databases , dbName )
560+ }
561+
562+ return err , databases
563+
564+ }
565+
431566// CreatePgbouncerSecret create a secret used by pgbouncer
432567func createPgbouncerSecret (clientset * kubernetes.Clientset , cl * crv1.Pgcluster , primary , replica , db , secretName , namespace string ) (error , string , string ) {
433568
0 commit comments