diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ce56f03..10637794 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## v4.6.1, unreleased +### Added + +- Added `wwctl overlay import --overwrite` to overwrite existing overlay file. + ### Fixed - Fixed panic in warewulfd if node netdev is only defined in a profile. #1817 diff --git a/internal/app/wwctl/overlay/imprt/main.go b/internal/app/wwctl/overlay/imprt/main.go index 335ab673..ef948fe7 100644 --- a/internal/app/wwctl/overlay/imprt/main.go +++ b/internal/app/wwctl/overlay/imprt/main.go @@ -42,7 +42,7 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { dest = path.Join(dest, path.Base(source)) } - if util.IsFile(overlay_.File(dest)) { + if !OverwriteFile && util.IsFile(overlay_.File(dest)) { return fmt.Errorf("a file with that name already exists in the overlay: %s", overlayName) } diff --git a/internal/app/wwctl/overlay/imprt/main_test.go b/internal/app/wwctl/overlay/imprt/main_test.go index 2003ce93..dbbfcc94 100644 --- a/internal/app/wwctl/overlay/imprt/main_test.go +++ b/internal/app/wwctl/overlay/imprt/main_test.go @@ -1,6 +1,7 @@ package imprt import ( + "bytes" "fmt" "os" "testing" @@ -8,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" warewulfconf "github.com/warewulf/warewulf/internal/pkg/config" "github.com/warewulf/warewulf/internal/pkg/node" + "github.com/warewulf/warewulf/internal/pkg/testenv" "github.com/warewulf/warewulf/internal/pkg/warewulfd" ) @@ -89,3 +91,80 @@ nodes: {} } }) } + +func Test_Import(t *testing.T) { + tests := map[string]struct { + initFiles []string + initDirs []string + args []string + errExpected bool + }{ + "import a file": { + initFiles: []string{"importfile"}, + initDirs: []string{"/var/lib/warewulf/overlays/to1/rootfs"}, + args: []string{"to1", "importfile"}, + }, + + "import missing parent": { + initFiles: []string{"importfile"}, + initDirs: []string{"/var/lib/warewulf/overlays/to1/rootfs"}, + args: []string{"to1", "importfile", "a/b/importfile"}, + errExpected: true, + }, + + "import create parents": { + initFiles: []string{"importfile"}, + initDirs: []string{"/var/lib/warewulf/overlays/to1/rootfs"}, + args: []string{"to1", "importfile", "a/b/importfile", "--parents"}, + errExpected: false, + }, + + "import fail overwrite": { + initFiles: []string{"importfile", "/var/lib/warewulf/overlays/to1/rootfs/importfile"}, + args: []string{"to1", "importfile"}, + errExpected: true, + }, + + "import overwrite": { + initFiles: []string{"importfile", "/var/lib/warewulf/overlays/to1/rootfs/importfile"}, + args: []string{"to1", "importfile", "--overwrite"}, + errExpected: false, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + env := testenv.New(t) + defer env.RemoveAll() + { + wd, err := os.Getwd() + assert.NoError(t, err) + defer func() { assert.NoError(t, os.Chdir(wd)) }() + } + assert.NoError(t, os.Chdir(env.GetPath("."))) + + OverwriteFile = false + CreateDirs = false + + for _, file := range tt.initFiles { + env.CreateFile(file) + } + for _, dir := range tt.initDirs { + env.MkdirAll(dir) + } + + cmd := GetCommand() + cmd.SetArgs(tt.args) + stdout := new(bytes.Buffer) + cmd.SetOut(stdout) + stderr := new(bytes.Buffer) + cmd.SetErr(stderr) + err := cmd.Execute() + if tt.errExpected { + assert.Error(t, err, stdout) + } else { + assert.NoError(t, err, stderr) + } + }) + } +} diff --git a/internal/app/wwctl/overlay/imprt/root.go b/internal/app/wwctl/overlay/imprt/root.go index 8d54521e..c3958d86 100644 --- a/internal/app/wwctl/overlay/imprt/root.go +++ b/internal/app/wwctl/overlay/imprt/root.go @@ -24,12 +24,14 @@ var ( } }, } + OverwriteFile bool NoOverlayUpdate bool CreateDirs bool Workers int ) func init() { + baseCmd.PersistentFlags().BoolVarP(&OverwriteFile, "overwrite", "o", false, "Overwrite file if exists") baseCmd.PersistentFlags().BoolVarP(&NoOverlayUpdate, "noupdate", "n", false, "Don't update overlays") baseCmd.PersistentFlags().BoolVarP(&CreateDirs, "parents", "p", false, "Create any necessary parent directories") baseCmd.PersistentFlags().IntVar(&Workers, "workers", 0, "The number of parallel workers building overlays (<=0 indicates 1 worker per CPU)") diff --git a/internal/pkg/util/copyfile.go b/internal/pkg/util/copyfile.go index ccaabbda..7f1a984b 100644 --- a/internal/pkg/util/copyfile.go +++ b/internal/pkg/util/copyfile.go @@ -14,27 +14,27 @@ func CopyFile(src string, dst string) error { // Open source file srcFD, err := os.Open(src) if err != nil { - wwlog.Error("Could not open source file %s: %s", src, err) + wwlog.Debug("Could not open source file %s: %s", src, err) return err } defer srcFD.Close() srcInfo, err := srcFD.Stat() if err != nil { - wwlog.Error("Could not stat source file %s: %s", src, err) + wwlog.Debug("Could not stat source file %s: %s", src, err) return err } dstFD, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcInfo.Mode()) if err != nil { - wwlog.Error("Could not create destination file %s: %s", dst, err) + wwlog.Debug("Could not create destination file %s: %s", dst, err) return err } defer dstFD.Close() bytes, err := io.Copy(dstFD, srcFD) if err != nil { - wwlog.Error("File copy from %s to %s failed.\n %s", src, dst, err) + wwlog.Debug("File copy from %s to %s failed.\n %s", src, dst, err) return err } else { wwlog.Debug("Copied %d bytes from %s to %s.", bytes, src, dst) @@ -42,7 +42,7 @@ func CopyFile(src string, dst string) error { err = CopyUIDGID(src, dst) if err != nil { - wwlog.Error("Ownership copy from %s to %s failed.\n %s", src, dst, err) + wwlog.Debug("Ownership copy from %s to %s failed.\n %s", src, dst, err) return err } return nil