mirror of
https://github.com/project-zot/zot.git
synced 2026-06-17 21:17:58 +08:00
432fde45af
fix: allow zot to build on a FreeBSD host (#3246) The build works as long as the protoc package is installed on the build host. This also fixes lint checks when building on FreeBSD, working around common lint complaints caused by the fact that rlim_t is int64 on FreeBSD. Signed-off-by: Doug Rabson <dfr@rabson.org>
223 lines
5.2 KiB
Go
223 lines
5.2 KiB
Go
//go:build stress
|
|
// +build stress
|
|
|
|
package server_test
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"sync"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
|
|
"zotregistry.dev/zot/pkg/api"
|
|
"zotregistry.dev/zot/pkg/api/config"
|
|
cli "zotregistry.dev/zot/pkg/cli/server"
|
|
test "zotregistry.dev/zot/pkg/test/common"
|
|
)
|
|
|
|
const (
|
|
MaxFileDescriptors = 100
|
|
WorkerRunningTime = 60 * time.Second
|
|
)
|
|
|
|
func TestStressTooManyOpenFiles(t *testing.T) {
|
|
oldArgs := os.Args
|
|
|
|
defer func() { os.Args = oldArgs }()
|
|
|
|
Convey("configure zot with dedupe=false", t, func(c C) {
|
|
// In case one of the So()-assertions will fail it will allow us to print
|
|
// all the log files to figure out what happened in this test (zot log file, scrub output, storage rootFS tree)
|
|
SetDefaultFailureMode(FailureContinues)
|
|
|
|
initialLimit, err := setMaxOpenFilesLimit(MaxFileDescriptors)
|
|
So(err, ShouldBeNil)
|
|
|
|
port := test.GetFreePort()
|
|
conf := config.New()
|
|
conf.HTTP.Port = port
|
|
conf.Storage.Dedupe = false
|
|
conf.Storage.GC = true
|
|
|
|
logFile, err := os.CreateTemp("", "zot-log*.txt")
|
|
So(err, ShouldBeNil)
|
|
|
|
defer func() {
|
|
data, err := os.ReadFile(logFile.Name())
|
|
if err != nil {
|
|
t.Logf("error when reading zot log file:\n%s\n", err)
|
|
}
|
|
|
|
t.Logf("\n\n Zot log file content:\n%s\n", string(data))
|
|
os.Remove(logFile.Name())
|
|
}()
|
|
t.Log("Log file is: ", logFile.Name())
|
|
conf.Log.Output = logFile.Name()
|
|
|
|
ctlr := api.NewController(conf)
|
|
dir := t.TempDir()
|
|
|
|
defer func() {
|
|
// list the content of the directory (useful in case of test fail)
|
|
out, err := exec.Command("du", "-ab", dir).Output()
|
|
if err != nil {
|
|
t.Logf("error when listing storage files:\n%s\n", err)
|
|
}
|
|
|
|
t.Logf("Listing Storage root FS:\n%s\n", out)
|
|
}()
|
|
|
|
t.Log("Storage root dir is: ", dir)
|
|
ctlr.Config.Storage.RootDirectory = dir
|
|
|
|
ctrlManager := test.NewControllerManager(ctlr)
|
|
ctrlManager.StartAndWait(port)
|
|
|
|
content := fmt.Sprintf(`{
|
|
"storage": {
|
|
"rootDirectory": "%s",
|
|
"dedupe": %t,
|
|
"gc": %t
|
|
},
|
|
"http": {
|
|
"address": "127.0.0.1",
|
|
"port": "%s"
|
|
},
|
|
"log": {
|
|
"level": "debug",
|
|
"output": "%s"
|
|
}
|
|
}`, dir, conf.Storage.Dedupe, conf.Storage.GC, port, logFile.Name())
|
|
|
|
cfgfile, err := os.CreateTemp("", "zot-test*.json")
|
|
So(err, ShouldBeNil)
|
|
|
|
defer os.Remove(cfgfile.Name()) // clean up
|
|
_, err = cfgfile.WriteString(content)
|
|
So(err, ShouldBeNil)
|
|
err = cfgfile.Close()
|
|
So(err, ShouldBeNil)
|
|
|
|
skopeoArgs := []string{
|
|
"copy", "--format=oci", "--insecure-policy", "--dest-tls-verify=false",
|
|
"docker://public.ecr.aws/zomato/alpine:3.11.3", fmt.Sprintf("oci:%s:alpine", dir),
|
|
}
|
|
|
|
out, err := exec.Command("skopeo", skopeoArgs...).Output()
|
|
if err != nil {
|
|
t.Logf("\nerror on skopeo copy:\n%s\n", err)
|
|
}
|
|
|
|
So(err, ShouldBeNil)
|
|
t.Logf("\nCopy test image locally:\n%s\n", out)
|
|
|
|
var wg sync.WaitGroup
|
|
for i := 1; i <= MaxFileDescriptors; i++ {
|
|
wg.Add(1)
|
|
|
|
i := i
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
worker(i, port, dir)
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
_, err = setMaxOpenFilesLimit(initialLimit)
|
|
So(err, ShouldBeNil)
|
|
|
|
data, err := os.ReadFile(logFile.Name())
|
|
So(err, ShouldBeNil)
|
|
So(string(data), ShouldContainSubstring, "too many open files")
|
|
|
|
ctrlManager.StopServer()
|
|
time.Sleep(2 * time.Second)
|
|
|
|
scrubFile, err := os.CreateTemp("", "zot-scrub*.txt")
|
|
So(err, ShouldBeNil)
|
|
|
|
defer func() {
|
|
data, err := os.ReadFile(scrubFile.Name())
|
|
if err != nil {
|
|
t.Logf("error when reading zot scrub file:\n%s\n", err)
|
|
}
|
|
|
|
t.Logf("\n\n Zot scrub file content:\n%s\n", string(data))
|
|
os.Remove(scrubFile.Name())
|
|
}()
|
|
t.Log("Scrub file is: ", scrubFile.Name())
|
|
|
|
os.Args = []string{"cli_test", "scrub", cfgfile.Name()}
|
|
cobraCmd := cli.NewServerRootCmd()
|
|
cobraCmd.SetOut(scrubFile)
|
|
err = cobraCmd.Execute()
|
|
So(err, ShouldBeNil)
|
|
|
|
data, err = os.ReadFile(scrubFile.Name())
|
|
So(err, ShouldBeNil)
|
|
So(string(data), ShouldNotContainSubstring, "affected")
|
|
})
|
|
}
|
|
|
|
func worker(id int, zotPort, rootDir string) {
|
|
start := time.Now()
|
|
|
|
for i := 0; ; i++ {
|
|
sourceImg := fmt.Sprintf("oci:%s:alpine", rootDir)
|
|
destImg := fmt.Sprintf("docker://localhost:%s/client%d:%d", zotPort, id, i)
|
|
|
|
skopeoArgs := []string{
|
|
"copy", "--format=oci", "--insecure-policy", "--dest-tls-verify=false",
|
|
sourceImg, destImg,
|
|
}
|
|
|
|
err := exec.Command("skopeo", skopeoArgs...).Run()
|
|
if err != nil { //nolint: wsl
|
|
continue // we expect clients to receive errors due to FD limit reached on server
|
|
}
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
end := time.Now()
|
|
latency := end.Sub(start)
|
|
|
|
if latency > WorkerRunningTime {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func setMaxOpenFilesLimit(limit test.RlimT) (test.RlimT, error) {
|
|
var rLimit syscall.Rlimit
|
|
|
|
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
fmt.Println("Current max. open files ", rLimit.Cur)
|
|
initialLimit := rLimit.Cur
|
|
rLimit.Cur = limit
|
|
fmt.Println("Changing max. open files to ", limit)
|
|
|
|
err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
|
|
if err != nil {
|
|
return initialLimit, err
|
|
}
|
|
|
|
err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
|
|
if err != nil {
|
|
return initialLimit, err
|
|
}
|
|
|
|
fmt.Println("Max. open files is set to", rLimit.Cur)
|
|
|
|
return initialLimit, nil
|
|
}
|