diff --git a/README.md b/README.md index f9c7ccaa..1961aa94 100644 --- a/README.md +++ b/README.md @@ -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}}" ``` diff --git a/charts/ext-postgres-operator/Chart.yaml b/charts/ext-postgres-operator/Chart.yaml index 54dd3192..bd50d708 100644 --- a/charts/ext-postgres-operator/Chart.yaml +++ b/charts/ext-postgres-operator/Chart.yaml @@ -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 @@ -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" diff --git a/charts/ext-postgres-operator/crds/db.movetokube.com_postgresusers_crd.yaml b/charts/ext-postgres-operator/crds/db.movetokube.com_postgresusers_crd.yaml index 1d9a5355..3b45527c 100644 --- a/charts/ext-postgres-operator/crds/db.movetokube.com_postgresusers_crd.yaml +++ b/charts/ext-postgres-operator/crds/db.movetokube.com_postgresusers_crd.yaml @@ -37,6 +37,10 @@ spec: type: object database: type: string + labels: + additionalProperties: + type: string + type: object privileges: type: string role: diff --git a/deploy/crds/db.movetokube.com_postgresusers_crd.yaml b/deploy/crds/db.movetokube.com_postgresusers_crd.yaml index 1d9a5355..3b45527c 100644 --- a/deploy/crds/db.movetokube.com_postgresusers_crd.yaml +++ b/deploy/crds/db.movetokube.com_postgresusers_crd.yaml @@ -37,6 +37,10 @@ spec: type: object database: type: string + labels: + additionalProperties: + type: string + type: object privileges: type: string role: diff --git a/deploy/crds/db_v1alpha1_postgresuser_cr.yaml b/deploy/crds/db_v1alpha1_postgresuser_cr.yaml index c1c875e6..4dd7b1a5 100644 --- a/deploy/crds/db_v1alpha1_postgresuser_cr.yaml +++ b/deploy/crds/db_v1alpha1_postgresuser_cr.yaml @@ -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 \ No newline at end of file + privileges: OWNER # Can be OWNER/READ/WRITE + labels: # optional labels to propagate to the secret + custom-label: custom-value diff --git a/pkg/apis/db/v1alpha1/postgresuser_types.go b/pkg/apis/db/v1alpha1/postgresuser_types.go index 80e70666..29c0fded 100644 --- a/pkg/apis/db/v1alpha1/postgresuser_types.go +++ b/pkg/apis/db/v1alpha1/postgresuser_types.go @@ -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 diff --git a/pkg/apis/db/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/db/v1alpha1/zz_generated.deepcopy.go index b8d36b75..c0f138f0 100644 --- a/pkg/apis/db/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/db/v1alpha1/zz_generated.deepcopy.go @@ -1,4 +1,3 @@ -//go:build !ignore_autogenerated // +build !ignore_autogenerated // Code generated by operator-sdk. DO NOT EDIT. @@ -217,6 +216,13 @@ func (in *PostgresUserSpec) DeepCopyInto(out *PostgresUserSpec) { (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } diff --git a/pkg/controller/postgresuser/postgresuser_controller.go b/pkg/controller/postgresuser/postgresuser_controller.go index de2adeaa..3759c5a5 100644 --- a/pkg/controller/postgresuser/postgresuser_controller.go +++ b/pkg/controller/postgresuser/postgresuser_controller.go @@ -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 { diff --git a/pkg/controller/postgresuser/postgresuser_controller_test.go b/pkg/controller/postgresuser/postgresuser_controller_test.go new file mode 100644 index 00000000..b30c7314 --- /dev/null +++ b/pkg/controller/postgresuser/postgresuser_controller_test.go @@ -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) + } +} diff --git a/tests/e2e/basic-operations/02-assert.yaml b/tests/e2e/basic-operations/02-assert.yaml index 05b3fa24..b1ec242a 100644 --- a/tests/e2e/basic-operations/02-assert.yaml +++ b/tests/e2e/basic-operations/02-assert.yaml @@ -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 diff --git a/tests/e2e/basic-operations/02-postgresuser.yaml b/tests/e2e/basic-operations/02-postgresuser.yaml index bc08e61a..f5785c47 100644 --- a/tests/e2e/basic-operations/02-postgresuser.yaml +++ b/tests/e2e/basic-operations/02-postgresuser.yaml @@ -7,3 +7,5 @@ spec: database: my-db secretName: my-secret privileges: OWNER + labels: + custom-label: custom-value diff --git a/tests/kuttl-test-self-hosted-postgres.yaml b/tests/kuttl-test-self-hosted-postgres.yaml index ab06990a..eca7f69c 100644 --- a/tests/kuttl-test-self-hosted-postgres.yaml +++ b/tests/kuttl-test-self-hosted-postgres.yaml @@ -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