Skip to content

Commit

Permalink
Allow global configuration options for API roles.
Browse files Browse the repository at this point in the history
Add options to the PgUser structure, potentially allowing to set
per-role options in the cluster definition as well.

Introduce api_roles_configuration operator option with the default
of log_statement=all
  • Loading branch information
alexeyklyukin committed Nov 3, 2017
1 parent 8680340 commit 0d04290
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 8 deletions.
1 change: 1 addition & 0 deletions manifests/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ data:
pod_terminate_grace_period: 5m
pdb_name_format: "postgres-{cluster}-pdb"
eol_node_label: "eol:true"
api_roles_configuration: "log_statement:all"
7 changes: 6 additions & 1 deletion pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,12 @@ func (c *Cluster) initHumanUsers() error {
}
}

c.pgUsers[username] = spec.PgUser{Name: username, Flags: flags, MemberOf: memberOf}
c.pgUsers[username] = spec.PgUser{
Name: username,
Flags: flags,
MemberOf: memberOf,
Parameters: c.OpConfig.APIRolesParameters,
}
}

return nil
Expand Down
6 changes: 5 additions & 1 deletion pkg/cluster/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,11 @@ func (c *Cluster) syncRoles(readFromDatabase bool) error {
if err != nil {
return fmt.Errorf("could not init db connection: %v", err)
}
defer c.closeDbConn()
defer func() {
if err := c.closeDbConn(); err != nil {
c.logger.Errorf("could not close db connection: %v", err)
}
}()

if readFromDatabase {
for _, u := range c.pgUsers {
Expand Down
2 changes: 2 additions & 0 deletions pkg/spec/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type syncUserOperation int
const (
PGSyncUserAdd = iota
PGsyncUserAlter
PGSyncAlterSet // handle ALTER ROLE SET parameter = value
)

// PodEvent describes the event for a single Pod
Expand All @@ -61,6 +62,7 @@ type PgUser struct {
Password string
Flags []string
MemberOf []string
Parameters map[string]string
}

// PgUserMap maps user names to the definitions.
Expand Down
13 changes: 7 additions & 6 deletions pkg/util/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,13 @@ type Config struct {
TeamAdminRole string `name:"team_admin_role" default:"admin"`
EnableLoadBalancer bool `name:"enable_load_balancer" default:"true"`
MasterDNSNameFormat stringTemplate `name:"master_dns_name_format" default:"{cluster}.{team}.{hostedzone}"`
ReplicaDNSNameFormat stringTemplate `name:"replica_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"`
PDBNameFormat stringTemplate `name:"pdb_name_format" default:"postgres-{cluster}-pdb"`
Workers uint32 `name:"workers" default:"4"`
APIPort int `name:"api_port" default:"8080"`
RingLogLines int `name:"ring_log_lines" default:"100"`
ClusterHistoryEntries int `name:"cluster_history_entries" default:"1000"`
ReplicaDNSNameFormat stringTemplate `name:"replica_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"`
PDBNameFormat stringTemplate `name:"pdb_name_format" default:"postgres-{cluster}-pdb"`
Workers uint32 `name:"workers" default:"4"`
APIPort int `name:"api_port" default:"8080"`
RingLogLines int `name:"ring_log_lines" default:"100"`
ClusterHistoryEntries int `name:"cluster_history_entries" default:"1000"`
APIRolesParameters map[string]string `name:"api_roles_configuration" default:"log_statement:all"`

PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"`
}
Expand Down
31 changes: 31 additions & 0 deletions pkg/util/users/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import (

"github.com/zalando-incubator/postgres-operator/pkg/spec"
"github.com/zalando-incubator/postgres-operator/pkg/util"
"reflect"
)

const (
createUserSQL = `SET LOCAL synchronous_commit = 'local'; CREATE ROLE "%s" %s %s;`
alterUserSQL = `ALTER ROLE "%s" %s`
alterRoleResetAllSQL = `ALTER ROLE "%s" RESET ALL`
alterRoleSetSQL = `ALTER ROLE "%s" SET "%s" TO "%s"`
grantToUserSQL = `GRANT %s TO "%s"`
doBlockStmt = `SET LOCAL synchronous_commit = 'local'; DO $$ BEGIN %s; END;$$;`
passwordTemplate = "ENCRYPTED PASSWORD '%s'"
Expand All @@ -34,6 +37,9 @@ func (s DefaultUserSyncStrategy) ProduceSyncRequests(dbUsers spec.PgUserMap,
dbUser, exists := dbUsers[name]
if !exists {
reqs = append(reqs, spec.PgSyncUserRequest{Kind: spec.PGSyncUserAdd, User: newUser})
if len(newUser.Parameters) > 0 {
reqs = append(reqs, spec.PgSyncUserRequest{Kind: spec.PGSyncAlterSet, User: newUser})
}
} else {
r := spec.PgSyncUserRequest{}
newMD5Password := util.PGUserPassword(newUser)
Expand All @@ -54,6 +60,9 @@ func (s DefaultUserSyncStrategy) ProduceSyncRequests(dbUsers spec.PgUserMap,
r.User.Name = newUser.Name
reqs = append(reqs, r)
}
if !reflect.DeepEqual(dbUser.Parameters, newUser.Parameters) {
reqs = append(reqs, spec.PgSyncUserRequest{Kind: spec.PGSyncAlterSet, User: newUser})
}
}
}

Expand All @@ -72,13 +81,26 @@ func (s DefaultUserSyncStrategy) ExecuteSyncRequests(reqs []spec.PgSyncUserReque
if err := s.alterPgUser(r.User, db); err != nil {
return fmt.Errorf("could not alter user %q: %v", r.User.Name, err)
}
case spec.PGSyncAlterSet:
if err := s.alterPgUserSet(r.User, db); err != nil {
return fmt.Errorf("could not set custom user %q parameters: %v", r.User.Name, err)
}
default:
return fmt.Errorf("unrecognized operation: %v", r.Kind)
}

}
return nil
}
func (strategy DefaultUserSyncStrategy) alterPgUserSet(user spec.PgUser, db *sql.DB) (err error) {
queries := produceAlterRoleSetStmts(user)
query := fmt.Sprintf(doBlockStmt, strings.Join(queries, ";"))
if _, err = db.Query(query); err != nil {
err = fmt.Errorf("dB error: %v, query: %q", err, query)
return
}
return
}

func (s DefaultUserSyncStrategy) createPgUser(user spec.PgUser, db *sql.DB) (err error) {
var userFlags []string
Expand Down Expand Up @@ -148,6 +170,15 @@ func produceAlterStmt(user spec.PgUser) string {
return fmt.Sprintf(alterUserSQL, user.Name, strings.Join(result, " "))
}

func produceAlterRoleSetStmts(user spec.PgUser) []string {
result := make([]string, 1)
result = append(result, fmt.Sprintf(alterRoleResetAllSQL, user.Name))
for key, value := range(user.Parameters) {
result = append(result, fmt.Sprintf(alterRoleSetSQL, user.Name, key, value))
}
return result
}

func produceGrantStmt(user spec.PgUser) string {
// GRANT ROLE "foo", "bar" TO baz
return fmt.Sprintf(grantToUserSQL, quoteMemberList(user), user.Name)
Expand Down

0 comments on commit 0d04290

Please sign in to comment.