diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a9eefb..d9e8b1d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/internal/pkg/overlay/config.go b/internal/pkg/overlay/config.go index eed5988a..73f0c8de 100644 --- a/internal/pkg/overlay/config.go +++ b/internal/pkg/overlay/config.go @@ -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 +} diff --git a/internal/pkg/warewulfd/nodedb.go b/internal/pkg/warewulfd/nodedb.go index 47322470..bdf58541 100644 --- a/internal/pkg/warewulfd/nodedb.go +++ b/internal/pkg/warewulfd/nodedb.go @@ -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()) diff --git a/internal/pkg/warewulfd/nodedb_test.go b/internal/pkg/warewulfd/nodedb_test.go index edfb35d1..46f904f0 100644 --- a/internal/pkg/warewulfd/nodedb_test.go +++ b/internal/pkg/warewulfd/nodedb_test.go @@ -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) + } }) } - } diff --git a/internal/pkg/warewulfd/provision.go b/internal/pkg/warewulfd/provision.go index e6ab0a59..09c678ac 100644 --- a/internal/pkg/warewulfd/provision.go +++ b/internal/pkg/warewulfd/provision.go @@ -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)