Merge pull request #1940 from anderbubble/fix-discoverable-autobuild
Rebuild overlays for discovered nodes
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user