Skip to content

Commit a3dbcea

Browse files
committed
fix concurrency issue by checking the secret update
1 parent 7e7e05b commit a3dbcea

File tree

1 file changed

+64
-6
lines changed

1 file changed

+64
-6
lines changed

internal/controller/postgrescluster/postgres.go

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"k8s.io/apimachinery/pkg/types"
2626
"k8s.io/apimachinery/pkg/util/sets"
2727
"k8s.io/apimachinery/pkg/util/validation/field"
28+
"k8s.io/client-go/util/retry"
2829
"sigs.k8s.io/controller-runtime/pkg/client"
2930

3031
"github.com/percona/percona-postgresql-operator/internal/feature"
@@ -49,6 +50,7 @@ import (
4950
func (r *Reconciler) generatePostgresUserSecret(
5051
cluster *v1beta1.PostgresCluster, spec *v1beta1.PostgresUserSpec, existing *corev1.Secret,
5152
) (*corev1.Secret, error) {
53+
log := logging.FromContext(context.Background())
5254
username := string(spec.Name)
5355
// K8SPG-359
5456
intent := &corev1.Secret{}
@@ -75,10 +77,12 @@ func (r *Reconciler) generatePostgresUserSecret(
7577
if existing != nil {
7678
intent.Data["password"] = existing.Data["password"]
7779
intent.Data["verifier"] = existing.Data["verifier"]
80+
log.Info("password located for existing secret", "secret", existing.String())
7881
}
7982

8083
// When password is unset, generate a new one according to the specified policy.
8184
if len(intent.Data["password"]) == 0 {
85+
log.Info("password is going to be generated for secret")
8286
// NOTE: The tests around ASCII passwords are lacking. When changing
8387
// this, make sure that ASCII is the default.
8488
generate := util.GenerateASCIIPassword
@@ -496,6 +500,9 @@ func (r *Reconciler) reconcilePostgresUserSecrets(
496500
userSpecs[string(specUsers[i].Name)] = &specUsers[i]
497501
}
498502

503+
// K8SPG-570 for secrets that were created manually, update them
504+
// with the right labels so that the selector called next to track them
505+
// and utilize their data.
499506
for _, user := range specUsers {
500507
if user.SecretName != "" {
501508
if err := r.updateCustomSecretLabels(ctx, cluster, user); err != nil {
@@ -590,9 +597,10 @@ func (r *Reconciler) reconcilePostgresUserSecrets(
590597
return specUsers, userSecrets, err
591598
}
592599

593-
// updateCustomSecretLabels checks if a custom secret exists - can be created manually through kubectl apply
594-
// and updates it with required labels if they are missing that enabled the
595-
// naming.AsSelector(naming.ClusterPostgresUsers(cluster.Name)) to identify them.
600+
// K8SPG-570
601+
// updateCustomSecretLabels checks if a custom secret exists - can be created manually through
602+
// kubectl apply - and updates it with required labels if they are missing. This enables the
603+
// naming.AsSelector(naming.ClusterPostgresUsers(cluster.Name)) to identify these secrets.
596604
func (r *Reconciler) updateCustomSecretLabels(
597605
ctx context.Context, cluster *v1beta1.PostgresCluster, user v1beta1.PostgresUserSpec,
598606
) error {
@@ -611,11 +619,10 @@ func (r *Reconciler) updateCustomSecretLabels(
611619
return errors.Wrap(err, fmt.Sprintf("failed to get user %s secret %s", userName, secretName))
612620
}
613621

614-
orig := secret.DeepCopy()
615-
616622
requiredLabels := map[string]string{
617623
naming.LabelCluster: cluster.Name,
618624
naming.LabelPostgresUser: userName,
625+
naming.LabelRole: naming.RolePostgresUser,
619626
}
620627

621628
needsUpdate := false
@@ -631,7 +638,58 @@ func (r *Reconciler) updateCustomSecretLabels(
631638
}
632639

633640
if needsUpdate {
634-
return errors.WithStack(r.Client.Patch(ctx, secret.DeepCopy(), client.MergeFrom(orig)))
641+
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
642+
current := &corev1.Secret{}
643+
if err := r.Client.Get(ctx, types.NamespacedName{
644+
Name: secretName,
645+
Namespace: cluster.Namespace,
646+
}, current); err != nil {
647+
return err
648+
}
649+
650+
currentOrig := current.DeepCopy()
651+
if current.Labels == nil {
652+
current.Labels = make(map[string]string)
653+
}
654+
655+
updateNeeded := false
656+
for labelKey, labelValue := range requiredLabels {
657+
if existing, exists := current.Labels[labelKey]; !exists || existing != labelValue {
658+
current.Labels[labelKey] = labelValue
659+
updateNeeded = true
660+
}
661+
}
662+
663+
if !updateNeeded {
664+
return nil
665+
}
666+
667+
return r.Client.Patch(ctx, current, client.MergeFrom(currentOrig))
668+
})
669+
670+
if err != nil {
671+
return errors.Wrap(err, fmt.Sprintf("failed to update secret %s", secretName))
672+
}
673+
674+
verifyErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
675+
verifySecret := &corev1.Secret{}
676+
if err := r.Client.Get(ctx, types.NamespacedName{
677+
Name: secretName,
678+
Namespace: cluster.Namespace,
679+
}, verifySecret); err != nil {
680+
return err
681+
}
682+
683+
for labelKey, labelValue := range requiredLabels {
684+
if existing, exists := verifySecret.Labels[labelKey]; !exists || existing != labelValue {
685+
return errors.Errorf("secret %s label %s not yet propagated", secretName, labelKey)
686+
}
687+
}
688+
689+
return nil
690+
})
691+
692+
return errors.Wrap(verifyErr, "failed to update secret")
635693
}
636694

637695
return nil

0 commit comments

Comments
 (0)