Merge pull request #1303 from mslacken/softlink
create soft links from overlays
This commit is contained in:
@@ -29,6 +29,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- Document "known issues."
|
- Document "known issues."
|
||||||
- Add `wwctl <node|profile> <add|set> --kernelversion` to specify the desired kernel version or path. #1556
|
- Add `wwctl <node|profile> <add|set> --kernelversion` to specify the desired kernel version or path. #1556
|
||||||
- Add `wwctl container kernels` to list discovered kernels from containers. #1556
|
- Add `wwctl container kernels` to list discovered kernels from containers. #1556
|
||||||
|
- Add possibility to define a softlink target with an overlay template
|
||||||
|
- Support defining a symlink with an overlay template. #1303
|
||||||
|
- New "localtime" overlay to define the system time zone. #1303
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
|
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
|
||||||
@@ -122,3 +123,16 @@ func createIgnitionJson(node *node.Node) string {
|
|||||||
tmpYaml, _ := json.Marshal(&conf)
|
tmpYaml, _ := json.Marshal(&conf)
|
||||||
return string(tmpYaml)
|
return string(tmpYaml)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func importSoftlink(lnk string) string {
|
||||||
|
target, err := filepath.EvalSymlinks(lnk)
|
||||||
|
if err != nil {
|
||||||
|
return "abort"
|
||||||
|
}
|
||||||
|
wwlog.Debug("importing softlink pointing to: %s", target)
|
||||||
|
return softlink(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
func softlink(target string) string {
|
||||||
|
return fmt.Sprintf("{{ /* softlink \"%s\" */ }}", target)
|
||||||
|
}
|
||||||
|
|||||||
@@ -238,13 +238,18 @@ func BuildOverlayIndir(nodeData node.Node, overlayNames []string, outputDir stri
|
|||||||
// search for magic file name comment
|
// search for magic file name comment
|
||||||
fileScanner := bufio.NewScanner(bytes.NewReader(buffer.Bytes()))
|
fileScanner := bufio.NewScanner(bytes.NewReader(buffer.Bytes()))
|
||||||
fileScanner.Split(ScanLines)
|
fileScanner.Split(ScanLines)
|
||||||
reg := regexp.MustCompile(`.*{{\s*/\*\s*file\s*["'](.*)["']\s*\*/\s*}}.*`)
|
regFile := regexp.MustCompile(`.*{{\s*/\*\s*file\s*["'](.*)["']\s*\*/\s*}}.*`)
|
||||||
|
regLink := regexp.MustCompile(`.*{{\s*/\*\s*softlink\s*["'](.*)["']\s*\*/\s*}}.*`)
|
||||||
foundFileComment := false
|
foundFileComment := false
|
||||||
for fileScanner.Scan() {
|
for fileScanner.Scan() {
|
||||||
line := fileScanner.Text()
|
line := fileScanner.Text()
|
||||||
filenameFromTemplate := reg.FindAllStringSubmatch(line, -1)
|
filenameFromTemplate := regFile.FindAllStringSubmatch(line, -1)
|
||||||
if len(filenameFromTemplate) != 0 {
|
softlinkFromTemplate := regLink.FindAllStringSubmatch(line, -1)
|
||||||
wwlog.Debug("Found multiple comment, new filename %s", filenameFromTemplate[0][1])
|
if len(softlinkFromTemplate) != 0 {
|
||||||
|
wwlog.Debug("Creating soft link %s -> %s", destFileName, softlinkFromTemplate[0][1])
|
||||||
|
return os.Symlink(softlinkFromTemplate[0][1], path.Join(outputDir, destFileName))
|
||||||
|
} else if len(filenameFromTemplate) != 0 {
|
||||||
|
wwlog.Debug("Writing file %s", filenameFromTemplate[0][1])
|
||||||
if foundFileComment {
|
if foundFileComment {
|
||||||
err = CarefulWriteBuffer(path.Join(outputDir, destFileName),
|
err = CarefulWriteBuffer(path.Join(outputDir, destFileName),
|
||||||
fileBuffer, backupFile, info.Mode())
|
fileBuffer, backupFile, info.Mode())
|
||||||
@@ -371,10 +376,13 @@ func RenderTemplateFile(fileName string, data TemplateStruct) (
|
|||||||
"Include": templateFileInclude,
|
"Include": templateFileInclude,
|
||||||
"IncludeFrom": templateContainerFileInclude,
|
"IncludeFrom": templateContainerFileInclude,
|
||||||
"IncludeBlock": templateFileBlock,
|
"IncludeBlock": templateFileBlock,
|
||||||
|
"ImportLink": importSoftlink,
|
||||||
"basename": path.Base,
|
"basename": path.Base,
|
||||||
"inc": func(i int) int { return i + 1 },
|
"inc": func(i int) int { return i + 1 },
|
||||||
"dec": func(i int) int { return i - 1 },
|
"dec": func(i int) int { return i - 1 },
|
||||||
"file": func(str string) string { return fmt.Sprintf("{{ /* file \"%s\" */ }}", str) },
|
"file": func(str string) string { return fmt.Sprintf("{{ /* file \"%s\" */ }}", str) },
|
||||||
|
"softlink": softlink,
|
||||||
|
"readlink": filepath.EvalSymlinks,
|
||||||
"IgnitionJson": func() string {
|
"IgnitionJson": func() string {
|
||||||
str := createIgnitionJson(data.ThisNode)
|
str := createIgnitionJson(data.ThisNode)
|
||||||
if str != "" {
|
if str != "" {
|
||||||
|
|||||||
56
overlays/localtime/internal/localtime_test.go
Normal file
56
overlays/localtime/internal/localtime_test.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package localtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/warewulf/warewulf/internal/app/wwctl/overlay/show"
|
||||||
|
"github.com/warewulf/warewulf/internal/pkg/config"
|
||||||
|
"github.com/warewulf/warewulf/internal/pkg/testenv"
|
||||||
|
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_localtimeOverlay(t *testing.T) {
|
||||||
|
env := testenv.New(t)
|
||||||
|
defer env.RemoveAll(t)
|
||||||
|
env.ImportFile(t, "etc/warewulf/nodes.conf", "nodes.conf")
|
||||||
|
assert.NoError(t, config.Get().Read(env.GetPath("etc/warewulf/warewulf.conf")))
|
||||||
|
env.ImportFile(t, "var/lib/warewulf/overlays/localtime/rootfs/etc/localtime.ww", "../rootfs/etc/localtime.ww")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
log string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "/etc/localtime",
|
||||||
|
args: []string{"--render", "node1", "localtime", "etc/localtime.ww"},
|
||||||
|
log: localtime,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
cmd := show.GetCommand()
|
||||||
|
cmd.SetArgs(tt.args)
|
||||||
|
stdout := bytes.NewBufferString("")
|
||||||
|
stderr := bytes.NewBufferString("")
|
||||||
|
logbuf := bytes.NewBufferString("")
|
||||||
|
cmd.SetOut(stdout)
|
||||||
|
cmd.SetErr(stderr)
|
||||||
|
wwlog.SetLogWriter(logbuf)
|
||||||
|
err := cmd.Execute()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, stdout.String())
|
||||||
|
assert.Empty(t, stderr.String())
|
||||||
|
assert.Equal(t, tt.log, logbuf.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const localtime string = `backupFile: true
|
||||||
|
writeFile: true
|
||||||
|
Filename: etc/localtime
|
||||||
|
{{ /* softlink "/usr/share/zoneinfo/GMT" */ }}
|
||||||
|
`
|
||||||
4
overlays/localtime/internal/nodes.conf
Normal file
4
overlays/localtime/internal/nodes.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
nodes:
|
||||||
|
node1:
|
||||||
|
tags:
|
||||||
|
localtime: "GMT"
|
||||||
1
overlays/localtime/rootfs/etc/localtime.ww
Normal file
1
overlays/localtime/rootfs/etc/localtime.ww
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{{ if .Tags.localtime }}{{ printf "%s/%s" "/usr/share/zoneinfo" .Tags.localtime | softlink }}{{ else }}{{ ImportLink "/etc/localtime" }}{{ end }}
|
||||||
@@ -212,6 +212,22 @@ A given string can be split into substrings.
|
|||||||
{{ $y := (split $x ":") -}}
|
{{ $y := (split $x ":") -}}
|
||||||
{{ range $y }} {{.}} {{ end }}
|
{{ range $y }} {{.}} {{ end }}
|
||||||
|
|
||||||
|
softlink
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
Creates a soft link to the given string for the template.
|
||||||
|
|
||||||
|
ImportLink
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
Evaluates the soft link on the Warewulf server and
|
||||||
|
then create the soft link to it in the overlay.
|
||||||
|
|
||||||
|
readlink
|
||||||
|
^^^^^^^^
|
||||||
|
|
||||||
|
Evaluates the soft link on the Warewulf server and returns the target.
|
||||||
|
|
||||||
|
|
||||||
Node specific files
|
Node specific files
|
||||||
-------------------
|
-------------------
|
||||||
|
|||||||
@@ -212,6 +212,7 @@ getent group %{wwgroup} >/dev/null || groupadd -r %{wwgroup}
|
|||||||
%attr(-, root, root) %{_sharedstatedir}/warewulf/overlays/wicked/rootfs/*
|
%attr(-, root, root) %{_sharedstatedir}/warewulf/overlays/wicked/rootfs/*
|
||||||
%attr(-, root, root) %{_sharedstatedir}/warewulf/overlays/wwclient/rootfs/*
|
%attr(-, root, root) %{_sharedstatedir}/warewulf/overlays/wwclient/rootfs/*
|
||||||
%attr(-, root, root) %{_sharedstatedir}/warewulf/overlays/wwinit/rootfs/*
|
%attr(-, root, root) %{_sharedstatedir}/warewulf/overlays/wwinit/rootfs/*
|
||||||
|
%attr(-, root, root) %{_sharedstatedir}/warewulf/overlays/localtime/rootfs/*
|
||||||
|
|
||||||
%attr(-, root, root) %{_bindir}/wwctl
|
%attr(-, root, root) %{_bindir}/wwctl
|
||||||
%attr(-, root, root) %{_prefix}/lib/firewalld/services/warewulf.xml
|
%attr(-, root, root) %{_prefix}/lib/firewalld/services/warewulf.xml
|
||||||
|
|||||||
Reference in New Issue
Block a user