Return HTTP 409 status when creating an existing overlay

Signed-off-by: Cédric Clerget <cedric.clerget@gmail.com>
This commit is contained in:
Cédric Clerget
2025-11-05 11:38:39 -06:00
committed by jason scott
parent e3a6f22673
commit 9f2ab5168d
3 changed files with 41 additions and 28 deletions

View File

@@ -58,6 +58,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Write `$tftpdir/warewulf/grub.cfg` to `tftproot` as configured in `warewulf.conf`. #2055 - Write `$tftpdir/warewulf/grub.cfg` to `tftproot` as configured in `warewulf.conf`. #2055
- Automatically create a GPT label when `sfdisk` overlay wipes disks. #2025 - Automatically create a GPT label when `sfdisk` overlay wipes disks. #2025
- Fix configuration of MTU on bonds with `NetworkManager`. #2059 - Fix configuration of MTU on bonds with `NetworkManager`. #2059
- Use device names in netplan bonds. #2013
- Fix ImageDelete API not returning error when checking if image is used by nodes/profiles
- Return HTTP 409 status when creating an existing overlay
### Dependencies ### Dependencies

View File

@@ -213,12 +213,13 @@ func createOverlay() usecase.Interactor {
u := usecase.NewInteractor(func(ctx context.Context, input createOverlayInput, output *OverlayResponse) error { u := usecase.NewInteractor(func(ctx context.Context, input createOverlayInput, output *OverlayResponse) error {
wwlog.Debug("api.createOverlay(Name:%v)", input.Name) 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 { if err != nil {
newOverlay, err = overlay.Create(input.Name) return err
if err != nil {
return err
}
} }
*output = *NewOverlayResponse(newOverlay.Name()) *output = *NewOverlayResponse(newOverlay.Name())
return nil return nil

View File

@@ -18,7 +18,8 @@ import (
const sampleTemplate = `{{ if .Tags.email }}eMail: {{ .Tags.email }}{{else}} noMail{{- end }} 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 initFiles map[string]string
request func(serverURL string) (*http.Request, error) request func(serverURL string) (*http.Request, error)
response string response string
@@ -26,7 +27,8 @@ var overlayTests = map[string]struct {
resultFiles []string resultFiles []string
validateFiles map[string]string // file path -> expected content validateFiles map[string]string // file path -> expected content
}{ }{
"get all overlays": { {
name: "get all overlays",
initFiles: map[string]string{ initFiles: map[string]string{
"/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, "/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate,
}, },
@@ -35,8 +37,8 @@ var overlayTests = map[string]struct {
}, },
response: `{"testoverlay":{"files":["/email.ww"], "site":false}}`, response: `{"testoverlay":{"files":["/email.ww"], "site":false}}`,
}, },
{
"get one specific overlay": { name: "get one specific overlay",
initFiles: map[string]string{ initFiles: map[string]string{
"/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, "/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate,
}, },
@@ -45,8 +47,8 @@ var overlayTests = map[string]struct {
}, },
response: `{"files":["/email.ww"], "site":false}`, response: `{"files":["/email.ww"], "site":false}`,
}, },
{
"get overlay file": { name: "get overlay file",
initFiles: map[string]string{ initFiles: map[string]string{
"/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, "/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate,
}, },
@@ -62,8 +64,8 @@ var overlayTests = map[string]struct {
"gid": "<<PRESENCE>>" "gid": "<<PRESENCE>>"
}`, }`,
}, },
{
"update overlay file": { name: "update overlay file",
initFiles: map[string]string{ initFiles: map[string]string{
"/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, "/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", "/var/lib/warewulf/overlays/testoverlay/email.ww": "hello world",
}, },
}, },
{
"create an overlay": { name: "create an overlay",
request: func(serverURL string) (*http.Request, error) { request: func(serverURL string) (*http.Request, error) {
return http.NewRequest(http.MethodPut, serverURL+"/api/overlays/test", nil) return http.NewRequest(http.MethodPut, serverURL+"/api/overlays/test", nil)
}, },
@@ -85,8 +87,15 @@ var overlayTests = map[string]struct {
"/var/lib/warewulf/overlays/test", "/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{ initFiles: map[string]string{
"/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate, "/usr/share/warewulf/overlays/testoverlay/email.ww": sampleTemplate,
"/var/lib/warewulf/overlays/test/rootfs/": "", "/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}}`, response: `{"test":{"files":null, "site":true},"testoverlay":{"files":["/email.ww"], "site":true}}`,
}, },
{
"delete overlay file": { name: "delete overlay file",
initFiles: map[string]string{ initFiles: map[string]string{
"/var/lib/warewulf/overlays/testoverlay/email.ww": sampleTemplate, "/var/lib/warewulf/overlays/testoverlay/email.ww": sampleTemplate,
}, },
@@ -107,8 +116,8 @@ var overlayTests = map[string]struct {
}, },
response: `{"files":null, "site":true}`, response: `{"files":null, "site":true}`,
}, },
{
"force delete site overlay": { name: "force delete site overlay",
initFiles: map[string]string{ initFiles: map[string]string{
"/var/lib/warewulf/overlays/test/": "", "/var/lib/warewulf/overlays/test/": "",
}, },
@@ -117,8 +126,8 @@ var overlayTests = map[string]struct {
}, },
response: `{"files":[], "site":true}`, response: `{"files":[], "site":true}`,
}, },
{
"force delete distribution overlay": { name: "force delete distribution overlay",
initFiles: map[string]string{ initFiles: map[string]string{
"/usr/share/warewulf/overlays/test/email.ww": sampleTemplate, "/usr/share/warewulf/overlays/test/email.ww": sampleTemplate,
}, },
@@ -130,12 +139,12 @@ var overlayTests = map[string]struct {
} }
func TestOverlayAPI(t *testing.T) { func TestOverlayAPI(t *testing.T) {
for name, tt := range overlayTests { warewulfd.SetNoDaemon()
t.Run(name, func(t *testing.T) { env := testenv.New(t)
warewulfd.SetNoDaemon() defer env.RemoveAll()
env := testenv.New(t)
defer env.RemoveAll()
for _, tt := range overlayTests {
t.Run(tt.name, func(t *testing.T) {
// Create test files // Create test files
for fileName, fileContent := range tt.initFiles { for fileName, fileContent := range tt.initFiles {
if strings.HasSuffix(fileName, "/") { if strings.HasSuffix(fileName, "/") {