Skip to content

Commit c8cc3f8

Browse files
refactor(storage): refactoring storage
Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
1 parent 2be5459 commit c8cc3f8

45 files changed

Lines changed: 848 additions & 716 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pkg/api/config/config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
distspec "github.com/opencontainers/distribution-spec/specs-go"
99

1010
extconf "zotregistry.io/zot/pkg/extensions/config"
11-
"zotregistry.io/zot/pkg/storage"
11+
storageConstants "zotregistry.io/zot/pkg/storage/constants"
1212
)
1313

1414
var (
@@ -147,7 +147,7 @@ func New() *Config {
147147
ReleaseTag: ReleaseTag,
148148
BinaryType: BinaryType,
149149
Storage: GlobalStorageConfig{
150-
StorageConfig: StorageConfig{GC: true, GCDelay: storage.DefaultGCDelay, Dedupe: true},
150+
StorageConfig: StorageConfig{GC: true, GCDelay: storageConstants.DefaultGCDelay, Dedupe: true},
151151
},
152152
HTTP: HTTPConfig{Address: "127.0.0.1", Port: "8080", Auth: &AuthConfig{FailDelay: 0}},
153153
Log: &LogConfig{Level: "debug"},

pkg/api/controller.go

Lines changed: 6 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"syscall"
1515
"time"
1616

17-
"github.com/docker/distribution/registry/storage/driver/factory"
1817
"github.com/gorilla/handlers"
1918
"github.com/gorilla/mux"
2019

@@ -29,7 +28,6 @@ import (
2928
"zotregistry.io/zot/pkg/storage"
3029
"zotregistry.io/zot/pkg/storage/cache"
3130
"zotregistry.io/zot/pkg/storage/constants"
32-
"zotregistry.io/zot/pkg/storage/local"
3331
"zotregistry.io/zot/pkg/storage/s3"
3432
)
3533

@@ -245,7 +243,7 @@ func (c *Controller) Init(reloadCtx context.Context) error {
245243

246244
c.Metrics = monitoring.NewMetricsServer(enabled, c.Log)
247245

248-
if err := c.InitImageStore(reloadCtx); err != nil {
246+
if err := c.InitImageStore(); err != nil { //nolint:contextcheck
249247
return err
250248
}
251249

@@ -265,185 +263,19 @@ func (c *Controller) InitCVEInfo() {
265263
}
266264
}
267265

268-
func (c *Controller) InitImageStore(ctx context.Context) error {
269-
c.StoreController = storage.StoreController{}
270-
266+
func (c *Controller) InitImageStore() error {
271267
linter := ext.GetLinter(c.Config, c.Log)
272268

273-
if c.Config.Storage.RootDirectory != "" {
274-
// no need to validate hard links work on s3
275-
if c.Config.Storage.Dedupe && c.Config.Storage.StorageDriver == nil {
276-
err := local.ValidateHardLink(c.Config.Storage.RootDirectory)
277-
if err != nil {
278-
c.Log.Warn().Msg("input storage root directory filesystem does not supports hardlinking," +
279-
"disabling dedupe functionality")
280-
281-
c.Config.Storage.Dedupe = false
282-
}
283-
}
284-
285-
var defaultStore storage.ImageStore
286-
if c.Config.Storage.StorageDriver == nil {
287-
// false positive lint - linter does not implement Lint method
288-
//nolint:typecheck,contextcheck
289-
defaultStore = local.NewImageStore(c.Config.Storage.RootDirectory,
290-
c.Config.Storage.GC, c.Config.Storage.GCDelay,
291-
c.Config.Storage.Dedupe, c.Config.Storage.Commit, c.Log, c.Metrics, linter,
292-
CreateCacheDatabaseDriver(c.Config.Storage.StorageConfig, c.Log),
293-
)
294-
} else {
295-
storeName := fmt.Sprintf("%v", c.Config.Storage.StorageDriver["name"])
296-
if storeName != storage.S3StorageDriverName {
297-
c.Log.Fatal().Err(errors.ErrBadConfig).Str("storageDriver", storeName).
298-
Msg("unsupported storage driver")
299-
}
300-
// Init a Storager from connection string.
301-
store, err := factory.Create(storeName, c.Config.Storage.StorageDriver)
302-
if err != nil {
303-
c.Log.Error().Err(err).Str("rootDir", c.Config.Storage.RootDirectory).Msg("unable to create s3 service")
304-
305-
return err
306-
}
307-
308-
/* in the case of s3 c.Config.Storage.RootDirectory is used for caching blobs locally and
309-
c.Config.Storage.StorageDriver["rootdirectory"] is the actual rootDir in s3 */
310-
rootDir := "/"
311-
if c.Config.Storage.StorageDriver["rootdirectory"] != nil {
312-
rootDir = fmt.Sprintf("%v", c.Config.Storage.StorageDriver["rootdirectory"])
313-
}
314-
315-
// false positive lint - linter does not implement Lint method
316-
//nolint: typecheck,contextcheck
317-
defaultStore = s3.NewImageStore(rootDir, c.Config.Storage.RootDirectory,
318-
c.Config.Storage.GC, c.Config.Storage.GCDelay, c.Config.Storage.Dedupe,
319-
c.Config.Storage.Commit, c.Log, c.Metrics, linter, store,
320-
CreateCacheDatabaseDriver(c.Config.Storage.StorageConfig, c.Log))
321-
}
322-
323-
c.StoreController.DefaultStore = defaultStore
324-
} else {
325-
// we can't proceed without global storage
326-
c.Log.Error().Err(errors.ErrImgStoreNotFound).Msg("controller: no storage config provided")
327-
328-
return errors.ErrImgStoreNotFound
269+
storeController, err := storage.New(c.Config, linter, c.Metrics, c.Log)
270+
if err != nil {
271+
return err
329272
}
330273

331-
if c.Config.Storage.SubPaths != nil {
332-
if len(c.Config.Storage.SubPaths) > 0 {
333-
subPaths := c.Config.Storage.SubPaths
334-
335-
//nolint: contextcheck
336-
subImageStore, err := c.getSubStore(subPaths, linter)
337-
if err != nil {
338-
c.Log.Error().Err(err).Msg("controller: error getting sub image store")
339-
340-
return err
341-
}
342-
343-
c.StoreController.SubStore = subImageStore
344-
}
345-
}
274+
c.StoreController = storeController
346275

347276
return nil
348277
}
349278

350-
func (c *Controller) getSubStore(subPaths map[string]config.StorageConfig,
351-
linter storage.Lint,
352-
) (map[string]storage.ImageStore, error) {
353-
imgStoreMap := make(map[string]storage.ImageStore, 0)
354-
355-
subImageStore := make(map[string]storage.ImageStore)
356-
357-
// creating image store per subpaths
358-
for route, storageConfig := range subPaths {
359-
// no need to validate hard links work on s3
360-
if storageConfig.Dedupe && storageConfig.StorageDriver == nil {
361-
err := local.ValidateHardLink(storageConfig.RootDirectory)
362-
if err != nil {
363-
c.Log.Warn().Msg("input storage root directory filesystem does not supports hardlinking, " +
364-
"disabling dedupe functionality")
365-
366-
storageConfig.Dedupe = false
367-
}
368-
}
369-
370-
if storageConfig.StorageDriver == nil {
371-
// Compare if subpath root dir is same as default root dir
372-
isSame, _ := config.SameFile(c.Config.Storage.RootDirectory, storageConfig.RootDirectory)
373-
374-
if isSame {
375-
c.Log.Error().Err(errors.ErrBadConfig).Msg("sub path storage directory is same as root directory")
376-
377-
return nil, errors.ErrBadConfig
378-
}
379-
380-
isUnique := true
381-
382-
// Compare subpath unique files
383-
for file := range imgStoreMap {
384-
// We already have image storage for this file
385-
if compareImageStore(file, storageConfig.RootDirectory) {
386-
subImageStore[route] = imgStoreMap[file]
387-
388-
isUnique = true
389-
}
390-
}
391-
392-
// subpath root directory is unique
393-
// add it to uniqueSubFiles
394-
// Create a new image store and assign it to imgStoreMap
395-
if isUnique {
396-
imgStoreMap[storageConfig.RootDirectory] = local.NewImageStore(storageConfig.RootDirectory,
397-
storageConfig.GC, storageConfig.GCDelay, storageConfig.Dedupe,
398-
storageConfig.Commit, c.Log, c.Metrics, linter, CreateCacheDatabaseDriver(storageConfig, c.Log))
399-
400-
subImageStore[route] = imgStoreMap[storageConfig.RootDirectory]
401-
}
402-
} else {
403-
storeName := fmt.Sprintf("%v", storageConfig.StorageDriver["name"])
404-
if storeName != storage.S3StorageDriverName {
405-
c.Log.Fatal().Err(errors.ErrBadConfig).Str("storageDriver", storeName).
406-
Msg("unsupported storage driver")
407-
}
408-
409-
// Init a Storager from connection string.
410-
store, err := factory.Create(storeName, storageConfig.StorageDriver)
411-
if err != nil {
412-
c.Log.Error().Err(err).Str("rootDir", storageConfig.RootDirectory).Msg("Unable to create s3 service")
413-
414-
return nil, err
415-
}
416-
417-
/* in the case of s3 c.Config.Storage.RootDirectory is used for caching blobs locally and
418-
c.Config.Storage.StorageDriver["rootdirectory"] is the actual rootDir in s3 */
419-
rootDir := "/"
420-
if c.Config.Storage.StorageDriver["rootdirectory"] != nil {
421-
rootDir = fmt.Sprintf("%v", c.Config.Storage.StorageDriver["rootdirectory"])
422-
}
423-
424-
// false positive lint - linter does not implement Lint method
425-
//nolint: typecheck
426-
subImageStore[route] = s3.NewImageStore(rootDir, storageConfig.RootDirectory,
427-
storageConfig.GC, storageConfig.GCDelay,
428-
storageConfig.Dedupe, storageConfig.Commit, c.Log, c.Metrics, linter, store,
429-
CreateCacheDatabaseDriver(storageConfig, c.Log),
430-
)
431-
}
432-
}
433-
434-
return subImageStore, nil
435-
}
436-
437-
func compareImageStore(root1, root2 string) bool {
438-
isSameFile, err := config.SameFile(root1, root2)
439-
// This error is path error that means either of root directory doesn't exist, in that case do string match
440-
if err != nil {
441-
return strings.EqualFold(root1, root2)
442-
}
443-
444-
return isSameFile
445-
}
446-
447279
func getUseRelPaths(storageConfig *config.StorageConfig) bool {
448280
return storageConfig.StorageDriver == nil
449281
}

pkg/api/controller_test.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ import (
5050
extconf "zotregistry.io/zot/pkg/extensions/config"
5151
"zotregistry.io/zot/pkg/log"
5252
"zotregistry.io/zot/pkg/meta/repodb/repodbfactory"
53-
"zotregistry.io/zot/pkg/storage"
54-
"zotregistry.io/zot/pkg/storage/local"
53+
storageConstants "zotregistry.io/zot/pkg/storage/constants"
5554
"zotregistry.io/zot/pkg/test"
55+
"zotregistry.io/zot/pkg/test/inject"
5656
)
5757

5858
const (
@@ -360,7 +360,7 @@ func TestObjectStorageController(t *testing.T) {
360360
conf.HTTP.Port = port
361361
storageDriverParams := map[string]interface{}{
362362
"rootdirectory": "zot",
363-
"name": storage.S3StorageDriverName,
363+
"name": storageConstants.S3StorageDriverName,
364364
}
365365
conf.Storage.StorageDriver = storageDriverParams
366366
ctlr := makeController(conf, "zot", "")
@@ -380,7 +380,7 @@ func TestObjectStorageController(t *testing.T) {
380380

381381
storageDriverParams := map[string]interface{}{
382382
"rootdirectory": "zot",
383-
"name": storage.S3StorageDriverName,
383+
"name": storageConstants.S3StorageDriverName,
384384
"region": "us-east-2",
385385
"bucket": bucket,
386386
"regionendpoint": endpoint,
@@ -409,7 +409,7 @@ func TestObjectStorageControllerSubPaths(t *testing.T) {
409409

410410
storageDriverParams := map[string]interface{}{
411411
"rootdirectory": "zot",
412-
"name": storage.S3StorageDriverName,
412+
"name": storageConstants.S3StorageDriverName,
413413
"region": "us-east-2",
414414
"bucket": bucket,
415415
"regionendpoint": endpoint,
@@ -5532,7 +5532,7 @@ func TestManifestImageIndex(t *testing.T) {
55325532

55335533
Convey("Corrupt index", func() {
55345534
err = os.WriteFile(path.Join(dir, "index", "blobs", index1dgst.Algorithm().String(), index1dgst.Encoded()),
5535-
[]byte("deadbeef"), local.DefaultFilePerms)
5535+
[]byte("deadbeef"), storageConstants.DefaultFilePerms)
55365536
So(err, ShouldBeNil)
55375537
resp, err = resty.R().Delete(baseURL + fmt.Sprintf("/v2/index/manifests/%s", index1dgst))
55385538
So(err, ShouldBeNil)
@@ -5905,7 +5905,7 @@ func TestInjectInterruptedImageManifest(t *testing.T) {
59055905

59065906
// Testing router path: @Router /v2/{name}/manifests/{reference} [put]
59075907
Convey("Uploading an image manifest blob (when injected simulates an interrupted image manifest upload)", func() {
5908-
injected := test.InjectFailure(0)
5908+
injected := inject.InjectFailure(0)
59095909

59105910
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewReader(content))
59115911
request = mux.SetURLVars(request, map[string]string{"name": "repotest", "reference": "1.0"})
@@ -5966,7 +5966,7 @@ func TestInjectTooManyOpenFiles(t *testing.T) {
59665966
So(digest, ShouldNotBeNil)
59675967

59685968
// monolithic blob upload
5969-
injected := test.InjectFailure(0)
5969+
injected := inject.InjectFailure(0)
59705970
if injected {
59715971
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, loc, bytes.NewReader(content))
59725972
tokens := strings.Split(loc, "/")
@@ -6039,7 +6039,7 @@ func TestInjectTooManyOpenFiles(t *testing.T) {
60396039
// Testing router path: @Router /v2/{name}/manifests/{reference} [put]
60406040
//nolint:lll // gofumpt conflicts with lll
60416041
Convey("Uploading an image manifest blob (when injected simulates that PutImageManifest failed due to 'too many open files' error)", func() {
6042-
injected := test.InjectFailure(1)
6042+
injected := inject.InjectFailure(1)
60436043

60446044
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewReader(content))
60456045
request = mux.SetURLVars(request, map[string]string{"name": "repotest", "reference": "1.0"})
@@ -6059,7 +6059,7 @@ func TestInjectTooManyOpenFiles(t *testing.T) {
60596059
}
60606060
})
60616061
Convey("when injected simulates a `too many open files` error inside PutImageManifest method of img store", func() {
6062-
injected := test.InjectFailure(2)
6062+
injected := inject.InjectFailure(2)
60636063

60646064
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewReader(content))
60656065
request = mux.SetURLVars(request, map[string]string{"name": "repotest", "reference": "1.0"})
@@ -6080,7 +6080,7 @@ func TestInjectTooManyOpenFiles(t *testing.T) {
60806080
}
60816081
})
60826082
Convey("code coverage: error inside PutImageManifest method of img store (unable to marshal JSON)", func() {
6083-
injected := test.InjectFailure(1)
6083+
injected := inject.InjectFailure(1)
60846084

60856085
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewReader(content))
60866086
request = mux.SetURLVars(request, map[string]string{"name": "repotest", "reference": "1.0"})
@@ -6101,7 +6101,7 @@ func TestInjectTooManyOpenFiles(t *testing.T) {
61016101
}
61026102
})
61036103
Convey("code coverage: error inside PutImageManifest method of img store (umoci.OpenLayout error)", func() {
6104-
injected := test.InjectFailure(3)
6104+
injected := inject.InjectFailure(3)
61056105

61066106
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewReader(content))
61076107
request = mux.SetURLVars(request, map[string]string{"name": "repotest", "reference": "1.0"})
@@ -6122,7 +6122,7 @@ func TestInjectTooManyOpenFiles(t *testing.T) {
61226122
}
61236123
})
61246124
Convey("code coverage: error inside PutImageManifest method of img store (oci.GC)", func() {
6125-
injected := test.InjectFailure(4)
6125+
injected := inject.InjectFailure(4)
61266126

61276127
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewReader(content))
61286128
request = mux.SetURLVars(request, map[string]string{"name": "repotest", "reference": "1.0"})

0 commit comments

Comments
 (0)