diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c86ff63..bfc9fe04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Fixed - Remove requisite dependency between ignition disk target and ignition service. #2083 +- Return HTTP 409 status when creating an existing overlay ## v4.6.5, 2026-01-12 @@ -156,7 +157,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Removed - Removed the gRPC API servers and client. #1876 -- Removed ``wwctl node import --csv``. #1862 +- Removed `wwctl node import --csv`. #1862 ## v4.6.1, 2025-04-04 @@ -165,7 +166,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Added `wwctl overlay import --overwrite` to overwrite existing overlay file. - wwclient uses `WW_IPADDR`, if set, to contact the Warewulf server. #1788 - Add `wwctl node import --yes` to assume yes to confirmations. -- Set an IPMI tag ``vlan`` to configure the vlan during ``ipmiwrite``. #1031 +- Set an IPMI tag `vlan` to configure the vlan during `ipmiwrite`. #1031 - Added net.ifnames=1 to default kernel argument list. #1820 - Add a new OpenAPI v3 REST API to warewulfd at /api. #1588 - New sos plugin in `warewulf-sos` subpackage. #1822 @@ -528,7 +529,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix dhcpd.conf static template to include next-server and dhcp-range #1536 - Fix panic when adding tag with existing netdev #1546 - ## v4.5.7, 2024-09-11 ### Added @@ -559,6 +559,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - `wwctl conatiner list --kernel` shows the kernel detected for each container. #1283 - `wwctl container list --size` shows the uncompressed size of each container. `--compressed` shows the compressed size, and `--chroot` shows the size of the container source on the server. #954, #1117 - Add a logrotate config for `warewulfd.log`. #1311 + ### Changed - Refactor URL handling in wwclient to consistently escape arguments. @@ -653,7 +654,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Document warewulf.conf:paths. #635 -- New "Overlay" template variable contains the name of the overlay being built. #1052 +- New "Overlay" template variable contains the name of the overlay being built. #1052 - Documented HTTP proxy environment variables for `wwctl container import`. #1214 ### Changed diff --git a/internal/pkg/warewulfd/api/overlay.go b/internal/pkg/warewulfd/api/overlay.go index a850cb82..46db6705 100644 --- a/internal/pkg/warewulfd/api/overlay.go +++ b/internal/pkg/warewulfd/api/overlay.go @@ -213,12 +213,13 @@ func createOverlay() usecase.Interactor { u := usecase.NewInteractor(func(ctx context.Context, input createOverlayInput, output *OverlayResponse) error { wwlog.Debug("api.createOverlay(Name:%v)", input.Name) - newOverlay, err := overlay.Get(input.Name) + if _, err := overlay.Get(input.Name); err == nil { + // existing overlay, return a conflict error + return status.Wrap(fmt.Errorf("%s overlay already exists", input.Name), status.AlreadyExists) + } + newOverlay, err := overlay.Create(input.Name) if err != nil { - newOverlay, err = overlay.Create(input.Name) - if err != nil { - return err - } + return err } *output = *NewOverlayResponse(newOverlay.Name()) return nil diff --git a/internal/pkg/warewulfd/api/overlay_test.go b/internal/pkg/warewulfd/api/overlay_test.go index d9991fd1..28022197 100644 --- a/internal/pkg/warewulfd/api/overlay_test.go +++ b/internal/pkg/warewulfd/api/overlay_test.go @@ -18,7 +18,8 @@ import ( const sampleTemplate = `{{ if .Tags.email }}eMail: {{ .Tags.email }}{{else}} noMail{{- end }} ` -var overlayTests = map[string]struct { +var overlayTests = []struct { + name string initFiles map[string]string request func(serverURL string) (*http.Request, error) response string @@ -26,7 +27,8 @@ var overlayTests = map[string]struct { resultFiles []string validateFiles map[string]string // file path -> expected content }{ - "get all overlays": { + { + name: "get all overlays", initFiles: map[string]string{ "/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, }, @@ -35,8 +37,8 @@ var overlayTests = map[string]struct { }, response: `{"testoverlay":{"files":["/email.ww"], "site":false}}`, }, - - "get one specific overlay": { + { + name: "get one specific overlay", initFiles: map[string]string{ "/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, }, @@ -45,8 +47,8 @@ var overlayTests = map[string]struct { }, response: `{"files":["/email.ww"], "site":false}`, }, - - "get overlay file": { + { + name: "get overlay file", initFiles: map[string]string{ "/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, }, @@ -62,8 +64,8 @@ var overlayTests = map[string]struct { "gid": "<>" }`, }, - - "update overlay file": { + { + name: "update overlay file", initFiles: map[string]string{ "/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, }, @@ -75,8 +77,8 @@ var overlayTests = map[string]struct { "/var/lib/warewulf/overlays/testoverlay/email.ww": "hello world", }, }, - - "create an overlay": { + { + name: "create an overlay", request: func(serverURL string) (*http.Request, error) { return http.NewRequest(http.MethodPut, serverURL+"/api/overlays/test", nil) }, @@ -85,8 +87,15 @@ var overlayTests = map[string]struct { "/var/lib/warewulf/overlays/test", }, }, - - "get all overlays after creation": { + { + name: "create an overlay conflict", + request: func(serverURL string) (*http.Request, error) { + return http.NewRequest(http.MethodPut, serverURL+"/api/overlays/test", nil) + }, + status: 409, + }, + { + name: "get all overlays after creation", initFiles: map[string]string{ "/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, "/var/lib/warewulf/overlays/test/rootfs/": "", @@ -97,8 +106,8 @@ var overlayTests = map[string]struct { }, response: `{"test":{"files":null, "site":true},"testoverlay":{"files":["/email.ww"], "site":true}}`, }, - - "delete overlay file": { + { + name: "delete overlay file", initFiles: map[string]string{ "/var/lib/warewulf/overlays/testoverlay/email.ww": sampleTemplate, }, @@ -107,8 +116,8 @@ var overlayTests = map[string]struct { }, response: `{"files":null, "site":true}`, }, - - "force delete site overlay": { + { + name: "force delete site overlay", initFiles: map[string]string{ "/var/lib/warewulf/overlays/test/": "", }, @@ -117,8 +126,8 @@ var overlayTests = map[string]struct { }, response: `{"files":[], "site":true}`, }, - - "force delete distribution overlay": { + { + name: "force delete distribution overlay", initFiles: map[string]string{ "/usr/share/warewulf/overlays/test/email.ww": sampleTemplate, }, @@ -130,12 +139,12 @@ var overlayTests = map[string]struct { } func TestOverlayAPI(t *testing.T) { - for name, tt := range overlayTests { - t.Run(name, func(t *testing.T) { - warewulfd.SetNoDaemon() - env := testenv.New(t) - defer env.RemoveAll() + warewulfd.SetNoDaemon() + env := testenv.New(t) + defer env.RemoveAll() + for _, tt := range overlayTests { + t.Run(tt.name, func(t *testing.T) { // Create test files for fileName, fileContent := range tt.initFiles { if strings.HasSuffix(fileName, "/") {