Skip to content

Commit 76900cd

Browse files
armrumnencialeonardoce
authored
refactor(instance,secrets): extract sub-reconciler for instance secrets management (cloudnative-pg#7265)
This patch introduces a dedicated subreconciler to manage PostgreSQL cryptographic material. The refactored logic is now reused across multiple components: * the instance manager reconciliation loop * the "join" bootstrap job * the PostgreSQL major upgrade process Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com> Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com> Signed-off-by: Leonardo Cecchi <leonardo.cecchi@enterprisedb.com> Co-authored-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com> Co-authored-by: Leonardo Cecchi <leonardo.cecchi@enterprisedb.com>
1 parent 9d3c513 commit 76900cd

File tree

12 files changed

+647
-328
lines changed

12 files changed

+647
-328
lines changed

internal/cmd/manager/instance/join/cmd.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,11 @@ import (
2929
ctrl "sigs.k8s.io/controller-runtime/pkg/client"
3030

3131
apiv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
32-
"github.com/cloudnative-pg/cloudnative-pg/internal/management/controller"
3332
"github.com/cloudnative-pg/cloudnative-pg/internal/management/istio"
3433
"github.com/cloudnative-pg/cloudnative-pg/internal/management/linkerd"
3534
"github.com/cloudnative-pg/cloudnative-pg/pkg/management"
3635
"github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres"
37-
"github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres/webserver/metricserver"
36+
instancecertificate "github.com/cloudnative-pg/cloudnative-pg/pkg/reconciler/instance/certificate"
3837
)
3938

4039
// NewCmd creates the new "join" command
@@ -108,22 +107,17 @@ func joinSubCommand(ctx context.Context, instance *postgres.Instance, info postg
108107
return err
109108
}
110109

111-
// Create a fake reconciler just to download the secrets and
112-
// the cluster definition
113-
metricExporter := metricserver.NewExporter(instance)
114-
reconciler := controller.NewInstanceReconciler(instance, client, metricExporter)
115-
116110
// Download the cluster definition from the API server
117111
var cluster apiv1.Cluster
118-
if err := reconciler.GetClient().Get(ctx,
112+
if err := client.Get(ctx,
119113
ctrl.ObjectKey{Namespace: instance.GetNamespaceName(), Name: instance.GetClusterName()},
120114
&cluster,
121115
); err != nil {
122116
contextLogger.Error(err, "Error while getting cluster")
123117
return err
124118
}
125119

126-
if _, err := reconciler.RefreshSecrets(ctx, &cluster); err != nil {
120+
if _, err := instancecertificate.NewReconciler(client, instance).RefreshSecrets(ctx, &cluster); err != nil {
127121
contextLogger.Error(err, "Error while refreshing secrets")
128122
return err
129123
}

internal/cmd/manager/instance/upgrade/execute/cmd.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import (
5252
"github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres/constants"
5353
postgresutils "github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres/utils"
5454
"github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres/webserver/metricserver"
55+
instancecertificate "github.com/cloudnative-pg/cloudnative-pg/pkg/reconciler/instance/certificate"
5556
"github.com/cloudnative-pg/cloudnative-pg/pkg/specs"
5657
"github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
5758
)
@@ -131,22 +132,22 @@ func upgradeSubCommand(
131132
return err
132133
}
133134

134-
// Create a fake reconciler just to download the secrets and
135-
// the cluster definition
136-
metricExporter := metricserver.NewExporter(instance)
137-
reconciler := controller.NewInstanceReconciler(instance, client, metricExporter)
138-
139135
// Download the cluster definition from the API server
140136
var cluster apiv1.Cluster
141-
if err := reconciler.GetClient().Get(ctx, clusterObjectKey, &cluster); err != nil {
137+
if err := client.Get(ctx, clusterObjectKey, &cluster); err != nil {
142138
contextLogger.Error(err, "Error while getting cluster")
143139
return err
144140
}
145141

146-
if _, err := reconciler.RefreshSecrets(ctx, &cluster); err != nil {
142+
if _, err := instancecertificate.NewReconciler(client, instance).RefreshSecrets(ctx, &cluster); err != nil {
147143
return fmt.Errorf("error while downloading secrets: %w", err)
148144
}
149145

146+
// Create a fake reconciler just to download the secrets and
147+
// the cluster definition
148+
metricExporter := metricserver.NewExporter(instance)
149+
reconciler := controller.NewInstanceReconciler(instance, client, metricExporter)
150+
150151
if err := reconciler.ReconcileWalStorage(ctx); err != nil {
151152
return fmt.Errorf("error while reconciling the WAL storage: %w", err)
152153
}

internal/management/controller/instance_controller.go

Lines changed: 1 addition & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ package controller
2121

2222
import (
2323
"context"
24-
"crypto/tls"
2524
"database/sql"
2625
"errors"
2726
"fmt"
@@ -49,7 +48,6 @@ import (
4948
"github.com/cloudnative-pg/cloudnative-pg/internal/management/controller/roles"
5049
"github.com/cloudnative-pg/cloudnative-pg/internal/management/controller/slots/reconciler"
5150
"github.com/cloudnative-pg/cloudnative-pg/internal/management/utils"
52-
"github.com/cloudnative-pg/cloudnative-pg/pkg/certs"
5351
"github.com/cloudnative-pg/cloudnative-pg/pkg/configfile"
5452
postgresManagement "github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres"
5553
"github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres/constants"
@@ -159,7 +157,7 @@ func (r *InstanceReconciler) Reconcile(
159157

160158
// Reconcile secrets and cryptographic material
161159
// This doesn't need the PG connection, but it needs to reload it in case of changes
162-
reloadNeeded, err := r.RefreshSecrets(ctx, cluster)
160+
reloadNeeded, err := r.certificateReconciler.RefreshSecrets(ctx, cluster)
163161
if err != nil {
164162
return reconcile.Result{}, fmt.Errorf("while refreshing secrets: %w", err)
165163
}
@@ -895,62 +893,6 @@ func (r *InstanceReconciler) reconcileMonitoringQueries(
895893
r.metricsServerExporter.SetCustomQueries(queriesCollector)
896894
}
897895

898-
// RefreshSecrets is called when the PostgreSQL secrets are changed
899-
// and will refresh the contents of the file inside the Pod, without
900-
// reloading the actual PostgreSQL instance.
901-
//
902-
// It returns a boolean flag telling if something changed. Usually
903-
// the invoker will check that flag and reload the PostgreSQL
904-
// instance it is up.
905-
func (r *InstanceReconciler) RefreshSecrets(
906-
ctx context.Context,
907-
cluster *apiv1.Cluster,
908-
) (bool, error) {
909-
type executor func(context.Context, *apiv1.Cluster) (bool, error)
910-
911-
contextLogger := log.FromContext(ctx)
912-
913-
var changed bool
914-
915-
secretRefresher := func(cb executor) error {
916-
localChanged, err := cb(ctx, cluster)
917-
if err == nil {
918-
changed = changed || localChanged
919-
return nil
920-
}
921-
922-
if !apierrors.IsNotFound(err) {
923-
return err
924-
}
925-
926-
return nil
927-
}
928-
929-
if err := secretRefresher(r.refreshServerCertificateFiles); err != nil {
930-
contextLogger.Error(err, "Error while getting server secret")
931-
return changed, err
932-
}
933-
934-
if err := secretRefresher(r.refreshReplicationUserCertificate); err != nil {
935-
contextLogger.Error(err, "Error while getting streaming replication secret")
936-
return changed, err
937-
}
938-
if err := secretRefresher(r.refreshClientCA); err != nil {
939-
contextLogger.Error(err, "Error while getting cluster CA Client secret")
940-
return changed, err
941-
}
942-
if err := secretRefresher(r.refreshServerCA); err != nil {
943-
contextLogger.Error(err, "Error while getting cluster CA Server secret")
944-
return changed, err
945-
}
946-
if err := secretRefresher(r.refreshBarmanEndpointCA); err != nil {
947-
contextLogger.Error(err, "Error while getting barman endpoint CA secret")
948-
return changed, err
949-
}
950-
951-
return changed, nil
952-
}
953-
954896
// reconcileInstance sets PostgreSQL instance parameters to current values
955897
func (r *InstanceReconciler) reconcileInstance(cluster *apiv1.Cluster) {
956898
detectRequiresDesignatedPrimaryTransition := func() bool {
@@ -1094,128 +1036,6 @@ func (r *InstanceReconciler) triggerRestartForDecrease(ctx context.Context, clus
10941036
)
10951037
}
10961038

1097-
// refreshCertificateFilesFromSecret receive a secret and rewrite the file
1098-
// corresponding to the server certificate
1099-
func (r *InstanceReconciler) refreshInstanceCertificateFromSecret(
1100-
secret *corev1.Secret,
1101-
) error {
1102-
certData, ok := secret.Data[corev1.TLSCertKey]
1103-
if !ok {
1104-
return fmt.Errorf("missing %s field in Secret", corev1.TLSCertKey)
1105-
}
1106-
1107-
keyData, ok := secret.Data[corev1.TLSPrivateKeyKey]
1108-
if !ok {
1109-
return fmt.Errorf("missing %s field in Secret", corev1.TLSPrivateKeyKey)
1110-
}
1111-
1112-
certificate, err := tls.X509KeyPair(certData, keyData)
1113-
if err != nil {
1114-
return fmt.Errorf("failed decoding Secret: %w", err)
1115-
}
1116-
1117-
r.instance.ServerCertificate = &certificate
1118-
1119-
return err
1120-
}
1121-
1122-
// refreshCertificateFilesFromSecret receive a secret and rewrite the file
1123-
// corresponding to the server certificate
1124-
func (r *InstanceReconciler) refreshCertificateFilesFromSecret(
1125-
ctx context.Context,
1126-
secret *corev1.Secret,
1127-
certificateLocation string,
1128-
privateKeyLocation string,
1129-
) (bool, error) {
1130-
contextLogger := log.FromContext(ctx)
1131-
1132-
certificate, ok := secret.Data[corev1.TLSCertKey]
1133-
if !ok {
1134-
return false, fmt.Errorf("missing %s field in Secret", corev1.TLSCertKey)
1135-
}
1136-
1137-
privateKey, ok := secret.Data[corev1.TLSPrivateKeyKey]
1138-
if !ok {
1139-
return false, fmt.Errorf("missing %s field in Secret", corev1.TLSPrivateKeyKey)
1140-
}
1141-
1142-
certificateIsChanged, err := fileutils.WriteFileAtomic(certificateLocation, certificate, 0o600)
1143-
if err != nil {
1144-
return false, fmt.Errorf("while writing server certificate: %w", err)
1145-
}
1146-
1147-
if certificateIsChanged {
1148-
contextLogger.Info("Refreshed configuration file",
1149-
"filename", certificateLocation,
1150-
"secret", secret.Name)
1151-
}
1152-
1153-
privateKeyIsChanged, err := fileutils.WriteFileAtomic(privateKeyLocation, privateKey, 0o600)
1154-
if err != nil {
1155-
return false, fmt.Errorf("while writing server private key: %w", err)
1156-
}
1157-
1158-
if privateKeyIsChanged {
1159-
contextLogger.Info("Refreshed configuration file",
1160-
"filename", privateKeyLocation,
1161-
"secret", secret.Name)
1162-
}
1163-
1164-
return certificateIsChanged || privateKeyIsChanged, nil
1165-
}
1166-
1167-
// refreshCAFromSecret receive a secret and rewrite the ca.crt file to the provided location
1168-
func (r *InstanceReconciler) refreshCAFromSecret(
1169-
ctx context.Context,
1170-
secret *corev1.Secret,
1171-
destLocation string,
1172-
) (bool, error) {
1173-
caCertificate, ok := secret.Data[certs.CACertKey]
1174-
if !ok {
1175-
return false, fmt.Errorf("missing %s entry in Secret", certs.CACertKey)
1176-
}
1177-
1178-
changed, err := fileutils.WriteFileAtomic(destLocation, caCertificate, 0o600)
1179-
if err != nil {
1180-
return false, fmt.Errorf("while writing server certificate: %w", err)
1181-
}
1182-
1183-
if changed {
1184-
log.FromContext(ctx).Info("Refreshed configuration file",
1185-
"filename", destLocation,
1186-
"secret", secret.Name)
1187-
}
1188-
1189-
return changed, nil
1190-
}
1191-
1192-
// refreshFileFromSecret receive a secret and rewrite the file corresponding to the key to the provided location
1193-
func (r *InstanceReconciler) refreshFileFromSecret(
1194-
ctx context.Context,
1195-
secret *corev1.Secret,
1196-
key, destLocation string,
1197-
) (bool, error) {
1198-
contextLogger := log.FromContext(ctx)
1199-
data, ok := secret.Data[key]
1200-
if !ok {
1201-
return false, fmt.Errorf("missing %s entry in Secret", key)
1202-
}
1203-
1204-
changed, err := fileutils.WriteFileAtomic(destLocation, data, 0o600)
1205-
if err != nil {
1206-
return false, fmt.Errorf("while writing file: %w", err)
1207-
}
1208-
1209-
if changed {
1210-
contextLogger.Info("Refreshed configuration file",
1211-
"filename", destLocation,
1212-
"secret", secret.Name,
1213-
"key", key)
1214-
}
1215-
1216-
return changed, nil
1217-
}
1218-
12191039
// Reconciler primary logic. DB needed.
12201040
func (r *InstanceReconciler) reconcilePrimary(ctx context.Context, cluster *apiv1.Cluster) error {
12211041
contextLogger := log.FromContext(ctx)

0 commit comments

Comments
 (0)