registry/docs/middleware/migration/enumerator.go
2016-09-28 14:25:04 -07:00

82 lines
2.8 KiB
Go

package migration
import (
"github.com/docker/distribution"
"github.com/docker/distribution/context"
"github.com/docker/distribution/reference"
"github.com/palantir/stacktrace"
log "github.com/Sirupsen/logrus"
)
type Enumerator interface {
EnumerateRepo(ctx context.Context, reg distribution.Namespace, repoName string) error
}
// NewEnumerator returns an enumerator which provides functions to iterate over
// a repository's tags, calling the given tagEnumerator function for each tag.
func NewEnumerator(onGetTag tagEnumerator) Enumerator {
return &enumerator{onGetTag}
}
// tagEnumerator is a function signature for handling a specific repository's tag
// on each tieration
type tagEnumerator func(ctx context.Context, repo distribution.Repository, tagName string, tag distribution.Descriptor) error
// enumerator handles iterating over a repository's tags, calling `onGetTag` on
// each tag
type enumerator struct {
onGetTag tagEnumerator
}
// EnumerateRepo iterates over a given repository's tags, calling `EnumerateTag`
// on each tag. The repository is specified as a string via the `repoName`
// argument.
// A context and registry (distribution.Namespace) must be supplied with valid,
// instantiated drivers.
func (e *enumerator) EnumerateRepo(ctx context.Context, reg distribution.Namespace, repoName string) error {
named, err := reference.ParseNamed(repoName)
if err != nil {
log.WithField("error", err).Errorf("failed to parse repo name %s", repoName)
return nil
}
repo, err := reg.Repository(ctx, named)
if err != nil {
log.WithField("error", err).Errorf("failed to construct repository %s", repoName)
return nil
}
// enumerate all repository tags
tags, err := repo.Tags(ctx).All(ctx)
if err != nil {
log.WithField("error", err).Errorf("failed to return all tags for repository %s", repoName)
return nil
}
for _, t := range tags {
if err = e.EnumerateTags(ctx, repo, t); err != nil {
log.WithField("error", err).Errorf("error processing tag during enumeration %s", t)
}
}
return nil
}
// EnumerateTags is called with a tag name as a string, loads the tag's
// descriptor and delegates to `enumerator.onGetTag` with the tag name
// and descriptor for further processing.
//
// This allows us to pass custom functions for migration and consistency
// checking whilst leveraging the same enumeration code.
func (e *enumerator) EnumerateTags(ctx context.Context, repo distribution.Repository, tagName string) error {
// TagService.All returns a slice of strings instead of a concrete
// distribution.Descriptor. Here we transform the tag name into a
// descriptor and call the supplied onGetTag function.
desc, err := repo.Tags(ctx).Get(ctx, tagName)
if err != nil {
return stacktrace.NewError("failed retrieving tag descriptor for tag %s: %s", tagName, err)
}
return e.onGetTag(ctx, repo, tagName, desc)
}