Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GCP wrapper #83

Merged
merged 3 commits into from
Apr 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ unit-test:
go tool cover -func coverage.out
unit-test-coverage: unit-test
go tool cover -html coverage.out
linux-build:
@GOBIN=/work/bin GO111MODULE=on GOOS=linux GOARC=x86_64 go build --mod=vendor -o operator github.com/movetokube/postgres-operator/cmd/manager
docker-build:
docker run -ti -v $(PWD):/work -w /work golang:1.13.15-stretch make linux-build
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ In order for this operator to work correctly with Azure managed PostgreSQL datab
* `POSTGRES_CLOUD_PROVIDER` set to `Azure`
* `POSTGRES_DEFAULT_DATABASE` set to your default database, i.e. `postgres`

### GCP

In order for this operator to work correctly with GCP, you need to set `POSTGRES_CLOUD_PROVIDER` to `GCP`

To have operator work with GCP properly you have to:
* use postgresql connection in secret
* manually create a Master role e.g. "devops-operators"
* use such role in database CR e.g. spec.masterRole: devops-operator

DropRole method will check for db owner and will skip master role dropping

## Installation

This operator requires a Kubernetes Secret to be created in the same namespace as operator itself.
Expand Down
3 changes: 3 additions & 0 deletions pkg/postgres/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ const (
GRANT_USAGE_SCHEMA = `GRANT USAGE ON SCHEMA "%s" TO "%s"`
GRANT_ALL_TABLES = `GRANT %s ON ALL TABLES IN SCHEMA "%s" TO "%s"`
DEFAULT_PRIVS_SCHEMA = `ALTER DEFAULT PRIVILEGES FOR ROLE "%s" IN SCHEMA "%s" GRANT %s ON TABLES TO "%s"`
REVOKE_CONNECT = `REVOKE CONNECT ON DATABASE "%s" FROM public`
TERMINATE_BACKEND = `SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = "%s" AND pid <> pg_backend_pid()`
GET_DB_OWNER = `SELECT pg_catalog.pg_get_userbyid(d.datdba) FROM pg_catalog.pg_database d WHERE d.datname = "%s"`
GRANT_CREATE_SCHEMA = `GRANT CREATE ON DATABASE "%s" TO "%s"`
)

Expand Down
85 changes: 85 additions & 0 deletions pkg/postgres/gcp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package postgres

import (
"fmt"

"github.com/go-logr/logr"
"github.com/lib/pq"
)

type gcppg struct {
pg
}

func newGCPPG(postgres *pg) PG {
return &gcppg{
*postgres,
}
}

func (c *gcppg) DropDatabase(database string, logger logr.Logger) error {

_, err := c.db.Exec(fmt.Sprintf(REVOKE_CONNECT, database))
// Error code 3D000 is returned if database doesn't exist
if err != nil && err.(*pq.Error).Code != "3D000" {
return err
}

_, err = c.db.Exec(fmt.Sprintf(TERMINATE_BACKEND, database))
// Error code 3D000 is returned if database doesn't exist
if err != nil && err.(*pq.Error).Code != "3D000" {
return err
}
_, err = c.db.Exec(fmt.Sprintf(DROP_DATABASE, database))
// Error code 3D000 is returned if database doesn't exist
if err != nil && err.(*pq.Error).Code != "3D000" {
return err
}

logger.Info(fmt.Sprintf("Dropped database %s", database))

aroundthecode marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

func (c *gcppg) CreateDB(dbname, role string) error {

err := c.GrantRole(role, c.user)
if err != nil {
return err
}
err = c.pg.CreateDB(dbname, role)
if err != nil {
return err
}
return nil
}

func (c *gcppg) DropRole(role, newOwner, database string, logger logr.Logger) error {

tmpDb, err := GetConnection(c.user, c.pass, c.host, database, c.args, logger)
q := fmt.Sprintf(GET_DB_OWNER, database)
logger.Info("Checking master role: "+ q)
rows, err := tmpDb.Query(q)
if err != nil {
return err
}
var masterRole string
for rows.Next() {
rows.Scan(&masterRole)
}

if( role != masterRole){
q = fmt.Sprintf(DROP_ROLE, role)
logger.Info("GCP Drop Role: "+ q)
_, err = tmpDb.Exec(q)
// Check if error exists and if different from "ROLE NOT FOUND" => 42704
if err != nil && err.(*pq.Error).Code != "42704" {
return err
}

aroundthecode marked this conversation as resolved.
Show resolved Hide resolved
defer tmpDb.Close()
} else {
logger.Info(fmt.Sprintf("GCP refusing DropRole on master role " + masterRole))
}
return nil
}
6 changes: 6 additions & 0 deletions pkg/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,16 @@ func NewPG(host, user, password, uri_args, default_database, cloud_type string,

switch cloud_type {
case "AWS":
logger.Info("Using AWS wrapper")
return newAWSPG(postgres), nil
case "Azure":
logger.Info("Using Azure wrapper")
return newAzurePG(postgres), nil
case "GCP":
logger.Info("Using GCP wrapper")
return newGCPPG(postgres), nil
default:
logger.Info("Using default postgres implementation")
return postgres, nil
}
}
Expand Down