zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/storage/gc/gc_test.go (about) 1 package gc_test 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path" 8 "testing" 9 "time" 10 11 "github.com/docker/distribution/registry/storage/driver/factory" 12 _ "github.com/docker/distribution/registry/storage/driver/s3-aws" 13 guuid "github.com/gofrs/uuid" 14 . "github.com/smartystreets/goconvey/convey" 15 "gopkg.in/resty.v1" 16 17 "zotregistry.dev/zot/pkg/api/config" 18 "zotregistry.dev/zot/pkg/extensions/monitoring" 19 zlog "zotregistry.dev/zot/pkg/log" 20 "zotregistry.dev/zot/pkg/meta" 21 "zotregistry.dev/zot/pkg/meta/boltdb" 22 "zotregistry.dev/zot/pkg/meta/dynamodb" 23 mTypes "zotregistry.dev/zot/pkg/meta/types" 24 "zotregistry.dev/zot/pkg/storage" 25 storageConstants "zotregistry.dev/zot/pkg/storage/constants" 26 "zotregistry.dev/zot/pkg/storage/gc" 27 "zotregistry.dev/zot/pkg/storage/local" 28 "zotregistry.dev/zot/pkg/storage/s3" 29 storageTypes "zotregistry.dev/zot/pkg/storage/types" 30 . "zotregistry.dev/zot/pkg/test/image-utils" 31 tskip "zotregistry.dev/zot/pkg/test/skip" 32 ) 33 34 const ( 35 region = "us-east-2" 36 ) 37 38 //nolint:gochecknoglobals 39 var testCases = []struct { 40 testCaseName string 41 storageType string 42 }{ 43 { 44 testCaseName: "S3APIs", 45 storageType: storageConstants.S3StorageDriverName, 46 }, 47 { 48 testCaseName: "LocalAPIs", 49 storageType: storageConstants.LocalStorageDriverName, 50 }, 51 } 52 53 func TestGarbageCollectAndRetention(t *testing.T) { 54 log := zlog.NewLogger("info", "/dev/null") 55 audit := zlog.NewAuditLogger("debug", "/dev/null") 56 57 metrics := monitoring.NewMetricsServer(false, log) 58 59 trueVal := true 60 61 for _, testcase := range testCases { 62 testcase := testcase 63 t.Run(testcase.testCaseName, func(t *testing.T) { 64 var imgStore storageTypes.ImageStore 65 66 var metaDB mTypes.MetaDB 67 68 if testcase.storageType == storageConstants.S3StorageDriverName { 69 tskip.SkipDynamo(t) 70 tskip.SkipS3(t) 71 72 uuid, err := guuid.NewV4() 73 if err != nil { 74 panic(err) 75 } 76 77 rootDir := path.Join("/oci-repo-test", uuid.String()) 78 cacheDir := t.TempDir() 79 80 bucket := "zot-storage-test" 81 82 storageDriverParams := map[string]interface{}{ 83 "rootDir": rootDir, 84 "name": "s3", 85 "region": region, 86 "bucket": bucket, 87 "regionendpoint": os.Getenv("S3MOCK_ENDPOINT"), 88 "accesskey": "minioadmin", 89 "secretkey": "minioadmin", 90 "secure": false, 91 "skipverify": false, 92 } 93 94 storeName := fmt.Sprintf("%v", storageDriverParams["name"]) 95 96 store, err := factory.Create(storeName, storageDriverParams) 97 if err != nil { 98 panic(err) 99 } 100 101 defer store.Delete(context.Background(), rootDir) //nolint: errcheck 102 103 // create bucket if it doesn't exists 104 _, err = resty.R().Put("http://" + os.Getenv("S3MOCK_ENDPOINT") + "/" + bucket) 105 if err != nil { 106 panic(err) 107 } 108 109 uuid, err = guuid.NewV4() 110 if err != nil { 111 panic(err) 112 } 113 114 params := dynamodb.DBDriverParameters{ //nolint:contextcheck 115 Endpoint: os.Getenv("DYNAMODBMOCK_ENDPOINT"), 116 Region: region, 117 RepoMetaTablename: "repo" + uuid.String(), 118 RepoBlobsInfoTablename: "repoblobsinfo" + uuid.String(), 119 ImageMetaTablename: "imagemeta" + uuid.String(), 120 UserDataTablename: "user" + uuid.String(), 121 APIKeyTablename: "apiKey" + uuid.String(), 122 VersionTablename: "version" + uuid.String(), 123 } 124 125 client, err := dynamodb.GetDynamoClient(params) 126 if err != nil { 127 panic(err) 128 } 129 130 metaDB, err = dynamodb.New(client, params, log) 131 if err != nil { 132 panic(err) 133 } 134 135 imgStore = s3.NewImageStore(rootDir, cacheDir, true, false, log, metrics, nil, store, nil) 136 } else { 137 // Create temporary directory 138 rootDir := t.TempDir() 139 140 // Create ImageStore 141 imgStore = local.NewImageStore(rootDir, false, false, log, metrics, nil, nil) 142 143 // init metaDB 144 params := boltdb.DBParameters{ 145 RootDir: rootDir, 146 } 147 148 boltDriver, err := boltdb.GetBoltDriver(params) 149 if err != nil { 150 panic(err) 151 } 152 153 metaDB, err = boltdb.New(boltDriver, log) 154 if err != nil { 155 panic(err) 156 } 157 } 158 159 storeController := storage.StoreController{} 160 storeController.DefaultStore = imgStore 161 162 ctx := context.Background() 163 164 Convey("setup gc images", t, func() { 165 // for gc testing 166 // basic images 167 gcTest1 := CreateRandomImage() 168 err := WriteImageToFileSystem(gcTest1, "gc-test1", "0.0.1", storeController) 169 So(err, ShouldBeNil) 170 171 // also add same image(same digest) with another tag 172 err = WriteImageToFileSystem(gcTest1, "gc-test1", "0.0.2", storeController) 173 So(err, ShouldBeNil) 174 175 gcTest2 := CreateRandomImage() 176 err = WriteImageToFileSystem(gcTest2, "gc-test2", "0.0.1", storeController) 177 So(err, ShouldBeNil) 178 179 gcTest3 := CreateRandomImage() 180 err = WriteImageToFileSystem(gcTest3, "gc-test3", "0.0.1", storeController) 181 So(err, ShouldBeNil) 182 183 // referrers 184 ref1 := CreateRandomImageWith().Subject(gcTest1.DescriptorRef()).Build() 185 err = WriteImageToFileSystem(ref1, "gc-test1", ref1.DigestStr(), storeController) 186 So(err, ShouldBeNil) 187 188 ref2 := CreateRandomImageWith().Subject(gcTest2.DescriptorRef()).Build() 189 err = WriteImageToFileSystem(ref2, "gc-test2", ref2.DigestStr(), storeController) 190 So(err, ShouldBeNil) 191 192 ref3 := CreateRandomImageWith().Subject(gcTest3.DescriptorRef()).Build() 193 err = WriteImageToFileSystem(ref3, "gc-test3", ref3.DigestStr(), storeController) 194 So(err, ShouldBeNil) 195 196 // referrers pointing to referrers 197 refOfRef1 := CreateRandomImageWith().Subject(ref1.DescriptorRef()).Build() 198 err = WriteImageToFileSystem(refOfRef1, "gc-test1", refOfRef1.DigestStr(), storeController) 199 So(err, ShouldBeNil) 200 201 refOfRef2 := CreateRandomImageWith().Subject(ref2.DescriptorRef()).Build() 202 err = WriteImageToFileSystem(refOfRef2, "gc-test2", refOfRef2.DigestStr(), storeController) 203 So(err, ShouldBeNil) 204 205 refOfRef3 := CreateRandomImageWith().Subject(ref3.DescriptorRef()).Build() 206 err = WriteImageToFileSystem(refOfRef3, "gc-test3", refOfRef3.DigestStr(), storeController) 207 So(err, ShouldBeNil) 208 209 // untagged images 210 gcUntagged1 := CreateRandomImage() 211 err = WriteImageToFileSystem(gcUntagged1, "gc-test1", gcUntagged1.DigestStr(), storeController) 212 So(err, ShouldBeNil) 213 214 gcUntagged2 := CreateRandomImage() 215 err = WriteImageToFileSystem(gcUntagged2, "gc-test2", gcUntagged2.DigestStr(), storeController) 216 So(err, ShouldBeNil) 217 218 gcUntagged3 := CreateRandomImage() 219 err = WriteImageToFileSystem(gcUntagged3, "gc-test3", gcUntagged3.DigestStr(), storeController) 220 So(err, ShouldBeNil) 221 222 // for image retention testing 223 // old images 224 gcOld1 := CreateRandomImage() 225 err = WriteImageToFileSystem(gcOld1, "retention", "0.0.1", storeController) 226 So(err, ShouldBeNil) 227 228 gcOld2 := CreateRandomImage() 229 err = WriteImageToFileSystem(gcOld2, "retention", "0.0.2", storeController) 230 So(err, ShouldBeNil) 231 232 gcOld3 := CreateRandomImage() 233 err = WriteImageToFileSystem(gcOld3, "retention", "0.0.3", storeController) 234 So(err, ShouldBeNil) 235 236 // new images 237 gcNew1 := CreateRandomImage() 238 err = WriteImageToFileSystem(gcNew1, "retention", "0.0.4", storeController) 239 So(err, ShouldBeNil) 240 241 gcNew2 := CreateRandomImage() 242 err = WriteImageToFileSystem(gcNew2, "retention", "0.0.5", storeController) 243 So(err, ShouldBeNil) 244 245 gcNew3 := CreateRandomImage() 246 err = WriteImageToFileSystem(gcNew3, "retention", "0.0.6", storeController) 247 So(err, ShouldBeNil) 248 249 err = meta.ParseStorage(metaDB, storeController, log) //nolint: contextcheck 250 So(err, ShouldBeNil) 251 252 retentionMeta, err := metaDB.GetRepoMeta(ctx, "retention") 253 So(err, ShouldBeNil) 254 255 // update timestamps for image retention 256 gcOld1Stats := retentionMeta.Statistics[gcOld1.DigestStr()] 257 gcOld1Stats.PushTimestamp = time.Now().Add(-10 * 24 * time.Hour) 258 gcOld1Stats.LastPullTimestamp = time.Now().Add(-10 * 24 * time.Hour) 259 260 gcOld2Stats := retentionMeta.Statistics[gcOld2.DigestStr()] 261 gcOld2Stats.PushTimestamp = time.Now().Add(-11 * 24 * time.Hour) 262 gcOld2Stats.LastPullTimestamp = time.Now().Add(-11 * 24 * time.Hour) 263 264 gcOld3Stats := retentionMeta.Statistics[gcOld3.DigestStr()] 265 gcOld3Stats.PushTimestamp = time.Now().Add(-12 * 24 * time.Hour) 266 gcOld3Stats.LastPullTimestamp = time.Now().Add(-12 * 24 * time.Hour) 267 268 gcNew1Stats := retentionMeta.Statistics[gcNew1.DigestStr()] 269 gcNew1Stats.PushTimestamp = time.Now().Add(-1 * 24 * time.Hour) 270 gcNew1Stats.LastPullTimestamp = time.Now().Add(-1 * 24 * time.Hour) 271 272 gcNew2Stats := retentionMeta.Statistics[gcNew2.DigestStr()] 273 gcNew2Stats.PushTimestamp = time.Now().Add(-2 * 24 * time.Hour) 274 gcNew2Stats.LastPullTimestamp = time.Now().Add(-2 * 24 * time.Hour) 275 276 gcNew3Stats := retentionMeta.Statistics[gcNew3.DigestStr()] 277 gcNew3Stats.PushTimestamp = time.Now().Add(-3 * 24 * time.Hour) 278 gcNew3Stats.LastPullTimestamp = time.Now().Add(-2 * 24 * time.Hour) 279 280 retentionMeta.Statistics[gcOld1.DigestStr()] = gcOld1Stats 281 retentionMeta.Statistics[gcOld2.DigestStr()] = gcOld2Stats 282 retentionMeta.Statistics[gcOld3.DigestStr()] = gcOld3Stats 283 284 retentionMeta.Statistics[gcNew1.DigestStr()] = gcNew1Stats 285 retentionMeta.Statistics[gcNew2.DigestStr()] = gcNew2Stats 286 retentionMeta.Statistics[gcNew3.DigestStr()] = gcNew3Stats 287 288 // update repo meta 289 err = metaDB.SetRepoMeta("retention", retentionMeta) 290 So(err, ShouldBeNil) 291 292 Convey("should not gc anything", func() { 293 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 294 Delay: storageConstants.DefaultGCDelay, 295 ImageRetention: config.ImageRetention{ 296 Delay: storageConstants.DefaultRetentionDelay, 297 Policies: []config.RetentionPolicy{ 298 { 299 Repositories: []string{"**"}, 300 DeleteReferrers: true, 301 DeleteUntagged: &trueVal, 302 KeepTags: []config.KeepTagsPolicy{ 303 {}, 304 }, 305 }, 306 }, 307 }, 308 }, audit, log) 309 310 err := gc.CleanRepo(ctx, "gc-test1") 311 So(err, ShouldBeNil) 312 313 err = gc.CleanRepo(ctx, "gc-test2") 314 So(err, ShouldBeNil) 315 316 err = gc.CleanRepo(ctx, "gc-test3") 317 So(err, ShouldBeNil) 318 319 err = gc.CleanRepo(ctx, "retention") 320 So(err, ShouldBeNil) 321 322 _, _, _, err = imgStore.GetImageManifest("gc-test1", gcTest1.DigestStr()) 323 So(err, ShouldBeNil) 324 325 _, _, _, err = imgStore.GetImageManifest("gc-test1", gcUntagged1.DigestStr()) 326 So(err, ShouldBeNil) 327 328 _, _, _, err = imgStore.GetImageManifest("gc-test1", ref1.DigestStr()) 329 So(err, ShouldBeNil) 330 331 _, _, _, err = imgStore.GetImageManifest("gc-test1", refOfRef1.DigestStr()) 332 So(err, ShouldBeNil) 333 334 _, _, _, err = imgStore.GetImageManifest("gc-test2", gcTest2.DigestStr()) 335 So(err, ShouldBeNil) 336 337 _, _, _, err = imgStore.GetImageManifest("gc-test2", gcUntagged2.DigestStr()) 338 So(err, ShouldBeNil) 339 340 _, _, _, err = imgStore.GetImageManifest("gc-test2", ref2.DigestStr()) 341 So(err, ShouldBeNil) 342 343 _, _, _, err = imgStore.GetImageManifest("gc-test2", refOfRef2.DigestStr()) 344 So(err, ShouldBeNil) 345 346 _, _, _, err = imgStore.GetImageManifest("gc-test3", gcTest3.DigestStr()) 347 So(err, ShouldBeNil) 348 349 _, _, _, err = imgStore.GetImageManifest("gc-test3", gcUntagged3.DigestStr()) 350 So(err, ShouldBeNil) 351 352 _, _, _, err = imgStore.GetImageManifest("gc-test3", ref3.DigestStr()) 353 So(err, ShouldBeNil) 354 355 _, _, _, err = imgStore.GetImageManifest("gc-test3", refOfRef3.DigestStr()) 356 So(err, ShouldBeNil) 357 358 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.1") 359 So(err, ShouldBeNil) 360 361 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.2") 362 So(err, ShouldBeNil) 363 364 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.3") 365 So(err, ShouldBeNil) 366 367 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.4") 368 So(err, ShouldBeNil) 369 370 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.5") 371 So(err, ShouldBeNil) 372 373 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.6") 374 So(err, ShouldBeNil) 375 }) 376 377 Convey("gc untagged manifests", func() { 378 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 379 Delay: storageConstants.DefaultGCDelay, 380 ImageRetention: config.ImageRetention{ 381 Delay: 1 * time.Millisecond, 382 Policies: []config.RetentionPolicy{ 383 { 384 Repositories: []string{"**"}, 385 DeleteReferrers: true, 386 DeleteUntagged: &trueVal, 387 KeepTags: []config.KeepTagsPolicy{}, 388 }, 389 }, 390 }, 391 }, audit, log) 392 393 err := gc.CleanRepo(ctx, "gc-test1") 394 So(err, ShouldBeNil) 395 396 err = gc.CleanRepo(ctx, "gc-test2") 397 So(err, ShouldBeNil) 398 399 err = gc.CleanRepo(ctx, "gc-test3") 400 So(err, ShouldBeNil) 401 402 err = gc.CleanRepo(ctx, "retention") 403 So(err, ShouldBeNil) 404 405 _, _, _, err = imgStore.GetImageManifest("gc-test1", gcTest1.DigestStr()) 406 So(err, ShouldBeNil) 407 408 _, _, _, err = imgStore.GetImageManifest("gc-test1", gcUntagged1.DigestStr()) 409 So(err, ShouldNotBeNil) 410 411 _, _, _, err = imgStore.GetImageManifest("gc-test1", ref1.DigestStr()) 412 So(err, ShouldBeNil) 413 414 _, _, _, err = imgStore.GetImageManifest("gc-test1", refOfRef1.DigestStr()) 415 So(err, ShouldBeNil) 416 417 _, _, _, err = imgStore.GetImageManifest("gc-test2", gcTest2.DigestStr()) 418 So(err, ShouldBeNil) 419 420 _, _, _, err = imgStore.GetImageManifest("gc-test2", gcUntagged2.DigestStr()) 421 So(err, ShouldNotBeNil) 422 423 _, _, _, err = imgStore.GetImageManifest("gc-test2", ref2.DigestStr()) 424 So(err, ShouldBeNil) 425 426 _, _, _, err = imgStore.GetImageManifest("gc-test2", refOfRef2.DigestStr()) 427 So(err, ShouldBeNil) 428 429 _, _, _, err = imgStore.GetImageManifest("gc-test3", gcTest3.DigestStr()) 430 So(err, ShouldBeNil) 431 432 _, _, _, err = imgStore.GetImageManifest("gc-test3", gcUntagged3.DigestStr()) 433 So(err, ShouldNotBeNil) 434 435 _, _, _, err = imgStore.GetImageManifest("gc-test3", ref3.DigestStr()) 436 So(err, ShouldBeNil) 437 438 _, _, _, err = imgStore.GetImageManifest("gc-test3", refOfRef3.DigestStr()) 439 So(err, ShouldBeNil) 440 }) 441 442 Convey("gc all tags, untagged, and afterwards referrers", func() { 443 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 444 Delay: 1 * time.Millisecond, 445 ImageRetention: config.ImageRetention{ 446 Delay: 1 * time.Millisecond, 447 Policies: []config.RetentionPolicy{ 448 { 449 Repositories: []string{"gc-test1"}, 450 DeleteReferrers: true, 451 DeleteUntagged: &trueVal, 452 KeepTags: []config.KeepTagsPolicy{ 453 { 454 Patterns: []string{"v1"}, // should not match any tag 455 }, 456 }, 457 }, 458 }, 459 }, 460 }, audit, log) 461 462 err := gc.CleanRepo(ctx, "gc-test1") 463 So(err, ShouldBeNil) 464 465 _, _, _, err = imgStore.GetImageManifest("gc-test1", gcUntagged1.DigestStr()) 466 So(err, ShouldNotBeNil) 467 468 // although we have two tags both should be deleted 469 _, _, _, err = imgStore.GetImageManifest("gc-test1", gcTest1.DigestStr()) 470 So(err, ShouldNotBeNil) 471 472 _, _, _, err = imgStore.GetImageManifest("gc-test1", ref1.DigestStr()) 473 So(err, ShouldNotBeNil) 474 475 _, _, _, err = imgStore.GetImageManifest("gc-test1", refOfRef1.DigestStr()) 476 So(err, ShouldNotBeNil) 477 478 // now repo should get gc'ed 479 repos, err := imgStore.GetRepositories() 480 So(err, ShouldBeNil) 481 So(repos, ShouldNotContain, "gc-test1") 482 So(repos, ShouldContain, "gc-test2") 483 So(repos, ShouldContain, "gc-test3") 484 So(repos, ShouldContain, "retention") 485 }) 486 487 Convey("gc with dry-run all tags, untagged, and afterwards referrers", func() { 488 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 489 Delay: 1 * time.Millisecond, 490 ImageRetention: config.ImageRetention{ 491 Delay: 1 * time.Millisecond, 492 DryRun: true, 493 Policies: []config.RetentionPolicy{ 494 { 495 Repositories: []string{"gc-test1"}, 496 DeleteReferrers: true, 497 DeleteUntagged: &trueVal, 498 KeepTags: []config.KeepTagsPolicy{ 499 { 500 Patterns: []string{"v1"}, // should not match any tag 501 }, 502 }, 503 }, 504 }, 505 }, 506 }, audit, log) 507 508 err := gc.CleanRepo(ctx, "gc-test1") 509 So(err, ShouldBeNil) 510 511 _, _, _, err = imgStore.GetImageManifest("gc-test1", gcUntagged1.DigestStr()) 512 So(err, ShouldBeNil) 513 514 _, _, _, err = imgStore.GetImageManifest("gc-test1", ref1.DigestStr()) 515 So(err, ShouldBeNil) 516 517 _, _, _, err = imgStore.GetImageManifest("gc-test1", refOfRef1.DigestStr()) 518 So(err, ShouldBeNil) 519 520 // now repo should not be gc'ed 521 repos, err := imgStore.GetRepositories() 522 So(err, ShouldBeNil) 523 So(repos, ShouldContain, "gc-test1") 524 So(repos, ShouldContain, "gc-test2") 525 So(repos, ShouldContain, "gc-test3") 526 So(repos, ShouldContain, "retention") 527 528 tags, err := imgStore.GetImageTags("gc-test1") 529 So(err, ShouldBeNil) 530 So(tags, ShouldContain, "0.0.1") 531 So(tags, ShouldContain, "0.0.2") 532 }) 533 534 Convey("all tags matches for retention", func() { 535 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 536 Delay: storageConstants.DefaultGCDelay, 537 ImageRetention: config.ImageRetention{ 538 Delay: storageConstants.DefaultRetentionDelay, 539 Policies: []config.RetentionPolicy{ 540 { 541 Repositories: []string{"**"}, 542 DeleteReferrers: true, 543 DeleteUntagged: &trueVal, 544 KeepTags: []config.KeepTagsPolicy{ 545 { 546 Patterns: []string{"0.0.*"}, 547 }, 548 }, 549 }, 550 }, 551 }, 552 }, audit, log) 553 554 err = gc.CleanRepo(ctx, "retention") 555 So(err, ShouldBeNil) 556 557 _, _, _, err = imgStore.GetImageManifest("gc-test1", "0.0.1") 558 So(err, ShouldBeNil) 559 560 _, _, _, err = imgStore.GetImageManifest("gc-test1", "0.0.2") 561 So(err, ShouldBeNil) 562 563 _, _, _, err = imgStore.GetImageManifest("gc-test2", "0.0.1") 564 So(err, ShouldBeNil) 565 566 _, _, _, err = imgStore.GetImageManifest("gc-test3", "0.0.1") 567 So(err, ShouldBeNil) 568 569 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.1") 570 So(err, ShouldBeNil) 571 572 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.2") 573 So(err, ShouldBeNil) 574 575 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.3") 576 So(err, ShouldBeNil) 577 578 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.4") 579 So(err, ShouldBeNil) 580 581 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.5") 582 So(err, ShouldBeNil) 583 584 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.6") 585 So(err, ShouldBeNil) 586 }) 587 588 Convey("retain new tags", func() { 589 sevenDays := 7 * 24 * time.Hour 590 591 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 592 Delay: storageConstants.DefaultGCDelay, 593 ImageRetention: config.ImageRetention{ 594 Delay: storageConstants.DefaultRetentionDelay, 595 Policies: []config.RetentionPolicy{ 596 { 597 Repositories: []string{"**"}, 598 DeleteReferrers: true, 599 DeleteUntagged: &trueVal, 600 KeepTags: []config.KeepTagsPolicy{ 601 { 602 Patterns: []string{".*"}, 603 PulledWithin: &sevenDays, 604 PushedWithin: &sevenDays, 605 }, 606 }, 607 }, 608 }, 609 }, 610 }, audit, log) 611 612 err = gc.CleanRepo(ctx, "retention") 613 So(err, ShouldBeNil) 614 615 tags, err := imgStore.GetImageTags("retention") 616 So(err, ShouldBeNil) 617 618 So(tags, ShouldContain, "0.0.4") 619 So(tags, ShouldContain, "0.0.5") 620 So(tags, ShouldContain, "0.0.6") 621 622 So(tags, ShouldNotContain, "0.0.1") 623 So(tags, ShouldNotContain, "0.0.2") 624 So(tags, ShouldNotContain, "0.0.3") 625 }) 626 627 Convey("retain 3 most recently pushed images", func() { 628 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 629 Delay: storageConstants.DefaultGCDelay, 630 ImageRetention: config.ImageRetention{ 631 Delay: storageConstants.DefaultRetentionDelay, 632 Policies: []config.RetentionPolicy{ 633 { 634 Repositories: []string{"**"}, 635 DeleteReferrers: true, 636 DeleteUntagged: &trueVal, 637 KeepTags: []config.KeepTagsPolicy{ 638 { 639 Patterns: []string{".*"}, 640 MostRecentlyPushedCount: 3, 641 }, 642 }, 643 }, 644 }, 645 }, 646 }, audit, log) 647 648 err = gc.CleanRepo(ctx, "retention") 649 So(err, ShouldBeNil) 650 651 tags, err := imgStore.GetImageTags("retention") 652 So(err, ShouldBeNil) 653 654 So(tags, ShouldContain, "0.0.4") 655 So(tags, ShouldContain, "0.0.5") 656 So(tags, ShouldContain, "0.0.6") 657 658 So(tags, ShouldNotContain, "0.0.1") 659 So(tags, ShouldNotContain, "0.0.2") 660 So(tags, ShouldNotContain, "0.0.3") 661 }) 662 663 Convey("retain 3 most recently pulled images", func() { 664 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 665 Delay: storageConstants.DefaultGCDelay, 666 ImageRetention: config.ImageRetention{ 667 Delay: storageConstants.DefaultRetentionDelay, 668 Policies: []config.RetentionPolicy{ 669 { 670 Repositories: []string{"**"}, 671 DeleteReferrers: true, 672 DeleteUntagged: &trueVal, 673 KeepTags: []config.KeepTagsPolicy{ 674 { 675 Patterns: []string{".*"}, 676 MostRecentlyPulledCount: 3, 677 }, 678 }, 679 }, 680 }, 681 }, 682 }, audit, log) 683 684 err = gc.CleanRepo(ctx, "retention") 685 So(err, ShouldBeNil) 686 687 tags, err := imgStore.GetImageTags("retention") 688 So(err, ShouldBeNil) 689 690 So(tags, ShouldContain, "0.0.4") 691 So(tags, ShouldContain, "0.0.5") 692 So(tags, ShouldContain, "0.0.6") 693 694 So(tags, ShouldNotContain, "0.0.1") 695 So(tags, ShouldNotContain, "0.0.2") 696 So(tags, ShouldNotContain, "0.0.3") 697 }) 698 699 Convey("retain 3 most recently pulled OR 4 most recently pushed images", func() { 700 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 701 Delay: storageConstants.DefaultGCDelay, 702 ImageRetention: config.ImageRetention{ 703 Delay: storageConstants.DefaultRetentionDelay, 704 Policies: []config.RetentionPolicy{ 705 { 706 Repositories: []string{"**"}, 707 DeleteReferrers: true, 708 DeleteUntagged: &trueVal, 709 KeepTags: []config.KeepTagsPolicy{ 710 { 711 Patterns: []string{".*"}, 712 MostRecentlyPulledCount: 3, 713 MostRecentlyPushedCount: 4, 714 }, 715 }, 716 }, 717 }, 718 }, 719 }, audit, log) 720 721 err = gc.CleanRepo(ctx, "retention") 722 So(err, ShouldBeNil) 723 724 tags, err := imgStore.GetImageTags("retention") 725 So(err, ShouldBeNil) 726 727 So(tags, ShouldContain, "0.0.1") 728 So(tags, ShouldContain, "0.0.4") 729 So(tags, ShouldContain, "0.0.5") 730 So(tags, ShouldContain, "0.0.6") 731 732 So(tags, ShouldNotContain, "0.0.2") 733 So(tags, ShouldNotContain, "0.0.3") 734 }) 735 736 Convey("test if first match rule logic works", func() { 737 twoDays := 2 * 24 * time.Hour 738 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 739 Delay: storageConstants.DefaultGCDelay, 740 ImageRetention: config.ImageRetention{ 741 Delay: storageConstants.DefaultRetentionDelay, 742 Policies: []config.RetentionPolicy{ 743 { 744 Repositories: []string{"**"}, 745 DeleteReferrers: true, 746 DeleteUntagged: &trueVal, 747 KeepTags: []config.KeepTagsPolicy{ 748 { 749 Patterns: []string{"0.0.1"}, 750 }, 751 { 752 Patterns: []string{"0.0.2"}, 753 }, 754 { 755 Patterns: []string{".*"}, 756 PulledWithin: &twoDays, 757 }, 758 }, 759 }, 760 }, 761 }, 762 }, audit, log) 763 764 err = gc.CleanRepo(ctx, "retention") 765 So(err, ShouldBeNil) 766 767 tags, err := imgStore.GetImageTags("retention") 768 So(err, ShouldBeNil) 769 t.Log(tags) 770 So(tags, ShouldContain, "0.0.1") 771 So(tags, ShouldContain, "0.0.2") 772 So(tags, ShouldContain, "0.0.4") 773 774 So(tags, ShouldNotContain, "0.0.3") 775 So(tags, ShouldNotContain, "0.0.5") 776 So(tags, ShouldNotContain, "0.0.6") 777 }) 778 779 Convey("gc - do not match any repo", func() { 780 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 781 Delay: 1 * time.Millisecond, 782 ImageRetention: config.ImageRetention{ 783 Delay: 1 * time.Millisecond, 784 Policies: []config.RetentionPolicy{ 785 { 786 Repositories: []string{"no-match"}, 787 DeleteReferrers: true, 788 DeleteUntagged: &trueVal, 789 }, 790 }, 791 }, 792 }, audit, log) 793 794 err := gc.CleanRepo(ctx, "gc-test1") 795 So(err, ShouldBeNil) 796 797 _, _, _, err = imgStore.GetImageManifest("gc-test1", gcUntagged1.DigestStr()) 798 So(err, ShouldBeNil) 799 800 _, _, _, err = imgStore.GetImageManifest("gc-test1", ref1.DigestStr()) 801 So(err, ShouldBeNil) 802 803 _, _, _, err = imgStore.GetImageManifest("gc-test1", refOfRef1.DigestStr()) 804 So(err, ShouldBeNil) 805 806 repos, err := imgStore.GetRepositories() 807 So(err, ShouldBeNil) 808 So(repos, ShouldContain, "gc-test1") 809 So(repos, ShouldContain, "gc-test2") 810 So(repos, ShouldContain, "gc-test3") 811 So(repos, ShouldContain, "retention") 812 }) 813 814 Convey("remove one tag because it didn't match, preserve tags without statistics in metaDB", func() { 815 // add new tag in retention repo which can not be found in metaDB, should be always retained 816 err = WriteImageToFileSystem(CreateRandomImage(), "retention", "0.0.7", storeController) 817 So(err, ShouldBeNil) 818 819 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 820 Delay: storageConstants.DefaultGCDelay, 821 ImageRetention: config.ImageRetention{ 822 Delay: storageConstants.DefaultRetentionDelay, 823 Policies: []config.RetentionPolicy{ 824 { 825 Repositories: []string{"**"}, 826 DeleteReferrers: true, 827 DeleteUntagged: &trueVal, 828 KeepTags: []config.KeepTagsPolicy{ 829 { 830 Patterns: []string{"0.0.[1-5]"}, 831 }, 832 }, 833 }, 834 }, 835 }, 836 }, audit, log) 837 838 err = gc.CleanRepo(ctx, "retention") 839 So(err, ShouldBeNil) 840 841 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.1") 842 So(err, ShouldBeNil) 843 844 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.2") 845 So(err, ShouldBeNil) 846 847 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.3") 848 So(err, ShouldBeNil) 849 850 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.4") 851 So(err, ShouldBeNil) 852 853 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.5") 854 So(err, ShouldBeNil) 855 856 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.6") 857 So(err, ShouldNotBeNil) 858 859 _, _, _, err = imgStore.GetImageManifest("retention", "0.0.7") 860 So(err, ShouldBeNil) 861 }) 862 863 Convey("gc with context done", func() { 864 gc := gc.NewGarbageCollect(imgStore, metaDB, gc.Options{ 865 Delay: storageConstants.DefaultGCDelay, 866 ImageRetention: config.ImageRetention{ 867 Delay: 1 * time.Millisecond, 868 Policies: []config.RetentionPolicy{ 869 { 870 Repositories: []string{"**"}, 871 DeleteReferrers: true, 872 DeleteUntagged: &trueVal, 873 KeepTags: []config.KeepTagsPolicy{ 874 { 875 Patterns: []string{"0.0.*"}, 876 }, 877 }, 878 }, 879 }, 880 }, 881 }, audit, log) 882 883 ctx, cancel := context.WithCancel(ctx) 884 cancel() 885 886 err := gc.CleanRepo(ctx, "gc-test1") 887 So(err, ShouldNotBeNil) 888 }) 889 }) 890 }) 891 } 892 }