Support for creating and updating overlay file in wwapi
Signed-off-by: jason yang <jasonyangshadow@gmail.com>
This commit is contained in:
committed by
Jonathon Anderson
parent
7b2c0901ed
commit
62d1aa654d
@@ -114,6 +114,25 @@ 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 {
|
||||
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 the file already exists and force is false, return an error
|
||||
if util.IsFile(fullPath) {
|
||||
if force {
|
||||
return os.WriteFile(fullPath, content, 0o644)
|
||||
}
|
||||
return fmt.Errorf("file %s already exists in overlay %s", filePath, overlay.Name())
|
||||
}
|
||||
|
||||
return os.WriteFile(fullPath, content, 0o644)
|
||||
}
|
||||
|
||||
// DeleteFile deletes a file or the entire overlay directory.
|
||||
// If the file belongs to a distribution overlay, it will be cloned to a site overlay
|
||||
// before deletion.
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
func Test_FindOverlays(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
tests := map[string]struct {
|
||||
distOverlays []string
|
||||
siteOverlays []string
|
||||
overlayList []string
|
||||
@@ -75,7 +75,7 @@ func Test_OverlayMethods(t *testing.T) {
|
||||
env.WriteFile(path.Join(sitedir, "both/rootfs/testfile"), "the site version")
|
||||
env.WriteFile(path.Join(distdir, "both/rootfs/testfile"), "the distribution version")
|
||||
|
||||
var tests = map[string]struct {
|
||||
tests := map[string]struct {
|
||||
name string
|
||||
path string
|
||||
rootfs string
|
||||
@@ -157,7 +157,7 @@ func Test_OverlayMethods(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BuildOverlayIndir(t *testing.T) {
|
||||
var tests = map[string]struct {
|
||||
tests := map[string]struct {
|
||||
node node.Node
|
||||
overlays []string
|
||||
overlayFiles map[string]string
|
||||
@@ -336,7 +336,7 @@ Tags:map[]
|
||||
}
|
||||
|
||||
func Test_BuildOverlay(t *testing.T) {
|
||||
var tests = []struct {
|
||||
tests := []struct {
|
||||
description string
|
||||
nodeName string
|
||||
context string
|
||||
@@ -377,7 +377,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
overlays: []string{"o1"},
|
||||
image: "o1.img",
|
||||
contents: []string{"o1.txt"},
|
||||
perms: []int{0644},
|
||||
perms: []int{0o644},
|
||||
},
|
||||
{
|
||||
description: "if multiple overlays are specified without a node, then the combined overlay is built directly in the overlay directory",
|
||||
@@ -386,7 +386,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
overlays: []string{"o1", "o2"},
|
||||
image: "o1-o2.img",
|
||||
contents: []string{"o1.txt", "o2.txt"},
|
||||
perms: []int{0644, 0644},
|
||||
perms: []int{0o644, 0o644},
|
||||
},
|
||||
{
|
||||
description: "if a single node overlay is specified, then the overlay is built in a node overlay directory",
|
||||
@@ -395,7 +395,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
overlays: []string{"o1"},
|
||||
image: "node1/o1.img",
|
||||
contents: []string{"o1.txt"},
|
||||
perms: []int{0644},
|
||||
perms: []int{0o644},
|
||||
},
|
||||
{
|
||||
description: "if multiple node overlays are specified, then the combined overlay is built in a node overlay directory",
|
||||
@@ -404,7 +404,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
overlays: []string{"o1", "o2"},
|
||||
image: "node1/o1-o2.img",
|
||||
contents: []string{"o1.txt", "o2.txt"},
|
||||
perms: []int{0644, 0644},
|
||||
perms: []int{0o644, 0o644},
|
||||
},
|
||||
{
|
||||
description: "if no node system overlays are specified, then context pointed overlay is generated",
|
||||
@@ -429,7 +429,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
overlays: []string{"o1"},
|
||||
image: "node1/__SYSTEM__.img",
|
||||
contents: []string{"o1.txt"},
|
||||
perms: []int{0644},
|
||||
perms: []int{0o644},
|
||||
},
|
||||
{
|
||||
description: "if a single node runtime overlay is specified, then a runtime overlay image is generated in a node overlay directory",
|
||||
@@ -438,7 +438,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
overlays: []string{"o1"},
|
||||
image: "node1/__RUNTIME__.img",
|
||||
contents: []string{"o1.txt"},
|
||||
perms: []int{0644},
|
||||
perms: []int{0o644},
|
||||
},
|
||||
{
|
||||
description: "if multiple node system overlays are specified, then a system overlay image is generated with the contents of both overlays",
|
||||
@@ -447,7 +447,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
overlays: []string{"o1", "o2"},
|
||||
image: "node1/__SYSTEM__.img",
|
||||
contents: []string{"o1.txt", "o2.txt"},
|
||||
perms: []int{0644, 0644},
|
||||
perms: []int{0o644, 0o644},
|
||||
},
|
||||
{
|
||||
description: "if multiple node runtime overlays are specified, then a runtime overlay image is generated with the contents of both overlays",
|
||||
@@ -456,7 +456,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
overlays: []string{"o1", "o2"},
|
||||
image: "node1/__RUNTIME__.img",
|
||||
contents: []string{"o1.txt", "o2.txt"},
|
||||
perms: []int{0644, 0644},
|
||||
perms: []int{0o644, 0o644},
|
||||
},
|
||||
{
|
||||
description: "validating altered permissions are retained",
|
||||
@@ -465,7 +465,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
overlays: []string{"o3"},
|
||||
image: "node1/__RUNTIME__.img",
|
||||
contents: []string{"subdir", "subdir/o3.txt"},
|
||||
perms: []int{0700, 0600},
|
||||
perms: []int{0o700, 0o600},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -473,12 +473,12 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
defer env.RemoveAll()
|
||||
|
||||
env.CreateFile("var/lib/warewulf/overlays/o1/rootfs/o1.txt")
|
||||
env.Chmod("var/lib/warewulf/overlays/o1/rootfs/o1.txt", 0644)
|
||||
env.Chmod("var/lib/warewulf/overlays/o1/rootfs/o1.txt", 0o644)
|
||||
env.CreateFile("var/lib/warewulf/overlays/o2/rootfs/o2.txt")
|
||||
env.Chmod("var/lib/warewulf/overlays/o2/rootfs/o2.txt", 0644)
|
||||
env.Chmod("var/lib/warewulf/overlays/o2/rootfs/o2.txt", 0o644)
|
||||
env.CreateFile("var/lib/warewulf/overlays/o3/rootfs/subdir/o3.txt.ww")
|
||||
env.Chmod("var/lib/warewulf/overlays/o3/rootfs/subdir", 0700)
|
||||
env.Chmod("var/lib/warewulf/overlays/o3/rootfs/subdir/o3.txt.ww", 0600)
|
||||
env.Chmod("var/lib/warewulf/overlays/o3/rootfs/subdir", 0o700)
|
||||
env.Chmod("var/lib/warewulf/overlays/o3/rootfs/subdir/o3.txt.ww", 0o600)
|
||||
|
||||
for _, tt := range tests {
|
||||
nodeInfo := node.NewNode(tt.nodeName)
|
||||
@@ -508,7 +508,7 @@ func Test_BuildOverlay(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BuildAllOverlays(t *testing.T) {
|
||||
var tests = []struct {
|
||||
tests := []struct {
|
||||
description string
|
||||
nodes []string
|
||||
systemOverlays [][]string
|
||||
@@ -585,8 +585,8 @@ func Test_BuildAllOverlays(t *testing.T) {
|
||||
assert.NoError(t, overlayDirErr)
|
||||
defer os.RemoveAll(overlayDir)
|
||||
conf.Paths.WWOverlaydir = overlayDir
|
||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o1"), 0700))
|
||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o2"), 0700))
|
||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o1"), 0o700))
|
||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o2"), 0o700))
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
@@ -620,7 +620,7 @@ func Test_BuildAllOverlays(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_BuildSpecificOverlays(t *testing.T) {
|
||||
var tests = []struct {
|
||||
tests := []struct {
|
||||
description string
|
||||
nodes []string
|
||||
overlays []string
|
||||
@@ -683,8 +683,8 @@ func Test_BuildSpecificOverlays(t *testing.T) {
|
||||
assert.NoError(t, overlayDirErr)
|
||||
defer os.RemoveAll(overlayDir)
|
||||
conf.Paths.WWOverlaydir = overlayDir
|
||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o1"), 0700))
|
||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o2"), 0700))
|
||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o1"), 0o700))
|
||||
assert.NoError(t, os.Mkdir(path.Join(overlayDir, "o2"), 0o700))
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
@@ -711,6 +711,39 @@ func Test_BuildSpecificOverlays(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_CreateOverlayFile(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
overlayName string
|
||||
filePath string
|
||||
content []byte
|
||||
force bool
|
||||
}{
|
||||
{"create file", "test", "newfile.ww", []byte("new file"), false},
|
||||
{"overwrite existing file", "test", "existingfile.ww", []byte("overwrite file"), true},
|
||||
}
|
||||
|
||||
conf := warewulfconf.Get()
|
||||
overlayDir, overlayDirErr := os.MkdirTemp(os.TempDir(), "ww-test-overlay-*")
|
||||
assert.NoError(t, overlayDirErr)
|
||||
defer os.RemoveAll(overlayDir)
|
||||
conf.Paths.WWOverlaydir = overlayDir
|
||||
|
||||
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)
|
||||
assert.NoError(t, err)
|
||||
|
||||
newFile := newOverlay.File(tt.filePath)
|
||||
assert.FileExists(t, newFile)
|
||||
readContent, err := os.ReadFile(newFile)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.content, readContent)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func dirIsEmpty(t *testing.T, name string) bool {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user