From d5e1ee4de88f46d57271b35d257932306e69006b Mon Sep 17 00:00:00 2001 From: wpedrak Date: Wed, 24 Nov 2021 13:13:49 +0100 Subject: [PATCH] Make writing version.txt more resilient Writing file first truncate it and writes later on. During disk space pressure it may cause file to become empty. To mitigate above, we create file with new version first and then move it in place of old one (to make sure that disk space is available) --- cluster/images/etcd/migrate/data_dir.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cluster/images/etcd/migrate/data_dir.go b/cluster/images/etcd/migrate/data_dir.go index 83bfd628f06..6ff0189e4a7 100644 --- a/cluster/images/etcd/migrate/data_dir.go +++ b/cluster/images/etcd/migrate/data_dir.go @@ -121,6 +121,10 @@ type VersionFile struct { path string } +func (v *VersionFile) nextPath() string { + return fmt.Sprintf("%s-next", v.path) +} + // Exists returns true if a version.txt file exists on the file system. func (v *VersionFile) Exists() (bool, error) { return exists(v.path) @@ -142,8 +146,14 @@ func (v *VersionFile) Read() (*EtcdVersionPair, error) { // Write creates or overwrites the contents of the version.txt file with the given EtcdVersionPair. func (v *VersionFile) Write(vp *EtcdVersionPair) error { - data := []byte(fmt.Sprintf("%s/%s", vp.version, vp.storageVersion)) - return ioutil.WriteFile(v.path, data, 0666) + // We do write + rename instead of just write to protect from version.txt + // corruption under full disk condition. + // See https://github.com/kubernetes/kubernetes/issues/98989. + err := ioutil.WriteFile(v.nextPath(), []byte(vp.String()), 0666) + if err != nil { + return fmt.Errorf("failed to write new version file %s: %v", v.nextPath(), err) + } + return os.Rename(v.nextPath(), v.path) } func exists(path string) (bool, error) {