@@ -104,10 +104,12 @@ func (r *PerconaServerMySQLReconciler) SetupWithManager(mgr ctrl.Manager) error
104104}
105105
106106const (
107- fieldSecretsName = ".spec.secretsName"
107+ fieldSecretsName = ".spec.secretsName"
108+ fieldEncryptionKeySecretName = ".spec.backup.encryptionKeySecret.name"
108109)
109110
110111func setupFieldIndexers (mgr ctrl.Manager ) error {
112+ // Index cluster secrets field
111113 if err := mgr .GetFieldIndexer ().IndexField (context .Background (), & apiv1.PerconaServerMySQL {}, fieldSecretsName , func (o client.Object ) []string {
112114 cluster , ok := o .(* apiv1.PerconaServerMySQL )
113115 if ! ok {
@@ -121,6 +123,34 @@ func setupFieldIndexers(mgr ctrl.Manager) error {
121123 }); err != nil {
122124 return errors .Wrapf (err , "index field %s" , fieldSecretsName )
123125 }
126+
127+ // Index cluster backup encryption key secrets field
128+ if err := mgr .GetFieldIndexer ().IndexField (
129+ context .Background (),
130+ & apiv1.PerconaServerMySQL {},
131+ fieldEncryptionKeySecretName ,
132+ func (rawObj client.Object ) []string {
133+ cluster := rawObj .(* apiv1.PerconaServerMySQL )
134+ if cluster .Spec .Backup == nil {
135+ return nil
136+ }
137+ result := []string {}
138+
139+ if cluster .Spec .Backup .EncryptionKeySecret != nil {
140+ result = append (result , cluster .Spec .Backup .EncryptionKeySecret .Name )
141+ }
142+
143+ for _ , storage := range cluster .Spec .Backup .Storages {
144+ if storage == nil || storage .EncryptionKeySecret == nil {
145+ continue
146+ }
147+ result = append (result , storage .EncryptionKeySecret .Name )
148+ }
149+ return result
150+ },
151+ ); err != nil {
152+ return errors .Wrapf (err , "unable to index field %s" , fieldEncryptionKeySecretName )
153+ }
124154 return nil
125155}
126156
@@ -161,38 +191,21 @@ func enqueueClusterFromEncryptionKeySecret(c client.Client) handler.EventHandler
161191 }
162192 clusters := & apiv1.PerconaServerMySQLList {}
163193 log := logf .FromContext (ctx )
164- if err := c .List (ctx , clusters , client .InNamespace (secret .Namespace )); err != nil {
194+ if err := c .List (ctx , clusters , client .InNamespace (secret .Namespace ), client.MatchingFields {
195+ fieldEncryptionKeySecretName : secret .Name ,
196+ }); err != nil {
165197 log .Error (err , "failed to list clusters" )
166198 return nil
167199 }
168200
169201 var requests []reconcile.Request
170202 for _ , cluster := range clusters .Items {
171- if cluster .Spec .Backup == nil {
172- continue
173- }
174-
175- if cluster .Spec .Backup .EncryptionKeySecret != nil && cluster .Spec .Backup .EncryptionKeySecret .Name == secret .Name {
176- requests = append (requests , reconcile.Request {
177- NamespacedName : types.NamespacedName {
178- Name : cluster .Name ,
179- Namespace : cluster .Namespace ,
180- },
181- })
182- continue
183- }
184-
185- for _ , storage := range cluster .Spec .Backup .Storages {
186- if storage != nil && storage .EncryptionKeySecret != nil && storage .EncryptionKeySecret .Name == secret .Name {
187- requests = append (requests , reconcile.Request {
188- NamespacedName : types.NamespacedName {
189- Name : cluster .Name ,
190- Namespace : cluster .Namespace ,
191- },
192- })
193- break
194- }
195- }
203+ requests = append (requests , reconcile.Request {
204+ NamespacedName : types.NamespacedName {
205+ Name : cluster .Name ,
206+ Namespace : cluster .Namespace ,
207+ },
208+ })
196209 }
197210 return requests
198211 })
@@ -1821,8 +1834,6 @@ func (r *PerconaServerMySQLReconciler) reconcileInternalEncryptionKeySecret(ctx
18211834 return nil
18221835 }
18231836
1824- log := logf .FromContext (ctx )
1825-
18261837 secret := & corev1.Secret {
18271838 ObjectMeta : metav1.ObjectMeta {
18281839 Name : naming .EncryptionKeyInternalSecretName (cr .Name ),
@@ -1842,43 +1853,44 @@ func (r *PerconaServerMySQLReconciler) reconcileInternalEncryptionKeySecret(ctx
18421853 return nil
18431854 }
18441855
1845- opResult , err := controllerutil .CreateOrUpdate (ctx , r .Client , secret , func () error {
1846- if version , ok := secret . Data [ naming . InternalEncryptionKeyVersionFileName ]; ok {
1847- data [ naming . InternalEncryptionKeyVersionFileName ] = version
1856+ if _ , err := controllerutil .CreateOrUpdate (ctx , r .Client , secret , func () error {
1857+ if err := controllerutil . SetControllerReference ( cr , secret , r . Scheme ); err != nil {
1858+ return errors . Wrap ( err , "set controller reference" )
18481859 }
1849- secret .Data = data
18501860 secret .Labels = cr .GlobalLabels ()
18511861 secret .Annotations = cr .GlobalAnnotations ()
18521862
1853- if err := controllerutil . SetControllerReference ( cr , secret , r . Scheme ); err != nil {
1854- return errors . Wrap ( err , "set controller reference" )
1863+ if encryptionKeyDataEqual ( secret . Data , data ) {
1864+ return nil
18551865 }
1856- return nil
1857- })
1858- if err != nil {
1859- return errors .Wrap (err , "create or update encryption key secret" )
1860- }
18611866
1862- if opResult == controllerutil .OperationResultNone {
1867+ // Store a version of the data along with the keys. The version is the timestamp at which
1868+ // the data was last modified. This version is used to signal the sidecar whether to wait
1869+ // for the data to be synced from the Secret to the pod.
1870+ // The sidecar reads the version file from its mounted Secret volume; when it matches this value,
1871+ // kubelet has refreshed the projected data and the sidecar can safely use the
1872+ // encryption keys.
1873+ version := []byte (strconv .FormatInt (time .Now ().UTC ().UnixNano (), 10 ))
1874+
1875+ secret .Data = data
1876+ secret .Data [naming .InternalEncryptionKeyVersionFileName ] = version
1877+
18631878 return nil
1879+ }); err != nil {
1880+ return errors .Wrap (err , "create or update encryption key secret" )
18641881 }
1882+ return nil
1883+ }
18651884
1866- // Store the Secret resourceVersion in the Secret data so backup requests can
1867- // tell the xtrabackup sidecar which key version to wait for. The sidecar reads
1868- // the version file from its mounted Secret volume; when it matches this value,
1869- // kubelet has refreshed the projected data and the sidecar can safely use the
1870- // encryption key. Use APIReader here to avoid reading a stale cache; this path
1871- // is only hit when encryption key data changes, so the direct read is fine.
1872- if err := r .APIReader .Get (ctx , client .ObjectKeyFromObject (secret ), secret ); err != nil {
1873- return errors .Wrap (err , "get encryption key secret" )
1885+ func encryptionKeyDataEqual (current , desired map [string ][]byte ) bool {
1886+ if len (current ) != len (desired )+ 1 {
1887+ return false
18741888 }
1875- secret . Data [ naming . InternalEncryptionKeyVersionFileName ] = [] byte ( secret . GetResourceVersion ())
1876-
1877- if err := r . Update ( ctx , secret ); err != nil {
1878- return errors . Wrap ( err , "update encryption key secret" )
1889+ for key , desiredValue := range desired {
1890+ if ! bytes . Equal ( current [ key ], desiredValue ) {
1891+ return false
1892+ }
18791893 }
1880-
1881- log .Info ("Created or updated internal backup encryption key secret" , "name" , secret .Name , "version" , secret .GetResourceVersion ())
1882-
1883- return nil
1894+ _ , ok := current [naming .InternalEncryptionKeyVersionFileName ]
1895+ return ok
18841896}
0 commit comments