diff --git a/internal/app/wwctl/overlay/chmod/main.go b/internal/app/wwctl/overlay/chmod/main.go index 11b2b8ef..3a7f28d6 100644 --- a/internal/app/wwctl/overlay/chmod/main.go +++ b/internal/app/wwctl/overlay/chmod/main.go @@ -3,7 +3,6 @@ package chmod import ( "fmt" "os" - "path" "strconv" "github.com/spf13/cobra" @@ -12,8 +11,6 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) error { - var overlaySourceDir string - overlayName := args[0] fileName := args[1] @@ -21,19 +18,19 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("could not convert requested mode: %s", err) } - err = overlay.CloneSiteOverlay(overlayName) - if err != nil { - return err + overlay_ := overlay.GetOverlay(overlayName) + if !overlay_.IsSiteOverlay() { + overlay_, err = overlay_.CloneSiteOverlay() + if err != nil { + return err + } } - overlaySourceDir, _ = overlay.GetOverlay(overlayName) - - if !util.IsDir(overlaySourceDir) { + if !overlay_.Exists() { return fmt.Errorf("overlay does not exist: %s", overlayName) } - overlayFile := path.Join(overlaySourceDir, fileName) - - if !util.IsFile(overlayFile) && !util.IsDir(overlayFile) { + overlayFile := overlay_.File(fileName) + if !(util.IsFile(overlayFile) || util.IsDir(overlayFile)) { return fmt.Errorf("file does not exist within overlay: %s:%s", overlayName, fileName) } diff --git a/internal/app/wwctl/overlay/chown/main.go b/internal/app/wwctl/overlay/chown/main.go index b32b8122..2afa2068 100644 --- a/internal/app/wwctl/overlay/chown/main.go +++ b/internal/app/wwctl/overlay/chown/main.go @@ -3,7 +3,6 @@ package chown import ( "fmt" "os" - "path" "strconv" "github.com/warewulf/warewulf/internal/pkg/overlay" @@ -13,7 +12,6 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) error { - var overlaySourceDir string var uid int var gid int var err error @@ -34,19 +32,21 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } else { gid = -1 } - err = overlay.CloneSiteOverlay(overlayName) - if err != nil { - return err - } - overlaySourceDir, _ = overlay.GetOverlay(overlayName) - if !util.IsDir(overlaySourceDir) { + overlay_ := overlay.GetOverlay(overlayName) + if !overlay_.Exists() { return fmt.Errorf("overlay does not exist: %s", overlayName) } - overlayFile := path.Join(overlaySourceDir, fileName) + if !overlay_.IsSiteOverlay() { + overlay_, err = overlay_.CloneSiteOverlay() + if err != nil { + return err + } + } - if !util.IsFile(overlayFile) && !util.IsDir(overlayFile) { + overlayFile := overlay_.File(fileName) + if !(util.IsFile(overlayFile) || util.IsDir(overlayFile)) { return fmt.Errorf("file does not exist within overlay: %s:%s", overlayName, fileName) } diff --git a/internal/app/wwctl/overlay/create/main.go b/internal/app/wwctl/overlay/create/main.go index 3ab4ba4f..201c02f2 100644 --- a/internal/app/wwctl/overlay/create/main.go +++ b/internal/app/wwctl/overlay/create/main.go @@ -6,6 +6,5 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) (err error) { - _, err = overlay.CreateSiteOverlay(args[0]) - return err + return overlay.GetSiteOverlay(args[0]).Create() } diff --git a/internal/app/wwctl/overlay/delete/main.go b/internal/app/wwctl/overlay/delete/main.go index 0b8576d7..ee439c08 100644 --- a/internal/app/wwctl/overlay/delete/main.go +++ b/internal/app/wwctl/overlay/delete/main.go @@ -5,7 +5,6 @@ import ( "os" "path" - "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/warewulf/warewulf/internal/pkg/overlay" "github.com/warewulf/warewulf/internal/pkg/util" @@ -13,7 +12,6 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) error { - var overlayPath string var fileName string overlayName := args[0] @@ -22,30 +20,22 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fileName = args[1] } - overlayPath, isSite := overlay.GetOverlay(overlayName) - if !isSite { + overlay_ := overlay.GetOverlay(overlayName) + if overlay_.IsDistributionOverlay() { return fmt.Errorf("distribution overlay can't deleted") - } - if overlayPath == "" { - return fmt.Errorf("overlay name did not resolve: '%s'", overlayName) - } - - if !util.IsDir(overlayPath) { + if !overlay_.Exists() { return fmt.Errorf("overlay does not exist: %s", overlayName) } if fileName == "" { - if overlayName == "wwinit" || overlayName == "host" { - return errors.New("refusing to delete the Warewulf overlay") - } if Force { - err := os.RemoveAll(overlayPath) + err := os.RemoveAll(overlay_.Path()) if err != nil { return fmt.Errorf("failed deleting overlay: %w", err) } } else { - err := os.Remove(overlayPath) + err := os.Remove(overlay_.Path()) if err != nil { return fmt.Errorf("failed deleting overlay: %w", err) } @@ -53,28 +43,28 @@ func CobraRunE(cmd *cobra.Command, args []string) error { wwlog.Info("Deleted overlay: %s\n", args[0]) } else { - removePath := path.Join(overlayPath, fileName) + removePath := overlay_.File(fileName) - if !util.IsDir(removePath) && !util.IsFile(removePath) { + if !(util.IsDir(removePath) || util.IsFile(removePath)) { return fmt.Errorf("path to remove doesn't exist in overlay: %s", removePath) } if Force { err := os.RemoveAll(removePath) if err != nil { - return fmt.Errorf("failed deleting file from overlay: %s:%s", overlayName, overlayPath) + return fmt.Errorf("failed deleting file from overlay: %s:%s", overlayName, removePath) } } else { err := os.Remove(removePath) if err != nil { - return fmt.Errorf("failed deleting overlay: %s:%s", overlayName, overlayPath) + return fmt.Errorf("failed deleting overlay: %s:%s", overlayName, removePath) } } if Parents { // Cleanup any empty directories left behind... i := path.Dir(removePath) - for i != overlayPath { + for i != overlay_.Rootfs() { wwlog.Debug("Evaluating directory to remove: %s", i) err := os.Remove(i) if err != nil { diff --git a/internal/app/wwctl/overlay/edit/main.go b/internal/app/wwctl/overlay/edit/main.go index 62e8cb44..34f89290 100644 --- a/internal/app/wwctl/overlay/edit/main.go +++ b/internal/app/wwctl/overlay/edit/main.go @@ -36,19 +36,19 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { overlayName := args[0] fileName := args[1] createdSite := false - overlaySourceDir, isSite := overlay.GetOverlay(overlayName) - if !isSite { - err = overlay.CloneSiteOverlay(overlayName) + overlay_ := overlay.GetOverlay(overlayName) + if !overlay_.IsSiteOverlay() { + overlay_, err = overlay_.CloneSiteOverlay() if err != nil { return err } createdSite = true } - if !util.IsDir(overlaySourceDir) { + if !overlay_.Exists() { return fmt.Errorf("overlay does not exist: %s", overlayName) } - overlayFile := path.Join(overlaySourceDir, fileName) + overlayFile := overlay_.File(fileName) wwlog.Debug("Will edit overlay file: %s", overlayFile) overlayFileDir := path.Dir(overlayFile) @@ -107,7 +107,7 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { if startTime == fileInfo.ModTime() { wwlog.Debug("No change detected. Not updating overlay.") if createdSite { - os.Remove(overlaySourceDir) + os.Remove(overlay_.Path()) } return nil } diff --git a/internal/app/wwctl/overlay/imprt/main.go b/internal/app/wwctl/overlay/imprt/main.go index d22aa115..fd76d33f 100644 --- a/internal/app/wwctl/overlay/imprt/main.go +++ b/internal/app/wwctl/overlay/imprt/main.go @@ -15,7 +15,6 @@ import ( func CobraRunE(cmd *cobra.Command, args []string) error { var dest string - var overlaySource string overlayName := args[0] source := args[1] @@ -27,22 +26,22 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } wwlog.Verbose("Copying '%s' into overlay '%s:%s'", source, overlayName, dest) - overlaySource, _ = overlay.GetOverlay(overlayName) + overlay_ := overlay.GetOverlay(overlayName) - if !util.IsDir(overlaySource) { + if !overlay_.Exists() { return fmt.Errorf("overlay does not exist: %s", overlayName) } - if util.IsDir(path.Join(overlaySource, dest)) { + if util.IsDir(overlay_.File(dest)) { dest = path.Join(dest, path.Base(source)) } - if util.IsFile(path.Join(overlaySource, dest)) { + if util.IsFile(overlay_.File(dest)) { return fmt.Errorf("a file with that name already exists in the overlay: %s", overlayName) } if CreateDirs { - parent := filepath.Dir(path.Join(overlaySource, dest)) + parent := filepath.Dir(overlay_.File(dest)) if _, err := os.Stat(parent); os.IsNotExist(err) { wwlog.Debug("Create dir: %s", parent) srcInfo, err := os.Stat(source) @@ -56,7 +55,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } } - err := util.CopyFile(source, path.Join(overlaySource, dest)) + err := util.CopyFile(source, overlay_.File(dest)) if err != nil { return fmt.Errorf("could not copy file into overlay: %w", err) } diff --git a/internal/app/wwctl/overlay/list/main.go b/internal/app/wwctl/overlay/list/main.go index 1089b940..d27cfcb3 100644 --- a/internal/app/wwctl/overlay/list/main.go +++ b/internal/app/wwctl/overlay/list/main.go @@ -6,6 +6,7 @@ import ( "syscall" "github.com/spf13/cobra" + "github.com/warewulf/warewulf/internal/app/wwctl/table" "github.com/warewulf/warewulf/internal/pkg/overlay" "github.com/warewulf/warewulf/internal/pkg/util" "github.com/warewulf/warewulf/internal/pkg/wwlog" @@ -24,51 +25,52 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } } + t := table.New(cmd.OutOrStdout()) if ListLong { - wwlog.Info("%-10s %5s %-5s %-18s %s\n", "PERM MODE", "UID", "GID", "SYSTEM-OVERLAY", "FILE PATH", "SITE") + t.AddHeader("PERM MODE", "UID", "GID", "SYSTEM-OVERLAY", "FILE PATH", "SITE") } else { - wwlog.Info("%-30s %-12s-%12s\n", "OVERLAY NAME", "FILES/DIRS", "SITE") + t.AddHeader("OVERLAY NAME", "FILES/DIRS", "SITE") } - for o := range overlays { - name := overlays[o] - path, isSite := overlay.GetOverlay(name) + for _, name := range overlays { + overlay_ := overlay.GetOverlay(name) - if util.IsDir(path) { - files := util.FindFiles(path) + if !overlay_.Exists() { + wwlog.Error("system/%s (path not found:%s)", name, overlay_.Rootfs()) + continue + } - wwlog.Debug("Iterating overlay path: %s", path) - if ListLong { - for file := range files { - s, err := os.Stat(files[file]) - if err != nil { - continue - } + files := util.FindFiles(overlay_.Rootfs()) - fileMode := s.Mode() - perms := fileMode & os.ModePerm - - sys := s.Sys() - - wwlog.Info("%v %5d %-5d %-18s /%s\n", perms, sys.(*syscall.Stat_t).Uid, sys.(*syscall.Stat_t).Gid, overlays[o], files[file], isSite) + wwlog.Debug("Iterating overlay rootfs: %s", overlay_.Rootfs()) + if ListLong { + for file := range files { + s, err := os.Stat(files[file]) + if err != nil { + continue } - } else if ListContents { - var fileCount int - for file := range files { - wwlog.Info("%-30s /%-12s\n", name, files[file]) - fileCount++ - } - if fileCount == 0 { - wwlog.Info("%-30s %-12d\n", name, 0) - } - } else { - wwlog.Info("%-30s %-12d\n", name, len(files), isSite) + + fileMode := s.Mode() + perms := fileMode & os.ModePerm + + sys := s.Sys() + + t.AddLine(perms, sys.(*syscall.Stat_t).Uid, sys.(*syscall.Stat_t).Gid, name, files[file], overlay_.IsSiteOverlay()) + } + } else if ListContents { + var fileCount int + for file := range files { + t.AddLine(name, files[file], overlay_.IsSiteOverlay()) + fileCount++ + } + if fileCount == 0 { + t.AddLine(name, 0, overlay_.IsSiteOverlay()) } - } else { - wwlog.Error("system/%s (path not found:%s)", overlays[o], path) + t.AddLine(name, len(files), overlay_.IsSiteOverlay()) } } + t.Print() return nil } diff --git a/internal/app/wwctl/overlay/mkdir/main.go b/internal/app/wwctl/overlay/mkdir/main.go index 32d16006..9314fabb 100644 --- a/internal/app/wwctl/overlay/mkdir/main.go +++ b/internal/app/wwctl/overlay/mkdir/main.go @@ -3,36 +3,33 @@ package mkdir import ( "fmt" "os" - "path" "github.com/spf13/cobra" "github.com/warewulf/warewulf/internal/pkg/overlay" - "github.com/warewulf/warewulf/internal/pkg/util" "github.com/warewulf/warewulf/internal/pkg/wwlog" ) func CobraRunE(cmd *cobra.Command, args []string) (err error) { - var overlaySourceDir string - overlayName := args[0] dirName := args[1] - err = overlay.CloneSiteOverlay(overlayName) - if err != nil { - return err - } - overlaySourceDir, _ = overlay.GetOverlay(overlayName) - if !util.IsDir(overlaySourceDir) { + overlay_ := overlay.GetOverlay(overlayName) + if !overlay_.IsSiteOverlay() { + overlay_, err = overlay_.CloneSiteOverlay() + if err != nil { + return err + } + } + + if !overlay_.Exists() { return fmt.Errorf("overlay does not exist: %s", overlayName) } - overlayDir := path.Join(overlaySourceDir, dirName) - + overlayDir := overlay_.File(dirName) wwlog.Debug("Will create directory in overlay: %s:%s", overlayName, dirName) - err = os.MkdirAll(overlayDir, os.FileMode(PermMode)) if err != nil { - return fmt.Errorf("could not create directory: %s", path.Dir(overlayDir)) + return fmt.Errorf("could not create directory: %s", overlayDir) } return nil diff --git a/internal/app/wwctl/overlay/show/main.go b/internal/app/wwctl/overlay/show/main.go index ea3041f4..01fdba77 100644 --- a/internal/app/wwctl/overlay/show/main.go +++ b/internal/app/wwctl/overlay/show/main.go @@ -5,7 +5,6 @@ import ( "bytes" "fmt" "os" - "path" "path/filepath" "regexp" "strings" @@ -18,18 +17,15 @@ import ( ) func CobraRunE(cmd *cobra.Command, args []string) error { - var overlaySourceDir string - overlayName := args[0] fileName := args[1] - overlaySourceDir, _ = overlay.GetOverlay(overlayName) - if !util.IsDir(overlaySourceDir) { - return fmt.Errorf("overlay dir: %s does not exist", overlaySourceDir) + overlay_ := overlay.GetOverlay(overlayName) + if !overlay_.Exists() { + return fmt.Errorf("overlay does not exist: %s", overlayName) } - overlayFile := path.Join(overlaySourceDir, fileName) - + overlayFile := overlay_.File(fileName) if !util.IsFile(overlayFile) { return fmt.Errorf("file: %s does not exist within overlay", overlayFile) } diff --git a/internal/pkg/configure/hostfile.go b/internal/pkg/configure/hostfile.go index 1f5057e6..1faafabe 100644 --- a/internal/pkg/configure/hostfile.go +++ b/internal/pkg/configure/hostfile.go @@ -14,8 +14,8 @@ import ( Creates '/etc/hosts' from the host template. */ func Hostfile() (err error) { - overlaySourceDir, _ := overlay.GetOverlay("host") - hostTemplate := path.Join(overlaySourceDir, "/etc/hosts.ww") + overlay_ := overlay.GetOverlay("host") + hostTemplate := path.Join(overlay_.Rootfs(), "/etc/hosts.ww") if !(util.IsFile(hostTemplate)) { return fmt.Errorf("'the overlay template '/etc/hosts.ww' does not exists in 'host' overlay") } diff --git a/internal/pkg/overlay/config.go b/internal/pkg/overlay/config.go index f08168ed..5d15b43e 100644 --- a/internal/pkg/overlay/config.go +++ b/internal/pkg/overlay/config.go @@ -8,7 +8,7 @@ import ( "github.com/containers/storage/drivers/copy" - warewulfconf "github.com/warewulf/warewulf/internal/pkg/config" + "github.com/warewulf/warewulf/internal/pkg/config" "github.com/warewulf/warewulf/internal/pkg/util" "github.com/warewulf/warewulf/internal/pkg/wwlog" ) @@ -16,79 +16,59 @@ import ( // GetOverlay returns the filesystem path of an overlay identified by its name, // along with a boolean indicating whether the returned overlayPath corresponds // to a site-specific overlay. -func GetOverlay(name string) (overlayPath string, isSite bool) { - overlayPath = GetSiteOverlay(name) - if _, err := os.Stat(overlayPath); err == nil { - return overlayPath, true +func GetOverlay(name string) (overlay Overlay) { + overlay = GetSiteOverlay(name) + if overlay.Exists() { + return overlay } - overlayPath = GetDistributionOverlay(name) - return overlayPath, false + overlay = GetDistributionOverlay(name) + if overlay.Exists() { + return overlay + } + return GetSiteOverlay(name) } // GetDistributionOverlay returns the filesystem path of a distribution overlay // identified by the given name. -func GetDistributionOverlay(name string) (overlayPath string) { - controller := warewulfconf.Get() - return getOverlay(controller.Paths.DistributionOverlaydir(), name) +func GetDistributionOverlay(name string) (overlay Overlay) { + return getOverlay(config.Get().Paths.DistributionOverlaydir(), name) } // GetSiteOverlay returns the filesystem path of a site-specific overlay // identified by the given name. -func GetSiteOverlay(name string) (overlayPath string) { - controller := warewulfconf.Get() - return getOverlay(controller.Paths.SiteOverlaydir(), name) +func GetSiteOverlay(name string) (overlay Overlay) { + return getOverlay(config.Get().Paths.SiteOverlaydir(), name) } -// getOverlay constructs the filesystem path of an overlay based on the given -// overlay directory and overlay name. -// -// The returned path will include a "rootfs" directory if it exists. -func getOverlay(overlaydir, name string) (overlayPath string) { - /* Assume using old style overlay dir without rootfs */ - overlayPath = path.Join(overlaydir, name) - if _, err := os.Stat(path.Join(overlayPath, "rootfs")); err == nil { - /* rootfs exists, use it. */ - overlayPath = path.Join(overlayPath, "rootfs") - } - return overlayPath +// getOverlay constructs an overlay based on the given overlay directory and +// overlay name. The overlay does not necessarily exist. +func getOverlay(overlaydir, name string) (overlay Overlay) { + return Overlay(path.Join(overlaydir, name)) } -// CreateSiteOverlay creates a new site overlay directory with the specified name. +// Create creates a new overlay directory for the given overlay // -// This function constructs the path for the new overlay based on the site's overlay directory -// configuration and checks if the directory already exists. If the overlay already exists, -// it returns an error. Otherwise, it creates the necessary directory structure, including a -// rootfs directory. -// -// Parameters: -// - overlayName: The name of the site overlay to be created. -// -// Returns: -// - overlayPath: The full path to the created site overlay directory. -// - err: An error if the overlay already exists or if directory creation fails. -func CreateSiteOverlay(overlayName string) (overlayPath string, err error) { - controller := warewulfconf.Get() - overlayPath = path.Join(controller.Paths.SiteOverlaydir(), overlayName) - if util.IsDir(overlayPath) { - return overlayPath, fmt.Errorf("overlay already exists: %s", overlayName) +// Returns an error if the overlay already exists or if directory creation fails. +func (this Overlay) Create() error { + if util.IsDir(this.Path()) { + return fmt.Errorf("overlay already exists: %s", this) } - overlayPath = path.Join(overlayPath, "rootfs") - err = os.MkdirAll(overlayPath, 0755) - return overlayPath, err + return os.MkdirAll(this.Rootfs(), 0755) } // Creates a site overlay from an existing distribution overlay. // // If the distribution overlay doesn't exist, return an error. -func CloneSiteOverlay(name string) (err error) { - controller := warewulfconf.Get() - distroPath := path.Join(controller.Paths.DistributionOverlaydir(), name) - sitePath := path.Join(controller.Paths.SiteOverlaydir(), name) - if !util.IsDir(distroPath) { - return fmt.Errorf("overlay %s does not exist", name) +func (this Overlay) CloneSiteOverlay() (siteOverlay Overlay, err error) { + siteOverlay = GetSiteOverlay(this.Name()) + if !util.IsDir(this.Path()) { + return siteOverlay, fmt.Errorf("source overlay does not exist: %s", this.Name()) } - err = copy.DirCopy(distroPath, sitePath, copy.Content, true) - return err + if siteOverlay.Exists() { + return siteOverlay, fmt.Errorf("site overlay already exists: %s", siteOverlay.Name()) + } + err = copy.DirCopy(this.Path(), siteOverlay.Path(), copy.Content, true) + return siteOverlay, err } // OverlayImage returns the full path to an overlay image based on the @@ -117,6 +97,5 @@ func OverlayImage(nodeName string, context string, overlayNames []string) string return "" } - conf := warewulfconf.Get() - return path.Join(conf.Paths.OverlayProvisiondir(), nodeName, name) + return path.Join(config.Get().Paths.OverlayProvisiondir(), nodeName, name) } diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index d7f1f84b..133633b9 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -14,9 +14,9 @@ import ( "text/template" "github.com/Masterminds/sprig/v3" - warewulfconf "github.com/warewulf/warewulf/internal/pkg/config" - "github.com/pkg/errors" + + "github.com/warewulf/warewulf/internal/pkg/config" "github.com/warewulf/warewulf/internal/pkg/node" "github.com/warewulf/warewulf/internal/pkg/util" "github.com/warewulf/warewulf/internal/pkg/wwlog" @@ -26,6 +26,82 @@ var ( ErrDoesNotExist = errors.New("overlay does not exist") ) +// Overlay represents an overlay directory path. +type Overlay string + +// Name returns the base name of the overlay directory. +// +// This is derived from the full path of the overlay. +func (this Overlay) Name() string { + return path.Base(this.Path()) +} + +// Path returns the string representation of the overlay path. +// +// This method allows the Overlay type to be easily converted back to its +// underlying string representation. +func (this Overlay) Path() string { + return string(this) +} + +// Rootfs returns the path to the root filesystem (rootfs) within the overlay. +// +// If the "rootfs" directory exists inside the overlay path, it returns the +// path to the "rootfs" directory. Otherwise, it checks if the overlay path +// itself is a directory and returns that. If neither exists, it defaults to +// returning the "rootfs" path. +func (this Overlay) Rootfs() string { + rootfs := path.Join(this.Path(), "rootfs") + if util.IsDir(rootfs) { + return rootfs + } else if util.IsDir(this.Path()) { + return this.Path() + } else { + return rootfs + } +} + +// File constructs a full path to a file within the overlay's root filesystem. +// +// Parameters: +// - filePath: The relative path of the file within the overlay. +// +// Returns: +// - The full path to the specified file in the overlay's rootfs. +func (this Overlay) File(filePath string) string { + return path.Join(this.Rootfs(), filePath) +} + +// Exists checks whether the overlay path exists and is a directory. +// +// Returns: +// - true if the overlay path exists and is a directory; false otherwise. +func (this Overlay) Exists() bool { + return util.IsDir(this.Path()) +} + +// IsSiteOverlay determines whether the overlay is a site overlay. +// +// A site overlay is identified by its parent directory matching the configured +// site overlay directory path. +// +// Returns: +// - true if the overlay is a site overlay; false otherwise. +func (this Overlay) IsSiteOverlay() bool { + return path.Dir(this.Path()) == config.Get().Paths.SiteOverlaydir() +} + +// IsDistributionOverlay determines whether the overlay is a distribution overlay. +// +// A distribution overlay is identified by its parent directory matching the configured +// distribution overlay directory path. +// +// Returns: +// - true if the overlay is a distribution overlay; false otherwise. +func (this Overlay) IsDistributionOverlay() bool { + return path.Dir(this.Path()) == config.Get().Paths.DistributionOverlaydir() +} + /* Build all overlays for a node */ @@ -71,7 +147,7 @@ func BuildHostOverlay() error { hostname, _ := os.Hostname() hostData := node.NewNode(hostname) wwlog.Info("Building overlay for %s: host", hostname) - hostdir, _ := GetOverlay("host") + hostdir := GetOverlay("host").Rootfs() stats, err := os.Stat(hostdir) if err != nil { return fmt.Errorf("could not build host overlay: %w ", err) @@ -87,7 +163,7 @@ Get all overlays present in warewulf */ func FindOverlays() (overlayList []string, err error) { dotfilecheck, _ := regexp.Compile(`^\..*`) - controller := warewulfconf.Get() + controller := config.Get() var files []fs.DirEntry if distfiles, err := os.ReadDir(controller.Paths.DistributionOverlaydir()); err == nil { files = append(files, distfiles...) @@ -177,7 +253,7 @@ func BuildOverlayIndir(nodeData node.Node, overlayNames []string, outputDir stri wwlog.Verbose("Processing node/overlay: %s/%s", nodeData.Id(), strings.Join(overlayNames, "-")) for _, overlayName := range overlayNames { wwlog.Verbose("Building overlay %s for node %s in %s", overlayName, nodeData.Id(), outputDir) - overlaySourceDir, _ := GetOverlay(overlayName) + overlaySourceDir := GetOverlay(overlayName).Rootfs() wwlog.Debug("Changing directory to OverlayDir: %s", overlaySourceDir) err := os.Chdir(overlaySourceDir) if err != nil { @@ -416,7 +492,7 @@ func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { // Get all the files as a string slice for a given overlay func OverlayGetFiles(name string) (files []string, err error) { - baseDir, _ := GetOverlay(name) + baseDir := GetOverlay(name).Rootfs() if !util.IsDir(baseDir) { err = fmt.Errorf("overlay %s doesn't exist", name) return diff --git a/internal/pkg/overlay/overlay_test.go b/internal/pkg/overlay/overlay_test.go index 56dab2f4..a409041d 100644 --- a/internal/pkg/overlay/overlay_test.go +++ b/internal/pkg/overlay/overlay_test.go @@ -10,10 +10,106 @@ 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/util" ) +func Test_OverlayMethods(t *testing.T) { + env := testenv.New(t) + defer env.RemoveAll(t) + + // Setup test data + sitedir := "/var/lib/warewulf/overlays/" + distdir := "/usr/share/warewulf/overlays/" + + env.WriteFile(t, path.Join(sitedir, "siteonly/rootfs/testfile"), "a site overlay") + env.WriteFile(t, path.Join(distdir, "distonly/rootfs/testfile"), "a distribution overlay") + env.WriteFile(t, path.Join(sitedir, "legacy/testfile"), "a legacy overlay") + env.WriteFile(t, path.Join(sitedir, "both/rootfs/testfile"), "the site version") + env.WriteFile(t, path.Join(distdir, "both/rootfs/testfile"), "the distribution version") + + var tests = map[string]struct { + name string + path string + rootfs string + file string + content string + exists bool + isSite bool + isDist bool + }{ + "site overlay": { + name: "siteonly", + path: path.Join(sitedir, "siteonly"), + rootfs: path.Join(sitedir, "siteonly/rootfs"), + file: path.Join(sitedir, "siteonly/rootfs/testfile"), + content: "a site overlay", + exists: true, + isSite: true, + isDist: false, + }, + "distribution overlay": { + name: "distonly", + path: path.Join(distdir, "distonly"), + rootfs: path.Join(distdir, "distonly/rootfs"), + file: path.Join(distdir, "distonly/rootfs/testfile"), + content: "a distribution overlay", + exists: true, + isSite: false, + isDist: true, + }, + "overlapping overlay": { + name: "both", + path: path.Join(sitedir, "both"), + rootfs: path.Join(sitedir, "both/rootfs"), + file: path.Join(sitedir, "both/rootfs/testfile"), + content: "the site version", + exists: true, + isSite: true, + isDist: false, + }, + "legacy overlay": { + name: "legacy", + path: path.Join(sitedir, "legacy"), + rootfs: path.Join(sitedir, "legacy"), + file: path.Join(sitedir, "legacy/testfile"), + content: "", + exists: true, + isSite: true, + isDist: false, + }, + "missing overlay": { + name: "absent", + path: path.Join(sitedir, "absent"), + rootfs: path.Join(sitedir, "absent/rootfs"), + file: path.Join(sitedir, "absent/rootfs/testfile"), + content: "", + exists: false, + isSite: true, + isDist: false, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + overlay := GetOverlay(tt.name) + assert.Equal(t, tt.name, overlay.Name()) + assert.Equal(t, env.GetPath(tt.path), overlay.Path()) + assert.Equal(t, env.GetPath(tt.rootfs), overlay.Rootfs()) + assert.Equal(t, env.GetPath(tt.file), overlay.File("testfile")) + if tt.content != "" { + buffer, err := os.ReadFile(overlay.File("testfile")) + assert.NoError(t, err) + assert.Equal(t, tt.content, string(buffer)) + } + assert.Equal(t, tt.exists, overlay.Exists()) + assert.Equal(t, tt.isSite, overlay.IsSiteOverlay()) + assert.Equal(t, tt.isDist, overlay.IsDistributionOverlay()) + }) + } +} + var buildOverlayTests = []struct { description string nodeName string diff --git a/internal/pkg/warewulfd/util.go b/internal/pkg/warewulfd/util.go index 06bcaa5a..a40c1781 100644 --- a/internal/pkg/warewulfd/util.go +++ b/internal/pkg/warewulfd/util.go @@ -54,7 +54,7 @@ func getOverlayFile(n node.Node, context string, stage_overlays []string, autobu build = util.PathIsNewer(stage_file, config.Get().Paths.NodesConf()) for _, overlayname := range stage_overlays { - overlayDir, _ := overlay.GetOverlay(overlayname) + overlayDir := overlay.GetOverlay(overlayname).Rootfs() build = build || util.PathIsNewer(stage_file, overlayDir) } }