Skip to content

Commit 8ce04d3

Browse files
committedOct 21, 2024·
Unlink existing CNI bin symlinks
Fixes "file exists" error when upgrading k3s. Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
1 parent ff23fb5 commit 8ce04d3

File tree

1 file changed

+50
-8
lines changed

1 file changed

+50
-8
lines changed
 

‎cmd/k3s/main.go

+50-8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ var criDefaultConfigPath = "/etc/crictl.yaml"
3030

3131
// main entrypoint for the k3s multicall binary
3232
func main() {
33+
if findDebug(os.Args) {
34+
logrus.SetLevel(logrus.DebugLevel)
35+
}
36+
3337
dataDir := findDataDir(os.Args)
3438

3539
// Handle direct invocation via symlink alias (multicall binary behavior)
@@ -87,6 +91,24 @@ func main() {
8791
}
8892
}
8993

94+
// findDebug reads debug settings from the environment, CLI args, and config file.
95+
func findDebug(args []string) bool {
96+
debug, _ := strconv.ParseBool(os.Getenv(version.ProgramUpper + "_DEBUG"))
97+
if debug {
98+
return debug
99+
}
100+
fs := pflag.NewFlagSet("debug-set", pflag.ContinueOnError)
101+
fs.ParseErrorsWhitelist.UnknownFlags = true
102+
fs.SetOutput(io.Discard)
103+
fs.BoolVarP(&debug, "debug", "", false, "(logging) Turn on debug logs")
104+
fs.Parse(args)
105+
if debug {
106+
return debug
107+
}
108+
debug, _ = strconv.ParseBool(configfilearg.MustFindString(args, "debug"))
109+
return debug
110+
}
111+
90112
// findDataDir reads data-dir settings from the environment, CLI args, and config file.
91113
// If not found, the default will be used, which varies depending on whether
92114
// k3s is being run as root or not.
@@ -280,31 +302,45 @@ func extract(dataDir string) (string, error) {
280302
return "", err
281303
}
282304

283-
// Rename the new directory into place, before updating symlinks
284-
if err := os.Rename(tempDest, dir); err != nil {
285-
return "", err
286-
}
287-
288305
// Create a stable CNI bin dir and place it first in the path so that users have a
289306
// consistent location to drop their own CNI plugin binaries.
290307
cniPath := filepath.Join(dataDir, "data", "cni")
291308
cniBin := filepath.Join(dir, "bin", "cni")
292309
if err := os.MkdirAll(cniPath, 0755); err != nil {
293310
return "", err
294311
}
312+
// Create symlink that points at the cni multicall binary itself
313+
logrus.Debugf("Creating symlink %s -> %s", filepath.Join(cniPath, "cni"), cniBin)
314+
os.Remove(filepath.Join(cniPath, "cni"))
295315
if err := os.Symlink(cniBin, filepath.Join(cniPath, "cni")); err != nil {
296316
return "", err
297317
}
298318

299319
// Find symlinks that point to the cni multicall binary, and clone them in the stable CNI bin dir.
300-
ents, err := os.ReadDir(filepath.Join(dir, "bin"))
320+
// Non-symlink plugins in the stable CNI bin dir will not be overwritten, to allow users to replace our
321+
// CNI plugins with their own versions if they want. Note that the cni multicall binary itself is always
322+
// symlinked into the stable bin dir and should not be replaced.
323+
ents, err := os.ReadDir(filepath.Join(tempDest, "bin"))
301324
if err != nil {
302325
return "", err
303326
}
304327
for _, ent := range ents {
305328
if info, err := ent.Info(); err == nil && info.Mode()&fs.ModeSymlink != 0 {
306-
if target, err := os.Readlink(filepath.Join(dir, "bin", ent.Name())); err == nil && target == "cni" {
307-
if err := os.Symlink(cniBin, filepath.Join(cniPath, ent.Name())); err != nil {
329+
if target, err := os.Readlink(filepath.Join(tempDest, "bin", ent.Name())); err == nil && target == "cni" {
330+
src := filepath.Join(cniPath, ent.Name())
331+
// Check if plugin already exists in stable CNI bin dir
332+
if info, err := os.Lstat(src); err == nil {
333+
if info.Mode()&fs.ModeSymlink != 0 {
334+
// Exists and is a symlink, remove it so we can create a new symlink for the new bin.
335+
os.Remove(src)
336+
} else {
337+
// Not a symlink, leave it alone
338+
logrus.Debugf("Not replacing non-symlink CNI plugin %s with mode %O", src, info.Mode())
339+
continue
340+
}
341+
}
342+
logrus.Debugf("Creating symlink %s -> %s", src, cniBin)
343+
if err := os.Symlink(cniBin, src); err != nil {
308344
return "", err
309345
}
310346
}
@@ -324,6 +360,12 @@ func extract(dataDir string) (string, error) {
324360
return "", err
325361
}
326362

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

0 commit comments

Comments
 (0)
Please sign in to comment.