introduce site overlays

site overlays are place in sysconfdir/overlays and take
precedence over distribution overlays with the same name.

Every `wwctl overlay` command changing overlays will create
an site overlay. distribution overlays can't be deleted or
modified with wwctl.

Signed-off-by: Christian Goll <cgoll@suse.com>
This commit is contained in:
Christian Goll
2024-11-21 14:52:46 +01:00
parent e8f7c01283
commit d5fc7e9320
12 changed files with 106 additions and 64 deletions

View File

@@ -1,31 +1,40 @@
package overlay
import (
"fmt"
"os"
"path"
"strings"
"github.com/containers/storage/drivers/copy"
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
"github.com/warewulf/warewulf/internal/pkg/util"
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
func OverlaySourceTopDir() string {
conf := warewulfconf.Get()
return conf.Paths.WWOverlaydir
}
/*
Return the path for the base of the overlay, strips rootfs
Return the path for the base of the overlay, adds rootfs
prefix in the overlay dir if this it exists
*/
func OverlaySourceDir(overlayName string) string {
func OverlaySourceDir(overlayName string) (overlaypath string, isSite bool) {
controller := warewulfconf.Get()
/* Assume using old style overlay dir without rootfs */
var overlaypath = path.Join(OverlaySourceTopDir(), overlayName)
overlaypath = path.Join(controller.Paths.Sysconfdir, "overlays", overlayName)
if _, err := os.Stat(path.Join(overlaypath, "rootfs")); err == nil {
/* rootfs exists, use it. */
overlaypath = path.Join(overlaypath, "rootfs")
}
return overlaypath
if _, err := os.Stat(overlaypath); err == nil {
return overlaypath, true
}
overlaypath = path.Join(controller.Paths.WWOverlaydir, overlayName)
if _, err := os.Stat(path.Join(overlaypath, "rootfs")); err == nil {
/* rootfs exists, use it. */
overlaypath = path.Join(overlaypath, "rootfs")
}
wwlog.Debug("found overlay %s in path: %s", overlayName, overlaypath)
return overlaypath, false
}
// OverlayImage returns the full path to an overlay image based on the
@@ -57,3 +66,24 @@ func OverlayImage(nodeName string, context string, overlayNames []string) string
conf := warewulfconf.Get()
return path.Join(conf.Paths.OverlayProvisiondir(), nodeName, name)
}
type OverlayDoesNotExist struct {
Name string
}
func (e *OverlayDoesNotExist) Error() string {
return fmt.Sprintf("overlay %s does not exist", e.Name)
}
// Creates a site overlay from an existing overlay and give back
// OverlayDoesNotExist error if distribution overlay doesn't exsist
func CreateSiteOverlay(name string) (err error) {
controller := warewulfconf.Get()
distroPath := path.Join(controller.Paths.WWOverlaydir, name)
sitePath := path.Join(controller.Paths.Sysconfdir, "overlays", name)
if !util.IsDir(distroPath) {
return &OverlayDoesNotExist{Name: name}
}
err = copy.DirCopy(distroPath, sitePath, copy.Content, true)
return err
}

View File

@@ -14,6 +14,7 @@ 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/node"
@@ -70,7 +71,7 @@ func BuildHostOverlay() error {
hostname, _ := os.Hostname()
hostData := node.NewNode(hostname)
wwlog.Info("Building overlay for %s: host", hostname)
hostdir := OverlaySourceDir("host")
hostdir, _ := OverlaySourceDir("host")
stats, err := os.Stat(hostdir)
if err != nil {
return fmt.Errorf("could not build host overlay: %w ", err)
@@ -84,38 +85,40 @@ func BuildHostOverlay() error {
/*
Get all overlays present in warewulf
*/
func FindOverlays() ([]string, error) {
var ret []string
func FindOverlays() (overlayList []string, err error) {
dotfilecheck, _ := regexp.Compile(`^\..*`)
files, err := os.ReadDir(OverlaySourceTopDir())
controller := warewulfconf.Get()
files, err := os.ReadDir(controller.Paths.WWOverlaydir)
if err != nil {
return ret, fmt.Errorf("could not get list of overlays: %w", err)
return overlayList, fmt.Errorf("could not get list of distribution overlays: %w", err)
}
sitefiles, err := os.ReadDir(path.Join(controller.Paths.Sysconfdir, "overlays"))
if err == nil { // we don't care if there are no site overlays
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) {
ret = append(ret, file.Name())
overlayList = append(overlayList, file.Name())
}
}
return ret, nil
return overlayList, nil
}
/*
Creates an empty overlay
*/
func OverlayInit(overlayName string) error {
path := OverlaySourceDir(overlayName)
if util.IsDir(path) {
return errors.New("Overlay already exists: " + overlayName)
controller := warewulfconf.Get()
overlayPath := path.Join(controller.Paths.Sysconfdir, "overlays", overlayName)
if util.IsDir(overlayPath) {
return fmt.Errorf("overlay already exists: %s", overlayName)
}
err := os.MkdirAll(path, 0755)
err := os.MkdirAll(path.Join(overlayPath, "rootfs"), 0755)
return err
}
@@ -190,7 +193,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 := OverlaySourceDir(overlayName)
overlaySourceDir, _ := OverlaySourceDir(overlayName)
wwlog.Debug("Changing directory to OverlayDir: %s", overlaySourceDir)
err := os.Chdir(overlaySourceDir)
if err != nil {
@@ -358,19 +361,6 @@ func RenderTemplateFile(fileName string, data TemplateStruct) (
err error) {
backupFile = true
writeFile = true
// parse the overlay name out of the absolute path
overlayPath, _ := filepath.Rel(OverlaySourceTopDir(), fileName)
withoutRootfs, err := filepath.Rel("rootfs", overlayPath)
if err != nil {
overlayPath = withoutRootfs
}
overlayPathElem := strings.Split(overlayPath, "/")
if len(overlayPathElem) > 1 {
data.Overlay = overlayPathElem[0]
} else {
data.Overlay = ""
}
// Build our FuncMap
funcMap := template.FuncMap{
"Include": templateFileInclude,
@@ -442,7 +432,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 := OverlaySourceDir(name)
baseDir, _ := OverlaySourceDir(name)
if !util.IsDir(baseDir) {
err = fmt.Errorf("overlay %s doesn't exist", name)
return