From 42661660389d421d486b39b09fa64d83e41ad62b Mon Sep 17 00:00:00 2001 From: Natalia Marukovich Date: Wed, 9 Jul 2025 10:03:35 +0200 Subject: [PATCH 1/3] K8SPG-768 skip annotation updates --- internal/postgres/config.go | 62 +++++++++++++--------------------- internal/postgres/reconcile.go | 8 ++--- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/internal/postgres/config.go b/internal/postgres/config.go index 3538c40ff3..66b80efaec 100644 --- a/internal/postgres/config.go +++ b/internal/postgres/config.go @@ -170,29 +170,7 @@ func Environment(cluster *v1beta1.PostgresCluster) []corev1.EnvVar { // reloadCommand returns an entrypoint that convinces PostgreSQL to reload // certificate files when they change. The process will appear as name in `ps` // and `top`. -func reloadCommand(name string, post250 bool) []string { - // Use a Bash loop to periodically check the mtime of the mounted - // certificate volume. When it changes, copy the replication certificate, - // signal PostgreSQL, and print the observed timestamp. - // - // PostgreSQL v10 reads its server certificate files during reload (SIGHUP). - // - https://www.postgresql.org/docs/current/ssl-tcp.html#SSL-SERVER-FILES - // - https://www.postgresql.org/docs/current/app-postgres.html - // - // PostgreSQL reads its replication credentials every time it opens a - // replication connection. It does not need to be signaled when the - // certificate contents change. - // - // The copy is necessary because Kubernetes sets g+r when fsGroup is enabled, - // but PostgreSQL requires client keys to not be readable by other users. - // - https://www.postgresql.org/docs/current/libpq-ssl.html - // - https://issue.k8s.io/57923 - // - // Coreutils `sleep` uses a lot of memory, so the following opens a file - // descriptor and uses the timeout of the builtin `read` to wait. That same - // descriptor gets closed and reopened to use the builtin `[ -nt` to check - // mtimes. - // - https://unix.stackexchange.com/a/407383 +func reloadCommand(name string, post250 bool, AutoGrowVolumes bool) []string { script := fmt.Sprintf(` declare -r directory=%q exec {fd}<> <(:) @@ -214,6 +192,27 @@ done ) if post250 { + // Only add annotation update logic if AutoGrowVolumes is true + autogrowScript := "" + if AutoGrowVolumes { + autogrowScript = ` + # Manage autogrow annotation. + # Return size in Mebibytes. + size=$(df --human-readable --block-size=M /pgdata | awk 'FNR == 2 {print $2}') + use=$(df --human-readable /pgdata | awk 'FNR == 2 {print $5}') + sizeInt="${size//M/}" + # Use the sed punctuation class, because the shell will not accept the percent sign in an expansion. + useInt=$(echo $use | sed 's/[[:punct:]]//g') + triggerExpansion="$((useInt > 75))" + if [ $triggerExpansion -eq 1 ]; then + newSize="$(((sizeInt / 2)+sizeInt))" + newSizeMi="${newSize}Mi" + d='[{"op": "add", "path": "/metadata/annotations/suggested-pgdata-pvc-size", "value": "'"$newSizeMi"'"}]' + curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -XPATCH "${APISERVER}/api/v1/namespaces/${NAMESPACE}/pods/${HOSTNAME}?fieldManager=kubectl-annotate" -H "Content-Type: application/json-patch+json" --data "$d" + fi +` + } + script = fmt.Sprintf(` # Parameters for curl when managing autogrow annotation. APISERVER="https://kubernetes.default.svc" @@ -233,21 +232,7 @@ while read -r -t 5 -u "${fd}" ||:; do exec {fd}>&- && exec {fd}<> <(:||:) stat --format='Loaded certificates dated %%y' "${directory}" fi - - # Manage autogrow annotation. - # Return size in Mebibytes. - size=$(df --human-readable --block-size=M /pgdata | awk 'FNR == 2 {print $2}') - use=$(df --human-readable /pgdata | awk 'FNR == 2 {print $5}') - sizeInt="${size//M/}" - # Use the sed punctuation class, because the shell will not accept the percent sign in an expansion. - useInt=$(echo $use | sed 's/[[:punct:]]//g') - triggerExpansion="$((useInt > 75))" - if [ $triggerExpansion -eq 1 ]; then - newSize="$(((sizeInt / 2)+sizeInt))" - newSizeMi="${newSize}Mi" - d='[{"op": "add", "path": "/metadata/annotations/suggested-pgdata-pvc-size", "value": "'"$newSizeMi"'"}]' - curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -XPATCH "${APISERVER}/api/v1/namespaces/${NAMESPACE}/pods/${HOSTNAME}?fieldManager=kubectl-annotate" -H "Content-Type: application/json-patch+json" --data "$d" - fi +%s done `, naming.CertMountPath, @@ -255,6 +240,7 @@ done naming.ReplicationCertPath, naming.ReplicationPrivateKeyPath, naming.ReplicationCACertPath, + autogrowScript, // This will be empty if AutoGrowVolumes is false ) } diff --git a/internal/postgres/reconcile.go b/internal/postgres/reconcile.go index 6a1dba8ad5..ccefb3355e 100644 --- a/internal/postgres/reconcile.go +++ b/internal/postgres/reconcile.go @@ -6,15 +6,13 @@ package postgres import ( "context" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - "github.com/percona/percona-postgresql-operator/internal/config" "github.com/percona/percona-postgresql-operator/internal/feature" "github.com/percona/percona-postgresql-operator/internal/initialize" "github.com/percona/percona-postgresql-operator/internal/naming" "github.com/percona/percona-postgresql-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" ) var ( @@ -182,7 +180,7 @@ func InstancePod(ctx context.Context, reloader := corev1.Container{ Name: naming.ContainerClientCertCopy, - Command: reloadCommand(naming.ContainerClientCertCopy, inCluster.CompareVersion("2.5.0") >= 0), + Command: reloadCommand(naming.ContainerClientCertCopy, inCluster.CompareVersion("2.5.0") >= 0, feature.Enabled(ctx, feature.AutoGrowVolumes)), Image: container.Image, ImagePullPolicy: container.ImagePullPolicy, From 6eebcbe9fb3b03e76cf3521e3339245695727c48 Mon Sep 17 00:00:00 2001 From: Natalia Marukovich Date: Wed, 9 Jul 2025 10:06:47 +0200 Subject: [PATCH 2/3] K8SPG-768 skip annotation updates --- internal/postgres/config.go | 23 +++++++++++++++++++++++ internal/postgres/reconcile.go | 6 ++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/internal/postgres/config.go b/internal/postgres/config.go index 66b80efaec..ab7bd39bd4 100644 --- a/internal/postgres/config.go +++ b/internal/postgres/config.go @@ -171,6 +171,29 @@ func Environment(cluster *v1beta1.PostgresCluster) []corev1.EnvVar { // certificate files when they change. The process will appear as name in `ps` // and `top`. func reloadCommand(name string, post250 bool, AutoGrowVolumes bool) []string { + // Use a Bash loop to periodically check the mtime of the mounted + // certificate volume. When it changes, copy the replication certificate, + // signal PostgreSQL, and print the observed timestamp. + // + // PostgreSQL v10 reads its server certificate files during reload (SIGHUP). + // - https://www.postgresql.org/docs/current/ssl-tcp.html#SSL-SERVER-FILES + // - https://www.postgresql.org/docs/current/app-postgres.html + // + // PostgreSQL reads its replication credentials every time it opens a + // replication connection. It does not need to be signaled when the + // certificate contents change. + // + // The copy is necessary because Kubernetes sets g+r when fsGroup is enabled, + // but PostgreSQL requires client keys to not be readable by other users. + // - https://www.postgresql.org/docs/current/libpq-ssl.html + // - https://issue.k8s.io/57923 + // + // Coreutils `sleep` uses a lot of memory, so the following opens a file + // descriptor and uses the timeout of the builtin `read` to wait. That same + // descriptor gets closed and reopened to use the builtin `[ -nt` to check + // mtimes. + // - https://unix.stackexchange.com/a/407383 + script := fmt.Sprintf(` declare -r directory=%q exec {fd}<> <(:) diff --git a/internal/postgres/reconcile.go b/internal/postgres/reconcile.go index ccefb3355e..3aabc09364 100644 --- a/internal/postgres/reconcile.go +++ b/internal/postgres/reconcile.go @@ -6,13 +6,15 @@ package postgres import ( "context" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + "github.com/percona/percona-postgresql-operator/internal/config" "github.com/percona/percona-postgresql-operator/internal/feature" "github.com/percona/percona-postgresql-operator/internal/initialize" "github.com/percona/percona-postgresql-operator/internal/naming" "github.com/percona/percona-postgresql-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" ) var ( From de4f99c6999dbb5a32fef263f4378d47a6f428b4 Mon Sep 17 00:00:00 2001 From: Natalia Marukovich Date: Wed, 9 Jul 2025 17:41:37 +0200 Subject: [PATCH 3/3] fix test --- internal/postgres/reconcile_test.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/internal/postgres/reconcile_test.go b/internal/postgres/reconcile_test.go index 2cd1e2b933..e26bef4440 100644 --- a/internal/postgres/reconcile_test.go +++ b/internal/postgres/reconcile_test.go @@ -190,20 +190,6 @@ containers: stat --format='Loaded certificates dated %y' "${directory}" fi - # Manage autogrow annotation. - # Return size in Mebibytes. - size=$(df --human-readable --block-size=M /pgdata | awk 'FNR == 2 {print $2}') - use=$(df --human-readable /pgdata | awk 'FNR == 2 {print $5}') - sizeInt="${size//M/}" - # Use the sed punctuation class, because the shell will not accept the percent sign in an expansion. - useInt=$(echo $use | sed 's/[[:punct:]]//g') - triggerExpansion="$((useInt > 75))" - if [ $triggerExpansion -eq 1 ]; then - newSize="$(((sizeInt / 2)+sizeInt))" - newSizeMi="${newSize}Mi" - d='[{"op": "add", "path": "/metadata/annotations/suggested-pgdata-pvc-size", "value": "'"$newSizeMi"'"}]' - curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -XPATCH "${APISERVER}/api/v1/namespaces/${NAMESPACE}/pods/${HOSTNAME}?fieldManager=kubectl-annotate" -H "Content-Type: application/json-patch+json" --data "$d" - fi done }; export -f monitor; exec -a "$0" bash -ceu monitor - replication-cert-copy