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:
@@ -21,8 +21,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not convert requested mode: %s", err)
|
||||
}
|
||||
|
||||
overlaySourceDir = overlay.OverlaySourceDir(overlayName)
|
||||
err = overlay.CreateSiteOverlay(overlayName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
overlaySourceDir, _ = overlay.OverlaySourceDir(overlayName)
|
||||
|
||||
if !util.IsDir(overlaySourceDir) {
|
||||
return fmt.Errorf("overlay does not exist: %s", overlayName)
|
||||
|
||||
@@ -34,8 +34,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
gid = -1
|
||||
}
|
||||
|
||||
overlaySourceDir = overlay.OverlaySourceDir(overlayName)
|
||||
err = overlay.CreateSiteOverlay(overlayName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
overlaySourceDir, _ = overlay.OverlaySourceDir(overlayName)
|
||||
|
||||
if !util.IsDir(overlaySourceDir) {
|
||||
return fmt.Errorf("overlay does not exist: %s", overlayName)
|
||||
|
||||
@@ -22,8 +22,11 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
fileName = args[1]
|
||||
}
|
||||
|
||||
overlayPath = overlay.OverlaySourceDir(overlayName)
|
||||
overlayPath, isSite := overlay.OverlaySourceDir(overlayName)
|
||||
if !isSite {
|
||||
return fmt.Errorf("distribution overlay can't deleted")
|
||||
|
||||
}
|
||||
if overlayPath == "" {
|
||||
return fmt.Errorf("overlay name did not resolve: '%s'", overlayName)
|
||||
}
|
||||
|
||||
@@ -30,16 +30,20 @@ const initialTemplate = `# This is a Warewulf Template file.
|
||||
# Keep the following for better reference:
|
||||
# ---
|
||||
# This file is autogenerated by warewulf
|
||||
# Host: {{.BuildHost}}
|
||||
# Time: {{.BuildTime}}
|
||||
# Source: {{.BuildSource}}
|
||||
`
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
overlayName := args[0]
|
||||
fileName := args[1]
|
||||
|
||||
overlaySourceDir := overlay.OverlaySourceDir(overlayName)
|
||||
createdSite := false
|
||||
overlaySourceDir, isSite := overlay.OverlaySourceDir(overlayName)
|
||||
if !isSite {
|
||||
err = overlay.CreateSiteOverlay(overlayName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createdSite = true
|
||||
}
|
||||
if !util.IsDir(overlaySourceDir) {
|
||||
return fmt.Errorf("overlay does not exist: %s", overlayName)
|
||||
}
|
||||
@@ -102,12 +106,15 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
if startTime == fileInfo.ModTime() {
|
||||
wwlog.Debug("No change detected. Not updating overlay.")
|
||||
os.Exit(0)
|
||||
if createdSite {
|
||||
os.Remove(overlaySourceDir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// try renaming the tempfile to overlayfile first
|
||||
err := os.Rename(tempFile.Name(), overlayFile)
|
||||
err = os.Rename(tempFile.Name(), overlayFile)
|
||||
if err != nil {
|
||||
// if it fails, which probably means that they exists on different partitions
|
||||
// fallback to data copy
|
||||
|
||||
@@ -27,7 +27,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
wwlog.Verbose("Copying '%s' into overlay '%s:%s'", source, overlayName, dest)
|
||||
overlaySource = overlay.OverlaySourceDir(overlayName)
|
||||
overlaySource, _ = overlay.OverlaySourceDir(overlayName)
|
||||
|
||||
if !util.IsDir(overlaySource) {
|
||||
return fmt.Errorf("overlay does not exist: %s", overlayName)
|
||||
|
||||
@@ -25,14 +25,14 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if ListLong {
|
||||
wwlog.Info("%-10s %5s %-5s %-18s %s\n", "PERM MODE", "UID", "GID", "SYSTEM-OVERLAY", "FILE PATH")
|
||||
wwlog.Info("%-10s %5s %-5s %-18s %s\n", "PERM MODE", "UID", "GID", "SYSTEM-OVERLAY", "FILE PATH", "SITE")
|
||||
} else {
|
||||
wwlog.Info("%-30s %-12s\n", "OVERLAY NAME", "FILES/DIRS")
|
||||
wwlog.Info("%-30s %-12s-%12s\n", "OVERLAY NAME", "FILES/DIRS", "SITE")
|
||||
}
|
||||
|
||||
for o := range overlays {
|
||||
name := overlays[o]
|
||||
path := overlay.OverlaySourceDir(name)
|
||||
path, isSite := overlay.OverlaySourceDir(name)
|
||||
|
||||
if util.IsDir(path) {
|
||||
files := util.FindFiles(path)
|
||||
@@ -50,7 +50,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
|
||||
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])
|
||||
wwlog.Info("%v %5d %-5d %-18s /%s\n", perms, sys.(*syscall.Stat_t).Uid, sys.(*syscall.Stat_t).Gid, overlays[o], files[file], isSite)
|
||||
}
|
||||
} else if ListContents {
|
||||
var fileCount int
|
||||
@@ -62,7 +62,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
wwlog.Info("%-30s %-12d\n", name, 0)
|
||||
}
|
||||
} else {
|
||||
wwlog.Info("%-30s %-12d\n", name, len(files))
|
||||
wwlog.Info("%-30s %-12d\n", name, len(files), isSite)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -11,13 +11,16 @@ import (
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
var overlaySourceDir string
|
||||
|
||||
overlayName := args[0]
|
||||
dirName := args[1]
|
||||
|
||||
overlaySourceDir = overlay.OverlaySourceDir(overlayName)
|
||||
err = overlay.CreateSiteOverlay(overlayName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
overlaySourceDir, _ = overlay.OverlaySourceDir(overlayName)
|
||||
|
||||
if !util.IsDir(overlaySourceDir) {
|
||||
return fmt.Errorf("overlay does not exist: %s", overlayName)
|
||||
@@ -27,7 +30,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
|
||||
wwlog.Debug("Will create directory in overlay: %s:%s", overlayName, dirName)
|
||||
|
||||
err := os.MkdirAll(overlayDir, os.FileMode(PermMode))
|
||||
err = os.MkdirAll(overlayDir, os.FileMode(PermMode))
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create directory: %s", path.Dir(overlayDir))
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
|
||||
overlayName := args[0]
|
||||
fileName := args[1]
|
||||
overlaySourceDir = overlay.OverlaySourceDir(overlayName)
|
||||
overlaySourceDir, _ = overlay.OverlaySourceDir(overlayName)
|
||||
|
||||
if !util.IsDir(overlaySourceDir) {
|
||||
return fmt.Errorf("overlay dir: %s does not exist", overlaySourceDir)
|
||||
@@ -66,6 +66,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
tstruct.BuildSource = overlayFile
|
||||
tstruct.Overlay = overlayName
|
||||
buffer, backupFile, writeFile, err := overlay.RenderTemplateFile(overlayFile, tstruct)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
Creates '/etc/hosts' from the host template.
|
||||
*/
|
||||
func Hostfile() (err error) {
|
||||
hostTemplate := path.Join(overlay.OverlaySourceDir("host"), "/etc/hosts.ww")
|
||||
overlaySourceDir, _ := overlay.OverlaySourceDir("host")
|
||||
hostTemplate := path.Join(overlaySourceDir, "/etc/hosts.ww")
|
||||
if !(util.IsFile(hostTemplate)) {
|
||||
return fmt.Errorf("'the overlay template '/etc/hosts.ww' does not exists in 'host' overlay")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -54,7 +54,8 @@ 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 {
|
||||
build = build || util.PathIsNewer(stage_file, overlay.OverlaySourceDir(overlayname))
|
||||
overlayDir, _ := overlay.OverlaySourceDir(overlayname)
|
||||
build = build || util.PathIsNewer(stage_file, overlayDir)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user