Skip to content

Commit

Permalink
fix: remove inline GC and set a default value of gc interval
Browse files Browse the repository at this point in the history
- remove inline GC
- add a default value of GC interval
- run the GC periodically by default with the default value if no interval provided
- generate GC tasks with a random delay(0-30s) between
- add IsReady() method to scheduler.TaskGenerator interface

Signed-off-by: Andreea-Lupu <[email protected]>
  • Loading branch information
Andreea-Lupu committed Aug 1, 2023
1 parent 42f9f78 commit b688e57
Show file tree
Hide file tree
Showing 22 changed files with 357 additions and 151 deletions.
4 changes: 2 additions & 2 deletions examples/config-conformance.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"distSpecVersion": "1.1.0-dev",
"storage": {
"rootDirectory": "/tmp/zot",
"gc": false,
"dedupe": false
"gc": true,
"dedupe": true
},
"http": {
"address": "0.0.0.0",
Expand Down
5 changes: 4 additions & 1 deletion pkg/api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,10 @@ func New() *Config {
ReleaseTag: ReleaseTag,
BinaryType: BinaryType,
Storage: GlobalStorageConfig{
StorageConfig: StorageConfig{GC: true, GCDelay: storageConstants.DefaultGCDelay, Dedupe: true},
StorageConfig: StorageConfig{
GC: true, GCDelay: storageConstants.DefaultGCDelay,
GCInterval: storageConstants.DefaultGCInterval, Dedupe: true,
},
},
HTTP: HTTPConfig{Address: "127.0.0.1", Port: "8080", Auth: &AuthConfig{FailDelay: 0}},
Log: &LogConfig{Level: "debug"},
Expand Down
4 changes: 2 additions & 2 deletions pkg/api/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ func (c *Controller) StartBackgroundTasks(reloadCtx context.Context) {
taskScheduler.RunScheduler(reloadCtx)

// Enable running garbage-collect periodically for DefaultStore
if c.Config.Storage.GC && c.Config.Storage.GCInterval != 0 {
if c.Config.Storage.GC {
c.StoreController.DefaultStore.RunGCPeriodically(c.Config.Storage.GCInterval, taskScheduler)
}

Expand All @@ -340,7 +340,7 @@ func (c *Controller) StartBackgroundTasks(reloadCtx context.Context) {
if c.Config.Storage.SubPaths != nil {
for route, storageConfig := range c.Config.Storage.SubPaths {
// Enable running garbage-collect periodically for subImageStore
if storageConfig.GC && storageConfig.GCInterval != 0 {
if storageConfig.GC {
c.StoreController.SubStore[route].RunGCPeriodically(storageConfig.GCInterval, taskScheduler)
}

Expand Down
61 changes: 17 additions & 44 deletions pkg/api/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4503,6 +4503,7 @@ func TestCrossRepoMount(t *testing.T) {
cm.StopServer()

ctlr.Config.Storage.Dedupe = true
ctlr.Config.Storage.GC = false
ctlr.Config.Storage.RootDirectory = newDir
cm = test.NewControllerManager(ctlr) //nolint: varnamelen
cm.StartAndWait(port)
Expand Down Expand Up @@ -7352,48 +7353,6 @@ func TestInjectTooManyOpenFiles(t *testing.T) {
So(resp.StatusCode, ShouldEqual, http.StatusCreated)
}
})
Convey("code coverage: error inside PutImageManifest method of img store (umoci.OpenLayout error)", func() {
injected := inject.InjectFailure(3)

request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewReader(content))
request = mux.SetURLVars(request, map[string]string{"name": "repotest", "reference": "1.0"})
request.Header.Set("Content-Type", "application/vnd.oci.image.manifest.v1+json")
response := httptest.NewRecorder()

rthdlr.UpdateManifest(response, request)

resp := response.Result()
defer resp.Body.Close()

So(resp, ShouldNotBeNil)

if injected {
So(resp.StatusCode, ShouldEqual, http.StatusInternalServerError)
} else {
So(resp.StatusCode, ShouldEqual, http.StatusCreated)
}
})
Convey("code coverage: error inside PutImageManifest method of img store (oci.GC)", func() {
injected := inject.InjectFailure(4)

request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewReader(content))
request = mux.SetURLVars(request, map[string]string{"name": "repotest", "reference": "1.0"})
request.Header.Set("Content-Type", "application/vnd.oci.image.manifest.v1+json")
response := httptest.NewRecorder()

rthdlr.UpdateManifest(response, request)

resp := response.Result()
defer resp.Body.Close()

So(resp, ShouldNotBeNil)

if injected {
So(resp.StatusCode, ShouldEqual, http.StatusInternalServerError)
} else {
So(resp.StatusCode, ShouldEqual, http.StatusCreated)
}
})
Convey("when index.json is not in json format", func() {
resp, err = resty.R().SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
SetBody(content).Put(baseURL + "/v2/repotest/manifests/v1.0")
Expand Down Expand Up @@ -7436,6 +7395,8 @@ func TestGCSignaturesAndUntaggedManifests(t *testing.T) {
ctlr.Config.Storage.GC = true
ctlr.Config.Storage.GCDelay = 1 * time.Millisecond

ctlr.Config.Storage.Dedupe = false

test.CopyTestFiles("../../test/data/zot-test", path.Join(dir, repoName))

cm := test.NewControllerManager(ctlr)
Expand Down Expand Up @@ -7519,6 +7480,9 @@ func TestGCSignaturesAndUntaggedManifests(t *testing.T) {
img := test.CreateRandomImage()

err = test.UploadImage(img, baseURL, repoName, img.DigestStr())
So(err, ShouldBeNil)

err = ctlr.StoreController.DefaultStore.RunGCRepo(repoName)
So(err, ShouldNotBeNil)

err = os.Chmod(path.Join(dir, repoName, "blobs", "sha256", refs.Manifests[0].Digest.Encoded()), 0o755)
Expand All @@ -7530,6 +7494,9 @@ func TestGCSignaturesAndUntaggedManifests(t *testing.T) {
So(err, ShouldBeNil)

err = test.UploadImage(img, baseURL, repoName, tag)
So(err, ShouldBeNil)

err = ctlr.StoreController.DefaultStore.RunGCRepo(repoName)
So(err, ShouldNotBeNil)

err = os.WriteFile(path.Join(dir, repoName, "blobs", "sha256", refs.Manifests[0].Digest.Encoded()), content, 0o600)
Expand Down Expand Up @@ -7568,6 +7535,9 @@ func TestGCSignaturesAndUntaggedManifests(t *testing.T) {
So(err, ShouldBeNil)
newManifestDigest := godigest.FromBytes(manifestBuf)

err = ctlr.StoreController.DefaultStore.RunGCRepo(repoName)
So(err, ShouldBeNil)

// both signatures should be gc'ed
resp, err = resty.R().Get(baseURL + fmt.Sprintf("/v2/%s/manifests/%s", repoName, cosignTag))
So(err, ShouldBeNil)
Expand Down Expand Up @@ -7658,6 +7628,9 @@ func TestGCSignaturesAndUntaggedManifests(t *testing.T) {
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)

err = ctlr.StoreController.DefaultStore.RunGCRepo(repoName)
So(err, ShouldBeNil)

resp, err = resty.R().SetHeader("Content-Type", ispec.MediaTypeImageIndex).
Get(baseURL + fmt.Sprintf("/v2/%s/manifests/latest", repoName))
So(err, ShouldBeNil)
Expand Down Expand Up @@ -7741,9 +7714,9 @@ func TestPeriodicGC(t *testing.T) {

data, err := os.ReadFile(logFile.Name())
So(err, ShouldBeNil)
// periodic GC is not enabled for default store
// periodic GC is enabled by default for default store with a default interval
So(string(data), ShouldContainSubstring,
"\"GCDelay\":3600000000000,\"GCInterval\":0,\"")
"\"GCDelay\":3600000000000,\"GCInterval\":3600000000000,\"")
// periodic GC is enabled for sub store
So(string(data), ShouldContainSubstring,
fmt.Sprintf("\"SubPaths\":{\"/a\":{\"RootDirectory\":\"%s\",\"Dedupe\":false,\"RemoteCache\":false,\"GC\":true,\"Commit\":false,\"GCDelay\":1000000000,\"GCInterval\":86400000000000", subDir)) //nolint:lll // gofumpt conflicts with lll
Expand Down
25 changes: 20 additions & 5 deletions pkg/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,8 +609,14 @@ func applyDefaultValues(config *config.Config, viperInstance *viper.Viper) {
}
}

if !config.Storage.GC && viperInstance.Get("storage::gcdelay") == nil {
config.Storage.GCDelay = 0
if !config.Storage.GC {
if viperInstance.Get("storage::gcdelay") == nil {
config.Storage.GCDelay = 0
}

if viperInstance.Get("storage::gcinterval") == nil {
config.Storage.GCInterval = 0
}
}

// cache settings
Expand Down Expand Up @@ -657,9 +663,18 @@ func applyDefaultValues(config *config.Config, viperInstance *viper.Viper) {
}
}

// if gc is enabled and gcDelay is not set, it is set to default value
if storageConfig.GC && !viperInstance.IsSet("storage::subpaths::"+name+"::gcdelay") {
storageConfig.GCDelay = storageConstants.DefaultGCDelay
// if gc is enabled
if storageConfig.GC {
// and gcDelay is not set, it is set to default value
if !viperInstance.IsSet("storage::subpaths::" + name + "::gcdelay") {
storageConfig.GCDelay = storageConstants.DefaultGCDelay
}

// and gcInterval is not set, it is set to default value
if !viperInstance.IsSet("storage::subpaths::" + name + "::gcinterval") {
storageConfig.GCInterval = storageConstants.DefaultGCInterval
}

config.Storage.SubPaths[name] = storageConfig
}
}
Expand Down
3 changes: 1 addition & 2 deletions pkg/debug/gqlplayground/gqlplayground.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ var playgroundHTML embed.FS

// SetupGQLPlaygroundRoutes ...
func SetupGQLPlaygroundRoutes(conf *config.Config, router *mux.Router,
storeController storage.StoreController, l log.Logger,
storeController storage.StoreController, log log.Logger,
) {
log := log.Logger{Logger: l.With().Caller().Timestamp().Logger()}
log.Info().Msg("setting up graphql playground route")

templ, err := template.ParseFS(playgroundHTML, "index.html.tmpl")
Expand Down
7 changes: 7 additions & 0 deletions pkg/extensions/extension_mgmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ func (gen *taskGeneratorSigValidity) Next() (scheduler.Task, error) {
gen.repoIndex++

if gen.repoIndex >= len(gen.repos) {
gen.log.Info().Msg("finished generating tasks for updating signatures validity")
gen.done = true

return nil, nil
Expand All @@ -293,6 +294,8 @@ func (gen *taskGeneratorSigValidity) IsDone() bool {
}

func (gen *taskGeneratorSigValidity) Reset() {
gen.log.Info().Msg("reset task generator for updating signatures validity")

gen.done = false
gen.repoIndex = -1
ctx := context.Background()
Expand All @@ -305,6 +308,10 @@ func (gen *taskGeneratorSigValidity) Reset() {
gen.repos = repos
}

func (gen *taskGeneratorSigValidity) IsReady() bool {
return true
}

type validityTask struct {
metaDB mTypes.MetaDB
repo mTypes.RepoMetadata
Expand Down
4 changes: 4 additions & 0 deletions pkg/extensions/extension_scrub.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ func (gen *taskGenerator) IsDone() bool {
return gen.done
}

func (gen *taskGenerator) IsReady() bool {
return true
}

func (gen *taskGenerator) Reset() {
gen.lastRepo = ""
gen.done = false
Expand Down
4 changes: 4 additions & 0 deletions pkg/extensions/extension_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ func (gen *TrivyTaskGenerator) IsDone() bool {
return status == done
}

func (gen *TrivyTaskGenerator) IsReady() bool {
return true
}

func (gen *TrivyTaskGenerator) Reset() {
gen.lock.Lock()
gen.status = pending
Expand Down
11 changes: 11 additions & 0 deletions pkg/extensions/extensions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ func TestMgmtExtension(t *testing.T) {
)
So(err, ShouldBeNil)

conf.Storage.GC = false
conf.Extensions = &extconf.ExtensionConfig{}
conf.Extensions.Search = &extconf.SearchConfig{}
conf.Extensions.Search.Enable = &defaultValue
Expand Down Expand Up @@ -786,6 +787,16 @@ func TestMgmtExtension(t *testing.T) {
time.Second)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)

found, err = test.ReadLogFileAndSearchString(logFile.Name(),
"finished generating tasks for updating signatures validity", 10*time.Second)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)

found, err = test.ReadLogFileAndSearchString(logFile.Name(), "reset task generator for updating signatures validity",
10*time.Second)
So(err, ShouldBeNil)
So(found, ShouldBeTrue)
})
}

Expand Down
3 changes: 3 additions & 0 deletions pkg/extensions/scrub/scrub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func TestScrubExtension(t *testing.T) {

conf.Storage.RootDirectory = dir
conf.Storage.Dedupe = false
conf.Storage.GC = false

substore := config.StorageConfig{RootDirectory: subdir}
conf.Storage.SubPaths = map[string]config.StorageConfig{"/a": substore}
Expand Down Expand Up @@ -89,6 +90,7 @@ func TestScrubExtension(t *testing.T) {

conf.Storage.RootDirectory = dir
conf.Storage.Dedupe = false
conf.Storage.GC = false

conf.Log.Output = logFile.Name()
trueValue := true
Expand Down Expand Up @@ -137,6 +139,7 @@ func TestScrubExtension(t *testing.T) {

conf.Storage.RootDirectory = dir
conf.Storage.Dedupe = false
conf.Storage.GC = false

conf.Log.Output = logFile.Name()
trueValue := true
Expand Down
4 changes: 4 additions & 0 deletions pkg/extensions/sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ func (gen *TaskGenerator) IsDone() bool {
return gen.done
}

func (gen *TaskGenerator) IsReady() bool {
return true
}

func (gen *TaskGenerator) Reset() {
gen.lastRepo = ""
gen.Service.ResetCatalog()
Expand Down
6 changes: 6 additions & 0 deletions pkg/extensions/sync/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ func makeUpstreamServer(
}

srcConfig.HTTP.Port = srcPort
srcConfig.Storage.GC = false

srcDir := t.TempDir()

Expand Down Expand Up @@ -1663,6 +1664,7 @@ func TestPermsDenied(t *testing.T) {

destDir := t.TempDir()

destConfig.Storage.GC = false
destConfig.Storage.RootDirectory = destDir

destConfig.Extensions = &extconf.ExtensionConfig{}
Expand Down Expand Up @@ -3038,6 +3040,8 @@ func TestSubPaths(t *testing.T) {

srcConfig.HTTP.Port = srcPort

srcConfig.Storage.GC = false

srcDir := t.TempDir()

subpath := "/subpath"
Expand Down Expand Up @@ -4506,6 +4510,7 @@ func TestOnDemandRetryGoroutine(t *testing.T) {
srcBaseURL := test.GetBaseURL(srcPort)

srcConfig.HTTP.Port = srcPort
srcConfig.Storage.GC = false

srcDir := t.TempDir()

Expand Down Expand Up @@ -4712,6 +4717,7 @@ func TestOnDemandMultipleImage(t *testing.T) {
srcBaseURL := test.GetBaseURL(srcPort)

srcConfig.HTTP.Port = srcPort
srcConfig.Storage.GC = false

srcDir := t.TempDir()

Expand Down
8 changes: 6 additions & 2 deletions pkg/scheduler/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# How to submit a Generator to the scheduler

## What is a generator and how should it be implemented?
In order to create a new generator (which will generate new tasks one by one) and add it to the scheduler there are 3 methods which should be implemented:
In order to create a new generator (which will generate new tasks one by one) and add it to the scheduler there are 4 methods which should be implemented:
1. ***GenerateTask() (Task, error)***
```
This method should implement the logic for generating a new task.
Expand All @@ -12,7 +12,11 @@ In order to create a new generator (which will generate new tasks one by one) an
```
This method should return true after the generator finished all the work and has no more tasks to generate.
```
3. ***Reset()***
3. ***IsReady() bool***
```
This method should return true if the generator is ready to generate a new task and should be used when it is needed to generate tasks with some delay between.
```
4. ***Reset()***
```
When this method is called the generator should reset to its initial state.
After the generator is reset, it will generate new tasks as if it hadn't been used before.
Expand Down
Loading

0 comments on commit b688e57

Please sign in to comment.