add support for repo deleted event also
by having another interface RepositoryRemover that is implemented by registry instance and is injected in app context for event tracking Signed-off-by: Manish Tomar <manish.tomar@docker.com>
This commit is contained in:
parent
0d8f4ac7b8
commit
328069bb4d
7 changed files with 76 additions and 7 deletions
|
@ -116,6 +116,13 @@ func (b *bridge) TagDeleted(repo reference.Named, tag string) error {
|
||||||
return b.sink.Write(*event)
|
return b.sink.Write(*event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *bridge) RepoDeleted(repo reference.Named) error {
|
||||||
|
event := b.createEvent(EventActionDelete)
|
||||||
|
event.Target.Repository = repo.Name()
|
||||||
|
|
||||||
|
return b.sink.Write(*event)
|
||||||
|
}
|
||||||
|
|
||||||
func (b *bridge) createManifestEventAndWrite(action string, repo reference.Named, sm distribution.Manifest) error {
|
func (b *bridge) createManifestEventAndWrite(action string, repo reference.Named, sm distribution.Manifest) error {
|
||||||
manifestEvent, err := b.createManifestEvent(action, repo, sm)
|
manifestEvent, err := b.createManifestEvent(action, repo, sm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -124,6 +124,18 @@ func TestEventBridgeTagDeleted(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEventBridgeRepoDeleted(t *testing.T) {
|
||||||
|
l := createTestEnv(t, testSinkFn(func(events ...Event) error {
|
||||||
|
checkDeleted(t, EventActionDelete, events...)
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
repoRef, _ := reference.WithName(repo)
|
||||||
|
if err := l.RepoDeleted(repoRef); err != nil {
|
||||||
|
t.Fatalf("unexpected error notifying repo deletion: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createTestEnv(t *testing.T, fn testSinkFn) Listener {
|
func createTestEnv(t *testing.T, fn testSinkFn) Listener {
|
||||||
pk, err := libtrust.GenerateECP256PrivateKey()
|
pk, err := libtrust.GenerateECP256PrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -26,9 +26,9 @@ type BlobListener interface {
|
||||||
BlobDeleted(repo reference.Named, desc digest.Digest) error
|
BlobDeleted(repo reference.Named, desc digest.Digest) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// RepoListener describes a listener that can respond to repository related events.
|
|
||||||
type RepoListener interface {
|
type RepoListener interface {
|
||||||
TagDeleted(repo reference.Named, tag string) error
|
TagDeleted(repo reference.Named, tag string) error
|
||||||
|
RepoDeleted(repo reference.Named) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listener combines all repository events into a single interface.
|
// Listener combines all repository events into a single interface.
|
||||||
|
@ -43,14 +43,30 @@ type repositoryListener struct {
|
||||||
listener Listener
|
listener Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type removerListener struct {
|
||||||
|
distribution.RepositoryRemover
|
||||||
|
listener Listener
|
||||||
|
}
|
||||||
|
|
||||||
// Listen dispatches events on the repository to the listener.
|
// Listen dispatches events on the repository to the listener.
|
||||||
func Listen(repo distribution.Repository, listener Listener) distribution.Repository {
|
func Listen(repo distribution.Repository, remover distribution.RepositoryRemover, listener Listener) (distribution.Repository, distribution.RepositoryRemover) {
|
||||||
return &repositoryListener{
|
return &repositoryListener{
|
||||||
Repository: repo,
|
Repository: repo,
|
||||||
listener: listener,
|
listener: listener,
|
||||||
|
}, &removerListener{
|
||||||
|
RepositoryRemover: remover,
|
||||||
|
listener: listener,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nl *removerListener) Remove(ctx context.Context, name reference.Named) error {
|
||||||
|
err := nl.RepositoryRemover.Remove(ctx, name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nl.listener.RepoDeleted(name)
|
||||||
|
}
|
||||||
|
|
||||||
func (rl *repositoryListener) Manifests(ctx context.Context, options ...distribution.ManifestServiceOption) (distribution.ManifestService, error) {
|
func (rl *repositoryListener) Manifests(ctx context.Context, options ...distribution.ManifestServiceOption) (distribution.ManifestService, error) {
|
||||||
manifests, err := rl.Repository.Manifests(ctx, options...)
|
manifests, err := rl.Repository.Manifests(ctx, options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -38,10 +38,15 @@ func TestListener(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error getting repo: %v", err)
|
t.Fatalf("unexpected error getting repo: %v", err)
|
||||||
}
|
}
|
||||||
repository = Listen(repository, tl)
|
|
||||||
|
remover, ok := registry.(distribution.RepositoryRemover)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("registry does not implement RepositoryRemover")
|
||||||
|
}
|
||||||
|
repository, remover = Listen(repository, remover, tl)
|
||||||
|
|
||||||
// Now take the registry through a number of operations
|
// Now take the registry through a number of operations
|
||||||
checkExerciseRepository(t, repository)
|
checkExerciseRepository(t, repository, remover)
|
||||||
|
|
||||||
expectedOps := map[string]int{
|
expectedOps := map[string]int{
|
||||||
"manifest:push": 1,
|
"manifest:push": 1,
|
||||||
|
@ -51,6 +56,7 @@ func TestListener(t *testing.T) {
|
||||||
"layer:pull": 2,
|
"layer:pull": 2,
|
||||||
"layer:delete": 2,
|
"layer:delete": 2,
|
||||||
"tag:delete": 1,
|
"tag:delete": 1,
|
||||||
|
"repo:delete": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(tl.ops, expectedOps) {
|
if !reflect.DeepEqual(tl.ops, expectedOps) {
|
||||||
|
@ -102,9 +108,14 @@ func (tl *testListener) TagDeleted(repo reference.Named, tag string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tl *testListener) RepoDeleted(repo reference.Named) error {
|
||||||
|
tl.ops["repo:delete"]++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// checkExerciseRegistry takes the registry through all of its operations,
|
// checkExerciseRegistry takes the registry through all of its operations,
|
||||||
// carrying out generic checks.
|
// carrying out generic checks.
|
||||||
func checkExerciseRepository(t *testing.T, repository distribution.Repository) {
|
func checkExerciseRepository(t *testing.T, repository distribution.Repository, remover distribution.RepositoryRemover) {
|
||||||
// TODO(stevvooe): This would be a nice testutil function. Basically, it
|
// TODO(stevvooe): This would be a nice testutil function. Basically, it
|
||||||
// takes the registry through a common set of operations. This could be
|
// takes the registry through a common set of operations. This could be
|
||||||
// used to make cross-cutting updates by changing internals that affect
|
// used to make cross-cutting updates by changing internals that affect
|
||||||
|
@ -210,4 +221,9 @@ func checkExerciseRepository(t *testing.T, repository distribution.Repository) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error deleting tag: %v", err)
|
t.Fatalf("unexpected error deleting tag: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = remover.Remove(ctx, repository.Named())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error deleting repo: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,11 @@ type RepositoryEnumerator interface {
|
||||||
Enumerate(ctx context.Context, ingester func(string) error) error
|
Enumerate(ctx context.Context, ingester func(string) error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepositoryRemover removes given repository
|
||||||
|
type RepositoryRemover interface {
|
||||||
|
Remove(ctx context.Context, name reference.Named) error
|
||||||
|
}
|
||||||
|
|
||||||
// ManifestServiceOption is a function argument for Manifest Service methods
|
// ManifestServiceOption is a function argument for Manifest Service methods
|
||||||
type ManifestServiceOption interface {
|
type ManifestServiceOption interface {
|
||||||
Apply(ManifestService) error
|
Apply(ManifestService) error
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/storage/driver"
|
"github.com/docker/distribution/registry/storage/driver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -70,6 +71,16 @@ func (reg *registry) Enumerate(ctx context.Context, ingester func(string) error)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove removes a repository from storage
|
||||||
|
func (r *registry) Remove(ctx context.Context, name reference.Named) error {
|
||||||
|
root, err := pathFor(repositoriesRootPathSpec{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
repoDir := path.Join(root, name.Name())
|
||||||
|
return r.driver.Delete(ctx, repoDir)
|
||||||
|
}
|
||||||
|
|
||||||
// lessPath returns true if one path a is less than path b.
|
// lessPath returns true if one path a is less than path b.
|
||||||
//
|
//
|
||||||
// A component-wise comparison is done, rather than the lexical comparison of
|
// A component-wise comparison is done, rather than the lexical comparison of
|
||||||
|
|
|
@ -23,6 +23,7 @@ type registry struct {
|
||||||
schema1SigningKey libtrust.PrivateKey
|
schema1SigningKey libtrust.PrivateKey
|
||||||
blobDescriptorServiceFactory distribution.BlobDescriptorServiceFactory
|
blobDescriptorServiceFactory distribution.BlobDescriptorServiceFactory
|
||||||
manifestURLs manifestURLs
|
manifestURLs manifestURLs
|
||||||
|
driver storagedriver.StorageDriver
|
||||||
}
|
}
|
||||||
|
|
||||||
// manifestURLs holds regular expressions for controlling manifest URL whitelisting
|
// manifestURLs holds regular expressions for controlling manifest URL whitelisting
|
||||||
|
@ -133,6 +134,7 @@ func NewRegistry(ctx context.Context, driver storagedriver.StorageDriver, option
|
||||||
},
|
},
|
||||||
statter: statter,
|
statter: statter,
|
||||||
resumableDigestEnabled: true,
|
resumableDigestEnabled: true,
|
||||||
|
driver: driver,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
|
|
Loading…
Reference in a new issue