add overlay file deletion support

Signed-off-by: jason yang <jasonyangshadow@gmail.com>
This commit is contained in:
jason yang
2025-07-14 04:33:58 +00:00
committed by Jonathon Anderson
parent 6b5115934b
commit e089fe0101
6 changed files with 122 additions and 12 deletions

View File

@@ -22,9 +22,7 @@ import (
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
var (
ErrDoesNotExist = fmt.Errorf("overlay does not exist")
)
var ErrDoesNotExist = fmt.Errorf("overlay does not exist")
// Overlay represents an overlay directory path.
type Overlay string
@@ -102,6 +100,69 @@ func (overlay Overlay) IsDistributionOverlay() bool {
return path.Dir(overlay.Path()) == config.Get().Paths.DistributionOverlaydir()
}
// 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 {
wwlog.Info("Deleting file %s from overlay %s, force: %v, cleanup: %v", filePath, overlay.Name(), force, cleanup)
if filePath == "" {
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 {
return fmt.Errorf("failed to delete overlay: %w", err)
}
}
} else {
if overlay.IsDistributionOverlay() {
siteOverlay, err := overlay.CloneSiteOverlay()
if err != nil {
return fmt.Errorf("failed to clone distribution overlay '%s' to site overlay: %w", overlay.Name(), err)
}
// replace the overlay with newly creatd 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)
}
} else {
if err := os.Remove(fullPath); err != nil {
return fmt.Errorf("failed to delete file %s from overlay %s: %w", filePath, overlay.Name(), err)
}
}
if cleanup {
// cleanup the empty parents
i := path.Dir(fullPath)
for i != overlay.Rootfs() {
wwlog.Debug("Evaluating directory to remove: %s", i)
err := os.Remove(i)
if err != nil {
// if the directory is not empty, we stop here
if !os.IsNotExist(err) {
wwlog.Debug("Could not remove directory %s: %v", i, err)
}
break
}
wwlog.Debug("Removed empty directory: %s", i)
i = path.Dir(i)
}
}
}
return nil
}
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)
@@ -196,7 +257,7 @@ func BuildHostOverlay() error {
if err != nil {
return fmt.Errorf("could not build host overlay: %w ", err)
}
if !(stats.Mode() == os.FileMode(0750|os.ModeDir) || stats.Mode() == os.FileMode(0700|os.ModeDir)) {
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())
}
registry, err := node.New()
@@ -257,7 +318,7 @@ func BuildOverlay(nodeConf node.Node, allNodes []node.Node, context string, over
overlayImage := OverlayImage(nodeConf.Id(), context, overlayNames)
overlayImageDir := path.Dir(overlayImage)
err := os.MkdirAll(overlayImageDir, 0750)
err := os.MkdirAll(overlayImageDir, 0o750)
if err != nil {
return fmt.Errorf("failed to create directory for %s: %s: %w", name, overlayImageDir, err)
}
@@ -292,8 +353,10 @@ func BuildOverlay(nodeConf node.Node, allNodes []node.Node, context string, over
return err
}
var regFile *regexp.Regexp
var regLink *regexp.Regexp
var (
regFile *regexp.Regexp
regLink *regexp.Regexp
)
func init() {
regFile = regexp.MustCompile(`.*{{\s*/\*\s*file\s*["'](.*)["']\s*\*/\s*}}.*`)
@@ -450,7 +513,6 @@ func BuildOverlayIndir(nodeData node.Node, allNodes []node.Node, overlayNames []
return nil
})
if err != nil {
return fmt.Errorf("failed to build overlay image directory: %w", err)
}
@@ -471,7 +533,6 @@ func CarefulWriteBuffer(destFile string, buffer bytes.Buffer, backupFile bool, p
return fmt.Errorf("failed to create backup: %s -> %s.wwbackup %w", destFile, destFile, err)
}
}
}
w, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
@@ -491,7 +552,8 @@ func RenderTemplateFile(fileName string, data TemplateStruct) (
buffer bytes.Buffer,
backupFile bool,
writeFile bool,
err error) {
err error,
) {
backupFile = true
writeFile = true
// Build our FuncMap