Skip to content

Commit 54abe90

Browse files
bug: fix moving files across different filesystems (#444)
go rename's function does not support moving files across different filesystems. implement our own 'move' function.
1 parent af82cea commit 54abe90

File tree

4 files changed

+138
-3
lines changed

4 files changed

+138
-3
lines changed

cmd/embedded-cluster/install.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func runCommand(bin string, args ...string) (string, error) {
5757
func installAndEnableLocalArtifactMirror() error {
5858
ourbin := defaults.PathToEmbeddedClusterBinary("local-artifact-mirror")
5959
hstbin := defaults.LocalArtifactMirrorPath()
60-
if err := os.Rename(ourbin, hstbin); err != nil {
60+
if err := helpers.MoveFile(ourbin, hstbin); err != nil {
6161
return fmt.Errorf("unable to move local artifact mirror binary: %w", err)
6262
}
6363
if err := goods.MaterializeLocalArtifactMirrorUnitFile(); err != nil {
@@ -258,7 +258,7 @@ func applyUnsupportedOverrides(c *cli.Context, cfg *k0sconfig.ClusterConfig) (*k
258258
func installK0s() error {
259259
ourbin := defaults.PathToEmbeddedClusterBinary("k0s")
260260
hstbin := defaults.K0sBinaryPath()
261-
if err := os.Rename(ourbin, hstbin); err != nil {
261+
if err := helpers.MoveFile(ourbin, hstbin); err != nil {
262262
return fmt.Errorf("unable to move k0s binary: %w", err)
263263
}
264264
if _, err := runCommand(hstbin, config.InstallFlags()...); err != nil {

cmd/embedded-cluster/join.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/replicatedhq/embedded-cluster/pkg/config"
2323
"github.com/replicatedhq/embedded-cluster/pkg/defaults"
2424
"github.com/replicatedhq/embedded-cluster/pkg/goods"
25+
"github.com/replicatedhq/embedded-cluster/pkg/helpers"
2526
"github.com/replicatedhq/embedded-cluster/pkg/metrics"
2627
)
2728

@@ -283,7 +284,7 @@ func saveTokenToDisk(token string) error {
283284
func installK0sBinary() error {
284285
ourbin := defaults.PathToEmbeddedClusterBinary("k0s")
285286
hstbin := defaults.K0sBinaryPath()
286-
if err := os.Rename(ourbin, hstbin); err != nil {
287+
if err := helpers.MoveFile(ourbin, hstbin); err != nil {
287288
return fmt.Errorf("unable to move k0s binary: %w", err)
288289
}
289290
return nil

pkg/helpers/fs.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package helpers
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
)
8+
9+
// MoveFile moves a file from one location to another, overwriting the destination if it
10+
// exists. File mode is preserved.
11+
func MoveFile(src, dst string) error {
12+
srcinfo, err := os.Stat(src)
13+
if err != nil {
14+
return fmt.Errorf("unable to stat %s: %s", src, err)
15+
}
16+
17+
if srcinfo.IsDir() {
18+
return fmt.Errorf("unable to move directory %s", src)
19+
}
20+
21+
srcfp, err := os.Open(src)
22+
if err != nil {
23+
return fmt.Errorf("unable to open source file: %s", err)
24+
}
25+
defer srcfp.Close()
26+
27+
opts := os.O_CREATE | os.O_WRONLY | os.O_TRUNC
28+
dstfp, err := os.OpenFile(dst, opts, srcinfo.Mode())
29+
if err != nil {
30+
return fmt.Errorf("unable to open destination file: %s", err)
31+
}
32+
defer dstfp.Close()
33+
34+
if _, err := io.Copy(dstfp, srcfp); err != nil {
35+
return fmt.Errorf("unable to copy file: %s", err)
36+
}
37+
38+
if err := dstfp.Sync(); err != nil {
39+
return fmt.Errorf("unable to sync file: %s", err)
40+
}
41+
42+
if err := os.Remove(src); err != nil {
43+
return fmt.Errorf("unable to remove source file: %s", err)
44+
}
45+
46+
return nil
47+
}

pkg/helpers/fs_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package helpers
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestMoveFile(t *testing.T) {
12+
srcContent := []byte("test")
13+
srcFile, err := os.CreateTemp("", "source-*")
14+
assert.NoError(t, err)
15+
defer os.Remove(srcFile.Name())
16+
defer srcFile.Close()
17+
18+
_, err = srcFile.Write(srcContent)
19+
assert.NoError(t, err)
20+
21+
dstFile, err := os.CreateTemp("", "destination-*")
22+
assert.NoError(t, err)
23+
defer os.Remove(dstFile.Name())
24+
defer dstFile.Close()
25+
26+
err = MoveFile(srcFile.Name(), dstFile.Name())
27+
assert.NoError(t, err)
28+
29+
_, err = os.Stat(dstFile.Name())
30+
assert.NoError(t, err)
31+
32+
content, err := os.ReadFile(dstFile.Name())
33+
assert.NoError(t, err)
34+
assert.Equal(t, srcContent, content)
35+
}
36+
37+
func TestMoveFile_PreserveMode(t *testing.T) {
38+
srcContent := []byte("test")
39+
srcFile, err := os.CreateTemp("", "source-*")
40+
assert.NoError(t, err)
41+
defer os.Remove(srcFile.Name())
42+
defer srcFile.Close()
43+
44+
_, err = srcFile.Write(srcContent)
45+
assert.NoError(t, err)
46+
47+
err = os.Chmod(srcFile.Name(), 0755)
48+
assert.NoError(t, err)
49+
50+
defer os.Remove("/tmp/testbin")
51+
err = MoveFile(srcFile.Name(), "/tmp/testbin")
52+
assert.NoError(t, err)
53+
54+
info, err := os.Stat("/tmp/testbin")
55+
assert.NoError(t, err)
56+
assert.Equal(t, os.FileMode(0755), info.Mode())
57+
}
58+
59+
func TestMoveFile_Directory(t *testing.T) {
60+
srcDir, err := os.MkdirTemp("", "sourcedir-*")
61+
assert.NoError(t, err)
62+
defer os.RemoveAll(srcDir)
63+
err = MoveFile(srcDir, "destination")
64+
assert.Error(t, err)
65+
}
66+
67+
func TestMoveFile_Symlink(t *testing.T) {
68+
srcFile, err := os.CreateTemp("", "source-*")
69+
assert.NoError(t, err)
70+
_, err = srcFile.Write([]byte("test"))
71+
assert.NoError(t, err)
72+
defer os.Remove(srcFile.Name())
73+
defer srcFile.Close()
74+
75+
symlinkPath := fmt.Sprintf("%s-symlink", srcFile.Name())
76+
err = os.Symlink(srcFile.Name(), symlinkPath)
77+
assert.NoError(t, err)
78+
defer os.Remove(symlinkPath)
79+
80+
err = MoveFile(symlinkPath, "/tmp/destination")
81+
assert.NoError(t, err)
82+
defer os.RemoveAll("/tmp/destination")
83+
84+
target, err := os.Readlink(symlinkPath)
85+
assert.Error(t, err)
86+
assert.Empty(t, target)
87+
}

0 commit comments

Comments
 (0)