added wwctl clean to remove cache/dead overlays

Signed-off-by: Christian Goll <cgoll@suse.com>
This commit is contained in:
Christian Goll
2024-10-21 11:44:46 +02:00
committed by Jonathon Anderson
parent 511938ac5c
commit ff84974506
7 changed files with 142 additions and 0 deletions

View File

@@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add support to render template using `host` or `$(uname -n)` as the value of `overlay show --render`. #623
- Added command line parameters for credentials of a container registry
- Add flag `--build` to `wwctl container copy`. #1378
- Add `wwctl clean` to remove OCI cache and overlays from deleted nodes
### Changed

View File

@@ -0,0 +1,13 @@
package clean
import (
"github.com/warewulf/warewulf/internal/pkg/api/clean"
"github.com/spf13/cobra"
)
func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) (err error) {
return func(cmd *cobra.Command, args []string) (err error) {
return clean.Clean()
}
}

View File

@@ -0,0 +1,33 @@
package clean
import (
"path"
"testing"
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
"github.com/stretchr/testify/assert"
"github.com/warewulf/warewulf/internal/pkg/testenv"
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
func Test_Clean(t *testing.T) {
wwlog.SetLogLevel(wwlog.DEBUG)
env := testenv.New(t)
env.WriteFile(t, "etc/warewulf/nodes.conf",
`WW_INTERNAL: 45
nodeprofiles: {}
nodes:
node1: {}
`)
wwconf := warewulfconf.Get()
env.WriteFileAbs(t, path.Join(wwconf.Paths.WWProvisiondir, "overlays/node1/__SYSTEM__.img"), "Fake System")
env.WriteFileAbs(t, path.Join(wwconf.Paths.WWProvisiondir, "overlays/node2/__SYSTEM__.img"), "Fake System")
env.WriteFileAbs(t, path.Join(wwconf.Paths.Cachedir, "warewulf/test"), "Nothing to see here")
baseCmd := GetCommand()
err := baseCmd.Execute()
assert.NoError(t, err)
assert.FileExists(t, path.Join(wwconf.Paths.WWProvisiondir, "overlays/node1/__SYSTEM__.img"))
assert.NoFileExists(t, path.Join(wwconf.Paths.WWProvisiondir, "overlays/node2/__SYSTEM__.img"))
assert.NoDirExists(t, path.Join(wwconf.Paths.Cachedir, "warewulf"))
}

View File

@@ -0,0 +1,20 @@
package clean
import (
"github.com/spf13/cobra"
)
type variables struct {
}
func GetCommand() *cobra.Command {
vars := variables{}
baseCmd := &cobra.Command{
DisableFlagsInUseLine: true,
Use: "clean",
Short: "Clean up",
Long: "This command cleans the OCI cache and removes leftovers from deleted nodes",
RunE: CobraRunE(&vars),
}
return baseCmd
}

View File

@@ -4,6 +4,7 @@ import (
"os"
"github.com/spf13/cobra"
"github.com/warewulf/warewulf/internal/app/wwctl/clean"
"github.com/warewulf/warewulf/internal/app/wwctl/configure"
"github.com/warewulf/warewulf/internal/app/wwctl/container"
"github.com/warewulf/warewulf/internal/app/wwctl/genconf"
@@ -58,6 +59,7 @@ func init() {
rootCmd.AddCommand(version.GetCommand())
rootCmd.AddCommand(ssh.GetCommand())
rootCmd.AddCommand(genconf.GetCommand())
rootCmd.AddCommand(clean.GetCommand())
}
// GetRootCommand returns the root cobra.Command for the application.

View File

@@ -0,0 +1,47 @@
package clean
import (
"os"
"path"
_ "golang.org/x/exp/slices"
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
"github.com/warewulf/warewulf/internal/pkg/node"
"github.com/warewulf/warewulf/internal/pkg/util"
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
/*
Cleans up the OCI cache and remains of deleted nodes
*/
func Clean() (err error) {
warewulfconf := warewulfconf.Get()
wwlog.Verbose("removing oci cache dir: %s", path.Join(warewulfconf.Paths.Cachedir+"/warewulf"))
err = os.RemoveAll(path.Join(warewulfconf.Paths.Cachedir + "/warewulf"))
if err != nil {
return err
}
nodeDB, err := node.New()
if err != nil {
return err
}
nodes := nodeDB.ListAllNodes()
dirList, err := os.ReadDir(path.Join(warewulfconf.Paths.WWProvisiondir, "overlays/"))
if err != nil {
return err
}
for _, item := range dirList {
if !item.IsDir() {
continue
}
if !util.InSlice(nodes, item.Name()) {
wwlog.Verbose("removing overlays of delete node: %s", item.Name())
err = os.RemoveAll(path.Join(warewulfconf.Paths.WWProvisiondir, "overlays/", item.Name()))
if err != nil {
return err
}
}
}
return
}

View File

@@ -9,6 +9,7 @@ import (
"os"
"path"
"path/filepath"
"strings"
"testing"
"time"
@@ -41,6 +42,7 @@ const Systemddir = "usr/lib/systemd/system"
const WWOverlaydir = "var/lib/warewulf/overlays"
const WWChrootdir = "var/lib/warewulf/chroots"
const WWProvisiondir = "srv/warewulf"
const Cachedir = "cache"
// New creates a test environment in a temporary directory and configures
// Warewulf to use it.
@@ -76,6 +78,7 @@ func New(t *testing.T) (env *TestEnv) {
conf.Paths.WWOverlaydir = env.GetPath(WWOverlaydir)
conf.Paths.WWChrootdir = env.GetPath(WWChrootdir)
conf.Paths.WWProvisiondir = env.GetPath(WWProvisiondir)
conf.Paths.Cachedir = env.GetPath(Cachedir)
conf.Paths.WWClientdir = "/warewulf"
for _, confPath := range []string{
@@ -161,3 +164,26 @@ func (env *TestEnv) RemoveAll(t *testing.T) {
err := os.RemoveAll(env.BaseDir)
assert.NoError(t, err)
}
// Writes to absolute path, but checks if given file name
// is within testenv.
//
// Asserts no errors occur.
func (env *TestEnv) WriteFileAbs(t *testing.T, fileName string, content string) {
ok := strings.HasPrefix(fileName, env.BaseDir)
if !ok {
assert.Fail(t, "given filename is not in testenv")
}
dirName := filepath.Dir(fileName)
err := os.MkdirAll(dirName, 0755)
assert.NoError(t, err)
f, err := os.Create(fileName)
assert.NoError(t, err)
defer f.Close()
_, err = f.WriteString(content)
assert.NoError(t, err)
err = os.Chtimes(fileName,
time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC),
time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC))
assert.NoError(t, err)
}