Skip to content

Commit 859ea81

Browse files
committed
Handle postgresql host change. Still need a general garbage collection mechanism.
1 parent 188c742 commit 859ea81

File tree

9 files changed

+105
-46
lines changed

9 files changed

+105
-46
lines changed

api/v1beta1/postgresql_types.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ import (
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
)
2323

24-
const DEFAULT_POSTGRESQL_ROOT_USER = "postgres"
24+
// defaults
25+
const (
26+
DEFAULT_POSTGRESQL_ROOT_USER = "postgres"
27+
DEFAULT_ROOT_AUTHENTICATION_DATABASE = "postgres"
28+
)
2529

2630
type PostgreSQLRootSecretLookup struct {
2731
Name string `json:"name"`
@@ -44,8 +48,10 @@ type PostgreSQLSpec struct {
4448
Host string `json:"host"`
4549
Port int64 `json:"port"`
4650
// +optional
47-
RootUsername string `json:"rootUsername"`
48-
RootSecretLookup PostgreSQLRootSecretLookup `json:"rootSecretLookup"`
51+
RootUsername string `json:"rootUsername"`
52+
// +optional
53+
RootAuthenticationDatabase string `json:"rootAuthDatabase"`
54+
RootSecretLookup PostgreSQLRootSecretLookup `json:"rootSecretLookup"`
4955
// Database credentials
5056
Credentials PostgreSQLCredentials `json:"credentials"`
5157
}
@@ -111,6 +117,9 @@ func (this *PostgreSQL) SetDefaults() error {
111117
if this.Spec.RootUsername == "" {
112118
this.Spec.RootUsername = DEFAULT_POSTGRESQL_ROOT_USER
113119
}
120+
if this.Spec.RootAuthenticationDatabase == "" {
121+
this.Spec.RootAuthenticationDatabase = DEFAULT_ROOT_AUTHENTICATION_DATABASE
122+
}
114123
if this.Spec.RootSecretLookup.Name == "" {
115124
return errors.New("must specify root secret")
116125
}

api/v1beta1/status.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,16 @@ type DatabaseStatus struct {
5151
Status StatusCode `json:"status"`
5252
Message string `json:"message"`
5353
Name string `json:"name"`
54+
Host string `json:"host"`
5455
}
5556

56-
func (s *DatabaseStatus) SetDatabaseStatus(code StatusCode, message string, name string) {
57+
func (s *DatabaseStatus) SetDatabaseStatus(code StatusCode, message string, name string, host string) {
5758
s.Status = code
5859
s.Message = message
5960
if name != "" {
6061
s.Name = name
6162
}
63+
if host != "" {
64+
s.Host = host
65+
}
6266
}

common/db/mongodb/repository.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ type UserHolder struct {
3131
}
3232

3333
type MongoDBServer struct {
34-
client *mongo.Client
35-
URI string
34+
client *mongo.Client
35+
uri string
36+
authenticationDatabase string
3637
}
3738

3839
func NewMongoDBServer(uri string, rootUser string, rootPassword string, authenticationDatabase string) (*MongoDBServer, error) {
@@ -54,31 +55,53 @@ func NewMongoDBServer(uri string, rootUser string, rootPassword string, authenti
5455
return nil, err
5556
}
5657
return &MongoDBServer{
57-
client: client,
58-
URI: uri,
58+
client: client,
59+
uri: uri,
60+
authenticationDatabase: authenticationDatabase,
5961
}, nil
6062
}
6163

62-
func (m *MongoDBServer) SetupUser() {
63-
64+
func (m *MongoDBServer) SetupUser(database string, username string, password string) (string, error) {
65+
doesUserExist, err := m.doesUserExist(database, username)
66+
if err != nil {
67+
return "", err
68+
}
69+
if !doesUserExist {
70+
return m.createUser(database, username, password)
71+
}
72+
return "user already exists", nil
6473
}
6574

66-
func (m *MongoDBServer) DoesUserExist(database string, username string) (*Users, error) {
75+
func (m *MongoDBServer) doesUserExist(database string, username string) (bool, error) {
6776
command := &bson.D{primitive.E{Key: "usersInfo", Value: username}}
6877
r := m.runCommand(database, command)
6978
if err := r.Err(); err != nil {
70-
return nil, err
79+
return false, err
7180
}
7281
var user Users
7382
if err := r.Decode(&user); err != nil {
74-
return nil, err
83+
return false, err
84+
}
85+
if user.Users == nil || len(user.Users) == 0 {
86+
return false, nil
7587
}
76-
return &user, nil
88+
return true, nil
89+
//if br, err := r.DecodeBytes(); err != nil {
90+
// return "", err
91+
//} else {
92+
// return br.String(), nil
93+
//}
94+
}
95+
96+
func (m *MongoDBServer) createUser(database string, username string, password string) (string, error) {
97+
//command := &bson.D{{"createUser", username}, {"pwd", password}, {"roles", []bson.M{{"role": "readWrite", "db": database}}}}
98+
//r := m.runCommand(m.authenticationDatabase, command)
7799
//if br, err := r.DecodeBytes(); err != nil {
78100
// return "", err
79101
//} else {
80102
// return br.String(), nil
81103
//}
104+
return "", nil
82105
}
83106

84107
func (m *MongoDBServer) runCommand(database string, command *bson.D) *mongo.SingleResult {

common/db/postgresql/cache.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ func NewCache() *Cache {
1111
}
1212
}
1313

14-
func (c *Cache) Get(host string, port string, rootUsername string, rootPassword string) (*PostgreSQLServer, error) {
14+
func (c *Cache) Get(host string, rootUsername string, rootPassword string, rootAuthenticationDatabase string) (*PostgreSQLServer, error) {
1515
if _, ok := c.cache[host]; !ok {
16-
if server, err := NewPostgreSQLServer(host, port, rootUsername, rootPassword); err != nil {
16+
if server, err := NewPostgreSQLServer(host, rootUsername, rootPassword, rootAuthenticationDatabase); err != nil {
1717
return nil, err
1818
} else {
1919
c.cache[host] = server

common/db/postgresql/repository.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,27 @@ import (
1111
type PostgreSQLServer struct {
1212
dbpool *pgxpool.Pool
1313
Host string
14-
Port string
1514
RootUser string
1615
RootPassword string
16+
RootDatabase string
1717
}
1818

19-
func NewPostgreSQLServer(host string, port string, rootUser string, rootPassword string) (*PostgreSQLServer, error) {
20-
dbpool, err := pgxpool.Connect(context.Background(), fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=postgres", host, port, rootUser, rootPassword))
19+
func getPostgreSQLConnectionURI(host string, rootUser string, rootPassword string, rootDatabase string) string {
20+
// alternative dsn string: "host=%s port=%s user=%s password=%s dbname=%s"
21+
return fmt.Sprintf("postgresql://%s:%s@%s/%s", rootUser, rootPassword, host, rootDatabase)
22+
}
23+
24+
func NewPostgreSQLServer(host string, rootUser string, rootPassword string, rootDatabase string) (*PostgreSQLServer, error) {
25+
dbpool, err := pgxpool.Connect(context.Background(), getPostgreSQLConnectionURI(host, rootUser, rootPassword, rootDatabase))
2126
if err != nil {
2227
return nil, err
2328
}
2429
return &PostgreSQLServer{
2530
dbpool: dbpool,
2631
Host: host,
27-
Port: port,
2832
RootUser: rootUser,
2933
RootPassword: rootPassword,
34+
RootDatabase: rootDatabase,
3035
}, nil
3136
}
3237

@@ -144,14 +149,6 @@ func (s *PostgreSQLServer) revokeAllPrivileges(user string, database string) err
144149
return nil
145150
}
146151

147-
func (s *PostgreSQLServer) connect() (*pgxpool.Pool, error) {
148-
dbpool, err := pgxpool.Connect(context.Background(), fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=postgres", s.Host, s.Port, s.RootUser, s.RootPassword))
149-
if err != nil {
150-
return nil, err
151-
}
152-
return dbpool, nil
153-
}
154-
155152
func (s *PostgreSQLServer) doesDatabaseExist(database string) (bool, error) {
156153
var result int64
157154
err := s.dbpool.QueryRow(context.Background(), fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname='%s';", database)).Scan(&result)

config/crd/bases/infra.doodle.com_mongodbs.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,16 @@ spec:
103103
type: array
104104
database:
105105
properties:
106+
host:
107+
type: string
106108
message:
107109
type: string
108110
name:
109111
type: string
110112
status:
111113
type: string
112114
required:
115+
- host
113116
- message
114117
- name
115118
- status

config/crd/bases/infra.doodle.com_postgresqls.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ spec:
7676
port:
7777
format: int64
7878
type: integer
79+
rootAuthDatabase:
80+
type: string
7981
rootSecretLookup:
8082
properties:
8183
field:
@@ -119,13 +121,16 @@ spec:
119121
type: array
120122
database:
121123
properties:
124+
host:
125+
type: string
122126
message:
123127
type: string
124128
name:
125129
type: string
126130
status:
127131
type: string
128132
required:
133+
- host
129134
- message
130135
- name
131136
- status

controllers/mongodb_controller.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package controllers
1818

1919
import (
2020
"context"
21-
"fmt"
2221
"github.com/pkg/errors"
2322
apierrors "k8s.io/apimachinery/pkg/api/errors"
2423
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -68,18 +67,18 @@ func (r *MongoDBReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
6867
}
6968

7069
for _, credential := range mongodb.Spec.Credentials {
71-
if u, err := mongodbserver.DoesUserExist(mongodb.Spec.DatabaseName, credential.UserName); err != nil {
70+
if u, err := mongodbserver.SetupUser(mongodb.Spec.DatabaseName, credential.UserName, "password"); err != nil {
7271
log.Error(err, "Error while getting user", "user", credential.UserName)
7372
mongodb.Status.DatabaseStatus.Status = infrav1beta1.Available
7473
mongodb.Status.DatabaseStatus.Message = err.Error()
7574
return r.updateAndReturn(&ctx, &mongodb, &log)
7675
} else {
77-
if u == nil {
78-
log.Info("user is nil")
79-
} else {
80-
log.Info("user returned", "whole struct", fmt.Sprintf("%+v", u))
81-
}
82-
//log.Info("user returned", "user", u)
76+
//if u == nil {
77+
// log.Info("user is nil")
78+
//} else {
79+
// log.Info("user returned", "whole struct", fmt.Sprintf("%+v", u))
80+
//}
81+
log.Info("user returned", "user", u)
8382
mongodb.Status.DatabaseStatus.Status = infrav1beta1.Available
8483
mongodb.Status.DatabaseStatus.Message = "Database up."
8584
}

controllers/postgresql_controller.go

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package controllers
1818

1919
import (
2020
"context"
21-
"fmt"
2221
infrav1beta1 "github.com/doodlescheduling/kubedb/api/v1beta1"
2322
postgresqlAPI "github.com/doodlescheduling/kubedb/common/db/postgresql"
2423
vaultAPI "github.com/doodlescheduling/kubedb/common/vault"
@@ -68,44 +67,64 @@ func (r *PostgreSQLReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error)
6867

6968
// set spec defaults. Does not mutate the spec, since we are not updating resource
7069
if err := postgresql.SetDefaults(); err != nil {
71-
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "")
70+
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "", "")
71+
postgresql.Status.CredentialsStatus = make(infrav1beta1.CredentialsStatus, 0)
7272
return r.updateAndReturn(&ctx, &postgresql, &log)
7373
}
7474

7575
// get root database password from k8s secret
7676
rootPassword, err := r.getRootPassword(&ctx, postgresql.Spec.RootSecretLookup.Name, postgresql.Spec.RootSecretLookup.Namespace, postgresql.Spec.RootSecretLookup.Field)
7777
if err != nil {
78-
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "")
78+
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "", "")
79+
postgresql.Status.CredentialsStatus = make(infrav1beta1.CredentialsStatus, 0)
7980
return r.updateAndReturn(&ctx, &postgresql, &log)
8081
}
8182

82-
// postgresql connection, cached
83-
postgreSQLServer, err := r.ServerCache.Get(postgresql.Spec.Host, fmt.Sprintf("%d", postgresql.Spec.Port), postgresql.Spec.RootUsername, rootPassword)
83+
// if host is changed, drop credentials for old host. Keep database & data for now, until we figure out what we'll do with it
84+
// TODO refactor to have a general garbage collector mechanism, instead of code throughout controller
85+
if postgresql.Spec.Host != postgresql.Status.DatabaseStatus.Host {
86+
// we might not be able to login with these old credentials anymore
87+
postgreSQLServerOld, err := r.ServerCache.Get(postgresql.Status.DatabaseStatus.Host, postgresql.Spec.RootUsername, rootPassword, postgresql.Spec.RootAuthenticationDatabase)
88+
if err != nil {
89+
// ignore the error for now
90+
} else {
91+
postgresql.Status.CredentialsStatus.ForEach(func(status *infrav1beta1.CredentialStatus) {
92+
_ = postgreSQLServerOld.DropUser(status.Username, postgresql.Status.DatabaseStatus.Name)
93+
})
94+
}
95+
}
96+
97+
// postgresql connection to spec host, cached
98+
postgreSQLServer, err := r.ServerCache.Get(postgresql.Spec.Host, postgresql.Spec.RootUsername, rootPassword, postgresql.Spec.RootAuthenticationDatabase)
8499
if err != nil {
85-
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "")
100+
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "", postgresql.Spec.Host)
101+
postgresql.Status.CredentialsStatus = make(infrav1beta1.CredentialsStatus, 0)
86102
return r.updateAndReturn(&ctx, &postgresql, &log)
87103
}
88104
// vault connection, cached
89105
vault, err := r.VaultCache.Get(postgresql.Spec.RootSecretLookup.Name)
90106
if err != nil {
91-
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "")
107+
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "", postgresql.Spec.Host)
108+
postgresql.Status.CredentialsStatus = make(infrav1beta1.CredentialsStatus, 0)
92109
return r.updateAndReturn(&ctx, &postgresql, &log)
93110
}
94111

95112
// TODO for now, disallow database renaming
96113
if postgresql.Spec.DatabaseName != postgresql.Status.DatabaseStatus.Name && postgresql.Status.DatabaseStatus.Name != "" {
97-
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, "Cannot change the name of the database.", "")
114+
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, "Cannot change the name of the database.", "", postgresql.Spec.Host)
115+
postgresql.Status.CredentialsStatus = make(infrav1beta1.CredentialsStatus, 0)
98116
r.ServerCache.Remove(postgresql.Spec.Host)
99117
return r.updateAndReturn(&ctx, &postgresql, &log)
100118
}
101119

102120
// Setup database
103121
if err := postgreSQLServer.CreateDatabaseIfNotExists(postgresql.Spec.DatabaseName); err != nil {
104-
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "")
122+
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Unavailable, err.Error(), "", postgresql.Spec.Host)
123+
postgresql.Status.CredentialsStatus = make(infrav1beta1.CredentialsStatus, 0)
105124
r.ServerCache.Remove(postgresql.Spec.Host)
106125
return r.updateAndReturn(&ctx, &postgresql, &log)
107126
}
108-
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Available, "Database up.", postgresql.Spec.DatabaseName)
127+
postgresql.Status.DatabaseStatus.SetDatabaseStatus(infrav1beta1.Available, "Database up.", postgresql.Spec.DatabaseName, postgresql.Spec.Host)
109128

110129
// Delete all credentials if they exist, and are no longer required by spec
111130
if postgresql.Spec.Credentials == nil {

0 commit comments

Comments
 (0)