mirror of
https://github.com/project-zot/zot.git
synced 2025-03-11 02:17:43 -05:00
storage: different subpaths can point to same root directory
currently different subpaths can only point to same root directory only when one or both of the storage config does not enable dedupe different subpath should be able to point to same root directory and in that case their storage config should be same i.e GC,Dedupe, GC delay and GC interval Signed-off-by: Shivam Mishra <shimish2@cisco.com>
This commit is contained in:
parent
3bccea7aa2
commit
6c293719e3
8 changed files with 441 additions and 50 deletions
|
@ -2,6 +2,7 @@ package config
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/getlantern/deepcopy"
|
||||
|
@ -144,6 +145,27 @@ func New() *Config {
|
|||
}
|
||||
}
|
||||
|
||||
func (expConfig StorageConfig) ParamsEqual(actConfig StorageConfig) bool {
|
||||
return expConfig.GC == actConfig.GC && expConfig.Dedupe == actConfig.Dedupe &&
|
||||
expConfig.GCDelay == actConfig.GCDelay && expConfig.GCInterval == actConfig.GCInterval
|
||||
}
|
||||
|
||||
// SameFile compare two files.
|
||||
// This method will first do the stat of two file and compare using os.SameFile method.
|
||||
func SameFile(str1, str2 string) (bool, error) {
|
||||
sFile, err := os.Stat(str1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
tFile, err := os.Stat(str2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return os.SameFile(sFile, tFile), nil
|
||||
}
|
||||
|
||||
// Sanitize makes a sanitized copy of the config removing any secrets.
|
||||
func (c *Config) Sanitize() *Config {
|
||||
sanitizedConfig := &Config{}
|
||||
|
|
32
pkg/api/config/config_elevated_test.go
Normal file
32
pkg/api/config/config_elevated_test.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
//go:build needprivileges
|
||||
// +build needprivileges
|
||||
|
||||
package config_test
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
)
|
||||
|
||||
func TestMountConfig(t *testing.T) {
|
||||
Convey("Test config utils mounting same directory", t, func() {
|
||||
// If two dirs are mounting to same location SameFile should be same
|
||||
dir1 := t.TempDir()
|
||||
dir2 := t.TempDir()
|
||||
dir3 := t.TempDir()
|
||||
|
||||
err := syscall.Mount(dir3, dir1, "", syscall.MS_BIND, "")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = syscall.Mount(dir3, dir2, "", syscall.MS_BIND, "")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
isSame, err := config.SameFile(dir1, dir2)
|
||||
So(err, ShouldBeNil)
|
||||
So(isSame, ShouldBeTrue)
|
||||
})
|
||||
}
|
67
pkg/api/config/config_test.go
Normal file
67
pkg/api/config/config_test.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package config_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
)
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
Convey("Test config utils", t, func() {
|
||||
firstStorageConfig := config.StorageConfig{
|
||||
GC: true, Dedupe: true,
|
||||
GCDelay: 1 * time.Minute, GCInterval: 1 * time.Hour,
|
||||
}
|
||||
secondStorageConfig := config.StorageConfig{
|
||||
GC: true, Dedupe: true,
|
||||
GCDelay: 1 * time.Minute, GCInterval: 1 * time.Hour,
|
||||
}
|
||||
|
||||
So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeTrue)
|
||||
|
||||
firstStorageConfig.GC = false
|
||||
|
||||
So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeFalse)
|
||||
|
||||
firstStorageConfig.GC = true
|
||||
firstStorageConfig.Dedupe = false
|
||||
|
||||
So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeFalse)
|
||||
|
||||
firstStorageConfig.Dedupe = true
|
||||
firstStorageConfig.GCDelay = 2 * time.Minute
|
||||
|
||||
So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeFalse)
|
||||
|
||||
firstStorageConfig.GCDelay = 1 * time.Minute
|
||||
firstStorageConfig.GCInterval = 2 * time.Hour
|
||||
|
||||
So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeFalse)
|
||||
|
||||
firstStorageConfig.GCInterval = 1 * time.Hour
|
||||
|
||||
So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeTrue)
|
||||
|
||||
isSame, err := config.SameFile("test-config", "test")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(isSame, ShouldBeFalse)
|
||||
|
||||
dir1 := t.TempDir()
|
||||
|
||||
isSame, err = config.SameFile(dir1, "test")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(isSame, ShouldBeFalse)
|
||||
|
||||
dir2 := t.TempDir()
|
||||
|
||||
isSame, err = config.SameFile(dir1, dir2)
|
||||
So(err, ShouldBeNil)
|
||||
So(isSame, ShouldBeFalse)
|
||||
|
||||
isSame, err = config.SameFile(dir1, dir1)
|
||||
So(err, ShouldBeNil)
|
||||
So(isSame, ShouldBeTrue)
|
||||
})
|
||||
}
|
|
@ -21,6 +21,7 @@ import (
|
|||
"zotregistry.io/zot/pkg/api/config"
|
||||
ext "zotregistry.io/zot/pkg/extensions"
|
||||
extconf "zotregistry.io/zot/pkg/extensions/config"
|
||||
"zotregistry.io/zot/pkg/extensions/lint"
|
||||
"zotregistry.io/zot/pkg/extensions/monitoring"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
|
@ -281,54 +282,11 @@ func (c *Controller) InitImageStore(reloadCtx context.Context) error {
|
|||
if len(c.Config.Storage.SubPaths) > 0 {
|
||||
subPaths := c.Config.Storage.SubPaths
|
||||
|
||||
subImageStore := make(map[string]storage.ImageStore)
|
||||
subImageStore, err := c.getSubStore(subPaths, linter)
|
||||
if err != nil {
|
||||
c.Log.Error().Err(err).Msg("controller: error getting sub image store")
|
||||
|
||||
// creating image store per subpaths
|
||||
for route, storageConfig := range subPaths {
|
||||
// no need to validate hard links work on s3
|
||||
if storageConfig.Dedupe && storageConfig.StorageDriver == nil {
|
||||
err := storage.ValidateHardLink(storageConfig.RootDirectory)
|
||||
if err != nil {
|
||||
c.Log.Warn().Msg("input storage root directory filesystem does not supports hardlinking, " +
|
||||
"disabling dedupe functionality")
|
||||
|
||||
storageConfig.Dedupe = false
|
||||
}
|
||||
}
|
||||
|
||||
if storageConfig.StorageDriver == nil {
|
||||
// false positive lint - linter does not implement Lint method
|
||||
// nolint: typecheck
|
||||
subImageStore[route] = storage.NewImageStore(storageConfig.RootDirectory,
|
||||
storageConfig.GC, storageConfig.GCDelay, storageConfig.Dedupe, storageConfig.Commit, c.Log, c.Metrics, linter)
|
||||
} else {
|
||||
storeName := fmt.Sprintf("%v", storageConfig.StorageDriver["name"])
|
||||
if storeName != storage.S3StorageDriverName {
|
||||
c.Log.Fatal().Err(errors.ErrBadConfig).Msgf("unsupported storage driver: %s", storageConfig.StorageDriver["name"])
|
||||
}
|
||||
|
||||
// Init a Storager from connection string.
|
||||
store, err := factory.Create(storeName, storageConfig.StorageDriver)
|
||||
if err != nil {
|
||||
c.Log.Error().Err(err).Str("rootDir", storageConfig.RootDirectory).Msg("Unable to create s3 service")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
/* in the case of s3 c.Config.Storage.RootDirectory is used for caching blobs locally and
|
||||
c.Config.Storage.StorageDriver["rootdirectory"] is the actual rootDir in s3 */
|
||||
rootDir := "/"
|
||||
if c.Config.Storage.StorageDriver["rootdirectory"] != nil {
|
||||
rootDir = fmt.Sprintf("%v", c.Config.Storage.StorageDriver["rootdirectory"])
|
||||
}
|
||||
|
||||
// false positive lint - linter does not implement Lint method
|
||||
// nolint: typecheck
|
||||
subImageStore[route] = s3.NewImageStore(rootDir, storageConfig.RootDirectory,
|
||||
storageConfig.GC, storageConfig.GCDelay,
|
||||
storageConfig.Dedupe, storageConfig.Commit, c.Log, c.Metrics, linter, store,
|
||||
)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
c.StoreController.SubStore = subImageStore
|
||||
|
@ -340,6 +298,100 @@ func (c *Controller) InitImageStore(reloadCtx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) getSubStore(subPaths map[string]config.StorageConfig,
|
||||
linter *lint.Linter,
|
||||
) (map[string]storage.ImageStore, error) {
|
||||
imgStoreMap := make(map[string]storage.ImageStore, 0)
|
||||
|
||||
subImageStore := make(map[string]storage.ImageStore)
|
||||
|
||||
// creating image store per subpaths
|
||||
for route, storageConfig := range subPaths {
|
||||
// no need to validate hard links work on s3
|
||||
if storageConfig.Dedupe && storageConfig.StorageDriver == nil {
|
||||
err := storage.ValidateHardLink(storageConfig.RootDirectory)
|
||||
if err != nil {
|
||||
c.Log.Warn().Msg("input storage root directory filesystem does not supports hardlinking, " +
|
||||
"disabling dedupe functionality")
|
||||
|
||||
storageConfig.Dedupe = false
|
||||
}
|
||||
}
|
||||
|
||||
if storageConfig.StorageDriver == nil {
|
||||
// Compare if subpath root dir is same as default root dir
|
||||
isSame, _ := config.SameFile(c.Config.Storage.RootDirectory, storageConfig.RootDirectory)
|
||||
|
||||
if isSame {
|
||||
c.Log.Error().Err(errors.ErrBadConfig).Msg("sub path storage directory is same as root directory")
|
||||
|
||||
return nil, errors.ErrBadConfig
|
||||
}
|
||||
|
||||
isUnique := true
|
||||
|
||||
// Compare subpath unique files
|
||||
for file := range imgStoreMap {
|
||||
// We already have image storage for this file
|
||||
if compareImageStore(file, storageConfig.RootDirectory) {
|
||||
subImageStore[route] = imgStoreMap[file]
|
||||
|
||||
isUnique = true
|
||||
}
|
||||
}
|
||||
|
||||
// subpath root directory is unique
|
||||
// add it to uniqueSubFiles
|
||||
// Create a new image store and assign it to imgStoreMap
|
||||
if isUnique {
|
||||
imgStoreMap[storageConfig.RootDirectory] = storage.NewImageStore(storageConfig.RootDirectory,
|
||||
storageConfig.GC, storageConfig.GCDelay, storageConfig.Dedupe, storageConfig.Commit, c.Log, c.Metrics, linter)
|
||||
|
||||
subImageStore[route] = imgStoreMap[storageConfig.RootDirectory]
|
||||
}
|
||||
} else {
|
||||
storeName := fmt.Sprintf("%v", storageConfig.StorageDriver["name"])
|
||||
if storeName != storage.S3StorageDriverName {
|
||||
c.Log.Fatal().Err(errors.ErrBadConfig).Msgf("unsupported storage driver: %s", storageConfig.StorageDriver["name"])
|
||||
}
|
||||
|
||||
// Init a Storager from connection string.
|
||||
store, err := factory.Create(storeName, storageConfig.StorageDriver)
|
||||
if err != nil {
|
||||
c.Log.Error().Err(err).Str("rootDir", storageConfig.RootDirectory).Msg("Unable to create s3 service")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* in the case of s3 c.Config.Storage.RootDirectory is used for caching blobs locally and
|
||||
c.Config.Storage.StorageDriver["rootdirectory"] is the actual rootDir in s3 */
|
||||
rootDir := "/"
|
||||
if c.Config.Storage.StorageDriver["rootdirectory"] != nil {
|
||||
rootDir = fmt.Sprintf("%v", c.Config.Storage.StorageDriver["rootdirectory"])
|
||||
}
|
||||
|
||||
// false positive lint - linter does not implement Lint method
|
||||
// nolint: typecheck
|
||||
subImageStore[route] = s3.NewImageStore(rootDir, storageConfig.RootDirectory,
|
||||
storageConfig.GC, storageConfig.GCDelay,
|
||||
storageConfig.Dedupe, storageConfig.Commit, c.Log, c.Metrics, linter, store,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return subImageStore, nil
|
||||
}
|
||||
|
||||
func compareImageStore(root1, root2 string) bool {
|
||||
isSameFile, err := config.SameFile(root1, root2)
|
||||
// This error is path error that means either of root directory doesn't exist, in that case do string match
|
||||
if err != nil {
|
||||
return strings.EqualFold(root1, root2)
|
||||
}
|
||||
|
||||
return isSameFile
|
||||
}
|
||||
|
||||
func (c *Controller) LoadNewConfig(reloadCtx context.Context, config *config.Config) {
|
||||
// reload access control config
|
||||
c.Config.AccessControl = config.AccessControl
|
||||
|
|
|
@ -839,6 +839,70 @@ func TestMultipleInstance(t *testing.T) {
|
|||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
})
|
||||
|
||||
Convey("Test zot multiple subpath with same root directory", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
htpasswdPath := test.MakeHtpasswdFile()
|
||||
defer os.Remove(htpasswdPath)
|
||||
|
||||
conf.HTTP.Auth = &config.AuthConfig{
|
||||
HTPasswd: config.AuthHTPasswd{
|
||||
Path: htpasswdPath,
|
||||
},
|
||||
}
|
||||
ctlr := api.NewController(conf)
|
||||
globalDir := t.TempDir()
|
||||
subDir := t.TempDir()
|
||||
|
||||
ctlr.Config.Storage.RootDirectory = globalDir
|
||||
subPathMap := make(map[string]config.StorageConfig)
|
||||
subPathMap["/a"] = config.StorageConfig{RootDirectory: globalDir, Dedupe: true, GC: true}
|
||||
subPathMap["/b"] = config.StorageConfig{RootDirectory: subDir, Dedupe: true, GC: true}
|
||||
|
||||
ctlr.Config.Storage.SubPaths = subPathMap
|
||||
|
||||
err := ctlr.Run(context.Background())
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
// subpath root directory does not exist.
|
||||
subPathMap["/a"] = config.StorageConfig{RootDirectory: globalDir, Dedupe: true, GC: true}
|
||||
subPathMap["/b"] = config.StorageConfig{RootDirectory: subDir, Dedupe: false, GC: true}
|
||||
|
||||
ctlr.Config.Storage.SubPaths = subPathMap
|
||||
|
||||
err = ctlr.Run(context.Background())
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
subPathMap["/a"] = config.StorageConfig{RootDirectory: subDir, Dedupe: true, GC: true}
|
||||
subPathMap["/b"] = config.StorageConfig{RootDirectory: subDir, Dedupe: true, GC: true}
|
||||
|
||||
ctlr.Config.Storage.SubPaths = subPathMap
|
||||
|
||||
go startServer(ctlr)
|
||||
defer stopServer(ctlr)
|
||||
test.WaitTillServerReady(baseURL)
|
||||
|
||||
// without creds, should get access error
|
||||
resp, err := resty.R().Get(baseURL + "/v2/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
||||
var e api.Error
|
||||
err = json.Unmarshal(resp.Body(), &e)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// with creds, should get expected status code
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusNotFound)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSWithBasicAuth(t *testing.T) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
glob "github.com/bmatcuk/doublestar/v4"
|
||||
|
@ -202,6 +203,34 @@ func NewCliRootCmd() *cobra.Command {
|
|||
return rootCmd
|
||||
}
|
||||
|
||||
func validateStorageConfig(cfg *config.Config) error {
|
||||
expConfigMap := make(map[string]config.StorageConfig, 0)
|
||||
|
||||
defaultRootDir := cfg.Storage.RootDirectory
|
||||
|
||||
for _, storageConfig := range cfg.Storage.SubPaths {
|
||||
if strings.EqualFold(defaultRootDir, storageConfig.RootDirectory) {
|
||||
log.Error().Err(errors.ErrBadConfig).Msg("storage subpaths cannot use default storage root directory")
|
||||
|
||||
return errors.ErrBadConfig
|
||||
}
|
||||
|
||||
expConfig, ok := expConfigMap[storageConfig.RootDirectory]
|
||||
if ok {
|
||||
equal := expConfig.ParamsEqual(storageConfig)
|
||||
if !equal {
|
||||
log.Error().Err(errors.ErrBadConfig).Msg("storage config with same root directory should have same parameters")
|
||||
|
||||
return errors.ErrBadConfig
|
||||
}
|
||||
} else {
|
||||
expConfigMap[storageConfig.RootDirectory] = storageConfig
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateConfiguration(config *config.Config) error {
|
||||
if err := validateGC(config); err != nil {
|
||||
return err
|
||||
|
@ -215,6 +244,10 @@ func validateConfiguration(config *config.Config) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err := validateStorageConfig(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check authorization config, it should have basic auth enabled or ldap
|
||||
if config.HTTP.RawAccessControl != nil {
|
||||
// checking for anonymous policy only authorization config: no users, no policies but anonymous policy
|
||||
|
|
|
@ -141,6 +141,82 @@ func TestVerify(t *testing.T) {
|
|||
So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic)
|
||||
})
|
||||
|
||||
Convey("Test verify subpath storage config", t, func(c C) {
|
||||
tmpfile, err := ioutil.TempFile("", "zot-test*.json")
|
||||
So(err, ShouldBeNil)
|
||||
defer os.Remove(tmpfile.Name()) // clean up
|
||||
content := []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/zot-a"},"/b": {"rootDirectory": "/zot-a"}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
|
||||
err = cli.NewServerRootCmd().Execute()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// sub paths that point to same directory should have same storage config.
|
||||
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"},
|
||||
"/b": {{"rootDirectory": "/zot-a","dedupe":"false"}}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
|
||||
So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic)
|
||||
|
||||
// sub paths that point to default root directory should not be allowed.
|
||||
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/tmp/zot","dedupe":"true"},"/b": {{"rootDirectory": "/zot-a"}}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
|
||||
So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic)
|
||||
|
||||
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true"},
|
||||
"/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"false"}}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
|
||||
So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic)
|
||||
|
||||
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true"},
|
||||
"/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
|
||||
So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic)
|
||||
|
||||
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"},
|
||||
"/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
|
||||
So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic)
|
||||
|
||||
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/tmp/zot","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"},
|
||||
"/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
|
||||
So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic)
|
||||
})
|
||||
|
||||
Convey("Test verify w/ authorization and w/o authentication", t, func(c C) {
|
||||
tmpfile, err := ioutil.TempFile("", "zot-test*.json")
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -420,6 +496,51 @@ func TestLoadConfig(t *testing.T) {
|
|||
err := cli.LoadConfiguration(config, "../../examples/config-policy.json")
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
Convey("Test subpath config combination", t, func(c C) {
|
||||
config := config.New()
|
||||
tmpfile, err := ioutil.TempFile("", "zot-test*.json")
|
||||
So(err, ShouldBeNil)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
content := []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/tmp/zot","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"},
|
||||
"/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
err = cli.LoadConfiguration(config, tmpfile.Name())
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"},
|
||||
"/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
err = cli.LoadConfiguration(config, tmpfile.Name())
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"},
|
||||
"/b": {"rootDirectory": "/zot-a","dedupe":"false"}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
err = cli.LoadConfiguration(config, tmpfile.Name())
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
content = []byte(`{"storage":{"rootDirectory":"/tmp/zot",
|
||||
"subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"},
|
||||
"/b": {"rootDirectory": "/zot-a","dedupe":"true"}}},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`)
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
err = cli.LoadConfiguration(config, tmpfile.Name())
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGC(t *testing.T) {
|
||||
|
|
|
@ -286,8 +286,6 @@ func TestORAS(t *testing.T) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(fileDir)
|
||||
|
||||
srcURL := strings.Join([]string{sctlr.Server.Addr, "/oras-artifact:v2"}, "")
|
||||
|
||||
cmd = exec.Command("oras", "push", "--plain-http", srcURL, "--config",
|
||||
|
@ -1220,7 +1218,9 @@ func TestBasicAuth(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
destConfig.Storage.RootDirectory = destDir
|
||||
rootDir := t.TempDir()
|
||||
|
||||
destConfig.Storage.RootDirectory = rootDir
|
||||
|
||||
regex := ".*"
|
||||
var semver bool
|
||||
|
|
Loading…
Add table
Reference in a new issue