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.
This commit is contained in:
Claudiu Belu 2020-12-23 00:35:12 -08:00
parent 80be1d6c72
commit 82a9fb9d0e

View File

@ -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:
// <target-dir>/podName
@ -113,9 +116,9 @@ const (
// The data directory itself is a link to a timestamped directory with
// the real data:
// <target-dir>/..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)