Merge pull request #1395 from mslacken/FixPanicContList

Fix panic when getting a long container list before building the container
This commit is contained in:
Jonathon Anderson
2024-09-26 18:47:27 -06:00
committed by GitHub
6 changed files with 62 additions and 67 deletions

View File

@@ -46,6 +46,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Return non-zero exit code on container sub-commands #1414 - Return non-zero exit code on container sub-commands #1414
- Fix excessive line spacing issue when listing nodes. #1241 - Fix excessive line spacing issue when listing nodes. #1241
- Return non-zero exit code on node sub-commands #1421 - Return non-zero exit code on node sub-commands #1421
- Fix panic when getting a long container list before building the container. #1391
## v4.5.8, unreleased ## v4.5.8, unreleased

View File

@@ -82,13 +82,13 @@ vet: $(config)
.PHONY: test .PHONY: test
test: $(config) test: $(config)
go test ./... TZ=UTC go test ./...
.PHONY: test-cover .PHONY: test-cover
test-cover: $(config) test-cover: $(config)
rm -rf coverage rm -rf coverage
mkdir coverage mkdir coverage
go list -f '{{if gt (len .TestGoFiles) 0}}"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}}' ./... | xargs -I {} bash -c {} go list -f '{{if gt (len .TestGoFiles) 0}}"TZ=UTC go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}}' ./... | xargs -I {} bash -c {}
echo "mode: count" >coverage/cover.out echo "mode: count" >coverage/cover.out
grep -h -v "^mode:" *.coverprofile >>"coverage/cover.out" grep -h -v "^mode:" *.coverprofile >>"coverage/cover.out"
rm *.coverprofile rm *.coverprofile

View File

@@ -4,68 +4,57 @@ import (
"bytes" "bytes"
"io" "io"
"os" "os"
"os/exec"
"path"
"strings" "strings"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/warewulf/warewulf/internal/pkg/api/routes/wwapiv1" "github.com/warewulf/warewulf/internal/pkg/testenv"
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
"github.com/warewulf/warewulf/internal/pkg/node"
"github.com/warewulf/warewulf/internal/pkg/warewulfd" "github.com/warewulf/warewulf/internal/pkg/warewulfd"
"github.com/warewulf/warewulf/internal/pkg/wwlog" "github.com/warewulf/warewulf/internal/pkg/wwlog"
) )
func Test_List(t *testing.T) { func Test_List_Args(t *testing.T) {
tests := []struct { tests := []struct {
name string args []string
args []string output string
stdout string fail bool
inDb string
mockFunc func()
}{ }{
{ {args: []string{""},
name: "container list test", output: ` CONTAINER NAME
args: []string{"-l"}, test
stdout: `test 1 kernel`,
inDb: `WW_INTERNAL: 45
nodeprofiles:
default: {}
nodes:
n01:
profiles:
- default
`, `,
mockFunc: func() { fail: false,
containerList = func() (containerInfo []*wwapiv1.ContainerInfo, err error) { },
containerInfo = append(containerInfo, &wwapiv1.ContainerInfo{ {args: []string{"-l"},
Name: "test", output: ` CONTAINER NAME NODES KERNEL VERSION CREATION TIME MODIFICATION TIME SIZE
NodeCount: 1, test 0 02 Jan 00 03:04 UTC 01 Jan 70 00:00 UTC 0 B
KernelVersion: "kernel", `,
CreateDate: uint64(time.Unix(0, 0).Unix()), fail: false,
ModDate: uint64(time.Unix(0, 0).Unix()), },
Size: uint64(1), {args: []string{"-c"},
}) output: ` CONTAINER NAME NODES SIZE
return test 0 37 B
} `,
}, fail: false,
}, },
} }
env := testenv.New(t)
conf_yml := ` env.WriteFile(t, path.Join(testenv.WWChrootdir, "test/rootfs/bin/sh"), `This is a fake shell, no pearls here.`)
WW_INTERNAL: 0 // need to touch the files, so that the creation date of the container is constant,
` // modification date of `../chroots/containername` is used as creation date.
// modification dates of directories change every time a file or subdir is added
conf := warewulfconf.Get() // so we have to make it constant *after* its creation.
err := conf.Parse([]byte(conf_yml)) cmd := exec.Command("touch", "-d", "2000-01-02 03:04:05 UTC",
env.GetPath(path.Join(testenv.WWChrootdir, "test/rootfs")),
env.GetPath(path.Join(testenv.WWChrootdir, "test")))
err := cmd.Run()
assert.NoError(t, err) assert.NoError(t, err)
defer env.RemoveAll(t)
warewulfd.SetNoDaemon() warewulfd.SetNoDaemon()
for _, tt := range tests { for _, tt := range tests {
_, err = node.Parse([]byte(tt.inDb)) t.Run(strings.Join(tt.args, "_"), func(t *testing.T) {
assert.NoError(t, err)
t.Logf("Running test: %s\n", tt.name)
t.Run(tt.name, func(t *testing.T) {
tt.mockFunc()
baseCmd := GetCommand() baseCmd := GetCommand()
baseCmd.SetArgs(tt.args) baseCmd.SetArgs(tt.args)
stdoutR, stdoutW, _ := os.Pipe() stdoutR, stdoutW, _ := os.Pipe()
@@ -73,10 +62,11 @@ WW_INTERNAL: 0
wwlog.SetLogWriter(os.Stdout) wwlog.SetLogWriter(os.Stdout)
baseCmd.SetOut(os.Stdout) baseCmd.SetOut(os.Stdout)
baseCmd.SetErr(os.Stdout) baseCmd.SetErr(os.Stdout)
err = baseCmd.Execute() err := baseCmd.Execute()
if err != nil { if tt.fail {
t.Errorf("Received error when running command, err: %v", err) assert.Error(t, err)
t.FailNow() } else {
assert.NoError(t, err)
} }
stdoutC := make(chan string) stdoutC := make(chan string)
go func() { go func() {
@@ -85,13 +75,12 @@ WW_INTERNAL: 0
stdoutC <- buf.String() stdoutC <- buf.String()
}() }()
stdoutW.Close() stdoutW.Close()
stdout := <-stdoutC stdout := <-stdoutC
assert.NotEmpty(t, stdout, "os.stdout should not be empty") assert.Equal(t, tt.output, stdout)
if !strings.Contains(stdout, tt.stdout) { assert.Equal(t,
t.Errorf("Got wrong output, got:\n '%s'\n, but want:\n '%s'\n", stdout, tt.stdout) strings.ReplaceAll(strings.TrimSpace(tt.output), " ", ""),
t.FailNow() strings.ReplaceAll(strings.TrimSpace(stdout), " ", ""))
}
}) })
} }
} }

View File

@@ -28,6 +28,5 @@ func GetCommand() *cobra.Command {
baseCmd.PersistentFlags().BoolVarP(&vars.size, "size", "s", false, "show size information") baseCmd.PersistentFlags().BoolVarP(&vars.size, "size", "s", false, "show size information")
baseCmd.PersistentFlags().BoolVarP(&vars.chroot, "chroot", "c", false, "show size of chroot") baseCmd.PersistentFlags().BoolVarP(&vars.chroot, "chroot", "c", false, "show size of chroot")
baseCmd.PersistentFlags().BoolVar(&vars.compressed, "compressed", false, "show size of the compressed image") baseCmd.PersistentFlags().BoolVar(&vars.compressed, "compressed", false, "show size of the compressed image")
return baseCmd return baseCmd
} }

View File

@@ -318,6 +318,7 @@ func ContainerList() (containerInfo []*wwapiv1.ContainerInfo, err error) {
_, kernelVersion, _ := kernel.FindKernel(container.RootFsDir(source)) _, kernelVersion, _ := kernel.FindKernel(container.RootFsDir(source))
var creationTime uint64 var creationTime uint64
sourceStat, err := os.Stat(container.SourceDir(source)) sourceStat, err := os.Stat(container.SourceDir(source))
wwlog.Debug("Checking creation time for: %s,%v", container.SourceDir(source), sourceStat.ModTime())
if err != nil { if err != nil {
wwlog.Error("%s\n", err) wwlog.Error("%s\n", err)
} else { } else {
@@ -332,13 +333,13 @@ func ContainerList() (containerInfo []*wwapiv1.ContainerInfo, err error) {
if err != nil { if err != nil {
wwlog.Error("%s\n", err) wwlog.Error("%s\n", err)
} }
imgF, err := os.Stat(container.ImageFile(source)) imgSize := 0
if err != nil { if imgF, err := os.Stat(container.ImageFile(source)); err == nil {
wwlog.Error("%s\n", err) imgSize = int(imgF.Size())
} }
imgFC, err := os.Stat(container.ImageFile(source) + ".gz") imgCSize := 0
if err != nil { if imgFC, err := os.Stat(container.ImageFile(source) + ".gz"); err == nil {
wwlog.Error("%s\n", err) imgCSize = int(imgFC.Size())
} }
containerInfo = append(containerInfo, &wwapiv1.ContainerInfo{ containerInfo = append(containerInfo, &wwapiv1.ContainerInfo{
Name: source, Name: source,
@@ -347,8 +348,8 @@ func ContainerList() (containerInfo []*wwapiv1.ContainerInfo, err error) {
CreateDate: creationTime, CreateDate: creationTime,
ModDate: modTime, ModDate: modTime,
Size: uint64(size), Size: uint64(size),
ImgSize: uint64(imgF.Size()), ImgSize: uint64(imgSize),
ImgSizeComp: uint64(imgFC.Size()), ImgSizeComp: uint64(imgCSize),
}) })
} }

View File

@@ -10,6 +10,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"testing" "testing"
"time"
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config" warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
@@ -131,6 +132,10 @@ func (env *TestEnv) WriteFile(t *testing.T, fileName string, content string) {
defer f.Close() defer f.Close()
_, err = f.WriteString(content) _, err = f.WriteString(content)
assert.NoError(t, err) assert.NoError(t, err)
err = os.Chtimes(env.GetPath(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)
} }
// ReadFile returns the content of fileName as converted to a // ReadFile returns the content of fileName as converted to a