fix: skip writing the file if the contents haven't changed

As the controller reconciles every /etc file present, it might be called
multiple times for the same file, even if the actual contents haven't
changed.

Rewriting the file might lead to some concurrent process seeing
incomplete file contents more often than needed.

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
Andrey Smirnov 2023-12-04 15:58:03 +04:00
parent 6329222bdc
commit dbf274ddf7
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811

View File

@ -5,6 +5,7 @@
package files
import (
"bytes"
"context"
"errors"
"fmt"
@ -132,7 +133,7 @@ func (ctrl *EtcFileController) Run(ctx context.Context, r controller.Runtime, lo
logger.Debug("writing file contents", zap.String("dst", dst), zap.Stringer("version", spec.Metadata().Version()))
if err = os.WriteFile(dst, spec.TypedSpec().Contents, spec.TypedSpec().Mode); err != nil {
if err = updateFile(dst, spec.TypedSpec().Contents, spec.TypedSpec().Mode); err != nil {
return fmt.Errorf("error updating %q: %w", dst, err)
}
@ -190,3 +191,14 @@ func createBindMount(src, dst string, mode os.FileMode) (err error) {
return nil
}
// updateFile is like `os.WriteFile`, but it will only update the file if the
// contents have changed.
func updateFile(filename string, contents []byte, mode os.FileMode) error {
oldContents, err := os.ReadFile(filename)
if err == nil && bytes.Equal(oldContents, contents) {
return nil
}
return os.WriteFile(filename, contents, mode)
}