Repository: k3s-io/k3s
File: cmd/k3s/main.go (Go)

Code before:
	if err := untar.Untar(buf, tempDest); err != nil {
		return "", err
	}
	if err := dataverify.Verify(filepath.Join(tempDest, "bin")); err != nil {
		return "", err
	}

	// Create a stable CNI bin dir and place it first in the path so that users have a
	// consistent location to drop their own CNI plugin binaries.
	cniPath := filepath.Join(dataDir, "data", "cni")
	cniBin := filepath.Join(dir, "bin", "cni")
	if err := os.MkdirAll(cniPath, 0755); err != nil {
		return "", err
	}
	// Create symlink that points at the cni multicall binary itself
	logrus.Debugf("Creating symlink %s -> %s", filepath.Join(cniPath, "cni"), cniBin)
	os.Remove(filepath.Join(cniPath, "cni"))
	if err := os.Symlink(cniBin, filepath.Join(cniPath, "cni")); err != nil {
		return "", err
	}

	// Find symlinks that point to the cni multicall binary, and clone them in the stable CNI bin dir.
	// Non-symlink plugins in the stable CNI bin dir will not be overwritten, to allow users to replace our
	// CNI plugins with their own versions if they want. Note that the cni multicall binary itself is always
	// symlinked into the stable bin dir and should not be replaced.
	ents, err := os.ReadDir(filepath.Join(tempDest, "bin"))
	if err != nil {
		return "", err
	}
	for _, ent := range ents {
		if info, err := ent.Info(); err == nil && info.Mode()&fs.ModeSymlink != 0 {
			if target, err := os.Readlink(filepath.Join(tempDest, "bin", ent.Name())); err == nil && target == "cni" {
				src := filepath.Join(cniPath, ent.Name())
				// Check if plugin already exists in stable CNI bin dir
				if info, err := os.Lstat(src); err == nil {
					if info.Mode()&fs.ModeSymlink != 0 {
						// Exists and is a symlink, remove it so we can create a new symlink for the new bin.
						os.Remove(src)
					} else {
						// Not a symlink, leave it alone
						logrus.Debugf("Not replacing non-symlink CNI plugin %s with mode %O", src, info.Mode())
						continue
					}
				}
				logrus.Debugf("Creating symlink %s -> %s", src, cniBin)
				if err := os.Symlink(cniBin, src); err != nil {
					return "", err
				}
			}
		}
	}

Review comment (suggestion):
This is weird. If the goal is to avoid dangling symlinks, I would expect to just move the
```
	if err := os.Rename(tempDest, dir); err != nil {
		return "", err
	}
```
right after the
```
	if err := dataverify.Verify(filepath.Join(tempDest, "bin")); err != nil {
		return "", err
	}
```
and everything else staying the same ...

Code after:
	if err := untar.Untar(buf, tempDest); err != nil {
		return "", err
	}
	if err := dataverify.Verify(filepath.Join(tempDest, "bin")); err != nil {
		return "", err
	}

	// Rotate 'current' symlink into 'previous', and create a new 'current' that points
	// at the new directory.
	currentSymLink := filepath.Join(dataDir, "data", "current")
	previousSymLink := filepath.Join(dataDir, "data", "previous")
	if _, err := os.Lstat(currentSymLink); err == nil {
		if err := os.Rename(currentSymLink, previousSymLink); err != nil {
			return "", err
		}
	}
	if err := os.Symlink(dir, currentSymLink); err != nil {
		return "", err
	}

	// Rename the new directory into place after updating symlinks, so that the k3s binary check at the start
	// of this function only succeeds if everything else has been completed successfully.
	if err := os.Rename(tempDest, dir); err != nil {
		return "", err
	}

	// Create a stable CNI bin dir and place it first in the path so that users have a
	// consistent location to drop their own CNI plugin binaries.
	cniPath := filepath.Join(dataDir, "data", "cni")
	cniBin := filepath.Join(dir, "bin", "cni")
	if err := os.MkdirAll(cniPath, 0755); err != nil {
		return "", err
	}
	// Create symlink that points at the cni multicall binary itself
	logrus.Debugf("Creating symlink %s -> %s", filepath.Join(cniPath, "cni"), cniBin)
	os.Remove(filepath.Join(cniPath, "cni"))
	if err := os.Symlink(cniBin, filepath.Join(cniPath, "cni")); err != nil {
		return "", err
	}

	// Find symlinks that point to the cni multicall binary, and clone them in the stable CNI bin dir.
	// Non-symlink plugins in the stable CNI bin dir will not be overwritten, to allow users to replace our
	// CNI plugins with their own versions if they want. Note that the cni multicall binary itself is always
	// symlinked into the stable bin dir and should not be replaced.
	ents, err := os.ReadDir(filepath.Join(dir, "bin"))
	if err != nil {
		return "", err
	}
	for _, ent := range ents {
		if info, err := ent.Info(); err == nil && info.Mode()&fs.ModeSymlink != 0 {
			if target, err := os.Readlink(filepath.Join(dir, "bin", ent.Name())); err == nil && target == "cni" {