diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ca0bedc..0d30a797 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Use sh to parse and exec IPMI command. #1663 - Use configured warewulf.conf path in `wwctl upgrade`. #1658 - Fixed negation for slice field elements during profile/node merge. #1677 +- Show each overlay only once, even when both site and distribution versions exist. #1675 ## v4.6.0rc1, 2025-01-29 diff --git a/internal/app/wwctl/node/add/root.go b/internal/app/wwctl/node/add/root.go index 51ddd618..6e7d63b5 100644 --- a/internal/app/wwctl/node/add/root.go +++ b/internal/app/wwctl/node/add/root.go @@ -44,13 +44,13 @@ func GetCommand() *cobra.Command { log.Println(err) } if err := baseCmd.RegisterFlagCompletionFunc("runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) } if err := baseCmd.RegisterFlagCompletionFunc("wwinit", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) diff --git a/internal/app/wwctl/node/set/root.go b/internal/app/wwctl/node/set/root.go index a84aaa30..f5c180e6 100644 --- a/internal/app/wwctl/node/set/root.go +++ b/internal/app/wwctl/node/set/root.go @@ -60,13 +60,13 @@ func GetCommand() *cobra.Command { log.Println(err) } if err := baseCmd.RegisterFlagCompletionFunc("runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) } if err := baseCmd.RegisterFlagCompletionFunc("wwinit", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) diff --git a/internal/app/wwctl/overlay/build/root.go b/internal/app/wwctl/overlay/build/root.go index 74055c6d..d6bd2098 100644 --- a/internal/app/wwctl/overlay/build/root.go +++ b/internal/app/wwctl/overlay/build/root.go @@ -39,7 +39,7 @@ func init() { baseCmd.PersistentFlags().StringSliceVarP(&OverlayNames, "overlay", "O", []string{}, "Build only specific overlay(s)") if err := baseCmd.RegisterFlagCompletionFunc("overlay", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) diff --git a/internal/app/wwctl/overlay/chmod/root.go b/internal/app/wwctl/overlay/chmod/root.go index fac28056..1ef9f3ce 100644 --- a/internal/app/wwctl/overlay/chmod/root.go +++ b/internal/app/wwctl/overlay/chmod/root.go @@ -16,7 +16,7 @@ var ( Args: cobra.ExactArgs(3), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 0 { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp } else if len(args) == 1 { ret, err := overlay.OverlayGetFiles(args[0]) diff --git a/internal/app/wwctl/overlay/chown/root.go b/internal/app/wwctl/overlay/chown/root.go index 8150c3d6..90012490 100644 --- a/internal/app/wwctl/overlay/chown/root.go +++ b/internal/app/wwctl/overlay/chown/root.go @@ -15,7 +15,7 @@ var ( Args: cobra.RangeArgs(3, 4), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 0 { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp } else if len(args) == 1 { ret, err := overlay.OverlayGetFiles(args[0]) diff --git a/internal/app/wwctl/overlay/delete/root.go b/internal/app/wwctl/overlay/delete/root.go index 289cea96..811b5560 100644 --- a/internal/app/wwctl/overlay/delete/root.go +++ b/internal/app/wwctl/overlay/delete/root.go @@ -16,7 +16,7 @@ var ( Aliases: []string{"rm", "remove", "del"}, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 0 { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp } else if len(args) == 1 { ret, err := overlay.OverlayGetFiles(args[0]) diff --git a/internal/app/wwctl/overlay/edit/root.go b/internal/app/wwctl/overlay/edit/root.go index f2cefdef..6151a4a3 100644 --- a/internal/app/wwctl/overlay/edit/root.go +++ b/internal/app/wwctl/overlay/edit/root.go @@ -15,7 +15,7 @@ var ( Args: cobra.ExactArgs(2), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 0 { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp } else if len(args) == 1 { ret, err := overlay.OverlayGetFiles(args[0]) diff --git a/internal/app/wwctl/overlay/imprt/root.go b/internal/app/wwctl/overlay/imprt/root.go index 38359676..ed49ed4f 100644 --- a/internal/app/wwctl/overlay/imprt/root.go +++ b/internal/app/wwctl/overlay/imprt/root.go @@ -20,7 +20,7 @@ var ( if len(args) != 0 { return nil, cobra.ShellCompDirectiveNoFileComp } - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }, } diff --git a/internal/app/wwctl/overlay/list/main.go b/internal/app/wwctl/overlay/list/main.go index d27cfcb3..06342d87 100644 --- a/internal/app/wwctl/overlay/list/main.go +++ b/internal/app/wwctl/overlay/list/main.go @@ -1,7 +1,6 @@ package list import ( - "fmt" "os" "syscall" @@ -18,11 +17,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if len(args) > 0 { overlays = args } else { - var err error - overlays, err = overlay.FindOverlays() - if err != nil { - return fmt.Errorf("could not obtain list of overlays from system: %w", err) - } + overlays = overlay.FindOverlays() } t := table.New(cmd.OutOrStdout()) diff --git a/internal/app/wwctl/overlay/list/root.go b/internal/app/wwctl/overlay/list/root.go index ed1e7e68..8dc976e1 100644 --- a/internal/app/wwctl/overlay/list/root.go +++ b/internal/app/wwctl/overlay/list/root.go @@ -18,7 +18,7 @@ var ( if len(args) != 0 { return nil, cobra.ShellCompDirectiveNoFileComp } - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }, } diff --git a/internal/app/wwctl/overlay/show/root.go b/internal/app/wwctl/overlay/show/root.go index 62464ef8..b64ef281 100644 --- a/internal/app/wwctl/overlay/show/root.go +++ b/internal/app/wwctl/overlay/show/root.go @@ -19,7 +19,7 @@ var ( Args: cobra.ExactArgs(2), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 0 { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp } else if len(args) == 1 { ret, err := overlay.OverlayGetFiles(args[0]) diff --git a/internal/app/wwctl/profile/add/root.go b/internal/app/wwctl/profile/add/root.go index e4a73e13..4f8d5277 100644 --- a/internal/app/wwctl/profile/add/root.go +++ b/internal/app/wwctl/profile/add/root.go @@ -43,13 +43,13 @@ func GetCommand() *cobra.Command { log.Println(err) } if err := baseCmd.RegisterFlagCompletionFunc("runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) } if err := baseCmd.RegisterFlagCompletionFunc("wwinit", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) diff --git a/internal/app/wwctl/profile/set/root.go b/internal/app/wwctl/profile/set/root.go index bb049075..483b8901 100644 --- a/internal/app/wwctl/profile/set/root.go +++ b/internal/app/wwctl/profile/set/root.go @@ -65,13 +65,13 @@ func GetCommand() *cobra.Command { log.Println(err) } if err := baseCmd.RegisterFlagCompletionFunc("runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) } if err := baseCmd.RegisterFlagCompletionFunc("wwinit", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - list, _ := overlay.FindOverlays() + list := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 3ff29b6a..fa80ee36 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -205,25 +205,29 @@ func BuildHostOverlay() error { /* Get all overlays present in warewulf */ -func FindOverlays() (overlayList []string, err error) { +func FindOverlays() (overlayList []string) { dotfilecheck, _ := regexp.Compile(`^\..*`) controller := config.Get() var files []fs.DirEntry - if distfiles, err := os.ReadDir(controller.Paths.DistributionOverlaydir()); err == nil { + if distfiles, err := os.ReadDir(controller.Paths.DistributionOverlaydir()); err != nil { + wwlog.Warn("error reading overlays from %s: %s", controller.Paths.DistributionOverlaydir(), err) + } else { files = append(files, distfiles...) } - if sitefiles, err := os.ReadDir(path.Join(controller.Paths.SiteOverlaydir())); err == nil { + if sitefiles, err := os.ReadDir(controller.Paths.SiteOverlaydir()); err != nil { + wwlog.Warn("error reading overalys from %s: %s", controller.Paths.SiteOverlaydir(), err) + } else { files = append(files, sitefiles...) } for _, file := range files { wwlog.Debug("Evaluating overlay source: %s", file.Name()) isdotfile := dotfilecheck.MatchString(file.Name()) - if (file.IsDir()) && !(isdotfile) { + if file.IsDir() && !isdotfile && !util.InSlice(overlayList, file.Name()) { overlayList = append(overlayList, file.Name()) } } - return overlayList, nil + return overlayList } /* diff --git a/internal/pkg/overlay/overlay_test.go b/internal/pkg/overlay/overlay_test.go index b423931e..b3c010b8 100644 --- a/internal/pkg/overlay/overlay_test.go +++ b/internal/pkg/overlay/overlay_test.go @@ -5,6 +5,7 @@ import ( "io" "os" "path" + "path/filepath" "runtime" "sort" "testing" @@ -18,6 +19,48 @@ import ( "github.com/cavaliergopher/cpio" ) +func Test_FindOverlays(t *testing.T) { + var tests = map[string]struct { + distOverlays []string + siteOverlays []string + overlayList []string + }{ + "dist overlays": { + distOverlays: []string{"do1", "do2", "do3"}, + overlayList: []string{"do1", "do2", "do3"}, + }, + "site overlays": { + siteOverlays: []string{"so1", "so2", "so3"}, + overlayList: []string{"so1", "so2", "so3"}, + }, + "both overlays": { + distOverlays: []string{"do1", "do2"}, + siteOverlays: []string{"so3"}, + overlayList: []string{"do1", "do2", "so3"}, + }, + "shadowed overlay": { + distOverlays: []string{"do1", "o1"}, + siteOverlays: []string{"o1", "so1"}, + overlayList: []string{"do1", "o1", "so1"}, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + env := testenv.New(t) + defer env.RemoveAll() + for _, overlay := range tt.distOverlays { + env.MkdirAll(filepath.Join("usr/share/warewulf/overlays", overlay)) + } + for _, overlay := range tt.siteOverlays { + env.MkdirAll(filepath.Join("var/lib/warewulf/overlays", overlay)) + } + overlayList := FindOverlays() + assert.Equal(t, tt.overlayList, overlayList) + }) + } +} + func Test_OverlayMethods(t *testing.T) { env := testenv.New(t) defer env.RemoveAll()