diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index ff418f5e..9a3f4241 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -114,12 +114,14 @@ func (overlay Overlay) IsDistributionOverlay() bool { return path.Dir(overlay.Path()) == config.Get().Paths.DistributionOverlaydir() } -func (overlay Overlay) CreateOverlayFile(filePath string, content []byte, force bool) error { +func (overlay Overlay) AddFile(filePath string, content []byte, parents bool, force bool) error { wwlog.Info("Creating file %s in overlay %s, force: %v", filePath, overlay.Name(), force) fullPath := overlay.File(filePath) // create necessary parent directories - if err := os.MkdirAll(path.Dir(fullPath), 0o755); err != nil { - return fmt.Errorf("failed to create parent directories for %s: %w", fullPath, err) + if parents { + if err := os.MkdirAll(path.Dir(fullPath), 0o755); err != nil { + return fmt.Errorf("failed to create parent directories for %s: %w", fullPath, err) + } } // if the file already exists and force is false, return an error diff --git a/internal/pkg/overlay/overlay_test.go b/internal/pkg/overlay/overlay_test.go index ae7c8af0..67c7b6f8 100644 --- a/internal/pkg/overlay/overlay_test.go +++ b/internal/pkg/overlay/overlay_test.go @@ -732,7 +732,7 @@ func Test_CreateOverlayFile(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { newOverlay := GetSiteOverlay(tt.overlayName) - err := newOverlay.CreateOverlayFile(tt.filePath, tt.content, tt.force) + err := newOverlay.AddFile(tt.filePath, tt.content, true, tt.force) assert.NoError(t, err) newFile := newOverlay.File(tt.filePath) diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index ca6615f5..839ee9ff 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -362,21 +362,6 @@ func AppendLines(fileName string, lines []string) error { return nil } -func OverwriteFile(fileName string, content []byte) error { - wwlog.Verbose("overwrite file %s", fileName) - file, err := os.OpenFile(fileName, os.O_RDWR|os.O_TRUNC, 0o644) - if err != nil { - return fmt.Errorf("failed to open file: %s, err: %w", fileName, err) - } - defer file.Close() - - _, err = file.Write(content) - if err != nil { - return fmt.Errorf("while writing file: %s, err: %w", fileName, err) - } - return file.Sync() -} - /* ****************************************************************************** diff --git a/internal/pkg/util/util_test.go b/internal/pkg/util/util_test.go index 0f64186d..35d7dbad 100644 --- a/internal/pkg/util/util_test.go +++ b/internal/pkg/util/util_test.go @@ -92,19 +92,3 @@ func Test_FindFilterFiles(t *testing.T) { }) } } - -func Test_Overwrite(t *testing.T) { - t.Run("overwrite a file", func(t *testing.T) { - env := testenv.New(t) - defer env.RemoveAll() - env.CreateFile("file") - env.WriteFile("file", "hello world") - - assert.Equal(t, "hello world", env.ReadFile("file")) - - err := OverwriteFile(env.GetPath("file"), []byte("hello warewulf")) - assert.NoError(t, err) - - assert.Equal(t, "hello warewulf", env.ReadFile("file")) - }) -} diff --git a/internal/pkg/warewulfd/api/api.go b/internal/pkg/warewulfd/api/api.go index de515235..cc16031d 100644 --- a/internal/pkg/warewulfd/api/api.go +++ b/internal/pkg/warewulfd/api/api.go @@ -71,10 +71,9 @@ func Handler(auth *config.Authentication, allowedNets []net.IPNet) *web.Service r.Method(http.MethodGet, "/{name}", nethttp.NewHandler(getOverlayByName())) r.Method(http.MethodGet, "/{name}/file", nethttp.NewHandler(getOverlayFile())) r.Method(http.MethodPut, "/{name}", nethttp.NewHandler(createOverlay())) - r.Method(http.MethodPut, "/{name}/file", nethttp.NewHandler(createOverlayFile())) + r.Method(http.MethodPut, "/{name}/file", nethttp.NewHandler(addOverlayFile())) r.Method(http.MethodDelete, "/{name}", nethttp.NewHandler(deleteOverlay())) r.Method(http.MethodDelete, "/{name}/file", nethttp.NewHandler(deleteOverlayFile())) - r.Method(http.MethodPut, "/{name}/file", nethttp.NewHandler(updateOverlayFile())) }) }) diff --git a/internal/pkg/warewulfd/api/overlay.go b/internal/pkg/warewulfd/api/overlay.go index a9fa497b..ea01981e 100644 --- a/internal/pkg/warewulfd/api/overlay.go +++ b/internal/pkg/warewulfd/api/overlay.go @@ -215,39 +215,6 @@ func createOverlay() usecase.Interactor { return u } -func createOverlayFile() usecase.Interactor { - type createOverlayFileInput struct { - Name string `path:"name" required:"true" description:"Name of overlay to create a file in"` - Path string `query:"path" required:"true" description:"Path to file to create in an overlay"` - Force bool `query:"force" default:"false" description:"Whether to forcefully create an overlay file, default:'false'"` - Content string `json:"content" required:"true" description:"Content of the file to create"` - } - - u := usecase.NewInteractor(func(ctx context.Context, input createOverlayFileInput, output *OverlayResponse) error { - wwlog.Debug("api.createOverlayFile(Name:%v, Path:%v, Force: %v)", input.Name, input.Path, input.Force) - if input.Path == "" { - return status.Wrap(fmt.Errorf("must specify a path"), status.InvalidArgument) - } - if input.Content == "" { - return status.Wrap(fmt.Errorf("content should not be empty"), status.InvalidArgument) - } - if relPath, err := url.QueryUnescape(input.Path); err != nil { - return fmt.Errorf("failed to decode path: %v: %w", input.Path, err) - } else { - newOverlay := overlay.GetOverlay(input.Name) - if err := newOverlay.CreateOverlayFile(relPath, []byte(input.Content), input.Force); err != nil { - return fmt.Errorf("unable to create overlay file %v: %v: %w", input.Name, relPath, err) - } - *output = *NewOverlayResponse(input.Name) - return nil - } - }) - u.SetTitle("Create a file in an overlay") - u.SetDescription("Create a file in an overlay from the overlay name and file path.") - u.SetTags("Overlay") - return u -} - func deleteOverlay() usecase.Interactor { type deleteOverlayInput struct { Name string `path:"name" required:"true" description:"Name of overlay to delete"` @@ -322,36 +289,35 @@ func deleteOverlayFile() usecase.Interactor { return u } -func updateOverlayFile() usecase.Interactor { - type updateOverlayInput struct { - Name string `path:"name" required:"true" description:"Name of overlay to update"` - Path string `query:"path" required:"true" description:"Path to file to get from an overlay"` - Content string `json:"content" required:"true" description:"New content"` +func addOverlayFile() usecase.Interactor { + type createOverlayFileInput struct { + Name string `path:"name" required:"true" description:"Name of overlay to add a file to"` + Path string `query:"path" required:"true" description:"Path to file to create in the overlay"` + Content string `json:"content" required:"true" description:"Content of the file to create"` + IfNoneMatch string `header:"If-None-Match" description:"Set to '*' to indicate that the file should only be added if it does not already exist"` } - u := usecase.NewInteractor(func(ctx context.Context, input updateOverlayInput, output *OverlayResponse) error { - wwlog.Debug("api.updateOverlay(Name: %s)", input.Name) + u := usecase.NewInteractor(func(ctx context.Context, input createOverlayFileInput, output *OverlayResponse) error { + wwlog.Debug("api.addOverlayFile(Name:%v, Path:%v, IfNoneMatch: %v)", input.Name, input.Path, input.IfNoneMatch) if input.Path == "" { return status.Wrap(fmt.Errorf("must specify a path"), status.InvalidArgument) } if input.Content == "" { - return status.Wrap(fmt.Errorf("new content should not be empty"), status.InvalidArgument) + return status.Wrap(fmt.Errorf("content should not be empty"), status.InvalidArgument) } - *output = *NewOverlayResponse(input.Name) - if relPath, err := url.QueryUnescape(input.Path); err != nil { - return status.Wrap(fmt.Errorf("failed to decode path"), status.InvalidArgument) + return fmt.Errorf("failed to decode path: %v: %w", input.Path, err) } else { overlay_ := overlay.GetOverlay(input.Name) - file := overlay_.File(relPath) - if err := util.OverwriteFile(file, []byte(input.Content)); err != nil { - return fmt.Errorf("failed to overwrite file: %s, err: %w", file, err) + if err := overlay_.AddFile(relPath, []byte(input.Content), true, !(input.IfNoneMatch == "*")); err != nil { + return fmt.Errorf("unable to add overlay file %v: %v: %w", input.Name, relPath, err) } + *output = *NewOverlayResponse(input.Name) + return nil } - return nil }) - u.SetTitle("Update an overlay") - u.SetDescription("Update an overlay") + u.SetTitle("Add a file to an overlay") + u.SetDescription("Add a file to an overlay from the overlay name and file path.") u.SetTags("Overlay") return u }