From 82a9fb9d0ecbd9f54656d4c6b7e8247a3a49ca7e Mon Sep 17 00:00:00 2001 From: Claudiu Belu Date: Wed, 23 Dec 2020 00:35:12 -0800 Subject: [PATCH] subatomic: Creates the symlinks to user-visible files later When creating a symlink on Windows, if the target does not exist, the created file is just a regular "symlink" file. But, if the target ultimately ends up being a folder, then that symlink file is not valid, it must be a "symlinkd" in order to function properly. Because the symlink file is not valid, the pods having that volume will fail to start. Creating the user-visible files after the timestamped and data folders have been created addresses this issue. --- pkg/volume/util/atomic_writer.go | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/pkg/volume/util/atomic_writer.go b/pkg/volume/util/atomic_writer.go index c6fb49192e8..805647ab7ed 100644 --- a/pkg/volume/util/atomic_writer.go +++ b/pkg/volume/util/atomic_writer.go @@ -98,7 +98,10 @@ const ( // data to determine if an update is required. // 5.  A new timestamped dir is created // 6. The payload is written to the new timestamped directory -// 7.  Symlinks and directory for new user-visible files are created (if needed). +// 7.  A symlink to the new timestamped directory ..data_tmp is created that will +// become the new data directory +// 8.  The new data directory symlink is renamed to the data directory; rename is atomic +// 9.  Symlinks and directory for new user-visible files are created (if needed). // // For example, consider the files: // /podName @@ -113,9 +116,9 @@ const ( // The data directory itself is a link to a timestamped directory with // the real data: // /..data -> ..2016_02_01_15_04_05.12345678/ -// 8.  A symlink to the new timestamped directory ..data_tmp is created that will -// become the new data directory -// 9.  The new data directory symlink is renamed to the data directory; rename is atomic +// NOTE(claudiub): We need to create these symlinks AFTER we've finished creating and +// linking everything else. On Windows, if a target does not exist, the created symlink +// will not work properly if the target ends up being a directory. // 10. Old paths are removed from the user-visible portion of the target directory // 11.  The previous timestamped directory is removed, if it exists func (w *AtomicWriter) Write(payload map[string]FileProjection) error { @@ -178,12 +181,6 @@ func (w *AtomicWriter) Write(payload map[string]FileProjection) error { klog.V(4).Infof("%s: performed write of new data to ts data directory: %s", w.logContext, tsDir) // (7) - if err = w.createUserVisibleFiles(cleanPayload); err != nil { - klog.Errorf("%s: error creating visible symlinks in %s: %v", w.logContext, w.targetDir, err) - return err - } - - // (8) newDataDirPath := filepath.Join(w.targetDir, newDataDirName) if err = os.Symlink(tsDirName, newDataDirPath); err != nil { os.RemoveAll(tsDir) @@ -191,7 +188,7 @@ func (w *AtomicWriter) Write(payload map[string]FileProjection) error { return err } - // (9) + // (8) if runtime.GOOS == "windows" { os.Remove(dataDirPath) err = os.Symlink(tsDirName, dataDirPath) @@ -206,6 +203,12 @@ func (w *AtomicWriter) Write(payload map[string]FileProjection) error { return err } + // (9) + if err = w.createUserVisibleFiles(cleanPayload); err != nil { + klog.Errorf("%s: error creating visible symlinks in %s: %v", w.logContext, w.targetDir, err) + return err + } + // (10) if err = w.removeUserVisiblePaths(pathsToRemove); err != nil { klog.Errorf("%s: error removing old visible symlinks: %v", w.logContext, err)