Update overlay edit with tempfile and mtime
The recent `overlay edit` command reimplementation included some incorrect ordering that led to spurious error messages for files that did not yet exist. This reimplementation reorders operations to avoid such error messages and clarifies the implementation by editing in a temporary file and using mtime to discern whether an edit has occurred. Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
@@ -1,13 +1,11 @@
|
||||
package edit
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/overlay"
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
@@ -15,50 +13,8 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
editor := os.Getenv("EDITOR")
|
||||
var overlaySourceDir string
|
||||
|
||||
overlayName := args[0]
|
||||
fileName := args[1]
|
||||
|
||||
if editor == "" {
|
||||
editor = "/bin/vi"
|
||||
}
|
||||
|
||||
overlaySourceDir = overlay.OverlaySourceDir(overlayName)
|
||||
|
||||
if !util.IsDir(overlaySourceDir) {
|
||||
wwlog.Error("Overlay does not exist: %s", overlayName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
overlayFile := path.Join(overlaySourceDir, fileName)
|
||||
|
||||
wwlog.Debug("Will edit overlay file: %s", overlayFile)
|
||||
|
||||
if CreateDirs {
|
||||
err := os.MkdirAll(path.Dir(overlayFile), 0755)
|
||||
if err != nil {
|
||||
wwlog.Error("Could not create directory: %s", path.Dir(overlayFile))
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
if !util.IsDir(path.Dir(overlayFile)) {
|
||||
wwlog.Error("Can not create file, parent directory does not exist, try adding the")
|
||||
wwlog.Error("'--parents' option to create the directory.")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
newFile := false
|
||||
if !util.IsFile(overlayFile) && filepath.Ext(overlayFile) == ".ww" {
|
||||
wwlog.Verbose("This is a new file, creating some default content")
|
||||
newFile = true
|
||||
w, err := os.OpenFile(overlayFile, os.O_RDWR|os.O_CREATE, os.FileMode(PermMode))
|
||||
if err != nil {
|
||||
wwlog.Warn("Could not create file for writing: %s", err)
|
||||
}
|
||||
fmtStr := `# This is a Warewulf Template file.
|
||||
const initialTemplate = `# This is a Warewulf Template file.
|
||||
#
|
||||
# This file (suffix '.ww') will be automatically rewritten without the suffix
|
||||
# when the overlay is rendered for the individual nodes. Here are some examples
|
||||
@@ -75,43 +31,107 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
# Time: {{.BuildTime}}
|
||||
# Source: {{.BuildSource}}
|
||||
`
|
||||
fmt.Fprint(w, fmtStr)
|
||||
w.Close()
|
||||
}
|
||||
fileDesc1, err := os.OpenFile(overlayFile, os.O_RDWR, os.FileMode(PermMode))
|
||||
if err != nil {
|
||||
wwlog.Verbose("Files doesn't exist or can't be created: %s", err)
|
||||
}
|
||||
defer fileDesc1.Close()
|
||||
_, _ = fileDesc1.Seek(0, 0)
|
||||
hasher := sha256.New()
|
||||
if _, err := io.Copy(hasher, fileDesc1); err != nil {
|
||||
wwlog.Verbose("Problems getting checksum of file %s\n", err)
|
||||
}
|
||||
sum1 := hex.EncodeToString(hasher.Sum(nil))
|
||||
fileDesc1.Close()
|
||||
err = util.ExecInteractive(editor, overlayFile)
|
||||
if err != nil {
|
||||
wwlog.Error("Editor process existed with non-zero")
|
||||
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
overlayName := args[0]
|
||||
fileName := args[1]
|
||||
|
||||
overlaySourceDir := overlay.OverlaySourceDir(overlayName)
|
||||
if !util.IsDir(overlaySourceDir) {
|
||||
wwlog.Error("Overlay does not exist: %s", overlayName)
|
||||
os.Exit(1)
|
||||
}
|
||||
fileDesc2, err := os.OpenFile(overlayFile, os.O_RDWR, os.FileMode(PermMode))
|
||||
if err != nil {
|
||||
wwlog.Warn("Could not open file for editing: %s", err)
|
||||
}
|
||||
defer fileDesc2.Close()
|
||||
_, _ = fileDesc2.Seek(0, 0)
|
||||
hasher.Reset()
|
||||
if _, err := io.Copy(hasher, fileDesc2); err != nil {
|
||||
wwlog.Error("Problems getting checksum of file %s\n", err)
|
||||
}
|
||||
sum2 := hex.EncodeToString(hasher.Sum(nil))
|
||||
if sum1 == sum2 && newFile {
|
||||
wwlog.Verbose("New template %s wasn't modified, deleting it", overlayFile)
|
||||
err = os.Remove(overlayFile)
|
||||
|
||||
overlayFile := path.Join(overlaySourceDir, fileName)
|
||||
wwlog.Debug("Will edit overlay file: %s", overlayFile)
|
||||
|
||||
overlayFileDir := path.Dir(overlayFile)
|
||||
if CreateDirs {
|
||||
err := os.MkdirAll(overlayFileDir, 0755)
|
||||
if err != nil {
|
||||
wwlog.Warn("Could not delete %s", overlayFile)
|
||||
wwlog.Error("Could not create directory: %s", overlayFileDir)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
if !util.IsDir(overlayFileDir) {
|
||||
wwlog.Error("%s does not exist. Use '--parents' option to create automatically.", overlayFileDir)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
tempFile, tempFileErr := os.CreateTemp("", "ww-overlay-edit-")
|
||||
if tempFileErr != nil {
|
||||
wwlog.Error("Unable to create temporary file for editing: %s", tempFileErr)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer os.Remove(tempFile.Name())
|
||||
wwlog.Debug("Using temporary file %s", tempFile.Name())
|
||||
|
||||
if util.IsFile(overlayFile) {
|
||||
originalFile, openErr := os.Open(overlayFile)
|
||||
if openErr != nil {
|
||||
wwlog.Error("Unable to open %s: %s", overlayFile, openErr)
|
||||
os.Exit(1)
|
||||
}
|
||||
if _, err := io.Copy(tempFile, originalFile); err != nil {
|
||||
wwlog.Error("Unable to copy %s to %s for editing: %s", originalFile.Name(), tempFile.Name(), err)
|
||||
os.Exit(1)
|
||||
}
|
||||
originalFile.Close()
|
||||
} else if filepath.Ext(overlayFile) == ".ww" {
|
||||
if _, err := tempFile.Write([]byte(initialTemplate)); err != nil {
|
||||
wwlog.Error("Unable to write to %s: %s", tempFile.Name(), err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
tempFile.Close()
|
||||
|
||||
var startTime time.Time
|
||||
if fileInfo, err := os.Stat(tempFile.Name()); err != nil {
|
||||
wwlog.Error("Unable to stat %s: %s", tempFile.Name(), err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
startTime = fileInfo.ModTime()
|
||||
}
|
||||
|
||||
editor := os.Getenv("EDITOR")
|
||||
if editor == "" {
|
||||
editor = "/bin/vi"
|
||||
}
|
||||
if editorErr := util.ExecInteractive(editor, tempFile.Name()); editorErr != nil {
|
||||
wwlog.Error("Editor process exited with an error: %s", editorErr)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
tempFileReader, tempFileErr := os.Open(tempFile.Name())
|
||||
if tempFileErr != nil {
|
||||
wwlog.Error("Unable to open %s: %s", tempFile.Name(), tempFileErr)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer tempFileReader.Close()
|
||||
|
||||
if fileInfo, err := os.Stat(tempFile.Name()); err != nil {
|
||||
wwlog.Error("Unable to stat %s: %s", tempFile.Name(), err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
if startTime == fileInfo.ModTime() {
|
||||
wwlog.Debug("No change detected. Not updating overlay.")
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
destination, destinationErr := os.OpenFile(overlayFile, os.O_RDWR|os.O_CREATE, os.FileMode(PermMode))
|
||||
if destinationErr != nil {
|
||||
wwlog.Error("Unable to update %s: %s", overlayFile, destinationErr)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer destination.Close()
|
||||
|
||||
wwlog.Debug("Copy %s to %s", tempFileReader.Name(), destination.Name())
|
||||
if _, copyErr := io.Copy(destination, tempFileReader); copyErr != nil {
|
||||
wwlog.Error("Unable to update %s: %s", destination.Name(), copyErr)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user