Skip to content

feat: custom secret labels #173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ spec:
privileges: OWNER # Can be OWNER/READ/WRITE
annotations: # Annotations to be propagated to the secrets metadata section (optional)
foo: "bar"
labels:
foo: "bar" # Labels to be propagated to the secrets metadata section (optional)
secretTemplate: # Output secrets can be customized using standard Go templates
PQ_URL: "host={{.Host}} user={{.Role}} password={{.Password}} dbname={{.Database}}"
```
Expand Down
6 changes: 3 additions & 3 deletions charts/ext-postgres-operator/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: v2
name: ext-postgres-operator
description: |
A Helm chart for the External Postgres operator

helm repo add ext-postgres-operator https://movetokube.github.io/postgres-operator/
helm upgrade --install -n operators ext-postgres-operator ext-postgres-operator/ext-postgres-operator --version 1.2.3

Expand All @@ -11,10 +11,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.2.6
version: 1.2.7

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.3.3"
appVersion: "1.3.5"
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ spec:
type: object
database:
type: string
labels:
additionalProperties:
type: string
type: object
privileges:
type: string
role:
Expand Down
4 changes: 4 additions & 0 deletions deploy/crds/db.movetokube.com_postgresusers_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ spec:
type: object
database:
type: string
labels:
additionalProperties:
type: string
type: object
privileges:
type: string
role:
Expand Down
4 changes: 3 additions & 1 deletion deploy/crds/db_v1alpha1_postgresuser_cr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ spec:
role: username
database: my-db # This references the Postgres CR
secretName: my-secret
privileges: OWNER # Can be OWNER/READ/WRITE
privileges: OWNER # Can be OWNER/READ/WRITE
labels: # optional labels to propagate to the secret
custom-label: custom-value
2 changes: 2 additions & 0 deletions pkg/apis/db/v1alpha1/postgresuser_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type PostgresUserSpec struct {
Privileges string `json:"privileges"`
// +optional
Annotations map[string]string `json:"annotations,omitempty"`
// +optional
Labels map[string]string `json:"labels,omitempty"`
}

// PostgresUserStatus defines the observed state of PostgresUser
Expand Down
8 changes: 7 additions & 1 deletion pkg/apis/db/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pkg/controller/postgresuser/postgresuser_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@ func (r *ReconcilePostgresUser) newSecretForCR(cr *dbv1alpha1.PostgresUser, role
labels := map[string]string{
"app": cr.Name,
}
// Merge in user-defined secret labels
for k, v := range cr.Spec.Labels {
labels[k] = v
}
annotations := cr.Spec.Annotations
name := fmt.Sprintf("%s-%s", cr.Spec.SecretName, cr.Name)
if r.keepSecretName {
Expand Down
138 changes: 138 additions & 0 deletions pkg/controller/postgresuser/postgresuser_controller_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package postgresuser

import (
"reflect"
"testing"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

dbv1alpha1 "github.com/movetokube/postgres-operator/pkg/apis/db/v1alpha1"
)

func TestNewSecretForCR_UserDefinedLabels(t *testing.T) {
r := &ReconcilePostgresUser{
pgHost: "localhost",
keepSecretName: false,
}
cr := &dbv1alpha1.PostgresUser{
ObjectMeta: metav1.ObjectMeta{
Name: "myuser",
Namespace: "myns",
},
Spec: dbv1alpha1.PostgresUserSpec{
SecretName: "mysecret",
Labels: map[string]string{
"custom": "label",
"foo": "bar",
},
Annotations: map[string]string{
"anno": "value",
},
},
Status: dbv1alpha1.PostgresUserStatus{
DatabaseName: "somedb",
},
}
secret, err := r.newSecretForCR(cr, "role1", "pass1", "login1")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedLabels := map[string]string{
"app": "myuser",
"custom": "label",
"foo": "bar",
}
if !reflect.DeepEqual(secret.Labels, expectedLabels) {
t.Errorf("labels mismatch: got %v, want %v", secret.Labels, expectedLabels)
}
if secret.Annotations["anno"] != "value" {
t.Errorf("annotations mismatch: got %v", secret.Annotations)
}
expectedName := "mysecret-myuser"
if secret.Name != expectedName {
t.Errorf("secret name mismatch: got %s, want %s", secret.Name, expectedName)
}
if secret.Namespace != "myns" {
t.Errorf("secret namespace mismatch: got %s", secret.Namespace)
}
if string(secret.Data["ROLE"]) != "role1" {
t.Errorf("secret data ROLE mismatch: got %s", secret.Data["ROLE"])
}
if string(secret.Data["PASSWORD"]) != "pass1" {
t.Errorf("secret data PASSWORD mismatch: got %s", secret.Data["PASSWORD"])
}
if string(secret.Data["LOGIN"]) != "login1" {
t.Errorf("secret data LOGIN mismatch: got %s", secret.Data["LOGIN"])
}
if string(secret.Data["DATABASE_NAME"]) != "somedb" {
t.Errorf("secret data DATABASE_NAME mismatch: got %s", secret.Data["DATABASE_NAME"])
}
if string(secret.Data["HOST"]) != "localhost" {
t.Errorf("secret data HOST mismatch: got %s", secret.Data["HOST"])
}
}

func TestNewSecretForCR_EmptyLabels(t *testing.T) {
r := &ReconcilePostgresUser{
pgHost: "localhost",
keepSecretName: false,
}
cr := &dbv1alpha1.PostgresUser{
ObjectMeta: metav1.ObjectMeta{
Name: "myuser2",
Namespace: "myns2",
},
Spec: dbv1alpha1.PostgresUserSpec{
SecretName: "mysecret2",
Labels: map[string]string{},
},
Status: dbv1alpha1.PostgresUserStatus{
DatabaseName: "somedb2",
},
}
secret, err := r.newSecretForCR(cr, "role2", "pass2", "login2")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedLabels := map[string]string{
"app": "myuser2",
}
if !reflect.DeepEqual(secret.Labels, expectedLabels) {
t.Errorf("labels mismatch: got %v, want %v", secret.Labels, expectedLabels)
}
expectedName := "mysecret2-myuser2"
if secret.Name != expectedName {
t.Errorf("secret name mismatch: got %s, want %s", secret.Name, expectedName)
}
if secret.Namespace != "myns2" {
t.Errorf("secret namespace mismatch: got %s", secret.Namespace)
}
}

func TestNewSecretForCR_KeepSecretName(t *testing.T) {
r := &ReconcilePostgresUser{
pgHost: "localhost",
keepSecretName: true,
}
cr := &dbv1alpha1.PostgresUser{
ObjectMeta: metav1.ObjectMeta{
Name: "myuser3",
Namespace: "myns3",
},
Spec: dbv1alpha1.PostgresUserSpec{
SecretName: "mysecret3",
Labels: map[string]string{},
},
Status: dbv1alpha1.PostgresUserStatus{
DatabaseName: "somedb3",
},
}
secret, err := r.newSecretForCR(cr, "role3", "pass3", "login3")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
expectedName := "mysecret3"
if secret.Name != expectedName {
t.Errorf("secret name mismatch with keepSecretName: got %s, want %s", secret.Name, expectedName)
}
}
11 changes: 11 additions & 0 deletions tests/e2e/basic-operations/02-assert.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,18 @@ apiVersion: db.movetokube.com/v1alpha1
kind: PostgresUser
metadata:
name: my-db-user
spec:
labels:
custom-label: custom-value
status:
databaseName: test-db
postgresGroup: test-db-group
succeeded: true
---
apiVersion: v1
kind: Secret
metadata:
name: my-secret-my-db-user
labels:
custom-label: custom-value
app: my-db-user
2 changes: 2 additions & 0 deletions tests/e2e/basic-operations/02-postgresuser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ spec:
database: my-db
secretName: my-secret
privileges: OWNER
labels:
custom-label: custom-value
2 changes: 1 addition & 1 deletion tests/kuttl-test-self-hosted-postgres.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ commands:
--wait
timeout: 120
- command: >-
helm install -n $NAMESPACE ext-postgres-operator ext-postgres-operator/ext-postgres-operator
helm install -n $NAMESPACE ext-postgres-operator ./charts/ext-postgres-operator
--set image.repository=postgres-operator
--set image.tag=build
--set postgres.host=postgresql
Expand Down