Skip to content

Commit f72306c

Browse files
pimmerkspcallewaert
authored andcommitted
Add separate host and port to secret template
1 parent 0230b1e commit f72306c

File tree

5 files changed

+43
-18
lines changed

5 files changed

+43
-18
lines changed

README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,14 @@ Every PostgresUser has a generated Kubernetes secret attached to it, which conta
194194
| Key | Comment |
195195
|----------------------|---------------------|
196196
| `DATABASE_NAME` | Name of the database, same as in `Postgres` CR, copied for convenience |
197-
| `HOST` | PostgreSQL server host |
197+
| `HOST` | PostgreSQL server host (including port number) |
198198
| `PASSWORD` | Autogenerated password for user |
199199
| `ROLE` | Autogenerated role with login enabled (user) |
200200
| `LOGIN` | Same as `ROLE`. In case `POSTGRES_CLOUD_PROVIDER` is set to "Azure", `LOGIN` it will be set to `{role}@{serverName}`, serverName is extracted from `POSTGRES_USER` from operator's config. |
201201
| `POSTGRES_URL` | Connection string for Posgres, could be used for Go applications |
202202
| `POSTGRES_JDBC_URL` | JDBC compatible Postgres URI, formatter as `jdbc:postgresql://{POSTGRES_HOST}/{DATABASE_NAME}` |
203+
| `HOSTNAME` | The PostgreSQL server hostname (without port) |
204+
| `PORT` | The PostgreSQL server port |
203205

204206
### Multiple operator support
205207

@@ -219,12 +221,14 @@ meeting the specific needs of different applications.
219221

220222
Available context:
221223

222-
| Variable | Meaning |
223-
|-------------|--------------------------|
224-
| `.Host` | Database host |
225-
| `.Role` | Generated user/role name |
226-
| `.Database` | Referenced database name |
227-
| `.Password` | Generated role password |
224+
| Variable | Meaning |
225+
|-------------|------------------------------|
226+
| `.Host` | Database host |
227+
| `.Role` | Generated user/role name |
228+
| `.Database` | Referenced database name |
229+
| `.Password` | Generated role password |
230+
| `.Hostname` | Database host (without port) |
231+
| `.Port` | Database port |
228232

229233
### Compatibility
230234

internal/controller/postgresuser_controller.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"maps"
7+
"net"
78

89
corev1 "k8s.io/api/core/v1"
910
"k8s.io/apimachinery/pkg/api/errors"
@@ -177,7 +178,7 @@ func (r *PostgresUserReconciler) Reconcile(ctx context.Context, req ctrl.Request
177178
return r.requeue(ctx, instance, err)
178179
}
179180

180-
secret, err := r.newSecretForCR(instance, role, password, login)
181+
secret, err := r.newSecretForCR(reqLogger, instance, role, password, login)
181182
if err != nil {
182183
return r.requeue(ctx, instance, err)
183184
}
@@ -232,10 +233,17 @@ func (r *PostgresUserReconciler) getPostgresCR(ctx context.Context, instance *db
232233
return &database, nil
233234
}
234235

235-
func (r *PostgresUserReconciler) newSecretForCR(cr *dbv1alpha1.PostgresUser, role, password, login string) (*corev1.Secret, error) {
236+
func (r *PostgresUserReconciler) newSecretForCR(reqLogger logr.Logger, cr *dbv1alpha1.PostgresUser, role, password, login string) (*corev1.Secret, error) {
237+
hostname, port, err := net.SplitHostPort(r.pgHost)
238+
if err != nil {
239+
hostname = r.pgHost
240+
port = "5432"
241+
reqLogger.Error(err, fmt.Sprintf("failed to parse host and port from: '%s', using default port 5432", r.pgHost))
242+
}
243+
236244
pgUserUrl := fmt.Sprintf("postgresql://%s:%s@%s/%s", role, password, r.pgHost, cr.Status.DatabaseName)
237245
pgJDBCUrl := fmt.Sprintf("jdbc:postgresql://%s/%s", r.pgHost, cr.Status.DatabaseName)
238-
pgDotnetUrl := fmt.Sprintf("User ID=%s;Password=%s;Host=%s;Port=5432;Database=%s;", role, password, r.pgHost, cr.Status.DatabaseName)
246+
pgDotnetUrl := fmt.Sprintf("User ID=%s;Password=%s;Host=%s;Port=%s;Database=%s;", role, password, hostname, port, cr.Status.DatabaseName)
239247
labels := map[string]string{
240248
"app": cr.Name,
241249
}
@@ -253,6 +261,8 @@ func (r *PostgresUserReconciler) newSecretForCR(cr *dbv1alpha1.PostgresUser, rol
253261
Host: r.pgHost,
254262
Database: cr.Status.DatabaseName,
255263
Password: password,
264+
Hostname: hostname,
265+
Port: port,
256266
})
257267
if err != nil {
258268
return nil, fmt.Errorf("render templated keys: %w", err)
@@ -267,6 +277,8 @@ func (r *PostgresUserReconciler) newSecretForCR(cr *dbv1alpha1.PostgresUser, rol
267277
"ROLE": []byte(role),
268278
"PASSWORD": []byte(password),
269279
"LOGIN": []byte(login),
280+
"PORT": []byte(port),
281+
"HOSTNAME": []byte(hostname),
270282
}
271283
// templates may override standard keys
272284
if len(templateData) > 0 {

internal/controller/postgresuser_controller_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66

7+
"github.com/go-logr/logr"
78
. "github.com/onsi/ginkgo/v2"
89
. "github.com/onsi/gomega"
910
"go.uber.org/mock/gomock"
@@ -324,6 +325,8 @@ var _ = Describe("PostgresUser Controller", func() {
324325
Expect(foundSecret.Data).To(HaveKey("POSTGRES_JDBC_URL"))
325326
Expect(foundSecret.Data).To(HaveKey("POSTGRES_URL"))
326327
Expect(foundSecret.Data).To(HaveKey("ROLE"))
328+
Expect(foundSecret.Data).To(HaveKey("HOSTNAME"))
329+
Expect(foundSecret.Data).To(HaveKey("PORT"))
327330
})
328331

329332
It("should fail if the database does not exist", func() {
@@ -528,7 +531,7 @@ var _ = Describe("PostgresUser Controller", func() {
528531
}
529532

530533
// Call newSecretForCR with test values
531-
secret, err := rp.newSecretForCR(cr, "role1", "pass1", "login1")
534+
secret, err := rp.newSecretForCR(logr.Discard(), cr, "role1", "pass1", "login1")
532535

533536
// Verify results
534537
Expect(err).NotTo(HaveOccurred())
@@ -574,7 +577,7 @@ var _ = Describe("PostgresUser Controller", func() {
574577
}
575578

576579
// Call newSecretForCR
577-
secret, err := rp.newSecretForCR(cr, "role2", "pass2", "login2")
580+
secret, err := rp.newSecretForCR(logr.Discard(), cr, "role2", "pass2", "login2")
578581

579582
// Verify results
580583
Expect(err).NotTo(HaveOccurred())
@@ -611,7 +614,7 @@ var _ = Describe("PostgresUser Controller", func() {
611614
}
612615

613616
// Call newSecretForCR
614-
secret, err := rp.newSecretForCR(cr, "role3", "pass3", "login3")
617+
secret, err := rp.newSecretForCR(logr.Discard(), cr, "role3", "pass3", "login3")
615618

616619
// Verify results
617620
Expect(err).NotTo(HaveOccurred())

pkg/utils/template.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ type TemplateContext struct {
1111
Role string
1212
Database string
1313
Password string
14+
Hostname string // Hostname is different from Host as it does not contain the port number.
15+
Port string
1416
}
1517

1618
func RenderTemplate(data map[string]string, tc TemplateContext) (map[string][]byte, error) {

pkg/utils/template_test.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,33 @@ var _ = ginkgo.Describe("Template Utils", func() {
1818
Role: "admin",
1919
Database: "postgres",
2020
Password: "secret",
21+
Hostname: "localhost",
22+
Port: "5432",
2123
}
2224
})
2325

2426
ginkgo.When("provided with valid templates", func() {
2527
ginkgo.BeforeEach(func() {
2628
templates = map[string]string{
27-
"simple": "Host: {{.Host}}",
28-
"all-fields": "Host: {{.Host}}, Role: {{.Role}}, DB: {{.Database}}, Password: {{.Password}}",
29-
"multi-line": "Connection Info:\n Host: {{.Host}}\n Database: {{.Database}}",
30-
"empty-templ": "",
29+
"simple": "Host: {{.Host}}",
30+
"all-fields": "Host: {{.Host}}, Role: {{.Role}}, DB: {{.Database}}, Password: {{.Password}}",
31+
"multi-line": "Connection Info:\n Host: {{.Host}}\n Database: {{.Database}}",
32+
"empty-templ": "",
33+
"connection-string": "postgres://{{.Role}}:{{.Password}}@{{.Hostname}}:{{.Port}}/{{.Database}}",
3134
}
3235
})
3336

3437
ginkgo.It("should render all templates correctly", func() {
3538
result, err := RenderTemplate(templates, templateContext)
3639

3740
gomega.Expect(err).NotTo(gomega.HaveOccurred())
38-
gomega.Expect(result).To(gomega.HaveLen(4))
41+
gomega.Expect(result).To(gomega.HaveLen(5))
3942

4043
gomega.Expect(string(result["simple"])).To(gomega.Equal("Host: localhost"))
4144
gomega.Expect(string(result["all-fields"])).To(gomega.Equal("Host: localhost, Role: admin, DB: postgres, Password: secret"))
4245
gomega.Expect(string(result["multi-line"])).To(gomega.Equal("Connection Info:\n Host: localhost\n Database: postgres"))
4346
gomega.Expect(string(result["empty-templ"])).To(gomega.Equal(""))
47+
gomega.Expect(string(result["connection-string"])).To(gomega.Equal("postgres://admin:secret@localhost:5432/postgres"))
4448
})
4549
})
4650

0 commit comments

Comments
 (0)