1
1
package certsyncpod
2
2
3
3
import (
4
- "bytes"
5
4
"context"
6
- "fmt"
7
5
"os"
8
6
"path/filepath"
9
7
"reflect"
@@ -19,8 +17,8 @@ import (
19
17
20
18
"github.com/openshift/library-go/pkg/controller/factory"
21
19
"github.com/openshift/library-go/pkg/operator/events"
22
- "github.com/openshift/library-go/pkg/operator/staticpod"
23
20
"github.com/openshift/library-go/pkg/operator/staticpod/controller/installer"
21
+ "github.com/openshift/library-go/pkg/operator/staticpod/internal/atomicfiles"
24
22
)
25
23
26
24
type CertSyncController struct {
@@ -154,7 +152,7 @@ func (c *CertSyncController) sync(ctx context.Context, syncCtx factory.SyncConte
154
152
continue
155
153
}
156
154
157
- errors = append (errors , writeFiles (& realFS , c .eventRecorder , "configmap" , configMap .ObjectMeta , contentDir , data , 0644 ))
155
+ errors = append (errors , writeFiles (c .eventRecorder , "configmap" , configMap .ObjectMeta , contentDir , data , 0644 ))
158
156
}
159
157
160
158
klog .Infof ("Syncing secrets: %v" , c .secrets )
@@ -239,104 +237,20 @@ func (c *CertSyncController) sync(ctx context.Context, syncCtx factory.SyncConte
239
237
continue
240
238
}
241
239
242
- errors = append (errors , writeFiles (& realFS , c .eventRecorder , "secret" , secret .ObjectMeta , contentDir , data , 0600 ))
240
+ errors = append (errors , writeFiles (c .eventRecorder , "secret" , secret .ObjectMeta , contentDir , data , 0600 ))
243
241
}
244
242
return utilerrors .NewAggregate (errors )
245
243
}
246
244
247
- type fileSystem struct {
248
- MkdirAll func (path string , perm os.FileMode ) error
249
- MkdirTemp func (dir , pattern string ) (string , error )
250
- RemoveAll func (path string ) error
251
- WriteFile func (name string , data []byte , perm os.FileMode ) error
252
- SwapDirectoriesAtomic func (dirA , dirB string ) error
253
- HashDirectory func (path string ) ([]byte , error )
254
- }
255
-
256
- var realFS = fileSystem {
257
- MkdirAll : os .MkdirAll ,
258
- MkdirTemp : os .MkdirTemp ,
259
- RemoveAll : os .RemoveAll ,
260
- WriteFile : os .WriteFile ,
261
- SwapDirectoriesAtomic : staticpod .SwapDirectoriesAtomic ,
262
- HashDirectory : hashDirectory ,
263
- }
264
-
265
245
func writeFiles [C string | []byte ](
266
- fs * fileSystem , eventRecorder events.Recorder ,
246
+ eventRecorder events.Recorder ,
267
247
typeName string , o metav1.ObjectMeta ,
268
248
targetDir string , files map [string ]C , filePerm os.FileMode ,
269
249
) error {
270
- // We are doing to prepare a tmp directory and write all files into that directory.
271
- // Then we are going to atomically swap the new data directory for the old one.
272
- // This is currently implemented as really atomically exchanging directories.
273
- //
274
- // The same goal of atomic swap could be implemented using symlinks much like AtomicWriter does in
275
- // https://github.com/kubernetes/kubernetes/blob/v1.34.0/pkg/volume/util/atomic_writer.go#L58
276
- // The reason we don't do that is that we already have a directory populated and watched that needs to we swapped,
277
- // in other words, it's for compatibility reasons. And if we were to migrate to the symlink approach,
278
- // we would anyway need to atomically turn the current data directory to a symlink.
279
- // This would all just increase complexity and require atomic swap on the OS level anyway.
280
-
281
- // In case the target directory does not exist, create it so that the directory not existing is not a special case.
282
- klog .Infof ("Ensuring content directory %q exists ..." , targetDir )
283
- if err := fs .MkdirAll (targetDir , 0755 ); err != nil && ! os .IsExist (err ) {
284
- eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed creating content directory for %s: %s/%s: %v" , typeName , o .Namespace , o .Name , err )
285
- return err
286
- }
287
-
288
- // We make sure the target directory is unchanged while we prepare the switch by computing the directory hash.
289
- klog .Infof ("Hashing current content directory %q ..." , targetDir )
290
- targetDirHashBefore , err := fs .HashDirectory (targetDir )
291
- if err != nil {
292
- eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed to hash current content directory for %s: %s/%s: %v" , typeName , o .Namespace , o .Name , err )
293
- return err
294
- }
295
-
296
- // Create a tmp source directory to be swapped.
297
- klog .Infof ("Creating temporary directory to swap for %q ..." , targetDir )
298
- tmpDir , err := fs .MkdirTemp (filepath .Dir (targetDir ), filepath .Base (targetDir )+ "-*" )
299
- if err != nil {
300
- eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed to create temporary directory for %s: %s/%s: %v" , typeName , o .Namespace , o .Name , err )
250
+ if err := atomicfiles .WriteFiles (typeName , o , targetDir , files , filePerm ); err != nil {
251
+ eventRecorder .Warning ("CertificateUpdateFailed" , err .Error ())
301
252
return err
302
253
}
303
- defer func () {
304
- if err := fs .RemoveAll (tmpDir ); err != nil {
305
- klog .Errorf ("Failed to remove temporary directory %q during cleanup: %v" , tmpDir , err )
306
- }
307
- }()
308
-
309
- // Populate the tmp directory with files.
310
- for filename , content := range files {
311
- fullFilename := filepath .Join (tmpDir , filename )
312
- klog .Infof ("Writing %s manifest %q ..." , typeName , fullFilename )
313
-
314
- if err := fs .WriteFile (fullFilename , []byte (content ), filePerm ); err != nil {
315
- eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed writing file for %s: %s/%s: %v" , typeName , o .Namespace , o .Name , err )
316
- return err
317
- }
318
- }
319
-
320
- // Make sure the target directory hasn't changed in the meantime.
321
- klog .Infof ("Hashing current content directory %q again and ensuring it's unchanged ..." , targetDir )
322
- targetDirHashAfter , err := fs .HashDirectory (targetDir )
323
- if err != nil {
324
- eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed to hash current content directory for %s: %s/%s: %v" , typeName , o .Namespace , o .Name , err )
325
- return err
326
- }
327
- if ! bytes .Equal (targetDirHashBefore , targetDirHashAfter ) {
328
- eventRecorder .Warningf ("CertificateUpdateFailed" , "Content directory changed while preparing to apply an update for %s: %s/%s" , typeName , o .Namespace , o .Name )
329
- klog .Warningf ("Content directory changed while preparing to apply an update: %q" , targetDir )
330
- return fmt .Errorf ("content directory changed while preparing to apply an update: %q" , targetDir )
331
- }
332
-
333
- // Swap directories atomically.
334
- klog .Infof ("Atomically swapping target directory %q with temporary directory %q for %s: %s/%s ..." , targetDir , tmpDir , typeName , o .Namespace , o .Name )
335
- if err := fs .SwapDirectoriesAtomic (targetDir , tmpDir ); err != nil {
336
- eventRecorder .Warningf ("CertificateUpdateFailed" , "Failed to swap target directory %q with temporary directory %q for %s: %s/%s: %v" , targetDir , tmpDir , typeName , o .Namespace , o .Name , err )
337
- return err
338
- }
339
-
340
254
eventRecorder .Eventf ("CertificateUpdated" , "Wrote updated %s: %s/%s" , typeName , o .Namespace , o .Name )
341
255
return nil
342
256
}
0 commit comments