Merge pull request #1940 from anderbubble/fix-discoverable-autobuild

Rebuild overlays for discovered nodes
This commit is contained in:
Jonathon Anderson
2025-07-14 15:04:23 -06:00
committed by GitHub
5 changed files with 69 additions and 11 deletions

View File

@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased
### Changed
- `warewulfd` overlay autobuild rebuilds overlays after node discovery. #1468
## v4.6.2, 2025-07-09
### Added

View File

@@ -105,3 +105,19 @@ func OverlayImage(nodeName string, context string, overlayNames []string) string
return path.Join(config.Get().Paths.OverlayProvisiondir(), nodeName, name)
}
func ClearOverlayImage(nodeName string, context string, overlayNames []string) error {
imagePath := OverlayImage(nodeName, context, overlayNames)
if util.IsFile(imagePath) {
if err := os.Remove(imagePath); err != nil {
return fmt.Errorf("failed to remove overlay image: %w", err)
}
}
compressedImagePath := imagePath + ".gz"
if util.IsFile(compressedImagePath) {
if err := os.Remove(compressedImagePath); err != nil {
return fmt.Errorf("failed to remove compressed overlay image: %w", err)
}
}
return nil
}

View File

@@ -6,6 +6,7 @@ import (
"sync"
"github.com/warewulf/warewulf/internal/pkg/node"
"github.com/warewulf/warewulf/internal/pkg/overlay"
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
@@ -53,7 +54,7 @@ func loadNodeDB() (err error) {
return nil
}
func GetNodeOrSetDiscoverable(hwaddr string) (node.Node, error) {
func GetNodeOrSetDiscoverable(hwaddr string, autobuildOverlays bool) (node.Node, error) {
db.lock.RLock()
defer db.lock.RUnlock()
// NOTE: since discoverable nodes will write an updated DB to file and then
@@ -97,9 +98,14 @@ func GetNodeOrSetDiscoverable(hwaddr string) (node.Node, error) {
if err != nil {
return nodeFound, fmt.Errorf("%s (failed to reload configuration) %w", hwaddr, err)
}
// NOTE: previously all overlays were built here, but that will also
// be done automatically when attempting to serve an overlay that
// hasn't been built (without blocking the database).
if autobuildOverlays {
if err := overlay.ClearOverlayImage(nodeFound.Id(), "system", []string{}); err != nil {
wwlog.Warn("Failed to clear system overlay image: %s: %s", nodeFound.Id(), err)
}
if err := overlay.ClearOverlayImage(nodeFound.Id(), "runtime", []string{}); err != nil {
wwlog.Warn("Failed to clear runtime overlay image: %s: %s", nodeFound.Id(), err)
}
}
wwlog.Serv("%s (node %s automatically configured)", hwaddr, nodeFound.Id())

View File

@@ -10,10 +10,12 @@ import (
func Test_GetNodeOrSetDiscoverable(t *testing.T) {
var tests = map[string]struct {
nodesConf string
hwaddr string
node string
err bool
nodesConf string
hwaddr string
node string
err bool
initFiles []string
removedFiles []string
}{
"empty": {
nodesConf: `
@@ -40,6 +42,29 @@ nodes:
discoverable: true
network devices:
default: {}
`,
hwaddr: "00:00:00:00:00:01",
node: "n1",
},
"discoverable autobuild": {
initFiles: []string{
"/srv/warewulf/overlays/n1/__SYSTEM__.img",
"/srv/warewulf/overlays/n1/__SYSTEM__.img.gz",
"/srv/warewulf/overlays/n1/__RUNTIME__.img",
"/srv/warewulf/overlays/n1/__RUNTIME__.img.gz",
},
removedFiles: []string{
"/srv/warewulf/overlays/n1/__SYSTEM__.img",
"/srv/warewulf/overlays/n1/__SYSTEM__.img.gz",
"/srv/warewulf/overlays/n1/__RUNTIME__.img",
"/srv/warewulf/overlays/n1/__RUNTIME__.img.gz",
},
nodesConf: `
nodes:
n1:
discoverable: true
network devices:
default: {}
`,
hwaddr: "00:00:00:00:00:01",
node: "n1",
@@ -77,20 +102,25 @@ nodes:
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
env := testenv.New(t)
for _, file := range tt.initFiles {
env.CreateFile(file)
}
defer env.RemoveAll()
env.WriteFile("/etc/warewulf/nodes.conf", tt.nodesConf)
err := LoadNodeDB()
assert.NoError(t, err)
node, err := GetNodeOrSetDiscoverable(tt.hwaddr)
node, err := GetNodeOrSetDiscoverable(tt.hwaddr, true)
if tt.err {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.node, node.Id())
}
for _, file := range tt.removedFiles {
assert.NoFileExists(t, env.GetPath(file), "File should not exist: %s", file)
}
})
}
}

View File

@@ -76,7 +76,7 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
// TODO: when module version is upgraded to go1.18, should be 'any' type
var tmpl_data *templateVars
remoteNode, err := GetNodeOrSetDiscoverable(rinfo.hwaddr)
remoteNode, err := GetNodeOrSetDiscoverable(rinfo.hwaddr, conf.Warewulf.AutobuildOverlays())
if err != nil && err != node.ErrNoUnconfigured {
wwlog.ErrorExc(err, "")
w.WriteHeader(http.StatusServiceUnavailable)