From 9ff5c605052008195c42468533192249dc0ccfe2 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Fri, 12 Jul 2024 15:05:04 +0200 Subject: [PATCH 1/7] create soft link with template Add the the function softlink to the template rendering, so that {{ softlink: "/bin/bash" }} for the file `/bin/run.ww` will create a soft link to `/bin/bash` It's also possible to "import" soft links from the host, e.g. the template {{ ImportLink "/etc/localtime" }} set the timezone from the host Signed-off-by: Christian Goll --- internal/pkg/overlay/funcmap.go | 10 ++++++++++ internal/pkg/overlay/overlay.go | 13 ++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/internal/pkg/overlay/funcmap.go b/internal/pkg/overlay/funcmap.go index a9758d76..a717ae31 100644 --- a/internal/pkg/overlay/funcmap.go +++ b/internal/pkg/overlay/funcmap.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path" + "path/filepath" "strings" warewulfconf "github.com/warewulf/warewulf/internal/pkg/config" @@ -122,3 +123,12 @@ func createIgnitionJson(node *node.Node) string { tmpYaml, _ := json.Marshal(&conf) return string(tmpYaml) } + +func importSoftlink(lnk string) string { + path, err := filepath.EvalSymlinks(lnk) + if err != nil { + return "abort" + } + wwlog.Debug("importing softlink pointing to: %s", path) + return fmt.Sprintf("{{ /* softlink \"%s\" */ }}", path) +} diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index 8542b346..c2167851 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -238,12 +238,17 @@ func BuildOverlayIndir(nodeData node.Node, overlayNames []string, outputDir stri // search for magic file name comment fileScanner := bufio.NewScanner(bytes.NewReader(buffer.Bytes())) 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 for fileScanner.Scan() { line := fileScanner.Text() - filenameFromTemplate := reg.FindAllStringSubmatch(line, -1) - if len(filenameFromTemplate) != 0 { + filenameFromTemplate := regFile.FindAllStringSubmatch(line, -1) + softlinkFromTemplate := regLink.FindAllStringSubmatch(line, -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("Found multiple comment, new filename %s", filenameFromTemplate[0][1]) if foundFileComment { err = CarefulWriteBuffer(path.Join(outputDir, destFileName), @@ -371,10 +376,12 @@ func RenderTemplateFile(fileName string, data TemplateStruct) ( "Include": templateFileInclude, "IncludeFrom": templateContainerFileInclude, "IncludeBlock": templateFileBlock, + "ImportLink": importSoftlink, "basename": path.Base, "inc": 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) }, + "softlink": func(str string) string { return fmt.Sprintf("{{ /* softlink \"%s\" */ }}", str) }, "IgnitionJson": func() string { str := createIgnitionJson(data.ThisNode) if str != "" { From a2b3ae1308aa8da166853e4ea293021c40067752 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Fri, 12 Jul 2024 16:25:40 +0200 Subject: [PATCH 2/7] added template for localtime Signed-off-by: Christian Goll --- overlays/localtime/rootfs/etc/localtime.ww | 1 + 1 file changed, 1 insertion(+) create mode 100644 overlays/localtime/rootfs/etc/localtime.ww diff --git a/overlays/localtime/rootfs/etc/localtime.ww b/overlays/localtime/rootfs/etc/localtime.ww new file mode 100644 index 00000000..2545ef80 --- /dev/null +++ b/overlays/localtime/rootfs/etc/localtime.ww @@ -0,0 +1 @@ +{{ ImportLink "/etc/localtime" }} \ No newline at end of file From 88016309a921cd5714ca6bfa59c8d492167e390e Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Fri, 12 Jul 2024 16:30:12 +0200 Subject: [PATCH 3/7] soft link documentation Signed-off-by: Christian Goll --- CHANGELOG.md | 1 + userdocs/contents/templating.rst | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44fdc00a..bc34d92d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Document "known issues." - Add `wwctl --kernelversion` to specify the desired kernel version or path. #1556 - Add `wwctl container kernels` to list discovered kernels from containers. #1556 +- Add possibility to define a softlink target with an overlay template ### Changed diff --git a/userdocs/contents/templating.rst b/userdocs/contents/templating.rst index 90420acd..2a6998bd 100644 --- a/userdocs/contents/templating.rst +++ b/userdocs/contents/templating.rst @@ -212,6 +212,17 @@ A given string can be split into substrings. {{ $y := (split $x ":") -}} {{ range $y }} {{.}} {{ end }} +softlink +^^^^^^^^ + +Will create a soft link to the given string for the template. + +ImportLink +^^^^^^^^^^ + +Tries to evaluate the soft link on the host running `wwctl`/`warewulfd` and +then create the soft link to it. + Node specific files ------------------- From a8b2f1111427b723a2dedd4163424dff6cc9c65d Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Fri, 15 Nov 2024 15:08:15 -0700 Subject: [PATCH 4/7] Include localtime overlay in RPM package Signed-off-by: Jonathon Anderson --- warewulf.spec.in | 1 + 1 file changed, 1 insertion(+) diff --git a/warewulf.spec.in b/warewulf.spec.in index 92972428..86dec4f7 100644 --- a/warewulf.spec.in +++ b/warewulf.spec.in @@ -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/wwclient/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) %{_prefix}/lib/firewalld/services/warewulf.xml From fc82244749ba26523a91257d06cd5630743a4614 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Fri, 15 Nov 2024 15:09:40 -0700 Subject: [PATCH 5/7] Refactor softlink functions to remove repetition and add flexibility Signed-off-by: Jonathon Anderson --- internal/pkg/overlay/funcmap.go | 10 +++++++--- internal/pkg/overlay/overlay.go | 5 +++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/internal/pkg/overlay/funcmap.go b/internal/pkg/overlay/funcmap.go index a717ae31..0a2e99fb 100644 --- a/internal/pkg/overlay/funcmap.go +++ b/internal/pkg/overlay/funcmap.go @@ -125,10 +125,14 @@ func createIgnitionJson(node *node.Node) string { } func importSoftlink(lnk string) string { - path, err := filepath.EvalSymlinks(lnk) + target, err := filepath.EvalSymlinks(lnk) if err != nil { return "abort" } - wwlog.Debug("importing softlink pointing to: %s", path) - return fmt.Sprintf("{{ /* softlink \"%s\" */ }}", path) + wwlog.Debug("importing softlink pointing to: %s", target) + return softlink(target) +} + +func softlink(target string) string { + return fmt.Sprintf("{{ /* softlink \"%s\" */ }}", target) } diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index c2167851..bef2edc3 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -249,7 +249,7 @@ func BuildOverlayIndir(nodeData node.Node, overlayNames []string, outputDir stri 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("Found multiple comment, new filename %s", filenameFromTemplate[0][1]) + wwlog.Debug("Writing file %s", filenameFromTemplate[0][1]) if foundFileComment { err = CarefulWriteBuffer(path.Join(outputDir, destFileName), fileBuffer, backupFile, info.Mode()) @@ -381,7 +381,8 @@ func RenderTemplateFile(fileName string, data TemplateStruct) ( "inc": 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) }, - "softlink": func(str string) string { return fmt.Sprintf("{{ /* softlink \"%s\" */ }}", str) }, + "softlink": softlink, + "readlink": filepath.EvalSymlinks, "IgnitionJson": func() string { str := createIgnitionJson(data.ThisNode) if str != "" { From 39707eaccfcd6c9e9bfcac382487646f404d0cb9 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Fri, 15 Nov 2024 15:10:17 -0700 Subject: [PATCH 6/7] Add tests for localtime overlay and make configurable localtime overlay can now be configured with a "localtime" tag. Signed-off-by: Jonathon Anderson --- CHANGELOG.md | 2 + overlays/localtime/internal/localtime_test.go | 56 +++++++++++++++++++ overlays/localtime/internal/nodes.conf | 4 ++ overlays/localtime/rootfs/etc/localtime.ww | 2 +- 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 overlays/localtime/internal/localtime_test.go create mode 100644 overlays/localtime/internal/nodes.conf diff --git a/CHANGELOG.md b/CHANGELOG.md index bc34d92d..0640f122 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Add `wwctl --kernelversion` to specify the desired kernel version or path. #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 diff --git a/overlays/localtime/internal/localtime_test.go b/overlays/localtime/internal/localtime_test.go new file mode 100644 index 00000000..36557553 --- /dev/null +++ b/overlays/localtime/internal/localtime_test.go @@ -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" */ }} +` diff --git a/overlays/localtime/internal/nodes.conf b/overlays/localtime/internal/nodes.conf new file mode 100644 index 00000000..e89e9c56 --- /dev/null +++ b/overlays/localtime/internal/nodes.conf @@ -0,0 +1,4 @@ +nodes: + node1: + tags: + localtime: "GMT" diff --git a/overlays/localtime/rootfs/etc/localtime.ww b/overlays/localtime/rootfs/etc/localtime.ww index 2545ef80..ccba4480 100644 --- a/overlays/localtime/rootfs/etc/localtime.ww +++ b/overlays/localtime/rootfs/etc/localtime.ww @@ -1 +1 @@ -{{ ImportLink "/etc/localtime" }} \ No newline at end of file +{{ if .Tags.localtime }}{{ printf "%s/%s" "/usr/share/zoneinfo" .Tags.localtime | softlink }}{{ else }}{{ ImportLink "/etc/localtime" }}{{ end }} \ No newline at end of file From 206b8290c350facf24393fd426fb113574e883ed Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Fri, 15 Nov 2024 15:12:55 -0700 Subject: [PATCH 7/7] Document "readlink" template funtion Signed-off-by: Jonathon Anderson --- userdocs/contents/templating.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/userdocs/contents/templating.rst b/userdocs/contents/templating.rst index 2a6998bd..c2164905 100644 --- a/userdocs/contents/templating.rst +++ b/userdocs/contents/templating.rst @@ -215,13 +215,18 @@ A given string can be split into substrings. softlink ^^^^^^^^ -Will create a soft link to the given string for the template. +Creates a soft link to the given string for the template. ImportLink ^^^^^^^^^^ -Tries to evaluate the soft link on the host running `wwctl`/`warewulfd` and -then create the soft link to it. +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