Skip to content

Commit

Permalink
create partman extension in partman schema and grant access (#233)
Browse files Browse the repository at this point in the history
* create partman extension in partman schema and grant access

* update golang version

* pinned version of envtest to avoid kubernetes-sigs/controller-runtime#2720
  • Loading branch information
bjeevan-ib authored Apr 15, 2024
1 parent 71be670 commit 8d7ef54
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 21 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,11 @@ kustomize: ## Download kustomize locally if necessary.
ENVTEST = $(shell pwd)/bin/setup-envtest
.PHONY: envtest
envtest: ## Download envtest-setup locally if necessary.
$(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest)
#commenting out the latest setup-envttest to use elease-0.16- because of https://github.com/kubernetes-sigs/controller-runtime/issues/2720
#$(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest)
#TODO- reuse the above command after fix from controller-runtime or after we go to go 1.22
$(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/[email protected])


# go-get-tool will 'go get' any package $2 and install it to $1.
PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
Expand Down
9 changes: 8 additions & 1 deletion controllers/databaseclaim_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1587,10 +1587,17 @@ func (r *DatabaseClaimReconciler) manageUser(dbClient dbclient.Client, status *p
rotationTime := r.getPasswordRotationTime()

// create role
_, err := dbClient.CreateGroup(dbName, baseUsername)
roleCreated, err := dbClient.CreateGroup(dbName, baseUsername)
if err != nil {
return err
}
if roleCreated {
// take care of special extentions related to the user
err = dbClient.CreateSpecialExtentions(dbName, baseUsername)
if err != nil {
return err
}
}

if dbu.IsUserChanged(*status) {
oldUsername := dbu.TrimUserSuffix(status.ConnectionInfo.Username)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ require (
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/text v0.13.0
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.14.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
Expand Down
2 changes: 1 addition & 1 deletion helm/db-controller/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ controllerConfig:
authSource: secret
# if aws authorization is used iam role must be provided
#iamRole: rds-role
caCertificateIdentifier: "rds-ca-2019"
caCertificateIdentifier: "rds-ca-rsa2048-g1"
dbMultiAZEnabled: false
dbSubnetGroupNameRef:
defaultBackupPolicyValue: Bronze
Expand Down
82 changes: 72 additions & 10 deletions pkg/dbclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,14 @@ const (
RDSSuperUserRole = "rds_superuser"
)

var extensions = []string{"citext", "uuid-ossp",
var defaultExtensions = []string{"citext", "uuid-ossp",
"pgcrypto", "hstore", "pg_stat_statements",
"plpgsql", "pg_partman", "hll", "pg_cron"}
"plpgsql", "hll"}

var specialExtensionsMap = map[string]func(*client, string, string) error{
"pg_partman": (*client).pg_partman,
"pg_cron": (*client).pg_cron,
}

type client struct {
dbType string
Expand Down Expand Up @@ -110,8 +115,9 @@ func (pc *client) CreateDataBase(name string) (bool, error) {
return pc.CreateDatabase(name)
}

// unit test override
var getDefaulExtensions = func() []string {
return extensions
return defaultExtensions
}

func (pc *client) CreateDatabase(dbName string) (bool, error) {
Expand Down Expand Up @@ -157,21 +163,77 @@ func (pc *client) CreateDefaultExtentions(dbName string) error {
}
pc.log.Info("created extension " + s)
}
var exists bool
err = db.QueryRow("SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = $1)", "pg_cron").Scan(&exists)

return nil
}

func (pc *client) CreateSpecialExtentions(dbName string, role string) error {
db, err := pc.getDB(dbName)
if err != nil {
pc.log.Error(err, "could not connect to db", "database", dbName)
return err
}
if exists {
// pg_cron extension is enabled - grant permission
_, err = db.Exec("GRANT USAGE ON SCHEMA cron TO public")
if err != nil {
pc.log.Error(err, "could not GRANT USAGE ON SCHEMA cron TO public")
pc.log.Info("connected to " + dbName)
defer db.Close()
for functionName := range specialExtensionsMap {
if err := specialExtensionsMap[functionName](pc, dbName, role); err != nil {
pc.log.Error(err, "error creating extention %s", functionName)
return err
}
}
return nil
}
func (pc *client) pg_cron(dbName string, role string) error {
// create extension pg_cron and grant usage to public
db, err := pc.getDB(dbName)
if err != nil {
pc.log.Error(err, "Failed to connect to database", "database", dbName)
return err
}
defer db.Close()

pc.log.Info("Connected to database", "database", dbName)

_, err = db.Exec(fmt.Sprintf(`
CREATE EXTENSION IF NOT EXISTS pg_cron;
GRANT USAGE ON SCHEMA cron TO %s;
`, pq.QuoteIdentifier(role)))
if err != nil {
pc.log.Error(err, "Failed to create extension pg_cron and grant usage on schema cron to public", "database", dbName)
return fmt.Errorf("failed to create extension pg_cron and grant usage on schema cron to public: %w", err)
}

pc.log.Info("Created pg_cron extension and granted usage on schema cron", "role", role)

return nil
}
func (pc *client) pg_partman(dbName string, role string) error {

db, err := pc.getDB(dbName)
if err != nil {
pc.log.Error(err, "could not connect to db", "database", dbName)
return err
}
defer db.Close()
createPartman := fmt.Sprintf(`
CREATE SCHEMA IF NOT EXISTS partman;
CREATE EXTENSION IF NOT EXISTS pg_partman WITH SCHEMA partman;
GRANT ALL ON SCHEMA partman TO %s;
GRANT ALL ON ALL TABLES IN SCHEMA partman TO %s;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA partman TO %s;
GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA partman TO %s;
`, pq.QuoteIdentifier(role), pq.QuoteIdentifier(role),
pq.QuoteIdentifier(role), pq.QuoteIdentifier(role))

_, err = db.Exec(createPartman)
if err != nil {
pc.log.Error(err, "could not create extension pg_partman")
return err
}
pc.log.Info("Created pg_partmann extension and granted usage on schema partman", "role", role)

return nil
}

func (pc *client) ManageSystemFunctions(dbName string, functions map[string]string) error {
db, err := pc.getDB(dbName)
Expand Down
1 change: 1 addition & 0 deletions pkg/dbclient/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type Client interface {
CreateUser(username, role, userPassword string) (bool, error)
CreateGroup(dbName, username string) (bool, error)
CreateDefaultExtentions(dbName string) error
CreateSpecialExtentions(dbName string, role string) error
RenameUser(oldUsername string, newUsername string) error
UpdateUser(oldUsername, newUsername, rolename, password string) error
UpdatePassword(username string, userPassword string) error
Expand Down
13 changes: 6 additions & 7 deletions pkg/pgctl/pgdump.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,12 @@ func (x *Dump) modifyPgDumpInfo() error {
return fmt.Errorf("error running sed command to comment create policy: %w", err)
}

// If pg_cron is installed, grant usage on schema cron to public
grantCmd := exec.Command("sed", "-i", "/^CREATE EXTENSION IF NOT EXISTS pg_cron/a GRANT USAGE ON SCHEMA cron TO public;", filePath)
grantCmd.Stderr = os.Stderr
grantCmd.Stdout = os.Stdout

if err := grantCmd.Run(); err != nil {
return fmt.Errorf("error running sed command to grant usage on schema cron: %w", err)
// add if not exists to partman schema creation
replaceCmd := exec.Command("sed", "-i", "s/CREATE SCHEMA partman;/CREATE SCHEMA IF NOT EXISTS partman;/", filePath)
replaceCmd.Stderr = os.Stderr
replaceCmd.Stdout = os.Stdout
if err := replaceCmd.Run(); err != nil {
return fmt.Errorf("error running sed command add if not exists to partman schema creation: %w", err)
}

return nil
Expand Down

0 comments on commit 8d7ef54

Please sign in to comment.