refactored overlay class

overlay.GetOverlay(name) returns now an error if the overlay doesn't
exist. This is the most canonical way to act if there is no overlay.
This commit is contained in:
Christian Goll
2025-08-04 15:18:51 +02:00
committed by Jonathon Anderson
parent c17fe8d512
commit 6f4fd60d8f
32 changed files with 1105 additions and 437 deletions

View File

@@ -100,7 +100,7 @@ func (overlay Overlay) Exists() bool {
// Returns:
// - true if the overlay is a site overlay; false otherwise.
func (overlay Overlay) IsSiteOverlay() bool {
return path.Dir(overlay.Path()) == config.Get().Paths.SiteOverlaydir()
return strings.Contains(overlay.Path(), config.Get().Paths.SiteOverlaydir())
}
// IsDistributionOverlay determines whether the overlay is a distribution overlay.
@@ -111,7 +111,7 @@ func (overlay Overlay) IsSiteOverlay() bool {
// Returns:
// - true if the overlay is a distribution overlay; false otherwise.
func (overlay Overlay) IsDistributionOverlay() bool {
return path.Dir(overlay.Path()) == config.Get().Paths.DistributionOverlaydir()
return strings.Contains(overlay.Path(), config.Get().Paths.DistributionOverlaydir())
}
func (overlay Overlay) AddFile(filePath string, content []byte, parents bool, force bool) error {
@@ -125,7 +125,9 @@ func (overlay Overlay) AddFile(filePath string, content []byte, parents bool, fo
// replace the overlay with newly created siteOverlay
overlay = siteOverlay
}
if !overlay.IsSiteOverlay() {
return fmt.Errorf("cloning of site overlay failed")
}
fullPath := overlay.File(filePath)
// create necessary parent directories
if parents {
@@ -146,23 +148,34 @@ func (overlay Overlay) AddFile(filePath string, content []byte, parents bool, fo
}
// DeleteFile deletes a file or the entire overlay directory.
// If the file belongs to a distribution overlay, it will be cloned to a site overlay
// before deletion.
func (overlay Overlay) DeleteFile(filePath string, force, cleanup bool) error {
func (overlay Overlay) DeleteFile(filePath string, force, cleanup bool) (err error) {
wwlog.Info("Deleting file %s from overlay %s, force: %v, cleanup: %v", filePath, overlay.Name(), force, cleanup)
if filePath == "" {
if overlay.IsDistributionOverlay() {
return fmt.Errorf("cannot delete a distribution overlay: %s", overlay.Name())
}
if force {
err := os.RemoveAll(overlay.Path())
if err != nil {
return fmt.Errorf("failed to delete overlay forcely: %w", err)
}
} else {
err := os.Remove(overlay.Path())
if err != nil {
// remove rootfs at first
if err = os.Remove(overlay.Rootfs()); err != nil {
return fmt.Errorf("failed to delete overlay: %w", err)
}
if overlay.Exists() {
if err = os.Remove(overlay.Path()); err != nil {
return fmt.Errorf("failed to delete overlay: %w", err)
}
}
}
} else {
// first check if file exists
if !util.IsFile(overlay.File(filePath)) {
return fmt.Errorf("file %s does not exist in overlay %s", filePath, overlay.Name())
}
if overlay.IsDistributionOverlay() {
siteOverlay, err := overlay.CloneSiteOverlay()
if err != nil {
@@ -171,12 +184,7 @@ func (overlay Overlay) DeleteFile(filePath string, force, cleanup bool) error {
// replace the overlay with newly created siteOverlay
overlay = siteOverlay
}
fullPath := overlay.File(filePath)
if !util.IsFile(fullPath) {
return fmt.Errorf("file %s does not exist in overlay %s", filePath, overlay.Name())
}
if force {
if err := os.RemoveAll(fullPath); err != nil {
return fmt.Errorf("failed to delete file %s from overlay %s: %w", filePath, overlay.Name(), err)
@@ -208,6 +216,51 @@ func (overlay Overlay) DeleteFile(filePath string, force, cleanup bool) error {
return nil
}
// chmod for the given oppath in the overlay
func (overlay Overlay) Chmod(path string, mode uint64) (err error) {
if !overlay.IsSiteOverlay() {
overlay, err = overlay.CloneSiteOverlay()
if err != nil {
return err
}
}
fullPath := overlay.File(path)
if !(util.IsFile(fullPath) || util.IsDir(fullPath)) {
return fmt.Errorf("file does not exist within overlay: %s:%s", overlay.Name(), fullPath)
}
return os.Chmod(fullPath, os.FileMode(mode))
}
// chown file or dir in overlay
func (overlay Overlay) Chown(path string, uid, gid int) (err error) {
if !overlay.IsSiteOverlay() {
overlay, err = overlay.CloneSiteOverlay()
if err != nil {
return err
}
}
fullPath := overlay.File(path)
if !(util.IsFile(fullPath) || util.IsDir(fullPath)) {
return fmt.Errorf("file does not exist within overlay: %s:%s", overlay.Name(), fullPath)
}
return os.Chown(fullPath, uid, gid)
}
func (overlay Overlay) Mkdir(path string, mode int32) (err error) {
if !overlay.IsSiteOverlay() {
overlay, err = overlay.CloneSiteOverlay()
if err != nil {
return err
}
}
fullPath := overlay.File(path)
if util.IsFile(fullPath) || util.IsDir(fullPath) {
wwlog.Warn("path already exists, overwriting permissions: %s:%s", overlay.Name(), fullPath)
}
return os.MkdirAll(fullPath, os.FileMode(mode))
}
func BuildAllOverlays(nodes []node.Node, allNodes []node.Node, workerCount int) error {
nodeChan := make(chan node.Node, len(nodes))
errChan := make(chan error, len(nodes)*2)
@@ -297,13 +350,16 @@ func BuildHostOverlay() error {
hostname, _ := os.Hostname()
hostData := node.NewNode(hostname)
wwlog.Info("Building overlay for %s: host", hostname)
hostdir := GetOverlay("host").Rootfs()
stats, err := os.Stat(hostdir)
hostdir, err := GetOverlay("host")
if err != nil {
return err
}
stats, err := os.Stat(hostdir.Rootfs())
if err != nil {
return fmt.Errorf("could not build host overlay: %w ", err)
}
if !(stats.Mode() == os.FileMode(0o750|os.ModeDir) || stats.Mode() == os.FileMode(0o700|os.ModeDir)) {
wwlog.SecWarn("Permissions of host overlay dir %s are %s (750 is considered as secure)", hostdir, stats.Mode())
wwlog.SecWarn("Permissions of host overlay dir %s are %s (750 is considered as secure)", hostdir.Rootfs(), stats.Mode())
}
registry, err := node.New()
if err != nil {
@@ -424,19 +480,19 @@ func BuildOverlayIndir(nodeData node.Node, allNodes []node.Node, overlayNames []
wwlog.Verbose("Processing node/overlays: %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)
overlayRootfs := GetOverlay(overlayName).Rootfs()
if !util.IsDir(overlayRootfs) {
return fmt.Errorf("overlay %s: %w", overlayName, ErrDoesNotExist)
overlayRootfs, err := GetOverlay(overlayName)
if err != nil {
return err
}
wwlog.Debug("Walking the overlay structure: %s", overlayRootfs)
err := filepath.Walk(overlayRootfs, func(walkPath string, info os.FileInfo, err error) error {
wwlog.Debug("Walking the overlay structure: %s", overlayRootfs.Rootfs())
err = filepath.Walk(overlayRootfs.Rootfs(), func(walkPath string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("error for %s: %w", walkPath, err)
}
wwlog.Debug("Found overlay file: %s", walkPath)
relPath, relErr := filepath.Rel(overlayRootfs, walkPath)
relPath, relErr := filepath.Rel(overlayRootfs.Rootfs(), walkPath)
if relErr != nil {
wwlog.Warn("Error computing relative path for %s: %v", walkPath, relErr)
return relErr
@@ -669,15 +725,10 @@ 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).Rootfs()
if !util.IsDir(baseDir) {
err = fmt.Errorf("overlay %s doesn't exist", name)
return
}
err = filepath.Walk(baseDir, func(path string, info fs.FileInfo, err error) error {
func (overlay Overlay) GetFiles() (files []string, err error) {
err = filepath.Walk(overlay.Rootfs(), func(path string, info fs.FileInfo, err error) error {
if util.IsFile(path) {
files = append(files, strings.TrimPrefix(path, baseDir))
files = append(files, strings.TrimPrefix(path, overlay.Rootfs()))
}
return nil
})