Add a --dry-run flag. If enabled this will print the mark and sweep process

with removing any files.

Signed-off-by: Richard Scothern <richard.scothern@gmail.com>
This commit is contained in:
Richard Scothern 2016-03-23 16:42:50 -07:00
parent 2f2875e8db
commit 15e3ffb3f2
2 changed files with 28 additions and 10 deletions

View file

@ -13,12 +13,16 @@ import (
"github.com/docker/distribution/registry/storage" "github.com/docker/distribution/registry/storage"
"github.com/docker/distribution/registry/storage/driver" "github.com/docker/distribution/registry/storage/driver"
"github.com/docker/distribution/registry/storage/driver/factory" "github.com/docker/distribution/registry/storage/driver/factory"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func emit(ctx context.Context, s string) {
if dryRun {
context.GetLogger(ctx).Infof("gc: %s", s)
}
}
func markAndSweep(ctx context.Context, storageDriver driver.StorageDriver) error { func markAndSweep(ctx context.Context, storageDriver driver.StorageDriver) error {
// Construct a registry
registry, err := storage.NewRegistry(ctx, storageDriver) registry, err := storage.NewRegistry(ctx, storageDriver)
if err != nil { if err != nil {
return fmt.Errorf("failed to construct registry: %v", err) return fmt.Errorf("failed to construct registry: %v", err)
@ -32,6 +36,8 @@ func markAndSweep(ctx context.Context, storageDriver driver.StorageDriver) error
// mark // mark
markSet := make(map[digest.Digest]struct{}) markSet := make(map[digest.Digest]struct{})
err = repositoryEnumerator.Enumerate(ctx, func(repoName string) error { err = repositoryEnumerator.Enumerate(ctx, func(repoName string) error {
emit(ctx, fmt.Sprint(repoName))
var err error var err error
named, err := reference.ParseNamed(repoName) named, err := reference.ParseNamed(repoName)
if err != nil { if err != nil {
@ -53,7 +59,8 @@ func markAndSweep(ctx context.Context, storageDriver driver.StorageDriver) error
} }
err = manifestEnumerator.Enumerate(ctx, func(dgst digest.Digest) error { err = manifestEnumerator.Enumerate(ctx, func(dgst digest.Digest) error {
// Mark the manifest's blob // Mark the manifest's blo
emit(ctx, fmt.Sprintf("%s: adding manifest %s ", repoName, dgst))
markSet[dgst] = struct{}{} markSet[dgst] = struct{}{}
manifest, err := manifestService.Get(ctx, dgst) manifest, err := manifestService.Get(ctx, dgst)
@ -64,6 +71,7 @@ func markAndSweep(ctx context.Context, storageDriver driver.StorageDriver) error
descriptors := manifest.References() descriptors := manifest.References()
for _, descriptor := range descriptors { for _, descriptor := range descriptors {
markSet[descriptor.Digest] = struct{}{} markSet[descriptor.Digest] = struct{}{}
emit(ctx, fmt.Sprintf("%s: marking blob %v", repoName, descriptor))
} }
switch manifest.(type) { switch manifest.(type) {
@ -77,11 +85,13 @@ func markAndSweep(ctx context.Context, storageDriver driver.StorageDriver) error
return fmt.Errorf("failed to get signatures for signed manifest: %v", err) return fmt.Errorf("failed to get signatures for signed manifest: %v", err)
} }
for _, signatureDigest := range signatures { for _, signatureDigest := range signatures {
emit(ctx, fmt.Sprintf("%s: marking signature %s", repoName, signatureDigest))
markSet[signatureDigest] = struct{}{} markSet[signatureDigest] = struct{}{}
} }
break break
case *schema2.DeserializedManifest: case *schema2.DeserializedManifest:
config := manifest.(*schema2.DeserializedManifest).Config config := manifest.(*schema2.DeserializedManifest).Config
emit(ctx, fmt.Sprintf("%s: marking configuration %s", repoName, config.Digest))
markSet[config.Digest] = struct{}{} markSet[config.Digest] = struct{}{}
break break
} }
@ -113,6 +123,10 @@ func markAndSweep(ctx context.Context, storageDriver driver.StorageDriver) error
// Construct vacuum // Construct vacuum
vacuum := storage.NewVacuum(ctx, storageDriver) vacuum := storage.NewVacuum(ctx, storageDriver)
for dgst := range deleteSet { for dgst := range deleteSet {
if dryRun {
emit(ctx, fmt.Sprintf("deleting %s", dgst))
continue
}
err = vacuum.RemoveBlob(string(dgst)) err = vacuum.RemoveBlob(string(dgst))
if err != nil { if err != nil {
return fmt.Errorf("failed to delete blob %s: %v\n", dgst, err) return fmt.Errorf("failed to delete blob %s: %v\n", dgst, err)
@ -122,13 +136,18 @@ func markAndSweep(ctx context.Context, storageDriver driver.StorageDriver) error
return err return err
} }
func init() {
GCCmd.Flags().BoolVarP(&dryRun, "dry-run", "d", false, "do everything expect remove the blobs")
}
var dryRun bool
// GCCmd is the cobra command that corresponds to the garbage-collect subcommand // GCCmd is the cobra command that corresponds to the garbage-collect subcommand
var GCCmd = &cobra.Command{ var GCCmd = &cobra.Command{
Use: "garbage-collect <config>", Use: "garbage-collect <config>",
Short: "`garbage-collects` deletes layers not referenced by any manifests", Short: "`garbage-collect` deletes layers not referenced by any manifests",
Long: "`garbage-collects` deletes layers not referenced by any manifests", Long: "`garbage-collect` deletes layers not referenced by any manifests",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
config, err := resolveConfiguration(args) config, err := resolveConfiguration(args)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "configuration error: %v\n", err) fmt.Fprintf(os.Stderr, "configuration error: %v\n", err)

View file

@ -161,16 +161,15 @@ func (ms *manifestStore) GetSignatures(ctx context.Context, manifestDigest diges
return nil, err return nil, err
} }
signaturesPath = path.Join(signaturesPath, "sha256") alg := string(digest.SHA256)
signaturePaths, err := ms.blobStore.driver.List(ctx, path.Join(signaturesPath, alg))
signaturePaths, err := ms.blobStore.driver.List(ctx, signaturesPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var digests []digest.Digest var digests []digest.Digest
for _, sigPath := range signaturePaths { for _, sigPath := range signaturePaths {
sigdigest, err := digest.ParseDigest("sha256:" + path.Base(sigPath)) sigdigest, err := digest.ParseDigest(alg + ":" + path.Base(sigPath))
if err != nil { if err != nil {
// merely found not a digest // merely found not a digest
continue continue