Skip to content

Commit b6e7c49

Browse files
committed
feat: Add support for replica urls (with bouncer supported)
1 parent 131c1bf commit b6e7c49

10 files changed

+537
-19
lines changed

api/postgresql/v1alpha1/postgresqlengineconfiguration_types.go

+6
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ type UserConnections struct {
7878
// Bouncer connection is referring to a pg bouncer node.
7979
// +optional
8080
BouncerConnection *GenericUserConnection `json:"bouncerConnection,omitempty"`
81+
// Replica connections are referring to the replica nodes.
82+
// +optional
83+
ReplicaConnections []*GenericUserConnection `json:"replicaConnections,omitempty"`
84+
// Replica Bouncer connections are referring to pg bouncer nodes.
85+
// +optional
86+
ReplicaBouncerConnections []*GenericUserConnection `json:"replicaBouncerConnections,omitempty"`
8187
}
8288

8389
type GenericUserConnection struct {

api/postgresql/v1alpha1/zz_generated.deepcopy.go

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/postgresql.easymile.com_postgresqlengineconfigurations.yaml

+38
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,44 @@ spec:
129129
- host
130130
- uriArgs
131131
type: object
132+
replicaBouncerConnections:
133+
description: Replica Bouncer connections are referring to pg bouncer
134+
nodes.
135+
items:
136+
properties:
137+
host:
138+
description: Hostname
139+
type: string
140+
port:
141+
description: Port
142+
type: integer
143+
uriArgs:
144+
description: URI args like sslmode, ...
145+
type: string
146+
required:
147+
- host
148+
- uriArgs
149+
type: object
150+
type: array
151+
replicaConnections:
152+
description: Replica connections are referring to the replica
153+
nodes.
154+
items:
155+
properties:
156+
host:
157+
description: Hostname
158+
type: string
159+
port:
160+
description: Port
161+
type: integer
162+
uriArgs:
163+
description: URI args like sslmode, ...
164+
type: string
165+
required:
166+
- host
167+
- uriArgs
168+
type: object
169+
type: array
132170
type: object
133171
waitLinkedResourcesDeletion:
134172
description: Wait for linked resource to be deleted

config/samples/engineconfiguration/full-example.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,16 @@ spec:
4545
# host: localhost
4646
# uriArgs: sslmode=disable
4747
# port: 6432
48+
# Replica connections are referring to the replica nodes.
49+
# replicaConnections:
50+
# - host: localhost
51+
# uriArgs: sslmode=disable
52+
# port: 5433
53+
# - host: localhost
54+
# uriArgs: sslmode=disable
55+
# port: 5434
56+
# Replica Bouncer connections are referring to pg bouncer nodes.
57+
# replicaBouncerConnections:
58+
# - host: localhost
59+
# uriArgs: sslmode=disable
60+
# port: 6432

docs/crds/PostgresqlEngineConfiguration.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@ All these names are available for `kubectl`:
4040

4141
### UserConnections
4242

43-
| Field | Description | Scheme | Required |
44-
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | -------- |
45-
| primaryConnection | Primary connection is referring to the primary node connection. If not being set, all values will be set from spec (host, port, uriArgs) | [GenericUserConnection](#genericuserconnection) | false |
46-
| bouncerConnection | Bouncer connection is referring to a pg bouncer node. The default port will be 6432 if other fields are filled but not port. | [GenericUserConnection](#genericuserconnection) | false |
43+
| Field | Description | Scheme | Required |
44+
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | -------- |
45+
| primaryConnection | Primary connection is referring to the primary node connection. If not being set, all values will be set from spec (host, port, uriArgs) | [GenericUserConnection](#genericuserconnection) | false |
46+
| bouncerConnection | Bouncer connection is referring to a pg bouncer node. The default port will be 6432 if other fields are filled but not port. | [GenericUserConnection](#genericuserconnection) | false |
47+
| replicaConnections | Replica connections are referring to the replica nodes. The default port will be 6432 if other fields are filled but not port. | [[GenericUserConnection](#genericuserconnection)] | false |
48+
| replicaBouncerConnections | Replica Bouncer connections are referring to pg bouncer nodes. The default port will be 6432 if other fields are filled but not port. | [[GenericUserConnection](#genericuserconnection)] | false |
4749

4850
### GenericUserConnection
4951

docs/crds/PostgresqlUserRole.md

+28
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,31 @@ data:
153153
PORT: "5432"
154154
ARGS: sslmode=require
155155
```
156+
157+
Here is an example with replica:
158+
159+
```yaml
160+
apiVersion: v1
161+
kind: Secret
162+
type: Opaque
163+
metadata:
164+
name: managed-simple-rotation
165+
data:
166+
ARGS: sslmode=disable
167+
DATABASE: database1
168+
HOST: localhost
169+
LOGIN: fake-0
170+
PASSWORD: password
171+
PORT: "5432"
172+
POSTGRES_URL: postgresql://fake-0:password@localhost:5432/database1
173+
POSTGRES_URL_ARGS: postgresql://fake-0:password@localhost:5432/database1?sslmode=disable
174+
REPLICA_0_ARGS: sslmode=disable
175+
REPLICA_0_DATABASE: database1
176+
REPLICA_0_HOST: localhost
177+
REPLICA_0_LOGIN: fake-0
178+
REPLICA_0_PASSWORD: password
179+
REPLICA_0_PORT: "5432"
180+
REPLICA_0_POSTGRES_URL: postgresql://fake-0:password@localhost:5432/database1
181+
REPLICA_0_POSTGRES_URL_ARGS: postgresql://fake-0:password@localhost:5432/database1?sslmode=disable
182+
# And so on, ... The numbers are the iteration number and so order in initial list.
183+
```

internal/controller/postgresql/postgresqlengineconfiguration_controller.go

+16
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,22 @@ func (*PostgresqlEngineConfigurationReconciler) addDefaultValues(instance *postg
317317
instance.Spec.UserConnections.BouncerConnection.Port = DefaultBouncerPort
318318
}
319319
}
320+
321+
// Loop over replica connections
322+
for _, item := range instance.Spec.UserConnections.ReplicaConnections {
323+
// Check port
324+
if item.Port == 0 {
325+
item.Port = DefaultPGPort
326+
}
327+
}
328+
329+
// Loop over replica bouncer connections
330+
for _, item := range instance.Spec.UserConnections.ReplicaBouncerConnections {
331+
// Check port
332+
if item.Port == 0 {
333+
item.Port = DefaultBouncerPort
334+
}
335+
}
320336
}
321337

322338
func (r *PostgresqlEngineConfigurationReconciler) manageError(

internal/controller/postgresql/postgresqluserrole_controller.go

+50-10
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ const (
5353
UsernameSecretKey = "USERNAME"
5454
PasswordSecretKey = "PASSWORD"
5555
ManagedPasswordSize = 15
56+
57+
SecretMainKeyPostgresURL = "POSTGRES_URL" //nolint:gosec // Nothing here
58+
SecretMainKeyPostgresURLArgs = "POSTGRES_URL_ARGS" //nolint:gosec // Nothing here
59+
SecretMainKeyPassword = "PASSWORD"
60+
SecretMainKeyLogin = "LOGIN"
61+
SecretMainKeyDatabase = "DATABASE"
62+
SecretMainKeyHost = "HOST"
63+
SecretMainKeyPort = "PORT"
64+
SecretMainKeyArgs = "ARGS"
65+
66+
SecretKeyReplicaPrefix = "REPLICA"
5667
)
5768

5869
// PostgresqlUserRoleReconciler reconciles a PostgresqlUserRole object.
@@ -513,6 +524,44 @@ func (r *PostgresqlUserRoleReconciler) newSecretForPGUser(
513524

514525
pgUserURL := postgres.TemplatePostgresqlURL(uc.Host, username, password, dbInstance.Status.Database, uc.Port)
515526
pgUserURLWArgs := postgres.TemplatePostgresqlURLWithArgs(uc.Host, username, password, uc.URIArgs, dbInstance.Status.Database, uc.Port)
527+
528+
// Create secret data
529+
data := map[string][]byte{
530+
SecretMainKeyPostgresURL: []byte(pgUserURL),
531+
SecretMainKeyPostgresURLArgs: []byte(pgUserURLWArgs),
532+
SecretMainKeyPassword: []byte(password),
533+
SecretMainKeyLogin: []byte(username),
534+
SecretMainKeyDatabase: []byte(dbInstance.Status.Database),
535+
SecretMainKeyHost: []byte(uc.Host),
536+
SecretMainKeyPort: []byte(strconv.Itoa(uc.Port)),
537+
SecretMainKeyArgs: []byte(uc.URIArgs),
538+
}
539+
540+
// Manage replica connections
541+
// Prepare replica user connections
542+
rucList := pgec.Spec.UserConnections.ReplicaConnections
543+
// Check if it is a bouncer connection
544+
if rolePrivilege.ConnectionType == v1alpha1.BouncerConnectionType {
545+
rucList = pgec.Spec.UserConnections.ReplicaBouncerConnections
546+
}
547+
// Loop over list to inject in data replica data
548+
for i, ruc := range rucList {
549+
replicaPGUserURL := postgres.TemplatePostgresqlURL(ruc.Host, username, password, dbInstance.Status.Database, ruc.Port)
550+
replicaPGUserURLWArgs := postgres.TemplatePostgresqlURLWithArgs(ruc.Host, username, password, ruc.URIArgs, dbInstance.Status.Database, ruc.Port)
551+
552+
// Build template
553+
keyTemplate := SecretKeyReplicaPrefix + "_" + strconv.Itoa(i) + "_%s"
554+
// Inject into data
555+
data[fmt.Sprintf(keyTemplate, SecretMainKeyPostgresURL)] = []byte(replicaPGUserURL)
556+
data[fmt.Sprintf(keyTemplate, SecretMainKeyPostgresURLArgs)] = []byte(replicaPGUserURLWArgs)
557+
data[fmt.Sprintf(keyTemplate, SecretMainKeyPassword)] = []byte(password)
558+
data[fmt.Sprintf(keyTemplate, SecretMainKeyLogin)] = []byte(username)
559+
data[fmt.Sprintf(keyTemplate, SecretMainKeyDatabase)] = []byte(dbInstance.Status.Database)
560+
data[fmt.Sprintf(keyTemplate, SecretMainKeyHost)] = []byte(ruc.Host)
561+
data[fmt.Sprintf(keyTemplate, SecretMainKeyPort)] = []byte(strconv.Itoa(ruc.Port))
562+
data[fmt.Sprintf(keyTemplate, SecretMainKeyArgs)] = []byte(ruc.URIArgs)
563+
}
564+
516565
labels := map[string]string{
517566
"app": instance.Name,
518567
}
@@ -522,16 +571,7 @@ func (r *PostgresqlUserRoleReconciler) newSecretForPGUser(
522571
Namespace: instance.Namespace,
523572
Labels: labels,
524573
},
525-
Data: map[string][]byte{
526-
"POSTGRES_URL": []byte(pgUserURL),
527-
"POSTGRES_URL_ARGS": []byte(pgUserURLWArgs),
528-
"PASSWORD": []byte(password),
529-
"LOGIN": []byte(username),
530-
"DATABASE": []byte(dbInstance.Status.Database),
531-
"HOST": []byte(uc.Host),
532-
"PORT": []byte(strconv.Itoa(uc.Port)),
533-
"ARGS": []byte(uc.URIArgs),
534-
},
574+
Data: data,
535575
}
536576

537577
// Set owner references

0 commit comments

Comments
 (0)